Skip to content

Repository files navigation

switchyard

One goal, many agents. switchyard runs Claude Code, Codex, Grok and Gemini (Antigravity) as one team from your terminal. They share a scope on disk, elect their own orchestrator, split the work by what each is good at — and when one of them runs out of its usage limit, another picks up its task exactly where it stopped.

$ switchyard init "add CSV export to the reports page, with tests"
$ switchyard run
· claude is orchestrating
· plan: 5 tasks
· codex takes "add the CSV serializer"
· claude takes "design the export button"
· codex hit quota; "add the CSV serializer" goes to someone else
· grok takes "add the CSV serializer"
· grok finished "add the CSV serializer"
…
5/5 tasks done

a run in the console: tasks as cars, handoffs as switches

Why

Every agent CLI is metered differently: a five-hour window here, a monthly subscription there, a request quota somewhere else. Working with one of them means stopping when it stops. switchyard treats them as interchangeable capacity: the budget of the whole team is the sum of its members, and a limit hit is a hand-off, not an outage.

How it works

Shared scope .switchyard/scope.json holds the goal, the tasks, who holds each, and short notes every agent leaves for the next. Writes are atomic, so a crash never tears it.
Self-organising roles The free provider with the best judgement becomes orchestrator and plans the run. If it runs dry, the team elects another.
Assignment by fit Each task names a skill (code, test, review, research, docs, plan). It goes to the free provider that lists that skill highest, with a penalty for providers already busy.
Failover Quota, rate-limit and auth messages are recognised in each vendor's own wording. The task is handed off with its history; the next owner is told who held it and to continue from the notes.
Cooling A limited provider rests until the reset time it printed ("resets in 3h 20m", "try again at 14:05"), or a sensible default. If nobody is free, switchyard waits for the first to return.

Beyond agent CLIs

Model APIs. AnthropicProvider and OpenAiProvider call a model directly — handy for planning and review, which edit no files. Anything OpenAI-compatible works through baseURL: xAI, OpenRouter, vLLM.

Local models. --ollama qwen2.5-coder:14b adds a model served by Ollama. It is slow and modest, but it never runs out, so the team always has someone left to write docs and tests.

MCP. switchyard mcp --as codex serves the scope over the Model Context Protocol. Register it in Claude Code, Codex, opencode or Copilot and the agent reads the briefing, claims tasks, leaves notes and finishes work through tools instead of prompt text.

// ~/.codex/config.toml equivalent, for Claude Code's .mcp.json
{ "mcpServers": { "switchyard": { "command": "switchyard", "args": ["mcp", "--as", "claude"] } } }

Evals. npm run evals -- claude codex ollama:qwen2.5-coder:14b runs the cases in evals/cases against each provider and prints a score per skill. Put the numbers into the provider table so assignment follows measurements.

Console

console/ is a Next.js app (tRPC, Prisma on Neon, shadcn/ui) that records runs and streams them live. Point the CLI at it with SWITCHYARD_CONSOLE_URL and SWITCHYARD_TOKEN; see console/README.md.

Install

npm install -g switchyard
switchyard providers

providers shows which agent CLIs are on your PATH. Log each of them in as you normally would; switchyard never stores credentials.

Commands

switchyard init "<goal>"                 start a scope in .switchyard/
switchyard run [--only claude,codex] [--parallel 3]
switchyard status                        tasks, owners, hand-offs and notes
switchyard providers                     installed agent CLIs and their skills

Library

import { run, newScope, CliProvider, KNOWN } from 'switchyard';

const team = [KNOWN.claude, KNOWN.codex].map((config) => new CliProvider(config!));
const scope = await run(newScope('migrate the date helpers to Temporal'), team, {
	onEvent: (line) => console.log(line),
});

Any object with name, skills, judgement and run(prompt) is a provider, so an HTTP API or a local model plugs in the same way.

Notes from running it

  • Several CLIs wait on standard input forever when it is left open by the parent. switchyard spawns every agent with stdin closed.
  • A stale OPENAI_API_KEY in the environment overrides a ChatGPT login in Codex and fails with 401. Put it in unsetEnv for that provider.
  • A task that fails the same way on every provider is not passed round forever: after twice the team size in hand-offs it is marked failed.

Development

npm install
npm test

License

MIT © Ivan Novikov

About

Run Claude Code, Codex, Grok and Gemini as one team: shared scope, self-assigned roles, failover when a provider runs dry.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages