Agents — roles and command specs¶
This area documents who runs an issue: which stage invokes which agent role, what that role's prompt grants and
forbids, how the role command specs (DEV_AGENT / REVIEW_AGENT / DECOMPOSE_AGENT) are parsed, and how the spec an
in-flight issue runs under is pinned for the life of its session. Label semantics, transitions, and per-handler
behavior belong to state-machine.md.
The pages in this area¶
workflow/roles.md— the three roles and the stages that spawn each one, where a handler and its spawn live, the session-reuse rules per role, the lifetime agent-run ledger every role spends from and the counters that reset without returning a run, the size gate every clean committed candidate passes before it is published and what its number earns — the exact commit an authorized settlement exempts included, and the proven workflow rewrites that exemption may rotate onto — what the late adjudication of an oversized committed candidate is asked and may answer, the owner read a finished run passes before anything acts on it and what each verdict earns past it, the order a clearedsplitruns its snapshot, children, supersession, and cleanup in, what a human's edit or answer changes while that candidate is frozen, and the local verify gate that is a stage step rather than a role.workflow/conversations.md— the two operator-applied conversation labels: what thequestionanddiscussionprompts grant and forbid, what a round may leave behind, the plan PR a confirmed design earns, the tracked-repository awareness block the working-agent prompts carry, the report contract every developer prompt teaches with the reader of its outcomes, the verification contract every reviewer prompt teaches with what its declaration earns, and the shared foreground execution guidance for asynchronous commands.workflow/command-specs.md— the spec grammar, backend selection andCODEX_BIN/CLAUDE_BIN/AGY_BIN, worked examples, and what pinning a spec buys.
For the higher-level design (multi-repo dispatch, push hardening, agent subprocess shape), see
architecture.md. For the audit event log and analytics sink, see
observability/event-streams.md; for the usage parser over them, see
observability/usage.md, and for the map over every observability surface,
observability.md. For env vars and the operator runbooks beside them, see
configuration.md. For the user-facing summary, see ../README.md.
Stage and label names are spelled apart across this area as they are in
state-machine/labels-and-state.md: a bare tag names the stage — the handler, the subpackage
under orchestrator/workflow/stages/ holding it, and the identifier a session's analytics row is attributed to —
while workflow:<tag> is the wire label the GitHub issue carries. in_review, question, discussion, and the
done / rejected terminals were never namespaced, so those read the same on both sides.
Roles at a glance¶
- Decomposer —
DECOMPOSE_AGENT(defaultclaude), spawned by the decomposing, question, and discussion stages, each of which pins its own session per issue. - Implementer / dev —
DEV_AGENT(defaultclaude), spawned by implementing and resumed by documenting, validating, fixing, and conflicts; locked per issue after the first spawn. - Reviewer —
REVIEW_AGENT(defaultcodex), spawned fresh by validating every round, so the current config always wins, and handed the developer report the pull request carries, quoted whole in its prompt.
The defaults (claude decomposes, claude implements, codex reviews) require those two CLIs; both need to be
authenticated on the host before the orchestrator starts. Per-role detail:
workflow/roles.md.
Question stage — read-only Q&A on the question label¶
The question workflow label is operator-applied: there are no automatic transitions in or out. _handle_question
runs the configured DECOMPOSE_AGENT backend in the issue's per-issue worktree with a read-only prompt that forbids
modifying, committing, or pushing files, posts the answer as a comment pinging HITL_HANDLE, opens no PR, and resumes
the session pinned to question_agent / question_session_id on every human reply. A read-only violation parks
awaiting human and preserves the worktree; closing the issue flips it to done. Full contract:
workflow/conversations.md#question-stage. Per-park_reason semantics:
state-machine/conversation-stages.md#_handle_question-label-question.
Discussion stage — architecture discussion on the discussion label¶
The discussion label is operator-applied like question and reuses the decomposer's backend to explore a design as
a tree, closing each round with numbered questions a human can answer or overrule by number. It is read-only in the
same way up to one point: once a human confirms on the thread that they and the agent understand the design the same
way, the agent may commit plans/issue-<number>.md alone, and the stage publishes that file as a plan pull request
whose verdict is the issue's ending — merged is done, closed unmerged is rejected. Full contract:
workflow/conversations.md#discussion-stage. Publication, recovery, and
park semantics:
state-machine/conversation-stages.md#_handle_discussion-label-discussion.
Tracked-repos awareness in working-agent prompts¶
When the orchestrator drives more than one repo (REPOS) and EXPOSE_TRACKED_REPOS is on (the default), the
reasoning-prompt builders prepend a compact, read-only awareness block naming the other repos this process tracks
and where their durable checkouts are. The framing is stage-neutral, so it never widens what the surrounding prompt
granted, and a single-repo host gets an empty string and zero added tokens. Which builders embed it and what the block
contains:
workflow/conversations.md#tracked-repository-awareness-in-working-agent-prompts. Disclosure
analysis: security.md#cross-repo-awareness-disclosure-expose_tracked_repos.
Commit-subject contract in commit-producing prompts¶
Every prompt whose agent may author a commit subject — the initial implementation, an automated-review fix, the final
docs pass, a requirements-drift resume, PR feedback, both discussion rounds, a late revision, the human-reply resume,
and the bare-continue retry — teaches one subject contract: read git log --oneline -20 and mirror whatever style
that repository's own recent history uses, as a single short imperative line with no body and no trailer. The
(#N) suffixes in that history are publication metadata rather than style, so the agent writes the descriptive
subject alone, never copies the tracked issue's number into one, and leaves the pull request reference to the
orchestrator, which under PR_REF_IN_SUBJECT (default on) ends every subject it publishes in that reference and
takes the tracked issue's own back off the line. The conflict-resolution prompt and the
conflict stage's bare continue carry no subject contract at all: that agent finishes an in-progress rebase and
authors no subject. Where each prompt carries it, and why the bare developer resumes restate it:
workflow/conversations.md#the-commit-subject-contract-in-commit-producing-prompts.
Developer report contract in developer prompts¶
Every prompt a developer can finish work on — the initial implementation, an automated-review fix, a requirements-drift
resume, PR feedback, a human-reply resume, a late revision against a human's guidance, a rewritten head's report
refresh, the bare-continue retry, and the AGY command recovery — teaches one report contract: the developer writes the
complete, current report, the orchestrator publishes it as routine work that needs no permission, and the prompt asks
the developer to keep the report at or below 4,000 characters by describing the final branch state rather than repeating
the issue, prior review rounds, every file, or every test. The report covers the final change, its rationale, and
unresolved risks, and leaves out verification sections, command inventories, and run-result summaries; that narrows what
the report says, not the checks the developer still runs, and a check still failing is named as a risk. The parser and
publication path enforce neither that writing budget nor that scope: the report is published as the developer wrote it.
A report that needs no repository change needs no commit, and finished work ends on exactly one outcome — either the
report between REPORT: READY and REPORT: END lines or a REPORT: VERIFIED <location> <revision> line naming a
report already on the pull request. The report may not contain this orchestrator's receipt prefix anywhere — not even in
a code span, a fence, or a quotation, since receipts are found by raw text — so a receipt is described in prose. A
report the orchestrator refuses to record publishes nothing and parks with a notice naming which refusal it was — a
quoted receipt, the report's own length, the pinned comment's room, or another invalid record — and the reply's resume
brings the corrected report with no new commit (the report contract). A record or binding the pinned
comment refuses instead — a comment that will not read, was replaced, or moved under what the write was decided on, or
an edit never confirmed — stops the tick with nothing published, parked, or written and no notice, and the next tick
decides afresh over the comment as it then stands. A fresh respawn's preamble
restates the ownership, the report's scope, and that restriction and defers the outcome to the task below it.
workflow/engine/report_outcomes.py reads an outcome only out of a run that completed, and the
initial implementation delivery is the road that acts on one: workflow/engine/report_delivery.py records what the
run wrote before the size gate and the push, and workflow/engine/report_binding.py binds it to the repository, pull
request, branch and commit the code reaches and publishes it there before the issue may move to
workflow:validating. Every road of the fix loop on an open pull request acts on one as well -- a
requirements-drift resume, a reviewer-requested round on either side of the park it may end on, and the
human-feedback round in_review routes to workflow:fixing: the report is recorded before the size gate, stamped
with the requirements revision the run was handed, bound once the code is out (or at once, for a report alone, which
spends the round a pushed fix spends because the next reviewer reads it), and the reviewer waits until the pull
request carries it. So does the report refresh workflow:validating runs for a head this orchestrator's own push
rewrote -- a rebase, a conflict resolution, or commits an earlier tick left unpushed, and an auto-rebase replay a late
adjudication took over, once its authorized settlement publishes it (a claimed
developer_report_rewrite_debt): before any reviewer, the claim is cleared at once where a published report of that
exact head, still intact and written against the current requirements, has already settled, and otherwise the
developer is asked with no human reply for a fresh REPORT: READY report of that head, recorded and settled the same
way, which clears it once it has -- a verification of the report the rewrite left behind pays nothing. A report of the
approved commit this orchestrator's approval squash collapsed into the head a later rebase replaced is refreshed the
same way, but only once the squash's own recorded lineage proves it and the report re-reads intact; it keeps naming
the commit it was written about. Each reviewer
is then handed the report re-read where it settled, and what it approves is
recorded as review_approved_subject — pull request, head, requirements, and report — so a report that changes on
an unchanged head goes back to a fresh reviewer rather than riding an earlier approval
(state-machine/labels-and-state.md).
The additive developer_report_* pinned records (workflow/engine/report_record*,
report_delivery_state.py and report_settlement_state.py) carry that report and the publication transaction it is
bound into across a process that dies mid-way; workflow/engine/report_transaction.py reconciles an outstanding
transaction ahead of every stage handler — proving the world it was recorded against, publishing or re-reading the
report, and settling the record in a single guarded commit (workflow/engine/report_settling.py) once the issue's
requirements read unchanged after that request, on this road and the binding's alike. The pull-request body leaves
the run's closing message out wherever a report is owed or settled, and a reused pull request's description is never
rewritten. Full contract:
workflow/conversations.md#the-developer-report-contract-in-developer-prompts;
the whole lifecycle in one place — ownership, identity and location, ready versus verified, the evidence, recovery,
review-subject freshness, and the round each road spends:
workflow/conversations.md#the-developer-report-lifecycle.
Reviewer verification contract in reviewer prompts¶
Every reviewer is handed, beside the complete current developer report, the workflow verification evidence current for
exactly its subject — quoted whole under the revision a reuse names, and never evidence about another head, report, or
requirements revision — with the configured VERIFY_COMMANDS or the plain statement that none are configured. It
closes on a declaration above its verdict: the commands it ran on the reviewed head, or the exact evidence revision it
reused. The orchestrator publishes that evidence itself, so a reviewer with valid evidence for the current tree does not
ask for a SHA, count, or command to be copied into the pull request; failed checks, missing verification, inaccurate
claims, and evidence about another subject stay actionable. The verdict is persisted before its evidence is published
or the verdict acted on, so a retry reruns no reviewer, and an approval without settled, passing evidence covering
every configured command parks under reviewer_unverified rather than reaching the approval arc. Full contract:
workflow/conversations.md#the-reviewer-verification-contract.
Foreground execution and asynchronous command guidance¶
Every developer and commit-producing prompt carries one shared foreground-execution note (_FOREGROUND_ONLY_NOTE in
workflow/engine/prompt_notes.py); read-only prompts (reviewer, question, decomposition) do not carry it. Under the
orchestrator's stateless, one-shot process execution model, an agent session terminates immediately upon responding, so
background jobs die with the session and are never observed. For agent backends that support asynchronous tool execution
such as Antigravity (agy), the note instructs the agent to use supported wait/status tools such as manage_task to
wait within the current response, treat a RUNNING status as requiring continued polling or waiting, and avoid ending
the response to await a notification, which terminates AGY and cancels the command. Contract details:
workflow/conversations.md#foreground-execution-and-asynchronous-command-guidance.
Examples¶
Any of the lines below is a valid value for any of the three role env vars; the full set, including the codex quoting
rules, is in workflow/command-specs.md#examples.
DEV_AGENT=claude --model claude-opus-4-7 --effort high
REVIEW_AGENT=codex -m gpt-5.5-codex -c 'model_reasoning_effort="high"'
DECOMPOSE_AGENT=claude
In-flight session lock — pinned full spec until the session ends¶
The parsed spec is persisted to pinned state as the durable identity of a session, and the pin is the full spec —
backend AND args — so a mid-flight resume cannot lose the model / reasoning-effort the session was started with. The
lock is per pin, not per issue: dev_agent is written on the first implementing spawn and read by every dev-side
resume for the life of the issue, while decomposer_agent, question_agent, and discussion_agent are each seeded
from DECOMPOSE_AGENT on their own first spawn. So a flip reaches any spawn that has no pin to read yet — including
the first question or discussion round on an issue whose decomposing session is already locked — and never a session
that has already pinned one. A dev conversation retired as failed (dev_session_retirement) keeps that pin too: the
fresh conversation replacing it runs the same dev_agent command, and the retired id is never resumed again
(session lifecycles).
The reviewer is spawned fresh every round, so REVIEW_AGENT takes effect on the next
validating tick. Per-role keys, the resume path, and the legacy values still honored on read:
workflow/command-specs.md#in-flight-session-lock.