8000 GitHub - aq2bq/hergy: A small CLI for running agent teams on herdr, with roles and rules in YAML and project context in gy. · GitHub
[go: up one dir, main page]

Skip to content
aq2bqPublic

About

A small CLI for running agent teams on herdr, with roles and rules in YAML and project context in gy.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

hergy

English | 日本語

Note

hergy is an experimental project. How you use it may change significantly for a while, and compatibility is not promised yet.

hergy is a small CLI, built on herdr and gy, for getting through highly uncertain work with a team of AI agents.

hergy is for people who want to build things with a team of AI agents, with as little effort as possible. Write in YAML who runs in which role on which model, and hergy brings the whole team up on herdr at once.

What hergy does, and what it doesn't

hergy only manages and runs the team's makeup and its rules. The AI agent harnesses that vendors provide, such as Claude Code, Codex and OpenCode, are used as they are. Coordination between agents, status checks and startup are left to herdr as they are. Needs, questions, requirements, acceptance criteria, decisions and the like that come up during a session are all recorded in gy and used from there.

For now, hergy aims to make putting a team together easy, by managing and running the roles and rules you set for your team as files.

Install

go install github.com/aq2bq/hergy@latest

# optional: install the hergy skill, so an AI agent can read it
npx skills add aq2bq/hergy

You also need herdr and the agent CLIs you use (claude, codex, opencode and so on).

Telling the AI about hergy

Put a sentence like the following in a prompt or in AGENTS.md / CLAUDE.md so it gets across, and the AI agent reads the hergy skill before it starts or joins a team.

When you start or close a hergy team, write a hergy team definition, or work inside a team hergy started, read the hergy skill.

Getting started

Write out a starter team of two, a lead and a worker.

hergy new myteam        # writes into the project's .hergy/ inside a git repository, into ~/.config/hergy/ outside one

You get the team's team.yaml and agreement.md (its agreements). The members' roles and profile are picked from what the project or the global settings already hold: a role document or a profile that is there is not written again. Only when neither place holds a role document does hergy new write roles/lead.md and roles/builder.md, and only when neither defines a profile does it write claude-default into profiles.yaml. Otherwise it names the roles and profiles to write in team.yaml, and hergy validate is the next step. Role and team rules are complete Markdown documents. Their saved text reaches the agent unchanged. The first line supplies the roster title. The team screen edits the team's rules and shared roles side by side; every document has one full-text field and a 1,200-character warning budget. See migration for old YAML settings.

In the team screen’s rules tab, switch to headings and use a heading’s ⋯ menu to choose another team or role, an insertion position, and whether to include child headings. Drag the grip to another column to move; hold Alt (⌥ on Mac) when dropping to copy, or Shift (⇧ on Mac) when starting the drag to include children. The selected text stays unchanged; a missing blank line at the insertion boundary is supplied. Review the drafts and undo before saving. Moves save the destination first; if saving the source fails, the screen says the text remains in both files. Select a document by its name to read and edit it. The rules tab opens with every document of the definition (the team rules and the role documents its members use) side by side at the standard reading width of about 40 Japanese characters per line in 16px text; the role screen uses the same standard width. Use 並べる to choose again which documents stand together, or すべて表示 to bring them all back. Switching documents preserves unsaved edits; each document keeps its own save target. Use Narrow or Wide in a column header, and Equal to reset the widths. Wide expands the selected document beyond the standard reading width. Apart from a column narrowed on purpose, no column is narrower than the standard reading width, and a wide column grows at twice the rate of the others; the board has its own horizontal scrollbar and an explanation when documents do not fit. At narrower widths, two selected documents are stacked. All four screens use the available width for the header and content, with no width limit and at least 40px of space on each side. Below 420px, each side uses at least 16px to leave more room for the content. At 420px and above, the header stays aligned when switching screens. Narrower screens do not reserve space for a scrollbar, so the right side of the header may move when the page length changes. With no focus in an input, the wheel over it scrolls the page; to read inside an input, press it once and then turn the wheel. Ctrl (⌘ on a Mac) with the wheel and pinch stay with the browser's zoom. Switching the display, re-reading, filtering or changing the theme never moves the page; only an act that names its destination (editing the selected attributes, a waiting row, opening a row from a URL) or one whose result would stand off the screen (copy, a new row, a duplicate) brings that destination into view.

Choose Light, Dark, or Follow OS at the top right. The preference stays in the same browser for the same host and port, across all four screens and projects. Different hostnames (including localhost versus 127.0.0.1), ports, and browsers do not share it. If browser storage cannot be read or written, the screens follow the OS and explain why. No hergy configuration file is changed.

Run it in a herdr shell pane.

hergy up myteam --dry   # check each member's prompt and the files it reads, without starting
hergy up myteam         # start

The members run in herdr as myteam-lead and myteam-builder: the team name is added to each member name for you (see below).

Lost, type hergy cheat for a short cheatsheet (hergy cheat --ai prints the whole shape for an agent). hergy <command> --help prints one command's flags, each with what it means for that command; hergy new --help says where it writes.

In the topology editor, selecting a member and opening プロンプト in the attribute panel shows the current topology text under Roster, Contact, Turn recipients, and Adding workers (when present), without rule bodies. The “全文と差分を読む” button opens the recorded body, current text, and their full line diff. No text is folded. Opening the diff shows how many lines were added and removed, and 「最初の差へ」 moves to the first difference in one step; opening the diff does not scroll by itself. Text labels distinguish topology origins from role and team rules in current text and unchanged or added diff lines. Removed lines and the recorded body have no origin metadata and remain unmarked. The four topology sections are drawn as one band from the heading to the end of the section. A heading that comes from the template stands inside the band and carries no origin label. The recorded body shows the operation and time; it excludes the change-reason preamble added by apply or reprompt and is not a receipt. Current text includes unsaved topology edits. A stopped member or missing record shows the reason and current text only. The panel does not save or send prompts. The text is built with the name of a team running from this definition when one is running, and with the definition's name otherwise; the panel also says which name it used. When the running team's name cannot be used, the text falls back to the definition's name and the reason is shown.After a start, a stop, or a change of aliases, the column's text and its note match within the ten-second reading without pressing anything. A worker's preview also includes unsaved edits and the running team's name.

Commands

Command What it does
hergy new <definition> Write out a starter team definition of two, a lead and a worker; roles and profiles either place already holds are picked, not written
hergy up [definition] Start a team from a team definition, named by --as (the definition name by default). --dry prints the plan (each member's prompt as text) without touching herdr; --json prints the plan as JSON instead
hergy down [team] / hergy down [worker] Close the panes hergy named for the team's members and hired workers, including panes whose agents have stopped. A name that is not a running team is looked for as a worker of one (short or herdr name), and only that worker's pane is closed; its own tab goes when that pane was the last one in it. After closing a team's panes, down waits up to 30000 ms in total for herdr to forget their names. A timeout fails and lists the remaining names. From a team pane, it waits for the other names before closing your own pane last; your own name cannot be awaited. On timeout it keeps your own pane open: run hergy down again after the names disappear. --dry never waits. For a team, the CLI lists remaining worktrees and clears its turn record even on a name-release timeout, before returning failure. Other errors stop before this cleanup. After closing, down lists the git worktrees that came while the team was running (after the worker was hired, for one worker), other than the project root, with their branch, uncommitted changes and commits not in main, and the project's stashes, with the commands that remove them — the time comes from the launch record, a worktree a closed pane stood in is marked, hergy removes nothing, and temporary documents are not listed. --dry prints what would close; a team's tab is never closed as a unit
hergy status [team] With a team name: one line per member and per worker, the live agent_status (working/idle/done/blocked), or not present when the member is not live; a worker carries (worker). Then who is waiting on the human (blocked), or that nobody is working. With no team name: every running team, with its team definition, its counts and the same judgement. Reads herdr only
hergy apply [<member>…] Compare the saved definition with the running teams and apply each member's drift: send its prompt again when the prompt changed (the conversation stays), start a member no agent is live for, or restart a member whose profile changed (the conversation goes). With no member named, every member with drift is applied. A member that is working or waiting for permission is left, with the reason, and the rest go on; the command answers 1 while one is left. --dry prints each member's way of applying, what changed and the team's own notes, and changes nothing
hergy refresh <member> / --all Restart each selected member of a running team: end its agent and start it again in the same pane, so its conversation starts empty. A member that is not live is started again in the pane hergy named after it, when that pane is still at its shell (a pane that is busy is an error, pointing at down then up). A member with no pane is refused, and hergy apply is named: adding a member to a running team is the apply's road. The team definition is read again, so an edited profile (its kind, args and prompt) takes effect (env is the exception; see below). A member cannot refresh itself: run it from another pane, or as the human
hergy reprompt <member> / --all Re-send the bootstrap prompt to waiting members, keeping each conversation. When the launch record shows that the definition changed, the prompt is headed with what changed and with the words that make it the new bootstrap prompt
hergy hire <name> --purpose X --task "…" [--from <member>] Start a worker in its own tab (labelled worker:<team>/<name>) and hand it a task (mostly used by members). --purpose must be a purpose the hiring member's workers: names, and the profile comes from that entry; anything else is refused, naming the purposes the member may hire for. --from may be left out when exactly one member hires for that purpose
hergy ls List the available team definitions and the running team names each one booted
hergy show <definition> Print the final team definition and which file each value came from
hergy migrate [--dry] [--global] Migrate legacy YAML definitions to Markdown rules explicitly, retaining adjacent backups; dry-run checks every target without wr 8000 iting
hergy validate Check every settings file and show each broken one. A team definition is checked once and a role document once (not once per team that uses it); it then prints the size of each team definition's rules and templates and of each role document, warning when one is over the provisional budget (1,200 characters each); a warning does not change the exit code
hergy serve Serve Activity, Team definitions (including prompt comparison), Roles and Profiles on 127.0.0.1. Print the URL and open the browser; --no-open skips opening it. --port selects the port (8787 by default; 0 chooses an available port). Ctrl-C waits for active responses and stops the server.
hergy version Print the commit and time of the installed hergy
hergy cheat Print a short cheatsheet. --ai prints the whole shape for an agent, in English, without reading any settings

Common options: -C <dir> (pick the project), --lang ja (the command line's output in Japanese; English by default; the WebUI that serve opens is Japanese whatever this says), --json (with --dry, print the plan as JSON instead of text). apply, refresh, reprompt and hire take --team to pick the team by team name, and apply and refresh also take --timeout. up takes --as <team> to run the same team definition under a different team name (see below).

hergy apply is the one operation for a change to a running team: hergy compares the saved definition with the prompt each member last read, decides the way for each member (send the prompt again, start it, restart it, or say it cannot be applied), and a person only picks whom to apply. The command line names the members (or applies every member with drift); the screens read the same plan at GET /api/apply and apply it with POST /api/apply. reprompt and refresh stay as the single-purpose tools: reprompt sends the prompt again (with a preamble saying what changed), and refresh restarts a member (for one that is stuck). env is fixed when the pane is made, so after editing env run hergy down then hergy up; apply says so and does not restart the member.

hergy serve shows the same settings in a browser, read the same way. It prints the URL and opens it in the default browser of this machine; --no-open prints the URL and opens nothing, and a browser that cannot be started is one line on stderr, with the URL to open by hand. It is for this machine only: it listens on 127.0.0.1, refuses a request that was not addressed to its own name, and takes a write only as a POST that carries a token which the running process and the pages it rendered know. It changes no file that a screen does not edit: a role document, the two profiles.yaml files, a team definition's two files, and the projects: list of the global config.yaml.

hergy serve is a headquarters for the projects you list: list them under projects: in the global config.yaml (absolute paths, or ~/…), and every listed project's teams, roles and profiles show, each with the project it belongs to, wherever hergy serve is started. Without projects: it shows the project it was started in and the global settings, as before. The sheet that Projects at the top of the screen opens lists and unlists projects (unlisting changes no file of that project; its 取り消す puts the project back at the position it stood in config.yaml, comments and all), and a team definition's 動き column starts and stops a listed project's team: its start button reads このプロジェクトで起動する for the project's definition and プロジェクトを選んで起動する for a global one, and the sheet it opens takes a team name (empty for the team definition's name, the same as hergy up --as) and a herdr workspace (one team to a workspace), with the same result as hergy up and hergy down. The band says 反映していない変更 N when a running team differs from its saved definition; the press opens the apply sheet, which shows each member's way of applying, what changed, and whether the conversation goes, and applies the members a person ticks, with the same result as hergy apply. The sheet shows the progress and any question the agent asks while a member starts. A running team is found even when no agent runs in it: a tab labelled with the team's name that holds an agent, or a pane named <team>-<member>, is that team. The activity screen at /activity shows waiting and stalled rows above one tile per running team. Each tile includes its diagram and member and worker counts, and links to the team definition and the apply sheet, and asks before a stop in a confirmation dialog that names the panes it closes (the stop sheet waits up to 30000 ms for herdr to release the closed names, then shows success or the remaining names on timeout; if serve runs in a team pane, that pane stays open on timeout). Deleting a team definition, a role or a profile, discarding a new row with input, stopping a team, and leaving a screen or a role edit with unsaved changes ask in one shared dialog: its body names what goes (the files and folder, what stays in the folder, the panes that close, the people who read a role, the fields a draft loses), and only its own 削除する / 終了する / 破棄する press runs it. A team.yaml, role document or profiles.yaml that cannot be read stays in its list as one row that says why, and the band counts that row. The REST API under /api/hq/ answers the same reading. 元に戻す on an unsaved edit goes at once and shows 取り消す in place; 取り消す brings the discarded edit and the unsaved mark back. The figure's 外す of a member, a turn or a worker, the conflict's 元に戻す and the [プロジェクト] sheet's 外す also show 取り消す where the person pressed, and ⌘Z in the figure takes back the newest operation too.

Where team definitions and settings live

Where Location
Outside the project $XDG_CONFIG_HOME/hergy/ (~/.config/hergy/ when unset)
The project <project>/.hergy/
  • A team definition lives in teams/<definition>/team.yaml. When a name is in both places, the project's one wins
  • profiles.yaml and the global config.yaml are settings files. profiles.yaml can be in both places: a team definition in the project reads the project's over the one outside it (the project's wins for the same name); a definition outside reads only the one outside
  • Put version: 1 and lang: ja in the global config.yaml to get Japanese without --lang; hergy new writes it, with the language that run showed, when it is missing, and leaves it alone when it is there
  • projects: in the global config.yaml is the headquarters' list: absolute paths or ~/… paths, expanded when read. Without the key, hergy serve shows the project it was started in; with an empty list, only the global settings. A relative path is a broken setting, and hergy validate and hergy serve say so
  • hergy up <definition> --dry shows each member's prompt and the files it read

A team definition (team.yaml)

version: 1              # required
description: "which case this team is meant for"  # required; one line, read where a person picks or reads a definition (the team list, a definition's screen, the start sheet, hergy show)
team: myteam            # optional; if written it must match the team definition name (teams/<definition>/)
cwd: .                  # working directory (relative to the project root)
                        # no key points at the documents: teams/<definition>/agreement.md
                        # (this team) and roles/<role>.md are read (the project's .hergy/
                        # first, then ~/.config/hergy/)
prompt: "…"             # bootstrap prompt template (optional); it must keep %{role_doc} and %{docs}
members:
  - name: lead            # the member name (short); the herdr name becomes "<team>-lead"
    role: lead          # reads roles/lead.md
    profile: opus       # a named profile from profiles.yaml; kind, args and env are written there, not here
workers:                # purpose-to-profile pairs a member may hire for (written into the prompt, not enforced)
  - from: lead          # the member that may hire this worker
    purpose: research   # what the worker is for
    profile: opus       # the profile that worker runs
turns:                  # who hands the turn to whom (the human is written "human")
  - human -> lead
  - lead -> human

Running one team definition as more than one team

--as <team> boots the same team definition under a different team name, so you can run two teams side by side from one team.yaml. Without --as, the team name is the team definition name (the directory name under teams/).

Write each members[].name as a short member name (lead, builder). hergy adds the team name when it boots the team, so the herdr name is <team>-<member>: the demo definition gives demo-lead and demo-builder, and --as dev2 gives dev2-lead and dev2-builder. Because hergy adds the team name for you, two team definitions that both name a member lead never collide in herdr. A member name that still contains %{team} is refused: that placeholder is no longer used in names.

The team name must match [a-z][a-z0-9_-]{0,24}, and the resulting <team>-<member> must match [a-z][a-z0-9_-]{0,31}. hergy reads live teams from herdr and finds their definitions in the launch record; each team's tab is labelled with its team name, so down, apply, refresh, reprompt and hire all point at a running team by its team name. The members on the command line (apply <member>, refresh <member>, reprompt <member>, hire --from <member>) are the short member names:

hergy up demo --as alpha            # boot the demo definition as the team "alpha"
hergy up demo --as beta             # and once more as "beta"
hergy apply --team alpha            # apply alpha's drift, showing what changed
hergy reprompt lead --team alpha    # re-send the prompt to alpha's lead, keeping its conversation
hergy down alpha                    # close alpha's members and hired workers only
hergy down alpha-bench              # close the worker alpha-bench alone

profiles.yaml

version: 1
profiles:
  opus:
    kind: claude                          # herdr's agent kind
    args: ["--model", "claude-opus-5-5"]  # passed to the agent CLI as is
  dev:
    kind: opencode
    env:                                  # environment variables for the pane
      OPENCODE_CONFIG_CONTENT: '{"model":"…"}'

Bootstrap prompt placeholders

Placeholder Content
%{team} / %{role} / %{name} Team name, role, herdr name ("<team>-<member>")
%{role_doc} The role document
%{docs} The docs documents
%{roster} The roster
%{herdr} How to check whether the agent is running inside herdr, reach others, and add a teammate (hergy hire, not herdr agent start)
%{turns} Who the member hands the turn to, from the definition's turns:
%{workers} What the member may hire, and the command (only for members workers: names one for)

The default template is provisional.

What's next

  • Show which member holds the turn (hergy turn)
  • A fixed shape and a record for messages between members (hergy pass, hergy log)
  • List the rules, and take one out to compare (hergy rules)
  • Receive questions for the human, give instructions by role name (hergy ask, hergy tell)
  • Validate the settings (hergy validate)
  • Promote and migrate settings (hergy promote, migrate)
  • Nested teams, a TUI

Contributing

Before you send a change, run go run ./tools/check diff once. It runs the quick checks for the changes since the upstream, in about a minute, and names the browser walks the change selects (go run ./tools/check e2e tests/<name>.spec.ts runs those alone). CI runs every quality gate on every push, the browser walks and the race detector among them. After fixing a failed gate, rerun that gate only, unless the fix affects other gates. go run ./tools/check -h lists the checks.

License

MIT

About

A small CLI for running agent teams on herdr, with roles and rules in YAML and project context in gy.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0