Add it to a workflow

View as markdown

The 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 }

category comes from the closed vocabulary: backlog, ready, active, handoff, done, archived. Because an agent is actively working the review while a task 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 in the TUI.

2. Reference it from the workflow

In the workflow file, reference the status by id between in-progress and review. Make it agent-owned and point it at the agent you authored:

# workflows/default.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: orchestrator }
  - { id: done,                owner: user }

owner: agent makes the status the orchestrator's to act on, so tasks that land here are auto-dispatched; the agent: adversarial-review field names which agent runs it. 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: [merge, delete_branch] }

What each edge does:

  • in-progress → adversarial-review runs push_branch and open_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.
  • adversarial-review → review has no actions: the branch is already pushed and PR'd, so promoting a clean pass to human review is a pure status change.
  • adversarial-review → in-progress is the bounce-back. When the skeptic files blockers and writes the transition marker, the task 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 → done is the only edge carrying merge (and delete_branch). That's deliberate.

The action primitives in play are push_branch (push the task 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. Tasks 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.

you@hub — webapp
Tasks · webapp 5 total Workflow: All ▾ Workspace: All ▾ TO DO (1) IN PROGRESS (1) ADVERSARIAL REVIEW (1)REVIEW (1) DONE (1) Add ratelimit to API Wire up OAuth flow Cache warm-up on Add CSV export Ship dark-mode ⎇ shelbi/wire-up-oaut…cold start ⎇ shelbi/add-csv-expo…toggle ⎇ shelbi/cache-warm-u…
h/l col j/k row open n new f filter r refresh

See also

  • Workflow config — the field-by-field reference for statuses, transitions, and their actions.
  • Statuses — the statuses.yaml catalog and the closed category vocabulary.
  • Orchestrator — how agent-owned statuses get auto-dispatched and handed off.