Add it to a workflow
View as markdownThe agent exists;
now give it a status to own. Wiring a new agent into a workflow is two
files: the status identity is declared once in statuses.yaml, and the
workflow file references it by id, adds an owner, and points it at the
agent. Keep that split correct: repeating name: or category: in the
workflow file fails the load.
1. Declare the status identity
Add the status to the project-wide catalog in
workflows/statuses.yaml, placed where you
want its column to sit, between in-progress and review:
# workflows/statuses.yaml
statuses:
- { id: backlog, name: Backlog, category: backlog }
- { id: todo, name: Todo, category: ready }
- { id: in-progress, name: In Progress, category: active }
- { id: adversarial-review, name: Adversarial Review, category: active }
- { id: review, name: Review, category: handoff }
- { id: done, name: Done, category: done }
- { id: canceled, name: Canceled, category: archived }Keep every shipped status in the list. The shipped task and subtask
workflows reference all six, and if task (the project's
default_workflow) can't load, the whole project fails to load.
category comes from the
closed vocabulary:
backlog, ready, active, handoff, done, archived. Because an
agent is actively working the review while an issue sits here, it's
active, not handoff: handoff means "one owner finished, another's
input is required next," which is what the human review status already
is. Declaration order here is the left-to-right column order on the board.
2. Reference it from the workflow
In the workflow file (the shipped
workflows/task.yaml in a new project), reference the status by id
between in-progress and review. Make it agent-owned and point it at the
agent you authored:
# workflows/task.yaml
statuses:
- { id: backlog, owner: user, agent: orchestrator }
- { id: todo, owner: agent, agent: orchestrator }
- { id: in-progress, owner: agent, agent: developer }
- { id: adversarial-review, owner: agent, agent: adversarial-review }
- { id: review, owner: user, agent: review, tags: [review] }
- { id: done, owner: user }
- { id: canceled, owner: user }owner: agent on an active status that isn't the workflow's main
in-progress makes it a gate: the hub daemon auto-dispatches issues
that land here to the named agent, and adds the gate's pass and reject
commands to its prompt. The agent: adversarial-review field names
which agent runs it. Leave review as shipped: agent: review with
tags: [review] is what puts a finished branch on a review workspace for
you. No name: or category: appears here. Those live in
statuses.yaml, and repeating them fails the load.
3. Rewire the transitions
Transitions declare the
hub-side side-effects that fire on an edge. For the moves a human makes on
the board, an unlisted edge is just a pure status change. For an
agent-initiated move (the reviewer's bounce), the block does double
duty as an allowlist: once a transitions: block exists, an agent may only
take edges it declares, so the bounce edge has to be listed or the poller
rejects it. Route the developer's branch into adversarial review, then on
to human review, with a bounce-back for when the skeptic finds problems,
and keep merge on the single final edge into done:
transitions:
- { from: in-progress, to: adversarial-review, actions: [push_branch, open_pr] }
- { from: adversarial-review, to: review, actions: [] }
- { from: adversarial-review, to: in-progress, actions: [] }
- { from: review, to: done, actions: [push_branch, merge] }
- { from: in-progress, to: canceled, actions: [close_pr, delete_branch] }
- { from: review, to: canceled, actions: [close_pr, delete_branch] }What each edge does:
in-progress → adversarial-reviewrunspush_branchandopen_pr, so the branch is on the remote with a PR open before the reviewer starts. The reviewer works against a real diff, and its findings have somewhere to land. This edge is also what routes the developer's ready marker into the gate: it must be the only edge fromin-progressinto an agent-owned active status. Without it, the ready marker skips the gate and goes straight toreview.adversarial-review → reviewhas no actions: the branch is already pushed and PR'd, so promoting a clean pass to human review is a pure status change. The reviewer takes it by writing the transition marker withreview.adversarial-review → in-progressis the bounce-back. When the skeptic files blockers and writes the transition marker, the issue drops to the developer with no git side-effects: same branch, same PR, another pass. This edge is what makes that bounce legal; drop it and the poller refuses the reviewer's send-back.review → doneis the only edge carryingmerge, as in the shipped workflow (push first, then merge; the merged branch is cleaned up separately). That's deliberate.→ cancelededges are the shipped ones: close the PR and delete the branch.
The action primitives in play are
push_branch (push the issue branch to origin), open_pr (open its PR),
merge (merge the branch into its target), and delete_branch (delete the
local and remote branch).
Keep merge on the final edge
merge trips Zen Mode's high-confidence bar.
Keeping it on the single review → done edge, and nowhere earlier, means
the automated reviewer never lands code. It surfaces findings; the human
still owns the accept.
What you see now
The board grows an Adversarial Review column between In Progress and
Review. Issues the developer marks ready flow into it, get auto-dispatched
to the adversarial-review agent, and either bounce back with blockers or
advance to human review with the skeptic's findings already waiting on the
PR.
See also
- Workflow config — the field-by-field
reference for
statuses,transitions, and their actions. - Statuses — the
statuses.yamlcatalog and the closed category vocabulary. - Orchestrator: how issues get dispatched and handed off.