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:

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. The EM, the role workers, and both reviewers all call the provider you pick with --auth and --model.

Write scope and approval

Workers run unattended. They edit files and run shell commands without asking for each action, so a run needs a write scope before it starts:
  • Pass --scope (repeatable), or set ceiling.scope in .voss/team.voss. With neither, the command exits with an error. --scope can’t replace a ceiling scope the team file already sets.
  • Each worker can write only inside its role scope, or the ceiling scope when the role sets none. On a terminal you’re asked before a write outside it. Without a terminal the write is refused.
  • Shell commands aren’t scope-limited. Any .voss/safety.yml and .voss/permissions.yml rules still apply to them.
  • Before any work starts, the command asks once whether to continue. --yes skips that question.
Cards are worked one at a time in the project directory. A card reaches Done only when the worker’s own test run exits 0 and both reviewers pass it. A failed gate or review sends the card back to its worker with the reviewer’s notes, up to the retry ceiling. After that the card is Blocked. When the run ends, the command prints the card counts and the path to run-final.json, then asks you to approve or reject the run. --no-signoff skips that question and leaves the run unsigned, so scripts can run voss team run --yes --no-signoff without a terminal.
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:

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: 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.