Inside an argus sandbox (cwd under ~/.argus/worktrees/ or ARGUS_TASK_ID set), coordinate multi-agent work via hera's mcp__argus__hera_* tools — bootstrap an orchestrator, claim or attach a worker/freelance role, spawn workers, and message roles over the idle-gated bus. Load this skill when you are (or are becoming) a coordinator, when you're spawned as a hera worker, or before delegating work that must run as its OWN argus session (separate worktree / long-running agent / own PR / own sandbox) — as opposed to in-process Claude sub-agents, which stay the right tool for ephemeral in-session fan-out. For staged or dependency-ordered multi-worker plans, this skill routes you to the companion `hera-plan` skill. NOT for non-argus sessions, where these MCP tools are not registered.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Inside an argus sandbox (cwd under ~/.argus/worktrees/ or ARGUS_TASK_ID set), coordinate multi-agent work via hera's mcp__argus__hera_* tools — bootstrap an orchestrator, claim or attach a worker/freelance role, spawn workers, and message roles over the idle-gated bus. Load this skill when you are (or are becoming) a coordinator, when you're spawned as a hera worker, or before delegating work that must run as its OWN argus session (separate worktree / long-running agent / own PR / own sandbox) — as opposed to in-process Claude sub-agents, which stay the right tool for ephemeral in-session fan-out. For staged or dependency-ordered multi-worker plans, this skill routes you to the companion `hera-plan` skill. NOT for non-argus sessions, where these MCP tools are not registered.
Hera is argus's native, in-tree layer for running a team of agents. It is not a separate
daemon or plugin — coordination runs in-process in the argus daemon, the rail/tree render directly
in the TUI's second tab, and agents drive it entirely through the mcp__argus__hera_* MCP
tools. State lives in the same ~/.argus/data.sql (the hera_* tables). You never touch the
plumbing; you call the tools.
1. When this applies (and when it does NOT)
This skill applies only inside an argus task sandbox. You are in one if either holds:
ARGUS_TASK_ID is set, or
the current working directory is under ~/.argus/worktrees/.
If neither holds, stop. The mcp__argus__hera_* tools are not registered in this session — there
is no CLI fallback and nothing below applies.
Every hera tool takes cwd — always pass cwd=$PWD. That is how hera resolves which argus task
(and therefore which role) this session is. There is no separate "auth" or session handle.
2. The role model
Orchestrator — a named coordination graph (one per project / feature / wave). Roles live under
it. Created by hera_new_orchestrator (idempotent by name).
Coordinator role — the orchestrator's driver. Created by hera_new_orchestrator. Talks to the
human in its own agent pane; talks to other roles via hera_send. Folded into the rail's
orchestrator header (it is not a separate row).
Worker role — does the actual work. Normally born-bound: spawned by a coordinator with
hera_spawn_worker, which creates the argus task (worktree + session) AND the role + binding in one
transaction. A born-bound worker does not need to hera_join — its session opens already bound.
Freelance role — a helper that attaches itself to an existing orchestrator on its own
initiative (no coordinator spawned it). Created via hera_join attach mode with kind=freelance.
Binding — the live link between this argus task and one role. Invariants:
One live binding per (task, orchestrator) — enforced by a partial unique index.
A task MAY hold several live bindings at once — one per orchestrator (e.g. a worker in A that
promotes itself to coordinator of nested orchestrator B). When a task holds 2+ live bindings,
you must pass orchestrator=<name> to every tool so hera knows which role you are acting as;
omitting it returns an ambiguity error listing your options.
3. The coordination tools
All take cwd. orchestrator is optional with exactly one live binding and required with 2+.
Arg names below are exact — do not invent others. These ten cover bootstrap, messaging, status, and
completion; the plan-DAG authoring/mutation tools live in the companion hera-plan skill (pointer at
the end of this section).
Bootstrap / join
hera_new_orchestrator(cwd, name, coordinator_role_name, [prompt]) — "I am the coordinator."
Creates (or fetches, idempotent-by-name) the orchestrator, creates the named coordinator role, and
binds this task to it. Returns the orchestrator name, role name, binding_id, and argus task id.
Rejects if this task already holds a live binding under that orchestrator (use hera_join to
retrieve it). The canonical "become an orchestrator" entry point — don't hera_join first; there is
nothing to join yet.
hera_join(cwd, [orchestrator], [role_name], [kind], [prompt], [status]) — two modes:
Claim mode (role_name omitted) — retrieves this task's existing live binding + role and its
unread message count. Use right after a born-bound worker terminal opens to read your assigned
role/mission. Pass orchestrator= if the task has 2+ bindings. Claim mode does not consume the
inbox.
Attach mode (role_name + kind supplied) — creates a new role under an existing
orchestrator (orchestrator required) and binds this task to it. kind must be worker or
freelance (coordinator is rejected — use hera_new_orchestrator). Optional prompt (stored on
the role) and status (idle/working/blocked/done). Use to join a team nobody spawned you
into.
hera_spawn_worker(cwd, prompt, [orchestrator], [role_name], [project], [branch], [backend], [model])
— spawn a new born-bound worker task + session under the caller's orchestrator. Caller must hold
a live coordinator binding. Creates an argus task (worktree + session) and, transactionally, a worker
role + binding pre-bound to it; an orientation prefix naming the coordinator + orchestrator is prepended
to the prompt automatically. Args:
prompt (required) — the worker's MISSION/task only. The verbatim prompt is also stored on the
role row and shown as the node's description in the plan-DAG view. Do NOT prepend the org/security
policy — see the mission-only gotcha in §6.
project — defaults to the coordinator's own task project (authoritative, not role.ArgusProject).
branch — base branch passed to argus task creation. Defaults to the project default — see the
base-branch gotcha in §6.
backend — defaults to project default.
model — per-worker model override, scoped to the worker's resolved backend (claude: opus/sonnet/
haiku; codex: e.g. gpt-5; pi: its ids). Empty = backend default. Match it to task complexity.
role_name — derived from a prompt slug if omitted; uniquified within the orchestrator.
orchestrator — disambiguates when the calling task holds multiple live coordinator bindings.
Returns the orchestrator, worker role name, binding_id, argus task id, and project.
Messaging (idle-gated bus)
hera_send(cwd, body, tldr, status, [to], [in_reply_to], [orchestrator]) — message another role
in the same orchestrator. body and tldr are required; tldr is a one-line summary ≤120
chars, written from the recipient's perspective (see §5). status is REQUIRED for worker/freelance
senders (one of idle/working/blocked/done/failed) and is applied to the sender's role
synchronously before the message is sent — it is never delivered async. Omitting status as a
worker/freelance sender is an error; coordinator senders may omit it. Worker/freelance senders may
omit to — it default-routes to the orchestrator's coordinator. Coordinators must supply an
explicit to.in_reply_to threads a reply to a prior message id. Returns the message_id,
recipient, and delivery mode. Caps: 64 KiB body, 500 unread per recipient, 50 sends/min/sender.
Cross-orchestrator messaging is not possible — to always resolves within your own orchestrator.
hera_inbox(cwd, [orchestrator]) — fetch all unread messages addressed to your role, oldest
first. Reading IS acknowledgment: this both cancels pending pane deliveries AND marks the
messages read — no separate hera_mark_read needed for normal consumption. Call it whenever you get a
doorbell.
hera_mark_read(cwd, message_ids, [orchestrator]) — explicitly mark specific message ids read and
cancel their pending deliveries. Use when you read via hera_get_messages instead of hera_inbox.
Status / tree
hera_status(cwd, status, [orchestrator]) — set your role status: idle | working | blocked
| done | failed. Mirrored (best-effort) to argus task_meta so the coordinator sees it without
asking. A worker-kind role reporting status=done also rolls its bound argus task to in_review
and stamps ready_to_close (visible in the rail) — see §4. A worker reporting status=failed
rolls its task to in_review WITHOUT ready_to_close (needs-attention, not ready to check off).
The gater treats a failed blocker as explicitly failed (no need to wait for session death).
Coordinators/freelancers just update status.
hera_accept(cwd, role_name, [orchestrator], [message]) — coordinator-only: mark a role's bound
task complete and send it a check-in asking whether it's winding down, has more work to do, or is
unsure. The reply is informational only — never auto-reopens the task; a premature accept is undone
via hera_revive alone. Never stops the session (completion and detachment are separate). Acts from
any non-complete status; a no-op if already complete. The plan-DAG gater fires this automatically
for blockers when dependent nodes materialize — use this tool for accepting work outside that flow
(ad hoc spawns, or roles with no plan-DAG dependents).
hera_tree_updates(cwd, [orchestrator], [since]) — scan the caller's orchestrator subtree
(nested sub-orchestrators included) for messages since a cursor. Returns TLDR-only subject lines —
no bodies (capped at 200), plus a next_cursor. The cursor is stored per-role and auto-advances
when you omit since; passing an explicit since is a one-off scan that does NOT clobber the stored
cursor. The token-efficient way to see whole-team activity without flooding context with bodies.
hera_get_messages(cwd, ids, [orchestrator]) — fetch full message bodies by id list, after
scanning hera_tree_updates. Access is scoped to the caller's orchestrator subtree (sender OR
recipient must live in it); inaccessible / missing ids get a per-id error field rather than a
top-level error.
Plan-DAG authoring (staged, dependency-ordered work) → the hera-plan skill
With a live coordinator binding, do NOT use the harness TaskCreate system-reminder for
coordinated work — coordinate via the hera tools (hera_spawn_worker, or the plan-DAG), never
bare task creation.
For work that decomposes into multiple hera worker units with dependencies among them (one stage
needs another's output, or a required ordering), hera offers a plan-DAG: planned nodes wired by
blocking edges that the daemon gater materializes into born-bound workers in dependency order,
auto-stacking each stage's branch on the prior. It renders in the TUI's second tab and is a living
graph (edit / re-point / cancel as work evolves).
Load the companion hera-plan skill before authoring or driving a plan-DAG. It carries the six
plan tools (hera_plan, hera_plan_node, hera_block, hera_plan_node_update, hera_unblock,
hera_plan_node_cancel), the gating contract (a node materializes ONLY when every blocker reaches
role-status done), automatic branch-stacking and its fan-in footgun, short-id node naming,
sub-coordinator nodes, and the self-guard prompt patterns — none of which the tool schemas convey. The
decision triad in §4 tells you when the plan-DAG is the right tool versus spawning workers directly
or using in-session sub-agents.
4. Decision rules
Starting a coordination effort?hera_new_orchestrator. Don't hera_join first.
A coordinator spawned you (fresh born-bound worker terminal)?hera_join(cwd) to read your role
mission, then hera_status(working). You are already bound — no attach needed.
Joining a team that didn't spawn you?hera_join attach mode with explicit role_name + kind.
new_orchestrator vs join:new_orchestrator makes you a coordinator of a new orchestrator;
join claims/attaches a role under an existing one. A worker can do BOTH — stay a worker in the
parent and hera_new_orchestrator to become a coordinator of a nested team (multi-binding).
spawn_worker vs adopt: native hera has no adopt step — workers are born bound at spawn time.
(The old depends_on-driven auto-adopt watcher was retired with the DAG.) To delegate, just
hera_spawn_worker.
Never hera_move your OWN coordinator binding to join another team.hera_move's kind is
worker/freelance only — moving away from a live coordinator role ends that binding and orphans
the whole orchestrator/subtree you were coordinating, leaving a disconnected freelance/worker stub
under the target with no link back to it (hera-freelancer-bug; the tool now rejects this outright).
There is no agent-facing tool to nest an existing coordinator + subtree under a new parent — that's
the Hera TUI's J (adopt/reparent) key, human-only. If a human wants your whole team folded under
another coordinator, tell them to press J on your orchestrator; don't try to self-relocate.
The coordination decision — in-session sub-agents vs hera workers vs the plan-DAG (settle this
BEFORE delegating):
Ephemeral, in-session work — research, review, fan-out reads, anything that returns results
to you and needs no worktree/PR of its own? → use Claude's native sub-agents (Agent/Task
tool). NOT hera. Hera is overkill and slower for in-session parallelism.
Work whose unit must be its OWN argus session — separate worktree / its own PR / long-running
/ its own sandbox? → hera. Then split by dependency:
Units have dependencies among them (one needs another's output, or a required ordering)? →
plan-DAG: load the hera-plan skill, author planned nodes + blocking edges, let the gater
run them in dependency order. Decide this yourself when the dependency is obvious — don't ask
the human.Internal dependencies are the clean signal to plan a DAG rather than spawn ad hoc.
Units are independent (no ordering)? → just hera_spawn_worker them in parallel; no DAG.
Ask the human only when it's genuinely ambiguous whether the work warrants multi-session
orchestration at all — never for the routine dependency call above.
This task holds 2+ bindings? Pass orchestrator= on EVERY tool call.
Got a doorbell? Call hera_inbox(cwd=$PWD) immediately — the content is in the inbox, not the
doorbell line.
Want whole-team state?hera_tree_updates(cwd=$PWD), then hera_get_messages(ids=[…]) for the
ones worth reading.
How completion flows back: a worker finishing sends a closing hera_send(status="done", …) — the
synchronous status apply rolls its task to in_review + ready_to_close, visible in the rail.
This is the worker's self-report, NOT task closure. Once you (the coordinator) have independently
verified the outcome (the PR actually merged, CI green, deliverables shipped—not just taken the worker's
word for it), call hera_accept(cwd=$PWD, role_name=<name>) in the SAME turn. Don't wait to be
asked, and don't treat a status message alone as sufficient closure. A worker that cannot complete
sends hera_send(status="failed", …) — rolls to in_review WITHOUT ready_to_close (needs
attention, not ready to check off); the gater holds any dependent planned nodes and pings you. Both
rolls are idempotent and only fire when the task is still in_progress. The live session is left
running.
Don't use hera_send to talk to the human — the human reads the coordinator's own agent pane;
the bus is role-to-role only.
5. TLDR discipline
Every hera_send requires a tldr ≤120 chars, written from the recipient's perspective. It is shown
in the doorbell, returned by hera_tree_updates, and stored permanently.
Good: "PR #47 open, tests green, needs review" / "Blocked on missing API key — need rotation"
Bad: "update" (says nothing) / "Done with the work" (no specifics) / multi-line.
6. Gotchas worth calling out
hera_send requires status for worker/freelance senders — omitting it is an error. The status
is applied synchronously before the send completes; it never rides the async delivery bus. This means
every hera_send call doubles as a role-status heartbeat. There is no default; the error message on
omission names the valid values (idle/working/blocked/done/failed).
Spawned workers default to the project's stale default branch, NOT the coordinator's branch.hera_spawn_worker's branch defaults to the project default (e.g. an old master/main), not the
coordinator's current worktree branch. If the worker must build on the coordinator's (or a sibling's)
work, pass branch= explicitly and verify ancestry — otherwise the worker starts from stale code.
Pass the MISSION only in hera_spawn_worker / hera_plan_node prompts — never prepend the
org/security policy. A hera worker is a full argus session that receives its org instructions
independently, via its OWN session's harness injection (an <organizationInstructions> block, verified
present in every spawned session regardless of the parent). So a manually prepended copy is a redundant
duplicate — and argus stores the prompt verbatim on the role and renders its opening lines as the node's
description in the plan-DAG, so a prepended policy pollutes the DAG (every node reads the boilerplate
instead of its mission). Write the prompt as exactly the message you want the worker to act on.
Bake all requirements into the initial hera_spawn_worker prompt. Mid-flight hera_send to a
worker is often missed: delivery is idle-gated and best-effort, so a busy worker never receives it and
an idle/finished worker may not act on it. Put the full spec in the spawn prompt; verify via the branch
diff and re-dispatch a fresh worker if one idled out without the requirement.
The message bus is idle-gated and best-effort for delivery, durable for storage. Storage always
succeeds (the row is committed); live pane delivery soft-fails (logged, never rolled back) when the
recipient has no live binding or never becomes idle. hera_inbox always returns the durable rows, so
the recipient can always catch up by reading — don't assume a sent message was seen just because it sent.
worker done must keep the role messageable. Native deliberately does NOT auto-archive a role on
hera_status(done) (the external plugin did). An archived role drops out of name-keyed recipient
resolution, so auto-archiving a still-live worker would make the coordinator's hera_send to it bounce.
Done flips the task to in_review; it does not archive the role.
Coordinators must name a recipient.hera_send from a coordinator with to omitted errors —
only worker/freelance senders get the default-to-coordinator routing.
7. Worked workflows
(a) Bootstrap an orchestrator, spawn two workers, collect results
You are a coordinator-to-be in your argus sandbox:
hera_new_orchestrator(cwd=$PWD, name="checkout-revamp", coordinator_role_name="coord", prompt="Coordinate the checkout revamp").
Spawn workers, each with the FULL spec baked in and an explicit base branch:
Poll progress without flooding context: hera_tree_updates(cwd=$PWD) → scan TLDRs →
hera_get_messages(cwd=$PWD, ids=[…]) for the interesting ones.
When a worker reports done (its task rolls to in_review + ready_to_close in the rail), review its
branch/PR independently (verify the PR merged, tests actually green, etc.). Once satisfied, call
hera_accept(cwd=$PWD, role_name=<worker-name>) to mark the task complete, then reply or spawn the
next stage. To stack work, branch the next worker off the prior worker's branch via branch=.
(b) A spawned worker reports completion
You opened in a born-bound worker terminal:
hera_join(cwd=$PWD) → read your role name, mission (role prompt), and unread count.
hera_status(cwd=$PWD, status="working").
Do the work in your worktree. If you hit a fork that needs the coordinator's call:
hera_send(cwd=$PWD, status="working", body="<question + context>", tldr="Need decision: X vs Y for the cart schema")
(no to needed — default-routes to the coordinator), then check hera_inbox(cwd=$PWD) on the
doorbell for the answer. Always supply status on every hera_send — it is required for
worker/freelance senders.
Land your work (open a PR via iris, or leave commits for the coordinator to pull).
hera_send(cwd=$PWD, status="done", body="<summary + PR link>", tldr="cart-api done, PR #47, tests green")
— the synchronous status apply rolls your task to in_review + ready_to_close so the coordinator
sees you finished. If you cannot complete: hera_send(cwd=$PWD, status="failed", body="<reason>", …).
(c) Author a staged plan-DAG
When the work decomposes into multiple multi-session units with dependencies among them, load the
hera-plan skill and author a plan-DAG — it carries the tools, gating, branch-stacking, naming, and
a full worked seed→fan-out→fan-in example. The §4 decision triad tells you when that's the right tool.
Worker promotion: becoming a sub-coordinator
If you already know up front (at plan-authoring time) that a stage is a sub-team, prefer the
declarative form: a kind=subcoord plan node (see the hera-plan skill). The gater then
materializes the sub-coordinator for you when its blockers finish. The runtime promotion below is for
when a worker discovers the need mid-task.
If a worker realizes mid-task it needs its own team (cross-repo work, real parallelism, a long sub-task):
hera_new_orchestrator(cwd=$PWD, name="<sub-team>", coordinator_role_name="coord", prompt="…") — now
this session is a coordinator of a nested orchestrator AND still a worker in the parent (multi-binding;
pass orchestrator= on subsequent calls).
hera_spawn_worker(...) to dispatch into the right project.
Report the sub-orchestrator name back to the parent coordinator via hera_send. Prefer using Claude's
native sub-agents for in-session parallelism; reserve hera_spawn_worker for work where the session
itself (separate worktree / repo / sandbox) is the unit.
8. Composition with sibling argus tools
Hera owns identity, messaging, and coordination — nothing else. Reach the rest through their own MCP
tools:
iris (mcp__argus__iris_*) — host-side git/gh. A worker codes + commits locally in its worktree,
then uses iris to push / open a PR / merge back. Use iris_gh_pr_create rather than gh pr create
so the PR is stamped onto the task's pr meta namespace — that is what the Hera rail's PR indicator
reads (best-effort, never fetched by the view).
plannotator-argus (mcp__argus__plannotator_*) — review UI. A coordinator routes a worker's output
to review there; hera carries the decision and the handoff message, plannotator carries the review
surface.
These are orthogonal — hera does not wrap them and they do not wrap hera. Pick per op: iris when an action
touches the host, plannotator when it's a review surface, hera when it's about roles or messaging.