Multi-Repo Coordination
Multi-repo coordination is the governed layer for work that spans more than one repository. It gives you one coordinator workspace, one super_run_id, coordinator-specific hooks and barriers, and repo-local execution that still treats each child repo's .agentxchain/ state as the source of truth.
If you only need one repository, stay on the normal governed lifecycle. Reach for multi when one change needs ordered work across repos, shared gates, or barrier-aware coordination.
If you want the literal cold-start path first, use Quickstart. This page stays focused on the full coordinator contract.
Live Coordinator Proof
The coordinator is not only covered by fixture E2E. A real model-backed proof now lives at examples/live-governed-proof/run-multi-repo-proof.mjs.
node examples/live-governed-proof/run-multi-repo-proof.mjs --json
The latest checked-in proof artifact is examples/live-governed-proof/evidence/multi-repo-proof.latest.json.
Recorded invocation:
node examples/live-governed-proof/run-multi-repo-proof.mjs --json --output examples/live-governed-proof/evidence/multi-repo-proof.latest.json
Fresh recorded run on 2026-04-18:
- CLI:
agentxchain v2.134.1 super_run_id:srun_1776532275887_1c3cf362- Child repos:
apiandweb - Coordinator dispatches:
4 - Accepted projections:
4 - Repo-local role order:
api(pm -> dev),web(pm -> dev) - Coordinator context proof: the first
webdispatch bundle includedCOORDINATOR_CONTEXT.jsonwith one upstream acceptance fromapi - Barrier result:
planning_sync_completionandimplementation_sync_completionboth reachedsatisfied - Checked-in evidence:
examples/live-governed-proof/evidence/multi-repo-proof.latest.json - Total API cost:
$0.0300
This proof intentionally keeps repo-local approvals real. Repo-local approvals remained required throughout the proof: each child repo turn was executed with agentxchain step --resume --auto-reject, then cleared with repo-local approve-transition or approve-completion before the coordinator advanced. The coordinator did not bypass child-repo gates.
Workspace Contract
The coordinator workspace is a directory with an agentxchain-multi.json file at its root plus checked-out governed repos underneath it.
Phase order is not negotiable: every child repo participating in the coordinator must declare the same ordered routing phases as the coordinator initiative. If the coordinator runs planning -> implementation -> qa, the child repos must expose the same routing order. If the coordinator is implementation-only, the child repos must also be implementation-only. multi init now rejects phase-order mismatches instead of letting them fail later during dispatch.
{
"schema_version": "0.1",
"project": {
"id": "agent-platform",
"name": "Agent Platform Rollout"
},
"repos": {
"web": {
"path": "./repos/web",
"default_branch": "main",
"required": true
},
"cli": {
"path": "./repos/cli",
"default_branch": "main",
"required": true
}
},
"workstreams": {
"protocol_doc_sync": {
"phase": "implementation",
"repos": ["web", "cli"],
"entry_repo": "cli",
"depends_on": [],
"completion_barrier": "all_repos_accepted"
}
},
"routing": {
"implementation": {
"entry_workstream": "protocol_doc_sync"
}
},
"gates": {
"initiative_ship": {
"requires_human_approval": true,
"requires_repos": ["web", "cli"]
}
}
}
The shipped coordinator state lives under .agentxchain/multirepo/, not in a separate .coordinator/ tree:
workspace/
agentxchain-multi.json
.agentxchain/
multirepo/
state.json
history.jsonl
decision-ledger.jsonl
barriers.json
barrier-ledger.jsonl
hook-audit.jsonl
hook-annotations.jsonl
context/
<context_ref>/
COORDINATOR_CONTEXT.json
COORDINATOR_CONTEXT.md
repos/
web/
agentxchain.json
.agentxchain/
state.json
cli/
agentxchain.json
.agentxchain/
state.json
Custom Coordinator Phases
Coordinator workflows are not limited to planning -> implementation -> qa.
If you need an intermediate phase such as design, declare it in the coordinator routing and in every participating child repo's agentxchain.json. The order must match exactly across all repos. Coordinator gates derive phase order from declaration order, so planning -> design -> implementation -> qa is valid, but planning -> implementation is not if design is declared in between.
{
"workstreams": {
"initiative_plan": {
"phase": "planning",
"repos": ["api", "web"],
"entry_repo": "api",
"depends_on": [],
"completion_barrier": "all_repos_accepted"
},
"initiative_design": {
"phase": "design",
"repos": ["api", "web"],
"entry_repo": "api",
"depends_on": ["initiative_plan"],
"completion_barrier": "all_repos_accepted"
},
"initiative_build": {
"phase": "implementation",
"repos": ["api", "web"],
"entry_repo": "api",
"depends_on": ["initiative_design"],
"completion_barrier": "all_repos_accepted"
},
"initiative_qa": {
"phase": "qa",
"repos": ["api", "web"],
"entry_repo": "qa",
"depends_on": ["initiative_build"],
"completion_barrier": "shared_human_gate"
}
},
"routing": {
"planning": { "entry_workstream": "initiative_plan" },
"design": { "entry_workstream": "initiative_design" },
"implementation": { "entry_workstream": "initiative_build" },
"qa": { "entry_workstream": "initiative_qa" }
}
}
The same order must exist in each child repo:
{
"routing": {
"planning": { "entry_role": "pm", "exit_gate": "planning_signoff" },
"design": { "entry_role": "architect", "exit_gate": "design_review" },
"implementation": { "entry_role": "dev", "exit_gate": "implementation_complete" },
"qa": { "entry_role": "qa", "exit_gate": "qa_ship_verdict" }
}
}
phase_transition_request may only target the immediate next declared phase. In the example above, planning -> design is valid; planning -> implementation is rejected with phase_skip_forbidden.
Command Lifecycle
The coordinator loop is explicit. The coordinator never auto-runs child repos behind your back.
agentxchain multi init- Loads
agentxchain-multi.json - Verifies coordinator/child repo phase-order alignment before writing coordinator state
- Links existing active child runs or initializes idle governed repos
- Writes
.agentxchain/multirepo/state.jsonand barrier snapshots
- Loads
agentxchain multi step- Detects divergence first
- Auto-resyncs from repo authority when the drift is safe to repair
- Selects the next assignable workstream and repo
- Writes the child repo dispatch bundle with
COORDINATOR_CONTEXT.jsonandCOORDINATOR_CONTEXT.md
- Inside the selected child repo, complete the repo-local turn normally
agentxchain accept-turn- The repo-local history is authoritative; the coordinator projects from that accepted result
- Run
agentxchain multi stepagain- Projects repo-local acceptance into coordinator history
- Updates barrier state
- Either dispatches the next repo assignment or requests a coordinator gate
- If the coordinator enters
blocked, fix the cause, fill in.agentxchain/multirepo/RECOVERY_REPORT.md, and runagentxchain multi resume- The system scaffolds
RECOVERY_REPORT.mdon any blocked coordinator transition, including hook-driven blocks and ambiguous resync results - Fill in
## Trigger,## Impact, and## Mitigationwith real content before resume multi resumevalidates the recovery report, then resyncs from repo authority- Restores the coordinator to
activewhen dispatch can continue - Restores the coordinator to
pausedwhen a coherentpending_gatestill exists
- The system scaffolds
- When a gate is pending, run
agentxchain multi approve-gate- Approves a phase-transition or completion gate for the coordinated initiative
- When you want an explicit divergence check, run
agentxchain multi resync --dry-run- Shows divergence without mutating state
- Follow with
agentxchain multi resyncto rebuild coordinator state from repo truth
Barrier Types
The shipped coordinator supports five completion-barrier modes:
| Barrier type | Meaning |
|---|---|
all_repos_accepted | The workstream completes only after every repo listed in the workstream has an accepted projection |
ordered_repo_sequence | Downstream repos stay blocked until upstream acceptance order is satisfied |
interface_alignment | Cross-repo contract alignment barrier. The workstream must declare interface_alignment.decision_ids_by_repo, and the barrier is satisfied only when each repo has accepted the declared DEC-NNN decisions for that repo. |
named_decisions | General decision-checkpoint barrier. The workstream must declare named_decisions.decision_ids_by_repo, and the barrier is satisfied only when each repo has accepted the declared DEC-NNN decisions for that repo. |
shared_human_gate | Never auto-satisfies from repo acceptances; requires human approval through multi approve-gate |
Barrier transitions are tracked in .agentxchain/multirepo/barriers.json and audited in .agentxchain/multirepo/barrier-ledger.jsonl.
interface_alignment is explicit, not magical. The coordinator does not infer semantic compatibility from changed files. You declare the required accepted decision IDs per repo in agentxchain-multi.json, and the barrier tracks progress per repo until every declared decision ID has been accepted.
Use named_decisions when the checkpoint is governance-driven rather than interface-specific. The evaluation logic is the same; the label is different because the operator intent is different.
Interface alignment end-to-end example
1. Config — declare what alignment means
{
"schema_version": "0.1",
"project": { "id": "payments", "name": "Payment API v2" },
"repos": {
"api": { "path": "./repos/api", "default_branch": "main", "required": true },
"web": { "path": "./repos/web", "default_branch": "main", "required": true }
},
"workstreams": {
"payment_flow": {
"phase": "implementation",
"repos": ["api", "web"],
"entry_repo": "api",
"depends_on": [],
"completion_barrier": "interface_alignment",
"interface_alignment": {
"decision_ids_by_repo": {
"api": ["DEC-101"],
"web": ["DEC-201"]
}
}
}
},
"routing": {
"implementation": { "entry_workstream": "payment_flow" }
},
"gates": {
"initiative_ship": { "requires_human_approval": true, "requires_repos": ["api", "web"] }
}
}
The config says: api must accept a turn containing decision DEC-101, and web must accept a turn containing decision DEC-201, before the workstream barrier is satisfied.
2. Turn result — include the decision IDs
When the agent working in the api repo accepts a turn, its turn-result.json must include the decision in the decisions array:
{
"decisions": [
{ "id": "DEC-101", "title": "Payment endpoint contract", "status": "accepted" }
]
}
After agentxchain accept-turn in the api repo and the next agentxchain multi step, the coordinator projects that acceptance and evaluates the barrier. At this point:
apihas acceptedDEC-101— alignedwebhas not acceptedDEC-201— not aligned- Barrier status:
partially_satisfied
3. Coordinator context — what the next repo sees
When multi step dispatches to web, the generated COORDINATOR_CONTEXT.md surfaces what is still required:
## Active Barriers
- barrier_payment_flow: interface_alignment (partially_satisfied)
Required decision IDs for web: DEC-201.
## Required Follow-ups
- Accept declared interface-alignment decisions for web: DEC-201.
COORDINATOR_CONTEXT.json carries the same data in machine-readable form, including the full alignment_decision_ids map and satisfied_repos list.
4. Completion — barrier satisfied
After the web repo accepts a turn with DEC-201 in its decisions array and the coordinator projects the result, the barrier reaches satisfied and the workstream can advance to the completion gate.
Cross-Repo Context
Every coordinator dispatch generates cross-repo context for the selected child repo:
COORDINATOR_CONTEXT.jsonCOORDINATOR_CONTEXT.md
Those artifacts summarize:
- upstream acceptance projections from related workstreams
- active non-satisfied barriers relevant to the target repo
- declared decision IDs still required for the target repo (
interface_alignmentornamed_decisions) - required follow-ups derived from dependencies and barrier notes
The generated context is also stored under .agentxchain/multirepo/context/<context_ref>/ so the coordinator can audit and invalidate stale context when upstream repos accept new work.
Coordinator Hooks
Coordinator hooks are defined in agentxchain-multi.json and are separate from repo-local hook phases.
| Hook phase | Behavior |
|---|---|
before_assignment | Pre-action guard — blocks dispatch but does not persist blocked state |
after_acceptance | Post-action audit — failure persists status: "blocked" and fires on_escalation |
before_gate | Pre-action guard — blocks gate approval but does not persist blocked state |
on_escalation | Advisory — fires when the coordinator enters a blocked state |
Coordinator hooks protect .agentxchain/multirepo/ files and repo-local protected files. They are not allowed to mutate child repo state, child repo history, or dispatch bundles.
Hook-Stop Semantics
Pre-action hooks (before_assignment, before_gate) and post-action hooks (after_acceptance) behave differently when they halt execution. This asymmetry is intentional.
Pre-action hooks prevent something from happening. When they block, no coordinator state changes. The coordinator remains active (or paused). Recovery is: fix the condition the hook is checking, then re-run multi step or multi approve-gate. No multi resume is needed.
Post-action hooks audit work that already happened. after_acceptance fires after a turn result has been projected into coordinator state. If the hook detects a problem (tamper, policy violation, failure), the coordinator state may be inconsistent. The coordinator persists status: "blocked", fires on_escalation, and requires explicit recovery via multi resume.
| Scenario | Coordinator state after halt | Recovery path |
|---|---|---|
before_assignment blocks dispatch | Unchanged (active or paused) | Fix hook condition → re-run multi step |
before_gate blocks gate approval | Unchanged (gate still pending) | Fix hook condition → re-run multi approve-gate |
after_acceptance fails or detects tamper | Persisted as blocked | Investigate → fix root cause → multi resume → continue |
Pre-action blocks do not fire on_escalation because they represent expected operational friction (policy gates, maintenance windows, approval holds). Post-action failures fire on_escalation because they represent unexpected integrity events that need investigation.
Coordinator Blocked States
When a coordinator enters blocked, the blocked_reason field in .agentxchain/multirepo/state.json describes why. Governance reports surface these reasons with structured diagnostic detail. The most common blocked states are:
| Blocked state | Cause | Diagnosis | Recovery |
|---|---|---|---|
| Hook violation | after_acceptance hook failed or detected tamper | Check hook audit log in .agentxchain/multirepo/hooks/ | Fix root cause → fill RECOVERY_REPORT.md → multi resume |
Run identity drift (repo_run_id_mismatch) | A child repo's run_id no longer matches what the coordinator recorded at initialization | Report shows expected vs actual run_id per repo | Investigate why the child repo was re-initialized → restore the correct run or multi resume after filling RECOVERY_REPORT.md |
| Gate coherence failure | Pending gate references repos whose state no longer supports the gate | Check pending_gate in coordinator state | Fix child repo state → multi resync → multi resume |
Run Identity Drift
Run identity drift is the most dangerous coordinator blocked state. It means a child repo was re-initialized (or its .agentxchain/state.json was replaced) after the coordinator linked it. The coordinator refuses to continue because the child repo's audit trail no longer belongs to the same governed run.
How it appears in reports:
Blocked reason:includesrun identity driftedRun ID mismatches:section lists each affected repo withexpectedandactualrun IDsNext Actions:includes per-reporepo_run_id_mismatchdiagnostics
How it appears in CLI output:
multi stepprints[repo_run_id_mismatch]with expected/actual run IDsmulti resyncdetects the drift and blocks instead of auto-adopting the new run
Recovery: Determine why the child repo's run changed. If it was accidental re-initialization, restore the correct .agentxchain/state.json from backup or git history. If it was intentional, fill in RECOVERY_REPORT.md explaining why, then agentxchain multi resume.
Dashboard And Recovery
The local dashboard exposes coordinator state through the Initiative and Cross-Repo views, with gate and blocked panels reading from the same .agentxchain/multirepo/ artifacts.
Do not blur the coordinator inspection commands together:
- Use
agentxchain auditfrom the current coordinator workspace when you need the live current multi-repo state. - Use
agentxchain exportwhen you need a portable coordinator artifact you can attach, compare, verify, or archive. - Use
agentxchain report --input <coordinator-export.json>when you want a derived summary from an existing verified artifact, not the live workspace. - Use
agentxchain replay export <coordinator-export.json>when you want the read-only dashboard for an existing artifact instead of a text, markdown, json, or html report.
That distinction matters most for partial coordinator artifacts. report --input keeps repo_ok_count / repo_error_count, preserves the failed repo row plus error, and does not invent missing child drill-down. replay export keeps the same verified coordinator artifact readable in the dashboard, but restores a placeholder child repo for failed nested exports so coordinator layout validation still works. audit is different from both: it inspects the current workspace directly and does not read a saved export artifact.
Recovery follows one hard rule: repo-local governed state is authoritative. The coordinator is a derived control plane, not the source of truth. If someone accepts or rejects a turn directly in a child repo, multi step will detect that divergence and auto-resync when safe; otherwise multi resync rebuilds or blocks explicitly instead of guessing.
Blocked-state recovery is a separate operator action:
- Use
agentxchain multi resync --dry-run/agentxchain multi resyncto inspect or rebuild divergence from repo truth - When the coordinator enters
blocked, including a resync that finds an ambiguous gate, aRECOVERY_REPORT.mdis scaffolded in.agentxchain/multirepo/ - Fill in
## Trigger,## Impact, and## Mitigationwith real content describing the incident - Use
agentxchain multi resumeonly after the recovery report is complete and the blocked cause is fixed - After
multi resume, continue withagentxchain multi steporagentxchain multi approve-gatedepending on the restored status
Intake Handoff
When a delivery signal is detected in a single repo but the resulting fix spans multiple repos, use intake handoff to bridge repo-local intake into a coordinator workstream.
# In the source repo: record, triage, approve, plan
agentxchain intake record --source ci_failure --category test_regression
agentxchain intake triage <event_id>
agentxchain intake approve <intent_id>
agentxchain intake plan <intent_id>
# Hand off to the coordinator workstream
agentxchain intake handoff <intent_id> --coordinator-root ../workspace --workstream payment_flow
The handoff writes a read-only reference to the coordinator at .agentxchain/multirepo/handoffs/<intent_id>.json. The coordinator's COORDINATOR_CONTEXT.md then includes the original intent charter and acceptance contract so agents in sibling repos understand why the workstream exists. The source repo retains authority over the intent — only intake resolve in the source repo can close it.
See Continuous Delivery Intake for the full intake lifecycle and handoff contract.
For the command-level reference, see CLI Reference. For the protocol overview, see Protocol.