Skip to main content

Chain any AI coding CLIs (Claude, Codex, Gemini, Aider, ...) into an approve-once pipeline.

Project description

agent-relay

Chain any AI coding CLIs into an approve-once pipeline.

English | 中文

You give a target. One agent plans, another reviews the plan, another implements it — automatically, with no copy-pasting between them. The only time it stops for you is the final gate, right before anything is committed.

  target ─▶ ┌──────┐   PLAN.md   ┌────────┐  review.md  ┌──────────┐   ⏸ you
            │ plan │ ──────────▶ │ review │ ──────────▶ │ implement│ ─────▶ commit?
            └──────┘             └────────┘             └──────────┘
            (claude)              (codex)                 (codex)

Each arrow is an automatic hand-off; files on disk are the medium. Swap any box for a different agent by changing one line of YAML.

Why

Running a multi-agent workflow by hand means copy-pasting one tool's output into the next, over and over. Add a third agent and the transfers multiply. agent-relay makes the hand-offs automatic and gates only the decision that actually needs a human.

Supported agents

Built-in adapters: claude (Claude Code), codex (OpenAI Codex), gemini (Gemini CLI), aider, and generic — wrap any CLI from YAML with no code:

- name: implement
  agent: generic
  command: ["mytool", "run", "--prompt", "{prompt}", "--out", "{output}"]

Placeholders: {prompt} {output} {workspace} {model} {role}.

Install

pipx install relaypipe         # once published
# or, from source:
pip install -e ".[dev]"

Quick start: idea → project (zero config)

The fastest path. Give an idea and a folder; agent-relay plans, loops the plan through review until it's solid, shows you the final plan, and — once you approve — builds the project into that folder. No YAML, no prompt files:

relaypipe new "a todo-list CLI in Rust with JSON persistence" -d ./todo-cli

What happens:

  1. plan — an agent drafts a build plan
  2. review loop — a reviewer critiques it; the plan is revised and re-reviewed until VERDICT: APPROVED or the loop cap (default 3) is hit
  3. ⏸ you approve — the final plan is printed; answer y to build
  4. build — the project is created in ./todo-cli

Useful options:

relaypipe new "..." -d ./app --agent codex          # use Codex to plan+review+build
relaypipe new "..." -d ./app --agent claude --build-agent codex   # mix agents
relaypipe new "..." -d ./app --max-iterations 5     # allow more review rounds
relaypipe new "..." -d ./app --dry-run              # preview the commands
relaypipe new "..." -d ./app --yes                  # CI: skip the approval prompt

For full control over steps, agents, and gates, write a pipeline (below) and use relaypipe run.

Use

# list available agents
relaypipe agents

# run the example pipeline
relaypipe run "Add a --json flag to the CLI" -p examples/pipeline.yaml

# preview commands without running anything
relaypipe run "..." -p examples/pipeline.yaml --dry-run

# resume an interrupted run
relaypipe run --resume -p examples/pipeline.yaml

# CI mode: auto-approve every gate
relaypipe run "..." -p pipeline.yaml --yes

# override the loop cap for this run (beats max_iterations in the YAML)
relaypipe run "..." -p pipeline.yaml --max-iterations 5

Example: agent-relay improving itself

The repo ships a self-hosted pipeline that points agent-relay at its own codebase. It reads this project's PLAN.md, has one agent review a roadmap item (agent-relay init), and has another implement it — pausing once for your approval before you commit:

# preview the chain (reads PLAN.md, no API calls)
relaypipe run -p examples/self-hosted/pipeline.yaml --dry-run

# run it for real
relaypipe run -p examples/self-hosted/pipeline.yaml

The goal is baked into the prompts, so no positional target is needed — the plan file is the input. This is the best worked example of the "review an existing plan → implement" flow: see examples/self-hosted/.

Pipeline config

name: plan-review-implement
workspace: .
steps:
  - name: plan
    agent: claude
    role: plan                  # plan | review | implement | generic
    prompt_file: prompts/plan.md
    output: PLAN.md             # what this agent writes

  - name: review-plan
    agent: codex
    role: review
    inputs: [PLAN.md]           # files fed into the prompt ({inputs})
    output: .agent-relay/plan-review.md

  - name: implement
    agent: codex
    role: implement
    inputs: [PLAN.md, .agent-relay/plan-review.md]
    approve_after: true         # the single human gate

Review loops (iterate up to a cap)

One plan→review pass is rarely enough. A loops: block repeats a contiguous group of steps until a reviewer approves — or a hard iteration cap is hit, so it never spins forever:

steps:
  - name: plan
    agent: claude
    role: plan
    inputs: [PLAN.md, .agent-relay/review.md]   # sees last round's feedback
    output: PLAN.md
  - name: review
    agent: codex
    role: review
    inputs: [PLAN.md]
    output: .agent-relay/review.md
  - name: implement
    agent: codex
    role: implement
    inputs: [PLAN.md]
    approve_after: true

loops:
  - name: plan-review
    steps: [plan, review]            # must be contiguous & in pipeline order
    until_step: review               # whose output holds the verdict
    max_iterations: 3                # the cap (override per-run with --max-iterations)
    approved_marker: "VERDICT: APPROVED"

How it stops:

  • The review prompt is told to end its output with VERDICT: APPROVED or VERDICT: NEEDS_WORK. The runner reads the verdict step's output: approved → exit the loop early; otherwise → re-run the group.
  • The feedback path is the normal file hand-off: list the review's output as an input of the first step, so the next pass sees the last review.
  • If the cap is reached without approval, the run logs 🛑 hit max_iterations and proceeds to the next step anyway (the human gate still backstops it).

The self-hosted example uses exactly this — see examples/self-hosted/pipeline.yaml.

Adding a new agent

Two ways:

  1. No code — use the generic adapter with a command: template (above).

  2. An adapter class — ~20 lines:

    from agent_relay.adapters.base import Agent, AgentContext, register
    
    @register
    class MyToolAgent(Agent):
        name = "mytool"
        binary = "mytool"
    
        def build_command(self, ctx: AgentContext) -> list[str]:
            cmd = [self.binary, "--prompt", ctx.prompt]
            if ctx.output_file:
                cmd += ["--out", str(ctx.output_file)]
            return cmd
    

    Ship it as a separate package by registering the agent_relay.adapters entry point — no fork needed.

Development

pip install -e ".[dev]"
pytest          # tests use mocked agents — no API keys needed
ruff check .

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

relaypipe-0.1.1.tar.gz (44.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

relaypipe-0.1.1-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file relaypipe-0.1.1.tar.gz.

File metadata

  • Download URL: relaypipe-0.1.1.tar.gz
  • Upload date:
  • Size: 44.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for relaypipe-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a61d57d88b94edc0921771a300c939bb92e08421e4a97c24b93827c8df378f33
MD5 0322a5223cc3adea241f11a99ec245fe
BLAKE2b-256 6343d6b59ff80f2d9a873d5619e4bb607e532a7742a32c5b1f0c439a9f5b9862

See more details on using hashes here.

Provenance

The following attestation bundles were made for relaypipe-0.1.1.tar.gz:

Publisher: python-publish.yml on yuzhiquan/agent-relay

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file relaypipe-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: relaypipe-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for relaypipe-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 008b0fb5328f21daf117b657a3cad0e9e4816e0a4528e8700d9ea02a841da9b2
MD5 0d87d2e841bb7bcb8b653b904403fe11
BLAKE2b-256 0c82927d1ebcab15a3c3098c38275d29b492859b66c999ef4b83d6f7d3e5dba2

See more details on using hashes here.

Provenance

The following attestation bundles were made for relaypipe-0.1.1-py3-none-any.whl:

Publisher: python-publish.yml on yuzhiquan/agent-relay

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page