Skip to main content
The Engineering Manager (EM) loop is the orchestrator. It is deliberately constrained — a tech lead that can decompose and delegate, but cannot invent roles, raise budget, or widen scope. Run it with:
voss team run "Add password reset flow with tests"
voss team run "<goal>" --cwd . --max-iterations 50

The loop

voss team run composes the team config, board, session tree, and the Reviewer-A/B pair, then drives em_loop to completion and persists a final record.
human idea
  -> derive cards (acceptance criteria + domain + risk tier)
  -> assign role from the declared roster (+ routing rationale)
  -> allocate budget and scope down the session tree
  -> dispatch workers
  -> tick the board
  -> route blockers (kill or rescope)
  -> request independent review
  -> integrate results
  -> finalize the run record
Each iteration: check whether all cards are terminal, snapshot the board, ask the EM agent for a plan, execute its ops, then tick the board once. The loop ends when every card is Done or Blocked, when max-iterations is reached (default 50), or when the budget is exhausted.

EM operations

The EM agent emits a plan of typed ops — it never mutates state directly:
OpEffect
create_ticketDerive a card from the idea, with acceptance criteria, domain (code/ai), and risk tier (low/med/high)
set_ac / set_dodSet acceptance criteria / definition of done
dispatch_cardAssign a card to a role, with a routing rationale and candidates considered
kill_cardTerminate a card, recording a kill rationale
rescope_cardReplace a card with a successor under a new role/scope
noopExplicit no-op

The cage

The cage is enforced by API surface, not by trusting the model. The handle the EM drives has no set_ceiling, set_budget, extend_budget, register_role, or mutate_team_config method. Violations raise EMCageViolation(op, reason):
  • Dispatching or ticketing a worker_role not in the roster.
  • Rescoping to a scope not contained in the ceiling.
  • Killing or rescoping a card already in Done.
A single violating op is logged and collected — it does not abort the iteration (audit-not-abort). Budget exhaustion forces all open cards to Blocked and ends the run.

The final record

When the loop ends it persists a RunFinal record:
FieldMeaning
root_idSession-tree root for the run
ideaThe original human idea
total_cardsCards created
done_count / blocked_countTerminal outcomes
killed_count / rescope_countKill and rescope lineage counts
em_iterationsLoop iterations consumed
tsFinalization timestamp
Kill and rescope events persist their own lineage records, so a killed or rescoped card stays inspectable. Inspect the result with voss review, voss board, and voss session tree.