Relay Protocol pre-alpha
Status: pre-alpha MIT licence aicanadiansolutions/ai-orchestrator 83 tests passing Public on GitHub

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.

§ 01

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.

Failure mode

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.

§ 02

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.

Input 01git diff & SHA
branch, dirty state
Input 02task graph
status + evidence
Input 03verification
cmd, exit, summary
Input 04decisions
rationale + rejected
Baton Regenerated from ground truth at every handoff. Never appended to, never carried forward as prose.
Receiving lega cold model — same vendor or another — resumes without a human re-explaining anything
baton.json — abridged, from the spike fixture schema_version 1.0
{
  "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"
    }
  ]
}
§ 03

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.

Why an arbitrary probe

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.

A/B results — blinded control, probe held outside the fixture
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.

2 / 2
Arbitrary decision — treatment, both handoffs
0 / 2
Arbitrary decision — blinded control, both handoffs
2
Vendors the result reproduces across

The baton is a protocol, not a prompt trick that happens to work on one vendor. It survived the vendor boundary intact.

Honest note on method

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.

§ 04

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.

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

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

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

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

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

§ 05

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.

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

§ 06

Requirements

RuntimeNode 22.6+
24 recommended — runs with no build step
Version controlgit
worktrees isolate parallel legs
Providersat least one
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.

§ 07

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.

four commands, start to finish 83 tests
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:

run_ce5c53a2 — live against the Claude Code CLI 0/12 → 12/12
  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.

§ 08

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.

Adjacent tools, and what each leaves open
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.

§ 09

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.