Trackers and landing
Where tickets live, how a wave lands and how waves chain. Every key named here is in the configuration reference; every subcommand is in the CLI reference.
Trackers
emet works with Linear, GitHub Issues or local files, set by tracker.kind. gh is required for the github tracker. A Linear MCP server must be declared in .mcp.json (or at user scope) for the linear tracker; see the dependencies reference.
Local tracker
With tracker.kind: "local", specs and tickets are markdown files under the main worktree’s .scratch/ (not versioned): .scratch/<slug>/spec.md and .scratch/<slug>/issues/<NN>-<slug>.md, each with Status: and Blocked by: lines and comments under ## Comments. The coordinator reads and writes them through emet tracker (create-spec, create-ticket, read, frontier, set-state, comment, close). emet init --tracker local sets this up. See ADR-0011.
Landing
landing.mode is "pr" (default) or "merge", independent of the tracker. In merge mode a wave lands as one local merge into trunk with emet land, with commands.selfCheck standing in for CI and no push. gh is only required when the tracker is github or landing is pr. See ADR-0010.
Landing PRs
One wave is one PR. Its body carries Closes #N for each ticket (the tracker’s closing keyword), and the coordinator moves the tickets to in-review when it opens the PR. The PR is then merged per pr.autoMerge, or left open when the wave was flagged, autoMerge is false, or CI fixes ran out (the PR then gets the human-decision label). After a merge, emet cleanup --run <runId> frees the wave’s branches, ticket claims, and worker slots.
After a wave’s branches are merged together, commands.fullSuite runs once on the integration branch. A red run blocks the PR and autoChain. The gate receives the result as --integration.
Chaining waves
Later waves run in their own sessions, never in the one that ran wave 1. Two optional emet.config.json sections control what happens next (both validated by emet preflight):
{ "pr": { "autoMerge": true, "mergeMethod": "squash", "maxCiFixAttempts": 2 }, "handoff": { "autoChain": false, "launcher": "auto", "permissionMode": "bypassPermissions" }}-
pr.autoMerge(defaulttrue): wait for the PR’s checks and merge; with no checks, merge at once. A failing check is fixed and pushed, up tomaxCiFixAttemptstimes, then the PR is left open for a human. A wave with anything flagged is never auto-merged. -
handoff.autoChain(defaultfalse): after a clean, merged wave with more waves left, launch the next one withclaude --bginstead of printing/emet:run --dispatch <spec-id>. Inspect it withclaude agents/claude attach emet-<spec-id>-w<n>. Requirements:claudeon PATH, with--bgsupport.- A trusted workspace.
--bgruns non-interactively, so the trust dialog never shows; openclaudeinteractively in the repo once and accept it. - The bypass warning accepted once in an interactive session (
skipDangerousModePermissionPrompt), since the next wave runs inhandoff.permissionMode(below), not in the launching session’s mode.
It launches only when the PR merged and nothing was flagged, and it skips if a
emet-<spec-id>-*session is already live (claude agents --json). If the launch fails, it falls back to printing/emet:run --dispatch <spec-id>. -
handoff.launcher(defaultauto): also open the wave in an Orca tab runningclaude attach.autoasks the Orca runtime (orca status), so it works fromclaude --bgsessions too, which have noTERM_PROGRAM;orcaalways tries,bgnever. The wave runs in the background either way, and a tab that fails to open never stops the chain.emet launch <spec-id> --wave <n>does the whole launch (duplicate-session check,claude --bg, tab) and prints{ name, id, attach, orcaTab: { opened, reason } }. Use it, not a bareclaude --bg, whenever you want a wave in another session by hand. -
handoff.permissionMode(defaultbypassPermissions): permission mode of the chained session. Not inherited from the launching session, becauseautomode’s classifier can deny a step such asgh pr mergeand leave a wave half-finished. Yourpermissions.denyrules still apply, but the bypass warning must have been accepted once interactively (skipDangerousModePermissionPrompt).
Gates, budgets and records
The phases don’t decide on their own when a ticket is done, mergeable or worth retrying. They call a CLI command that reads a record on disk and prints the decision. Run records live under .emet/runs/<run-id>/ and the review ledger under .emet/review/, in the main checkout, not in a worker’s worktree. Every command prints its usage with --help. The table of commands and what each enforces is in Gates and records.
Budgets (emet.config.json, all optional):
{ "budgets": { "workerAttempts": 2, "reviewRounds": 2, "stallNudgeCap": 6 } }workerAttempts: how many times a ticket can failverifybefore the gate answersdefer. The ticket gets the deferred label and the rest of the wave continues. An environment fault, such as the test command exiting 126/127 or a provider outage, pauses the run without spending an attempt.reviewRounds: how many review/fix rounds a ticket gets before one escalation to the next model tier. Whatever is still open after that gets a ruling.stallNudgeCap: how many times a stalled worker gets nudged. The count never resets.
Living specs, map and metrics
Living specs. After a wave auto-merges, emet spec-merge --spec <id> merges the spec’s ADDED/MODIFIED/REMOVED requirement deltas into docs/specs/<area>.md (specs.dir). It checks every area before writing anything. A conflict, or a requirement that would lose a scenario, exits 1 and leaves every file untouched.
Codebase map. emet map writes a brief of an existing codebase (stack, structure, conventions, testing, hotspots) to docs/agents/codebase.md (map.path), stamped with the commit SHA it was built from. The same commit always produces the same file. emet map --stale exits 1 once HEAD has moved past the stamp, and emet preflight warns in that case. emet map --for <globs> prints only the sections that match a ticket’s edit surfaces. That output is the only part of the map a worker brief includes.
Metrics. emet metrics --run <id> reports tokens, API-equivalent cost and wall time per ticket, per wave and per run, read from the session transcripts. It also compares the context budget estimated per ticket with what each worker actually used. Its summary goes at the end of the run’s final report.