Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .agents/skills/ringer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
name: ringer
description: >-
Orchestrate implementation and evaluation work through Ringer verified
worker swarms. Use before drafting or running a Ringer manifest, delegating
repeatable edits or reviews, choosing Claude/Codex/OpenCode/Grok workers,
or diagnosing a failed Ringer run. Skip for read-only exploration, pure
conversation, and a single one-shot edit that does not start an edit/test loop.
---

# Ringer orchestrator playbook for Codex

You are the decision-maker. Ringer workers are the implementation and review
lanes. Keep planning, task boundaries, check design, result review, and final
synthesis in the parent Codex thread; give mechanical or parallelizable work to
Ringer.

When the user requests Sol Advanced, use GPT-5.6 Sol as the parent orchestrator.
In the Codex app, choose Sol and an appropriate reasoning level under Advanced.
For CLI sessions, the equivalent quality-first starting point is:

```bash
codex -m gpt-5.6-sol -c model_reasoning_effort=high
```

`Advanced` is a product selector, not a value for `model_reasoning_effort`.
Raise or lower the effort only when task difficulty warrants it.

## Operating contract

1. Read `templates/README.md` before inventing a swarm shape.
2. Keep each worker task bounded, stateless, and independently verifiable.
3. Put instructions in `spec`; do not make the worker chase an instruction file.
4. Give concurrent editing workers disjoint file ownership, normally through
worktrees.
5. Write a check that executes the artifact and prints a useful reason on
failure. `expect_files` is only a fast existence preflight.
6. Run `./ringer.py lint MANIFEST` before spending worker tokens.
7. Use `./ringer.py run MANIFEST --baseline` when a check can be proved against
the untouched tree.
8. Run the real swarm with an explicit identity, for example:

```bash
./ringer.py run MANIFEST --identity sol-advanced
```

9. Review the run state, raw logs for failures or retries, and at least one
passing artifact. A worker's summary is never proof.
10. Integrate worker patches serially and run the repository's full validation
after integration.

Keep Ringside visible for interactive work. Do not use `--no-dashboard` unless
the user asks for headless execution or the run is an automated test.

## Worker routing

The manifest selects a worker with `engine` and, where supported, `model`.
Ringer applies the same closed-stdin, timeout, retry, raw-log, and executed-check
rules to every engine.

- `claude`: Claude Code's non-interactive worker lane. The built-in engine pins
`claude-sonnet-5`, enables Claude's native task-directory sandbox, refuses to
fall back to unsandboxed Bash, and streams raw JSON events. Use `engine_args`
such as `["--effort", "low"]` or `["--effort", "high"]` per task.
- `codex`: the default Codex CLI worker lane. Do not confuse this with the parent
Sol orchestrator; it is just another worker when selected in a manifest.
- `opencode`: the OpenRouter harness for third-party models. Put the model slug
in the manifest `model` field.
- `grok`: the Grok Build CLI lane when configured.

Prefer Claude or another cheaper/proven lane for tightly specified typing,
tests, mechanical changes, and independent reviews. Keep architecture choices,
cross-task dependencies, conflict resolution, and acceptance judgment with Sol.
Use `./ringer.py models --task-type TYPE` and local evidence when choosing among
available workers; do not assume one model is best for every task shape.

Example task:

```json
{
"key": "claude-tests",
"engine": "claude",
"model": "claude-sonnet-5",
"engine_args": ["--effort", "medium"],
"task_type": "test-hardening",
"spec": "You own only tests/test_widget.py. Add the named regression tests, do not edit production code, run python -m unittest tests.test_widget, and leave changes uncommitted.",
"check": "python -m unittest tests.test_widget || { echo 'FAIL: widget regression tests did not pass'; exit 1; }",
"verified": "The widget regression suite executes and passes"
}
```

## Safety boundaries

- The built-in Claude sandbox is fail-closed on macOS, Linux, and WSL2. If the
platform cannot start it, the worker must fail setup rather than run loose.
- `full_access: true` is exceptional and still requires `allow_full_access =
true` in Ringer config. Use it only when the task genuinely needs to spawn
its own processes outside the task boundary.
- Worktree PASS cleanup removes the worktree. Export patches and any ignored
deliverables outside the worktree in the check before it exits zero.
- Do not let review workers fix what they discovered. Sol confirms findings,
then creates a separate fix swarm.

## Completion report

Return the plan chosen, worker/model routing, checks executed, attempt/retry
results, artifacts or patches produced, integration validation, and any
remaining uncertainty. Separate verified facts from worker claims.
5 changes: 4 additions & 1 deletion .claude/skills/ringer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ description: >-
`--no-dashboard` except in automated tests or when the user explicitly
asks.

Ringer runs manifest tasks in parallel across cheap CLI workers (Codex,
Ringer runs manifest tasks in parallel across CLI workers (Claude Code, Codex,
OpenCode/GLM, others via config) and verifies every task by **executing a
check command** — exit 0 is the only PASS. Failed tasks are retried once
with the check's actual failure output injected into the retry prompt. You —
Expand Down Expand Up @@ -229,6 +229,9 @@ per task via the manifest `engine` field. Defaults are deliberate:

- **codex** (default): strongest general worker. Use per-task `engine_args`
to set reasoning effort — spend it on hard tasks, not boilerplate.
- **claude**: built-in Claude Code worker lane, pinned to `claude-sonnet-5`
with a fail-closed native task-directory sandbox. Use per-task
`engine_args` such as `["--effort", "low|medium|high"]`.
- **opencode**: the universal lane — any OpenRouter model via the `model`
field (engine `model_default` is GLM-5.2, the cheap-intelligence pick).
Validate a model new to you with a trivial one-task manifest before
Expand Down
40 changes: 34 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Frontier models are finally good enough to trust with real implementation — but their tokens are priced like senior-engineer hours, and most of a build is not senior-engineer work. It's scaffolding, migrations, test suites, batch transforms. Mechanical labor.

So split the roles. Your best model writes the specs and reviews the results. A swarm of cheap workers — Codex, Grok, anything with a CLI — does the implementation in parallel. Your premium budget stops scaling with lines of code written and starts scaling with decisions made.
So split the roles. Your best model writes the specs and reviews the results. A swarm of cheaper workers — Claude, Codex, Grok, anything with a CLI — does the implementation in parallel. Your premium budget stops scaling with lines of code written and starts scaling with decisions made.

One problem: parallel agents lie. "Done" doesn't mean working. Ringer doesn't take the worker's word for anything — it **executes your check command** against the artifact. Pass or fail is decided by running the code, not by reading the agent's summary. Failures retry once with the failure context injected, and every attempt is logged so your setup gets measurably better over time.

Expand All @@ -17,7 +17,7 @@ And because a swarm you can't see is a swarm you don't trust: **Ringside**, a lo
## How it works

```
manifest.json ──▶ ringer.py ──▶ N parallel workers (codex exec, each in its own dir)
manifest.json ──▶ ringer.py ──▶ N parallel workers (Claude/Codex/etc., one dir each)
│ │
│ ▼
│ executed checks ── fail ──▶ retry once w/ failure context
Expand Down Expand Up @@ -47,10 +47,10 @@ git clone https://github.com/NateBJones-Projects/ringer && cd ringer
mkdir -p ~/.config/ringer && cp config.sample.toml ~/.config/ringer/config.toml # optional — sane defaults without it
```

3. Teach your agent to route work through Ringer:
3. Teach Codex and Claude Code to route work through Ringer:

```bash
# optional but recommended: teach your agent to route work through ringer
# optional but recommended: installs both host skills; Claude also gets nudge hooks
./ringer.py install-agent
```

Expand All @@ -62,6 +62,21 @@ mkdir -p ~/.config/ringer && cp config.sample.toml ~/.config/ringer/config.toml

The demo spawns three Codex workers in parallel, verifies each artifact by executing it, and prints a verdict table — and Ringside, the live dashboard, opens in your browser on its own. If all three say PASS, that's the whole setup.

### Sol Advanced orchestrator + Claude workers

Ringer now ships the inverse of its original Claude-orchestrator/Codex-worker setup as a first-class path: GPT-5.6 Sol can own planning and acceptance in Codex while Claude Code and any other configured engines do bounded worker tasks.

```bash
npm install -g @anthropic-ai/claude-code
claude auth login
./ringer.py install-agent --target codex
codex -m gpt-5.6-sol -c model_reasoning_effort=high
```

In the Codex app, choose GPT-5.6 Sol and High reasoning under Advanced, then invoke `$ringer`. The built-in `claude` engine is immediately selectable with `"engine": "claude"`; its default lane pins `claude-sonnet-5`, uses Claude's native sandbox in fail-closed mode, and accepts per-task effort through `"engine_args": ["--effort", "medium"]`.

The architecture, setup, mixed-worker manifest, security boundaries, and acceptance rollout are in [Sol Advanced orchestrator, heterogeneous workers](docs/SOL-ORCHESTRATOR.md).

Run your own batch:

```bash
Expand Down Expand Up @@ -144,7 +159,7 @@ Run one command:
./ringer.py install-agent
```

It installs the ringer skill — the orchestrator playbook user-level for Claude Code, and registers two gentle hooks: a Bash hook that notices model-calling or harness commands running outside a live Ringer run, and an edit-loop hook that notices batch editing without a run. Each hook nudges ONCE per session, pointing the agent at the skill.
It installs the Ringer orchestrator playbook user-level for both Codex (`~/.agents/skills/ringer`) and Claude Code (`~/.claude/skills/ringer`). Claude also receives two gentle hooks: a Bash hook that notices model-calling or harness commands running outside a live Ringer run, and an edit-loop hook that notices batch editing without a run. Each hook nudges ONCE per session, pointing the agent at the skill. Use `--target codex` or `--target claude` when you want only one host, and `--project` for repo-local installation.

The hooks never block anything. A user who says "just do it inline" is obeyed; uninstall with `./ringer.py uninstall-agent`.

Expand All @@ -154,7 +169,7 @@ For CI and evals, `config.sample.toml` includes `[engines.mock]` so the enforcem

![Identical workers, each under its own light](docs/engines.png)

Ringer ships with three worker lanes: **Codex CLI** is the built-in default, and `config.sample.toml` carries verified engine blocks for **Grok Build CLI** (works as-is once you `grok login`) and **OpenCode + OpenRouter** (one edit: point `bin` at the sandbox wrapper in your clone). Anything else with a headless CLI is a config block away:
Ringer ships with four worker lanes: **Codex CLI** is the built-in default, **Claude Code** is also built in, and `config.sample.toml` carries verified engine blocks for **Grok Build CLI** (works as-is once you `grok login`) and **OpenCode + OpenRouter** (one edit: point `bin` at the sandbox wrapper in your clone). Anything else with a headless CLI is a config block away:

```toml
[engines.mymodel]
Expand All @@ -164,6 +179,19 @@ args_template = ["run", "{spec}", "--dir", "{taskdir}"]

Per-task `"engine": "mymodel"` routes work to it — the invariants (stdin closed, process-group kill, executed verification, raw logs) apply to every engine identically.

### Claude Code worker lane

Install and authenticate Claude Code once:

```bash
npm install -g @anthropic-ai/claude-code
claude auth login
```

Then route any task with `"engine": "claude"`. The built-in argv puts the spec immediately after `-p`, selects `claude-sonnet-5` explicitly, streams verbose JSON into the raw worker log, and disables session persistence. Sandboxed tasks enable Claude's native sandbox with automatic approval only inside that boundary, remove its unsandboxed-command escape hatch, and fail if the platform sandbox is unavailable. On Linux/WSL2, install `bubblewrap` and `socat`; Claude's sandbox is not available on WSL1.

Use per-task `engine_args` for worker effort, for example `["--effort", "low"]` on mechanical work or `["--effort", "high"]` on a demanding bounded task. `full_access: true` switches Claude to bypass mode only when Ringer's separate `allow_full_access` gate is enabled.

### The universal harness: OpenCode + OpenRouter

Unless a model ships its own first-class harness (Codex does), OpenCode is the harness that runs it — one engine block covers every OpenRouter-served model. `config.sample.toml` includes a ready-to-uncomment engine whose `{model}` placeholder is filled per task from the manifest's `"model"` field, with `model_default` as the fallback. The shipped default is OpenRouter's `z-ai/glm-5.2` — roughly $0.74/M input and $2.33/M output (2026-07), about 20-30x cheaper output than frontier coding models; a complete write-code-and-pass-the-check task lands around a penny.
Expand Down
38 changes: 38 additions & 0 deletions config.sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,44 @@ token_regex = "tokens\\s+used\\s*:?\\s*([0-9][0-9,]*)"
# default reads the `model:` header; override it here only if that format changes.
model_report_regex = "(?m)^model:[ \\t]*([^ \\t\\r\\n]+)[ \\t]*\\r?$"

# Claude Code is a built-in worker lane, so no config block is required. This
# explicit block documents and lets you override the shipped defaults. Install
# with `npm install -g @anthropic-ai/claude-code`, then `claude auth login`.
# Ringer runs Claude in non-interactive stream-JSON mode, pins the current
# Sonnet model instead of inheriting local settings drift, and passes per-task
# `engine_args` through (for example ["--effort", "low|medium|high"]).
[engines.claude]
bin = "claude"
model_default = "claude-sonnet-5"
args_template = [
"-p",
"{spec}",
"--output-format",
"stream-json",
"--verbose",
"--no-session-persistence",
"--model",
"{model}",
"{access_args}",
"{engine_args}",
]

# Claude's native sandbox writes only inside the worker cwd. failIfUnavailable
# prevents a missing Seatbelt/bubblewrap setup from silently running loose, and
# allowUnsandboxedCommands=false removes Claude's sandbox escape hatch.
sandbox_args = [
"--permission-mode",
"acceptEdits",
"--settings",
'{"sandbox":{"enabled":true,"failIfUnavailable":true,"autoAllowBashIfSandboxed":true,"allowUnsandboxedCommands":false}}',
]
full_access_args = [
"--dangerously-skip-permissions",
"--settings",
'{"sandbox":{"enabled":false}}',
]
model_report_regex = '"model"\s*:\s*"([^"]+)"'

# Grok Build CLI (xAI). Install: curl -fsSL https://x.ai/cli/install.sh | bash
# (or: npm install -g @xai-official/grok), then `grok login` — OAuth on a
# SuperGrok or X Premium Plus plan. Headless mode (-p) runs a full agentic
Expand Down
Loading