Keep one project moving across many AI models — and print the receipt.
A capable model runs out of session, quota or capability before the work is finished. When it does, you lose the reasoning that got you there: what was tried, what was rejected, and why. The human becomes the transport layer. Relay carries that context instead.
The handoff is where the work dies
Every model has an edge. It is reached mid-task, not at a convenient boundary: the session ends, the quota is spent, or the problem turns out to need a capability this model does not have.
The code survives that boundary. The reasoning does not. The next model receives a working tree and no account of how it got that way — which approaches were already tried and abandoned, which constraints came from outside the repository, which decisions were deliberate rather than incidental.
So a person re-explains it. Badly, from memory, every time. That person is not orchestrating anything; they are acting as the transport layer between two models that cannot talk to each other.
Switching models is not the same as letting a session continue across the switch. The expensive thing is not the tokens — it is the context.
Silent divergence
A model that never learns a decision does not fail loudly. It writes correct, idiomatic, fully passing code that quietly violates a constraint nobody wrote down — and nothing downstream detects it.
The baton is derived from ground truth
When a model runs out, Relay does not ask it to write a summary. It derives a baton: a structured artefact reconstructed from the state of the repository and the run at that exact boundary, then hands it to another model that picks the work up cold.
The distinction matters more than it sounds. A summary that is appended to at every handoff compounds its own errors until the briefing describes a project that no longer exists. A derived baton is regenerated from scratch every time, so it cannot drift away from the repository it describes.
The receiving model is not asked to trust a narrative. It receives the diff, the task graph with per-task status and evidence, the last verification result including its exit code, and the decisions already taken — each with its rationale and the alternatives that were rejected.
branch, dirty state
status + evidence
cmd, exit, summary
rationale + rejected
{
"schema_version": "1.0",
"git": { "sha": "811606c", "branch": "master", "dirty": true },
"goal": "Implement the three normalizers so the visible suite passes.",
"task_graph": [
{ "id": "t1", "status": "done", "evidence": "file:src/normalize.js" },
{ "id": "t2", "status": "pending" }
],
"verification": {
"tests": { "cmd": "node --test test/visible.test.js",
"exit": 1, "summary": "pass 3, fail 9" }
},
"decisions": [
{
"id": "D1",
"statement": "normalizeDate must REJECT ambiguous slash dates
rather than guessing...",
"rationale": "Records come from CA and EU suppliers, so DD/MM
and MM/DD both occur in one dataset. A silent
wrong guess is undetectable downstream.",
"rejected": ["default to US MM/DD", "infer from locale"],
"decided_by": "claude-cli"
}
]
}
Is the baton actually load-bearing?
That is a testable claim, so it was tested rather than asserted.
One leg implements part of a task and records three decisions. The work is then handed to a cold receiving process in two arms that differ in exactly one way. The treatment arm gets the baton. The control arm gets byte-identical code, a naive continue the work prompt, and is verified blind — the decisions are absent from its working tree and from its git history.
A probe held outside the test then checks an arbitrary decision: an unrecognised currency code must map to ISO 4217 XXX rather than being rejected, because an external ledger requires a code on every row. That fact appears nowhere in the code, and it cannot be reasoned to. Either the model was told, or it was not.
A visible test suite cannot detect this
A competent model passes the visible tests either way — that is what makes the result interesting. The probe isolates the one thing the code itself cannot teach: an external constraint that exists only because somebody decided it.
Both arms wrote correct, working code. Only the baton arm knew the rule.
| Handoff | Arm | Visible test suite | Arbitrary decision |
|---|---|---|---|
| Same-vendor cold Claude CLI → cold Claude CLI |
Treatment (baton) | 12 / 12 pass | 2 / 2 pass |
| Control (blinded) | 12 / 12 pass | 0 / 2 fail | |
| Cross-vendor Anthropic → DeepSeek |
Treatment (baton) | 10 / 12 pass | 2 / 2 pass |
| Control (blinded) | 10 / 12 pass | 0 / 2 fail |
Visible-suite scores are equal within each handoff: the arms differ only in whether the baton was passed. The cross-vendor pair scores 10/12 in both arms — a property of the receiving model, not of the baton.
The baton is a protocol, not a prompt trick that happens to work on one vendor. It survived the vendor boundary intact.
It took seven runs to get two clean measurements
Five runs failed. None of them crashed — every one produced a confident wrong verdict, which is the harder failure to notice. One control arm turned out not to be blind at all: the decisions were still recoverable from git HEAD, so the arm was reading the answer it was supposed to be missing. That is documented rather than hidden, because for anyone building an evaluation harness it is the most transferable finding here.
Design commitments
These are constraints on the implementation, not aspirations. Each one exists because the obvious alternative fails in a way that is difficult to detect from the outside.
-
C.01
The baton is derived, never accumulated
It is regenerated from ground truth at every boundary. Appending to a running summary compounds error until the briefing describes a project that no longer exists.
-
C.02
Verification is the orchestrator's job
A leg cannot mark its own homework. Relay runs the verification and records the result. A leg that ends red is handed off as red, explicitly — not quietly repaired by the narrative.
-
C.03
Findings need reproductions
In cross-model review a criticism is admitted only when it comes with a failing test, a type error, or a measured regression. Opinions without evidence are not findings.
-
C.04
An unreachable provider abstains — it never votes
If a provider cannot be reached, its silence must not be counted. Otherwise an outage silently converts itself into a code criticism.
-
C.05
One lead per worktree
Parallel models get parallel git worktrees. Concurrency is handled by isolation, not by asking two agents to be polite inside one checkout.
Substrate: processes, not just API keys
Relay drives agent processes, not only API endpoints. Vendor CLIs are executed inside the flat-rate subscription you already pay for. Metered API keys are used only for providers that have no CLI, and for media generation.
This is a billing distinction before it is an architectural one, and it is the part most orchestrators get wrong.
An API key is a separate meter from a subscription. Building an orchestrator on keys alone does not spend your subscription — it opens a second bill.
| Adapter | Kind | Billing | Role | Status |
|---|---|---|---|---|
| claude-cli | process | subscription | lead coding | working |
| codex-cli | process | subscription | second coding vendor | built, untested |
| deepseek-api | API | metered | advisor / alternate perspective | working |
| openai-images | API | metered | image generation | planned |
Status is stated as measured, not as intended. codex-cli is written but has never executed.
Requirements
24 recommended — runs with no build step
worktrees isolate parallel legs
a vendor CLI, or an API key
No build step and no framework. Relay is a protocol and a runner around tools you already have.
Run it yourself
Zero npm dependencies. The whole suite runs with no provider, no key and no network — if it is green, the engine works on your machine.
git clone https://github.com/aicanadiansolutions/ai-orchestrator
npm test # 83 tests, no credentials needed
relay demo ../relay-demo # a repo with 12 failing tests
relay run --path ../relay-demo --goal "make the test suite pass"
A real session, four legs, one task each — the baton re-derived from git and test results at every boundary:
leg 1/5 → claude normalizeAmount 1 task, verify exit 1, 25s
leg 2/5 → claude normalizeDate 2 tasks, verify exit 1, 65s
leg 3/5 → claude normalizePhone 3 tasks, verify exit 1, 33s
leg 4/5 → claude normalizeCurrencyCode 4 tasks, verify exit 0, 42s
run run_ce5c53a2 completed
The suite was then re-run directly, outside Relay, to confirm the result. A harness that grades its own output is the one thing this project refuses to trust — see § 03.
Your keys, your accounts. Relay drives the vendor CLIs under your own subscription and calls metered APIs with your own key. There is no shared account, no pooled capacity, and no key of ours anywhere in the repository. Authentication is per-machine, and both metered adapters work on any repository through a sandboxed file toolset.
How this differs
Connecting several models to one endpoint is table stakes and has been for years. The tools below all do real work and several are more mature than this one. What none of them do is carry verifiable project state across a provider boundary — which is the only thing Relay is for.
| Tool | What it does well | What it leaves open |
|---|---|---|
| OpenRouter, LiteLLM | One endpoint across many models, fallback chains, spend tracking | No project state, no continuity between sessions, no scheduled critique |
| Aider | Multi-model, separate architect and editor roles, git-checkpointed edits | One session at a time; no cross-model handoff protocol, no asynchronous human gate |
| Cline, Roo Code, Continue | Multi-provider agents inside the editor, per-provider keys | A human drives every switch; no durable baton that survives the session |
| LangGraph, CrewAI, AutoGen | Multi-agent graphs, role assignment, orchestration primitives | Frameworks rather than products — no billing-aware routing, and you build the rest |
If a single model finishes your work in one session, you do not need any of this — including Relay. The problem only exists at the boundary.
Read further
The specification argues both sides — § 2 is a written case for not building this, including the billing assumption that turned out to be wrong and reshaped the architecture.
Built by AI Canadian Solutions
Need custom AI orchestration or agent systems for your team?
Relay Protocol is open source and MIT licensed — clone it, run the suite, point it at your own repository with your own keys. If you are building multi-model workflows, handoff infrastructure, or agent systems that have to be verifiable, get in touch.