Ringer — swarm power without the frontier bill
Every copyable block in this guide is a prompt for Claude Code — Ringer is designed to run from it, with a frontier Claude model in the orchestrator seat while cheap workers do the typing. Other terminal agents can run these prompts too. The orchestrator should delegate implementation to a separate worker process rather than doing it inline, but that worker can use the same model. You still keep separate context, task directories, logs, retries, and executed verification; you only give up the cheap-model cost advantage. Ringer runs on macOS and Linux (Windows works inside WSL) and needs Python 3.11+ plus one worker CLI signed in; your agent checks both and fixes what's missing.
Hand your agent the whole setup — it proves each step as it goes
You don't install Ringer — your agent does, and proves it the Ringer way: three demo workers build in parallel, every artifact is verified by executing it, and a verdict table prints. Then the same prompt keeps going: the cheap worker lanes, your first real manifest on your own work, and the agent integration, one phase at a time, asking before each. Paste it once; everything below this section is the why, not a checklist you have to come back for.
You do Paste the prompt, approve commands as they go by, complete any sign-ins yourself, and answer the interview questions between phases.
The AI does Checks prerequisites, clones and configures, runs the demo, wires the lanes you want, drafts and runs your first real manifest, and installs the agent integration — proving every step with an executed check.
Show the full prompt
Set up Ringer on this machine end to end: prove it works by running its built-in
demo swarm, then walk me through the rest of the setup — cheap worker lanes,
my first real manifest, the agent integration — pacing each step with me.
Ringer is a single-file Python orchestrator that fans tasks out to cheap parallel
worker agents and verifies every result by executing a check command. It is
designed to be run from Claude Code: you are the orchestrator, and inexpensive
worker CLIs do the typing.
Repo: https://github.com/NateBJones-Projects/ringer — the README documents every
manifest field, engine, and config option, and templates/ ships manifest
skeletons. Read them as you go; they are the source of truth for anything this
prompt doesn't carry.
Treat this prompt as the whole setup guide: assume I will not read anything else.
After each phase, tell me what I now have, what's possible next, and ask whether
to continue.
1 — Prove it. Check python3 is 3.11 or newer (install a current Python via
Homebrew if not — stock macOS is usually old). Check a worker CLI is installed and
signed in — try codex --version (Codex is the demo's default worker); if none is
present, install one and hand me the sign-in. Clone the repo, copy
config.sample.toml to ~/.config/ringer/config.toml, and run ./ringer.py demo.
Show me the verdict table and confirm Ringside opened in my browser, with its URL.
2 — Cheap lanes. Offer to wire the worker lanes: OpenCode + OpenRouter
(one key in front of virtually every pay-per-token model — I paste it into
opencode auth login myself), and Grok Build if I hold a SuperGrok or X Premium
Plus plan (browser OAuth, cost reported as included-in-plan). Prove every lane
you set up with a one-task manifest whose check executes a real artifact.
3 — Real work. Interview me: what small batch of real work do I want done?
Draft swarm.json — 2-4 independent tasks, each with a self-contained spec, a
check that verifies the artifact by executing it and prints WHY it fails when it
fails, expect_files, and a one-sentence verified line saying what the check
proves. Run ./ringer.py lint swarm.json and fix what it flags, then run it and
walk me through the results in Ringside.
4 — Make it stick. Run ./ringer.py install-agent so you reach for Ringer
on your own when work is swarm-shaped, and tell me about ./ringer.py models —
the scoreboard that turns my own pass rates into routing once history
accumulates.
Sign-ins are mine: pause and hand me the terminal or browser — never
ask me to paste keys or credentials into chat, and never read them from files.
One phase at a time. After each, summarize what I have, then ask
before starting the next. If I stop early, tell me exactly what remains and that
pasting this prompt again resumes from wherever we left off.
The fields that matter
key names the task and its working directory. spec is the worker's prompt — write it as a self-contained brief, because it's also what anyone watching the dashboard reads as "what this agent was asked to do." check is a shell command run after the worker exits — exit 0 is PASS, anything else is FAIL. expect_files must exist and be non-empty for the task to pass — they're judged after the check runs, so a check is free to generate or export a deliverable itself — and they're harvested into the results page as clickable deliverables. verified is one plain-English sentence saying what the check proves. timeout_s kills runaways (default 900s). engine routes the task to a harness, and model picks which model that harness runs (section 04). task_type tags what kind of work it is — that's the bucket the scoreboard in section 06 accumulates pass rates under. full_access unlocks nested sub-workers — a flagged worker can spawn its own parallel crew on cheap tokens — and must also be enabled in config, so nobody trips into it.
Two newer fields exist for controlling spend and exposure. max_attempts caps how many tries a task gets (default 2); set it to 1 when you want a no-retry lane, because a second attempt at an oversized or over-limit request only repeats the waste. redact_spec hides the spec from Ringer's state, its logged command, and the eval row — use it when the prompt itself carries something you do not want written to disk.
Have your agent write your next manifest
A manifest is just JSON: a name, a working directory, and a list of tasks — each one a spec (the worker's prompt), a check (any shell command — exit 0 means pass), the files you expect to exist, and one plain-English sentence saying what the check proves. The craft is in the checks: a check that prints WHY it fails is what makes the retry prompt smart. Your agent knows all of this once it reads the README — so point it at real work and let it draft.
You do Tell it what small batch of real work you want done, and read the results page with it.
The AI does Drafts the manifest, writes checks that fail loudly, lints it, runs it, and walks you through what passed and why.
Write my next Ringer manifest and run it.
- Read README.md in my ringer clone for the manifest schema and check-writing guidance.
- Interview me briefly: what small batch of real work do I want done? Aim for 2-4 independent tasks.
- Write swarm.json: for each task, a self-contained spec, a check that verifies the artifact by executing it and prints WHY it fails when it fails, expect_files, and a one-sentence "verified" line saying what the check proves.
- Run ./ringer.py lint swarm.json and fix everything it flags before spending a token.
- Run ./ringer.py run swarm.json, then walk me through the results page in Ringside: what passed, how each check proved it, and what any retry did with the failure output.
The full quickstart prompt already walked you through your first one — this is the standalone brief for every batch after.
Failures get one honest second chance
When a check fails or a worker times out, Ringer retries once — and injects the failure output into the retry prompt, so the worker sees exactly what broke instead of guessing. One retry, not an endless loop: if a task can't pass in two informed attempts, you want to know, because the spec is usually what's broken.
Parallel workers on one repo, without the collisions
Turn on worktrees mode and every task gets its own isolated git worktree of your repo — ten workers editing the same codebase with zero stepped-on toes. One footgun to respect: passing tasks get their worktrees removed, including anything written inside them. Write deliverables outside the worktree, or have your check copy artifacts out before it exits 0.
ringer ask — a read-only question over a selected packet
A single question, answered by one clean worker over a context packet that was selected for it rather than inherited from your session. The packet selector lives inside ringer.py itself — the single-file rule survived — so there is no sibling module to install.
It is read-only by design. Point it at sources with --source (repeatable) and an accepted-result file with --state, cap the packet with --max-packet-bytes, hide sensitive material with --redact, and see exactly what would be sent with --dry-run before spending anything. Engine and model selection work the same way they do in a manifest.
This is the lane for "what did we decide about X," "does this file already handle Y," and "summarize the three relevant passages" — questions where the cost is not the thinking, it is everything the question would otherwise drag along with it.
Use ringer ask instead of reading these files into your own context.
- Run ./ringer.py ask with --dry-run first and show me the selected packet: which sources it pulled from, how many bytes, and what got left out.
- If the packet looks right, run it for real and show me the answer plus the reported token use.
- Tell me plainly what the check proved and what it did not.
The check on an ask proves that an answer was produced. It never proves the answer is right. Treat it as a bounded read, not a verified result — that distinction is written into the skill on purpose.
Spend your own context deliberately
The orchestrator playbook now carries a section the four rules never covered: how the seat doing the orchestrating spends its own context. Delegating implementation was always the point; quietly reading twelve files into the orchestrator before writing the manifest was the hole in it.
The rule is the same one the Token Saver skill applies inside Codex and Claude — search before you read, select passages rather than whole files, carry the accepted result rather than the argument that produced it, and do not open tools this job cannot use. Ringer's ask lane exists so the orchestrator has somewhere to send a question that would otherwise be answered by loading the repository into itself.
What ask is not: the pre-call gateway
[Get the standalone Token Saver skill ↓](https://unlock-ai.natebjones.com/guides/cut-token-waste#the-skill)
ringer ask runs when you invoke it. It is not the local gateway that sits between Codex CLI and the model provider and reduces a request before the provider ever receives it. That gateway is a separate, optional path with its own tradeoffs: it needs provider configuration and API credentials, those calls may bill against your API account rather than the subscription in your consumer app, and its verified coverage today is Codex CLI text-answer turns.
Be specific about the gap: the Anthropic request adapter passes its unit tests, but a live Claude Code 2.1.132 request retried after a gateway stop, so that path is not being called compatible yet. Claude Code users who want most of this benefit should use the standalone Token Saver skill, which needs no gateway at all.
An engine is a config block
Codex ships built in. Any other harness is a few lines of TOML in your config — the binary, an argument template, and optionally a regex that parses token usage out of its output. The shipped config.sample.toml carries verified blocks for Grok Build CLI and OpenCode, ready to uncomment — and OpenCode is the universal one: a single engine block with a {model} placeholder runs virtually any model behind one CLI. Set model_default in the config, override per task in the manifest.
Hand the lane setup to your agent
OpenRouter is one account and one API key in front of virtually every model on the market — GLM, Kimi, DeepSeek, whatever drops next week — and a few dollars of prepaid credit goes a long way at these rates. Grok Build is xAI's coding-agent CLI: if you already hold a SuperGrok or X Premium Plus plan, it's a worker lane with no per-token bill at all, and Ringer reports its cost as included in plan. Your agent wires up both lanes end to end. One rule survives the delegation: credentials never travel through the agent — each tool's own sign-in holds them (OpenCode keeps the key in its own auth store; Grok is browser OAuth), and you're the one who completes it.
You do Paste your OpenRouter key into opencode auth login when the agent hands you the terminal, and finish Grok's browser OAuth if you hold the plan.
The AI does Installs the CLIs, wires the engine blocks into your config, and proves each lane with a real verified run.
Show the full prompt
Set up Ringer's cheap worker lanes on this machine: OpenCode + OpenRouter, plus Grok Build if I have the plan for it.
Whether I already have an OpenRouter account and API key.
Whether I hold a SuperGrok or X Premium Plus plan.
The absolute path of my ringer clone.
Install the OpenCode CLI if it's missing — pick the official method that fits this system and tell me which you chose before running it.
Run opencode auth login, select OpenRouter, then pause and hand me the terminal so I can paste my API key myself. I'll create it at openrouter.ai/settings/keys.
In ~/.config/ringer/config.toml, uncomment [engines.opencode] and set bin to the ABSOLUTE path of engines/opencode-sandboxed.sh inside my ringer clone. On Linux or WSL, point bin at the opencode binary itself instead — the sandbox wrapper is macOS-only.
If I hold a SuperGrok or X Premium Plus plan: install Grok Build, run grok login, let me finish the OAuth in the browser, then uncomment [engines.grok].
Prove every lane you set up: for each, write a one-task manifest whose check verifies a real artifact by executing it, run ./ringer.py run on it, and show me the PASS.
Never ask me to paste an API key or credential into chat, and never read one out of a file. Sign-ins are mine; everything around them is yours.
Two models ride the Grok lane: grok-build for heavier work, and grok-composer-2.5-fast — the speed pick — as the default. The quickstart prompt offers this same setup in its phase 2.
Mix models inside a single swarm
engine and model are per-task fields. That means one manifest can send the gnarly refactor to your strongest worker, the test-writing sweep to the cheapest one, and a genuine bakeoff can run three different models on the same task — in the same run, on the same dashboard, under the same verification. The dashboard shows which model actually did each task's typing, so a bakeoff can't quietly run one model under three names. Cross-model isn't a migration project; it's a JSON field.
The safety rails travel with every engine
The invariants that make headless agents behave — stdin closed so they can't hang waiting for a keyboard, explicit sandbox flags so writes don't silently fail, process-group kills so timeouts actually kill, raw output in every log — are enforced by the orchestrator, not by the engine. Plug in a new model and it inherits all of them on day one.
What you're looking at
The top of the page is the run's results document, updating live: what the job is, a progress bar of green and red rounds, and "The work" — every deliverable each worker has filed, with a plain-English line saying what the check proved and the check's raw output one click away. Below it, the agents: expand a round, click a worker, and you see the exact brief it was handed, which engine and model are doing the typing, and its live work stream — the agent actually thinking and working, not a spinner. Past runs stay in the library with every round versioned, so "what did the swarm make last Tuesday" is a dropdown, not an archaeology dig.
The state every other dashboard forgets
Finished and running are easy. Ringside also knows died — a swarm whose orchestrator vanished without finishing, detected by checking whether the process is actually still alive. Silent orchestrator death is the failure mode that turns "I thought it was running" into an hour of lost time, and it gets its own unmissable state.
Open it
There's nothing to install and nothing to do: the first run starts Ringside and opens the tab for you, and every run after that streams into the same tab instead of popping a new one. It's a local page served from your machine on 127.0.0.1; your specs, logs, and results never leave the building. (A native desktop build of Ringside exists as a v0.1.1 prototype for Windows and Linux on the release page, but the web dashboard is currently ahead of it — start there.)
Tab gone?./ringer.py hud brings the page back any time, at http://127.0.0.1:8700 — or just ask your agent to open Ringside.
Everything lands in one local file
Out of the box, every attempt lands in a JSONL file on your machine — zero setup, no accounts, nothing leaves the building. Each row records which model did the typing, what kind of task it was, whether it passed on the first try, and what it cost in time and tokens. Failure rows are deliberately the most detailed: a failed attempt with its raw check output tells you which spec styles, engines, and task shapes actually work.
The scoreboard: your own pass rates, turned into routing
./ringer.py models turns that log into a per-model, per-task-type scoreboard, and first-try pass rate is the routing signal: which model to hand which kind of work, answered from your machine's own verified history instead of a leaderboard built on someone else's workload. Don't read it like a report — have your agent read it and hand you a policy.
Read my Ringer scoreboard and turn it into a routing policy.
- In my ringer clone, run ./ringer.py models — and ./ringer.py models --open so I get the rendered page too.
- For each task_type with real history, tell me which model should own it and why. First-try pass rate is the signal; cost is the tiebreaker.
- Flag any bucket where the data is too thin to call, and what kind of run would fill it.
- Finish with the exact "engine" and "model" lines to put in my next manifest.
It watches the market and auditions the rookies
./ringer.py catalog keeps a local snapshot of every model on OpenRouter — prices, context sizes, and a change log of what arrived, what got cheaper, and what just went free (models genuinely do). Runs refresh it quietly in the background, at most once a day. Then models --explore splits your history into tiers — proven, on probation, and cheap untested candidates worth a look. The habit that compounds: hand one low-stakes task per swarm to a promising unknown, and let the receipts decide whether it gets promoted.
Find me a rookie worth auditioning.
- In my ringer clone, run ./ringer.py catalog --changes and ./ringer.py catalog --free: what's new, what got cheaper, what's free right now.
- Run ./ringer.py models --explore: which cheap models are proven, on probation, or untested in MY log.
- Pick one promising untested model and make the case for it in two sentences.
- Add one low-stakes task routed to it in my next manifest — the receipts decide whether it gets promoted.
The flywheel this unlocks
When a new cheap model drops, you don't argue about whether it's ready — you audition it and read the pass rates. When a task class keeps failing, the eval rows show whether the spec, the engine, or the check is at fault. And because the log is yours, the answers are too: every user's workload is different, and a model that's proven in someone else's log is untested in yours until you've run it. Model choice stops being a debate and becomes a query. That's the quiet superpower: the expensive part of cross-model isn't wiring, it's knowing — and the log knows.
One day, zero hand-written implementation
The orchestrator, the dashboard, and the native HUD were all implemented by cheap parallel workers from written specs, reviewed by a frontier model, in a single day. The tool's own verify stage caught its first three real bugs — a sandbox that silently blocked writes, a run-ID collision between same-second swarms, a state field that never serialized. Same-day field testing by an agent on a second machine produced four more fixes, merged within the hour. Every one of those lessons is now baked in, and nobody who downloads it pays that tuition again.
The four rules that cost real debugging hours
One: stdin is always closed — headless CLI agents hang forever waiting on a keyboard that isn't there. Two: sandbox mode is always explicit — defaults silently resolve to read-only in temp directories and every write fails without an error you'll see. Three: verification executes the artifact — an agent's own "done" is not evidence. Four: raw output only — logs carry verbatim worker output, never a summary, because anything that needs judgment should read the real data. You get all four for free, on every engine.
Everything is on GitHub — and it ships its own playbook
The repo is public, the README documents every manifest field and config option, and templates/ ships ready-made manifest skeletons for the patterns that work: review swarms, fix swarms, focus groups, model bakeoffs, research-with-proof. If you ran the quickstart, you already have all of it. The move that makes it stick: have your agent match those templates to the work you actually do — the first time a swarm of cheap workers hands you a stack of verified PASSes on your own backlog, the economics stop being an argument and start being your default.
Open templates/ in my ringer clone and walk me through the manifest skeletons it ships — review swarm, fix swarm, focus group, model bakeoff, research-with-proof.
Then interview me about the work I actually do most weeks, recommend the one template that fits it best, and adapt it into a manifest I could run this week. Lint it with ./ringer.py lint before you hand it to me.
The repo: github.com/NateBJones-Projects/ringer — clone and demo are covered by the quickstart prompt in section 01.
Make your agent reach for it on its own
If an AI agent does your orchestrating, one more step matters: between swarms, agents drift back to invisible inline work, and reminders decay. install-agent ships the enforcement with the product — it installs the orchestrator playbook as a skill in Claude Code, the seat this guide has assumed all along, and registers two gentle hooks that notice swarm-shaped work happening outside a run and point the agent back at Ringer, once per session. Nothing is ever blocked; telling your agent "just do it inline" still works. Fittingly, the agent installs its own leash.
Install Ringer's agent integration on yourself.
- Run ./ringer.py install-agent in my ringer clone.
- Show me what it installed: the orchestrator-playbook skill, the session hooks, and where each lives on disk.
- Explain in three sentences what you'll now do differently when you see swarm-shaped work in our sessions.
Undo any time:./ringer.py uninstall-agent. The quickstart prompt runs this as its final phase.