Cross-model review
The model that reviews a plan or a diff is never the one that wrote it. Nothing grades its own homework, and reviewers run read-only.
planner: claude · planReviewer: codex
Relay is where you build them. Connect a repository, pick a workflow, and from then on a label on an issue is enough: coding agents plan it, write it, review each other’s work and open a pull request, all inside your own GitHub Actions.
03 / Build
Codex implements the reviewed plan in an isolated git worktree. Your working directory stays available while the agent works.
A diff ready for independent review
test("retries a failed request", async () => {
+ vi.useFakeTimers();
const result = retry(request);
- await sleep(1000);
+ await vi.advanceTimersByTimeAsync(1000);
expect(await result).toEqual(response);
+ vi.useRealTimers();
});
A sample workflow, step by step. Label an issue, and this is what runs in your repository.
How it works
Set it up once, in about two minutes. After that a label on an issue is all it takes.
Say which repository. Relay never asks for access to your code: it writes a workflow file and the rules it runs under, and you commit them like any other change.
acme/api
runs on GitHub Actions
.github/workflows/issue-to-pull-request.yml
.relay/config.json
.relay/workflows/issue-to-pull-request.json
committed by you · no access to your code is asked for
Start with issue to pull request: label an issue, and two agents plan it, write it and review each other. Or describe your own in a sentence and edit it on the canvas.
Issue to pull request
label relay:go
Quick fix from an issue
one agent, one session
Describe your own
a sentence in, a workflow out
Who may start a run, a screen for prompt injection, and where a person has to say yes. A run that breaks a rule does not start.
Injection screen
nothing in the ticket reads as an instruction
Allowlist
@mallory is not on it
Approval
waits for a named person
Kill switch
re-read before every start
On your repository’s own minutes, with the Claude and ChatGPT plans you already pay for, held as secrets only GitHub has. One agent writes the plan and the other attacks it; then they swap for the code.
Codex reviews the planBLOCKING
The plan adds a retry inside withTimeout, which already retries. Two layers multiply the wait.
Claude Code answersACCEPT
Revised: retry once, at the call site. Plan v2 goes to implementation.
round 1 of 2 · the diff is computed from git, not taken from the agent
Tested, reviewed, and reported back on the issue. A run nobody is watching stops at a draft: the merge is yours.
Fix the flaky retry test
#143 · relay/142-fix-the-flaky-retry-test → main · +84 −12
#eng-agents PR #143 is ready for review · usage $1.84
The studio
Design visually, try a simulated run, then export the config and GitHub Actions workflow. The preview below uses the same compiler as the studio.
GitHub label to pull request
Valid6 nodes, drawn from the templateScroll sideways to see it all
.relay/config.json · What the CLI reads. Commit it to the repository this workflow is attached to.
{
"version": 1,
"agents": {
"planner": "claude",
"planReviewer": "codex",
"implementer": "codex",
"codeReviewer": "claude"
},
"models": {},
"workflow": {
"maxConcurrentRuns": 1,
"review": "standard",
"plan": "review",
"reviewCode": true,
"maxPlanReviewRounds": 2,
"maxCodeReviewRounds": 2,
"baseBranch": "",
"branchPrefix": "relay",
"runTests": true,
"deliver": "pr",
"mergeMethod": "squash",
"offerMerge": false,
"maxTransientRetries": 2,
"maxCostUsd": null,
"confirmAboveUsd": null,
"primeReviewers": true,
"concurrentTests": true,
"typos": false,
"triggerLabel": "relay:go"
},
"unattended": {
"enabled": false,
"authors": [],
"teams": [],
"maxDailyCostUsd": null,
"maxRunCostUsd": null,
"pollSeconds": 60,
"deliver": "pr"
},
"github": {
"autoPush": true,
"autoPr": true,
"autoMerge": false,
"mergeMethod": "squash",
"deleteBranchOnMerge": true,
"protectedBranches": [
"main",
"master"
]
},
"tests": {
"command": null
},
"delivery": {
"comment": true
},
"notify": {
"webhook": null,
"bell": false,
"system": false,
"command": null
}
}
Why it holds up
Independent reviews, verifiable results, and limits you control.
The model that reviews a plan or a diff is never the one that wrote it. Nothing grades its own homework, and reviewers run read-only.
planner: claude · planReviewer: codex
Relay computes the diff itself, judges tests by exit code and takes usage from what the CLIs report. An agent saying “done” proves nothing.
git diff --cached <baseSha>
An empty allowlist means nobody may start a run. A ticket that reads like a prompt injection is refused before any agent sees it, and an unattended run stops at a draft pull request.
unattended.deliver: "pr"
A red main, a new Sentry error, a security alert, a finished feature flag, a bug report in Slack: each has a workflow that carries its evidence to the agents. Seven of the ten start by themselves on a machine of yours; the rest are test-run here and started by hand.
10 ready-made workflows
Claude Code signs in with your Claude plan and Codex with your ChatGPT plan. There are no API keys to paste, and every sign-in stays on the machine that runs your agents.
claude auth login · codex login
Export writes a GitHub Actions workflow next to the config, so real runs happen in your repository, on your runner minutes. Usage stays on your own plans.
.github/workflows/<name>.yml
What’s different
Hosted coding agents do the work in someone else’s cloud with one model checking itself. Automation canvases can call a model, but do not know what a pull request is. This is the space between them.
Every check a run makes is written down as a row: what the agent claimed, what git and the test command’s exit code showed, and whether they agree. Where nothing was measured, the row says so.
One command turns a finished run into a file you can play back: drag to any moment and see the plan, each review and its answers, the diff and the tests as they stood. The ones on this site are Relay’s own runs on its own repository.
Type one sentence — “when a Sentry error is new, fix it and ping Discord” — and watch the graph build itself. It runs in your browser: no model call, no credits, nothing leaves the page.
Hundreds of simulated runs of your graph show roughly how much of your plans a typical run uses, what a heavy one does, a month at your ticket volume, and how many tickets end in a pull request.
Publish a workflow at a public link with secrets, links, addresses and logins removed. Anyone can remix it into their own studio, and a README badge points people to it.
A snapshot before every editing session, named versions when you want them, and a restore you can undo.
The reviewer is the other vendor’s model, on every plan and every diff
Some hosted agents let you ask a second model for a review. Here it is the default, and a run says so when it did not happen.
Receipts: each claim an agent made, beside what git and the test exit code showed
Play a finished run back step by step, from a file you can share
Runs on the Claude and ChatGPT plans you already pay for
Hosted agents usually bill seats or credits of their own; canvases call APIs per key.
Your code stays on your computer or on your own CI runner
A rough usage forecast before the first real run
Build a workflow from a sentence without spending AI credits
The canvas is what runs: a step that cannot be performed is reported as not performed, never as done
One table says which steps are real, and the engine and the studio read the same copy of it.
Guardrails that refuse by default: allowlists, an injection screen, an approval that waits for a person
Unattended runs can never merge on their own
Exports to plain files you own, run by an open-source CLI or GitHub Actions: nothing hosted in the loop
Public share links that anyone can remix
Yes Partly No“Partly” means some tools in the category do it, or it takes setup. Categories, not products: individual tools change often.
Integrations
A real run uses GitHub, Linear, Sentry, Slack, Discord and any URL. The rest of the catalog is in the builder to design and test against, and says so.
A label, an assignment or a red build starts a run. Steps comment, label and open issues, and ask for review on the pull request.
An issue assigned or labelled starts a run. Steps move the ticket, attach the pull request and comment, with your API key.
A new or regressed error starts a run, with its trace as the task.
Steps post to your channel through an incoming webhook.
Steps post to your channel through a webhook.
Any tool that can send a webhook starts a run, and a step can call any URL, with headers kept out of the workflow.
Trackers, CI, error trackers, security scanners, support and chat are all in the catalog, so a workflow can be drawn around the tools you have. In a real run, a planned app’s step is sent to an endpoint of your own, or skipped and reported as not performed.
Explore the integrationsPricing
Free while in beta: make an account and build as much as you like. When you run for real, usage stays on the plans you already have.
$0while in beta, with an account
Design a workflow, inspect every step, and try it with simulated runs.
$0paid to Relay
Run on your repository’s own GitHub Actions, or pair your own computer with relay connect. Your providers bill their own usage.
FAQ
How the agents run, where your code lives, and what stays in your hands.
Connect a repository, pick a workflow, label an issue. It runs on your own GitHub Actions.