Deterministic multi-step Claude flows.
Write the flow once. Run it the same way every time. A typed, checkpointed DAG of Claude Code invocations that resumes after crashes and never bills the API by surprise.
What Relay is
Relay is a TypeScript library and CLI for running multi-step Claude
workflows. You describe the workflow as a graph of steps in a
typed config file. Relay compiles that file into a DAG, executes each step
in topological order, and writes a checkpoint after every step. A crash, a
network blip, or a deliberate ^C never costs you a redo —
relay resume <runId> picks up at the last completed step.
It ships as two packages:
| Package | What it does |
|---|---|
@ganderbite/relay | The relay CLI. Runs flows, resumes failed runs, scaffolds new flows, inspects auth. |
@ganderbite/relay-core | The TypeScript library. Compiles a flow spec into a validated DAG and executes it. |
A flow is a directed acyclic graph of steps — prompt, script, branch, parallel, loop, ask, terminal — that pass typed JSON handoffs between them.
Why Relay exists
If you delegate work to AI agents, you have probably hit these walls:
- The longer a turn ran, the worse the output got — the conversation window filled with chatter.
- You forgot to invoke the right subagent, and the main agent half-finished the work.
- You wrote the same prompt a dozen times over, changing one file path or argument each time.
- Compacting the conversation to free up room meant re-explaining the whole goal from scratch.
- The main agent skipped steps to keep its window from filling, and you only noticed downstream.
- The same prompt produced different answers on re-run.
Relay turns a multi-agent run into a typed, checkpointed graph:
- Each step gets a fresh conversation window of its own — no chatter accrues across steps.
- Subagent definitions live in the flow file. You can't forget to invoke one.
- Prompts are templated files. You write the shape once and pass variables in.
- Every step is checkpointed. A crash or
^Cresumes from the last completed step. - Execution order is a DAG you can read, not a vibe the model decides.
60-second tour
Three commands take you from install to a real artifact on disk.
npm install -g @ganderbite/relay
relay init # configure your provider
relay doctor # check your environment
relay run codebase-discovery --repoPath=. # produce a real artifact relay init writes your provider choice to
~/.relay/settings.json. Without it, the CLI exits with
NoProviderConfiguredError before any step executes.
relay doctor tells you whether your environment is safe to run.
What a flow looks like
import { defineFlow, step, z } from "@ganderbite/relay-core";
export default defineFlow({
name: "hello",
version: "0.1.0",
input: z.object({ name: z.string() }),
steps: {
greet: step.prompt({
promptFile: "prompts/01_greet.md",
output: { handoff: "greeting" },
}),
summarize: step.prompt({
promptFile: "prompts/02_summarize.md",
dependsOn: ["greet"],
contextFrom: ["greeting"],
output: { artifact: "greeting.md" },
}),
},
});
A flow package is a directory containing flow.ts, a
prompts/ folder, and a package.json. The CLI runs it; the
library compiles and executes it. The handlebars-style templating engine
substitutes input fields and prior handoffs into the prompt files at step
start.
What you get
| DAG execution | Steps run in topological order. Cycles and missing dependencies fail at defineFlow() time, before a single token is spent. |
| Checkpoint & resume | Every step writes a checkpoint; relay resume <runId> continues a failed or aborted run from the last completed step. |
| Prompt templating | Handlebars interpolation of the flow's input and prior handoffs into prompt files. Write the shape once. |
| Typed handoffs | Zod schemas validate the JSON each step produces before the next step reads it. HandoffSchemaError exits with a distinct code so CI can route on it. |
| Subagent definitions | Declare ephemeral subagents per step — name, system prompt, tools, model. Resolved before the provider is invoked. |
| Cost tracking | Per-step tokens and dollar estimates persisted to metrics.json during the run. |
| Billing safety | The CLI refuses to silently route tokens to a paid API account when subscription credentials are configured. |
| A testing path | @ganderbite/relay-core/testing exports MockProvider, a zero-network, zero-cost provider for Vitest suites. |
Where to go next
- Step types — what
prompt,script,branch,parallel,loop,ask, andterminaldo, with one example each. - Real-world patterns — iterate-until-pass loops, dynamic agent fan-out, dynamic-question asks. Sourced from production flows.
- CLI commands — every
relayverb, what it prints, and the exit codes you can route on. - Author a flow — scaffold → run → fail → fix → resume, in seven small steps.