[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-92905":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":9,"rankLanguage":9,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":9,"pushedAt":9,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":15,"starSnapshotCount":15,"syncStatus":26,"lastSyncTime":27,"discoverSource":28},92905,"ringer","NateBJones-Projects\u002Fringer","NateBJones-Projects","Ringer — parallel AI-agent swarm orchestrator. Ringside — its native mission-control HUD. Fable-quality output without Fable-level burn.",null,"Python",75,34,3,4,0,6,45.23,"Other",false,"main",true,[],"2026-07-22 04:02:07","# Ringer\n\n![Ringer — she reviews; the wall works](docs\u002Fhero.png)\n\n**Parallel AI-agent swarms that prove their work. Your expensive model plans and reviews; cheap workers do the typing.**\n\nFrontier 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.\n\nSo 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.\n\nOne 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.\n\nAnd because a swarm you can't see is a swarm you don't trust: **Ringside**, a local web page every run opens automatically, showing every live swarm on your machine — who's running it, what each worker is doing, elapsed time, token burn — in real time, plus a versioned library of what past runs produced.\n\n## How it works\n\n```\nmanifest.json ──▶ ringer.py ──▶ N parallel workers (codex exec, each in its own dir)\n                      │                │\n                      │                ▼\n                      │         executed checks ── fail ──▶ retry once w\u002F failure context\n                      │                │\n                      ▼                ▼\n              ~\u002F.ringer\u002Fruns\u002F    eval log (JSONL or Postgres)\n                      │\n                      ▼\n              Ringside, in the browser (live, all swarms, all identities)\n```\n\n## Quickstart\n\nRinger runs on macOS and Linux (Windows via WSL) and needs Python 3.11+.\n\n1. Install a worker CLI and sign in (Codex is the built-in default engine):\n\n```bash\nnpm install -g @openai\u002Fcodex   # or: brew install --cask codex\ncodex login                    # sign in with your ChatGPT plan\n```\n\n2. Get the repo:\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002FNateBJones-Projects\u002Fringer && cd ringer\nmkdir -p ~\u002F.config\u002Fringer && cp config.sample.toml ~\u002F.config\u002Fringer\u002Fconfig.toml   # optional — sane defaults without it\n```\n\n3. Teach your agent to route work through Ringer:\n\n```bash\n# optional but recommended: teach your agent to route work through ringer\n.\u002Fringer.py install-agent\n```\n\n4. Run the demo:\n\n```bash\n.\u002Fringer.py demo                                      # 3 real workers, verified end to end\n```\n\nThe 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.\n\nRun your own batch:\n\n```bash\n.\u002Fringer.py run swarm.json --max-parallel 4\n```\n\n```json\n{\n  \"run_name\": \"my-batch\",\n  \"workdir\": \"\u002Ftmp\u002Fmy-batch\",\n  \"max_parallel\": 3,\n  \"tasks\": [\n    {\n      \"key\": \"alpha\",\n      \"spec\": \"Create alpha.txt containing exactly: alpha ready\",\n      \"check\": \"test \\\"$(cat alpha.txt)\\\" = \\\"alpha ready\\\"\",\n      \"expect_files\": [\"alpha.txt\"]\n    }\n  ]\n}\n```\n\nEach task gets its own directory, its own worker, its own log, and its own verdict. `check` is any shell command — exit 0 is the only thing Ringer believes.\n\n> **Write checks that print why they fail.** A silent `exit 1` (the `git diff --quiet` style) costs you twice: the retry prompt gets no failure context to fix against, and the eval log records an undiagnosable row. `diff` beats `diff -q`; an assert with a message beats a bare test.\n\n**Identity**: runs are stamped with an orchestrator identity (shown in Ringside and eval rows). Resolution order: `--identity` > `FLEET_IDENTITY`\u002F`RINGER_IDENTITY` env > a `.fleet-agent` file found walking up from the working directory (drop one in a repo root to give that repo's swarms their own name) > `identity_default` in config > short hostname.\n\n### Manifest fields\n\n| Field | What it does |\n|---|---|\n| `key` | Task name — becomes the working subdirectory and the label everywhere |\n| `spec` | The prompt handed to the worker |\n| `check` | Shell command run after the worker exits; exit 0 = PASS |\n| `expect_files` | Files that must exist and be non-empty before the check runs |\n| `engine` | Which configured engine runs this task (default `codex`) |\n| `model` | Which model a harness engine runs for this task — fills the engine's `{model}` placeholder (e.g. `\"openrouter\u002Fmoonshotai\u002Fkimi-k2.7\"`); empty uses the engine's `model_default` |\n| `task_type` | Optional free-form string naming the kind of work this task is, so the model-performance log can slice pass rates by task shape rather than only by model. Suggested vocabulary: `code-feature`, `code-fix`, `code-review`, `test-hardening`, `docs`, `research`, `persona-review`, `copywriting`, `site-build`, `motion-design`, `image-gen`, `data-pipeline`, `format-conversion`, `probe`, `bakeoff`. Empty is allowed; the log just reports it under `(none)`. |\n| `timeout_s` | Per-task kill timer (default 900) |\n| `engine_args` | Extra CLI flags for this task's worker, spliced in at the engine's `{engine_args}` placeholder — e.g. `[\"-c\", \"model_reasoning_effort=low\"]` so the orchestrator picks reasoning depth per task |\n| `verified` | One plain-English sentence saying what the check proves — shown on the results page next to \"finished & checked\" |\n| `full_access` | Worker runs unsandboxed — required for workers that spawn their own sub-workers; must also be enabled in config |\n| `worktrees` (run-level) | Give each task an isolated git worktree of `repo` so parallel workers can't collide |\n\n> **Worktree footgun:** on PASS the task's worktree is removed — including anything written inside it. In worktrees mode, worker logs live outside task worktrees in `workdir\u002Flogs\u002F`; have workers write deliverables outside the worktree too, or have your `check` copy artifacts out before it exits 0.\n\nNot sure what your tasks even are yet? [`docs\u002Finterview-prompt.md`](docs\u002Finterview-prompt.md) is a prompt you paste into any chatbot; it interviews you about the job and hands back a brief your orchestrating agent can turn into a manifest. Ready-made skeletons for the patterns that work live in [`templates\u002F`](templates\u002F).\n\n## Lint\n\nLint checks a manifest for the mistakes that make swarms hard to trust: checks that cannot fail, silent checks, worktree deliverables that disappear, worker commits that die with deleted worktrees, serial fan-out, write collisions, and underspecified specs.\n\n```bash\n.\u002Fringer.py lint templates\u002Freview-swarm\u002Fmanifest.json\nlint: clean (1 tasks)\n```\n\n`run` and `demo` also print any lint findings as non-blocking warnings after the manifest loads. They teach at the moment of use; they do not stop a run.\n\nA check that cannot fail is trusting the worker with extra steps.\n\n## Make your agent actually use this\n\nBetween swarms, agents drift back to invisible inline work. Reminders decay, so enforcement ships with the product.\n\nRun one command:\n\n```bash\n.\u002Fringer.py install-agent\n```\n\nIt 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.\n\nThe hooks never block anything. A user who says \"just do it inline\" is obeyed; uninstall with `.\u002Fringer.py uninstall-agent`.\n\nFor CI and evals, `config.sample.toml` includes `[engines.mock]` so the enforcement stack can be tested without an API bill.\n\n## Engines are pluggable\n\n![Identical workers, each under its own light](docs\u002Fengines.png)\n\nRinger 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:\n\n```toml\n[engines.mymodel]\nbin = \"\u002Fusr\u002Flocal\u002Fbin\u002Fmycli\"\nargs_template = [\"run\", \"{spec}\", \"--dir\", \"{taskdir}\"]\n```\n\nPer-task `\"engine\": \"mymodel\"` routes work to it — the invariants (stdin closed, process-group kill, executed verification, raw logs) apply to every engine identically.\n\n### The universal harness: OpenCode + OpenRouter\n\nUnless 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\u002Fglm-5.2` — roughly $0.74\u002FM input and $2.33\u002FM 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.\n\nOpenCode ships no OS sandbox, so the engine's `bin` points at an absolute path to `engines\u002Fopencode-sandboxed.sh` (ringer does not resolve engine bins relative to the repo): a macOS Seatbelt wrapper that leaves network and reads open but confines writes to the task dir, a per-run scratch dir (wired as the agent's `TMPDIR`\u002F`XDG_CACHE_HOME`), and OpenCode's own state\u002Fconfig dirs. Its `--dangerously-skip-permissions` flag only silences OpenCode's interactive prompts; Seatbelt is the actual containment. Task paths reach the profile as `sandbox-exec -D` parameters rather than string interpolation, so a task dir with quotes or parens can't inject sandbox rules. `--no-sandbox` is wired as the engine's `full_access_args`, so ringer's `allow_full_access` gate still governs escapes. Non-macOS installs need their own sandbox (or full-access mode).\n\nSetting it up takes about five minutes:\n\n```bash\n# 1) Install the OpenCode CLI (pick one)\ncurl -fsSL https:\u002F\u002Fopencode.ai\u002Finstall | bash\n# or: npm install -g opencode-ai\n# or: brew install anomalyco\u002Ftap\u002Fopencode\n\n# 2) Connect OpenRouter — create a key at https:\u002F\u002Fopenrouter.ai\u002Fsettings\u002Fkeys\nopencode auth login   # select OpenRouter, paste the key\n\n# 3) In ~\u002F.config\u002Fringer\u002Fconfig.toml, uncomment [engines.opencode] and set\n#    bin to the ABSOLUTE path of engines\u002Fopencode-sandboxed.sh in this clone.\n#    (Linux\u002FWSL: the wrapper is macOS-only — set bin to the opencode binary\n#    itself; there is no OS write-confinement then, so keep manifests scoped.)\n```\n\nRoute with per-task `\"engine\": \"opencode\"`, pick the model with per-task `\"model\": \"openrouter\u002F\u003Cany-model>\"`, and set reasoning effort via `engine_args`: `[\"--variant\", \"low|high|max\"]`. A sensible split: mechanical or tightly-specced tasks on the cheap lane, gnarly ones on your frontier engine — the executed check catches shortfalls either way, and `swarm_runs` rows tell you whether the cheap lane's pass rate holds.\n\n### The plan lane: Grok Build CLI\n\nIf you already pay for SuperGrok or X Premium Plus, Grok Build is a second flat-rate worker lane — no per-token bill:\n\n```bash\n# 1) Install (pick one)\ncurl -fsSL https:\u002F\u002Fx.ai\u002Fcli\u002Finstall.sh | bash\n# or: npm install -g @xai-official\u002Fgrok\n\n# 2) Sign in — OAuth on a SuperGrok or X Premium Plus plan\ngrok login\n\n# 3) In ~\u002F.config\u002Fringer\u002Fconfig.toml, uncomment [engines.grok]\n```\n\nRoute with per-task `\"engine\": \"grok\"` and pick the model with `\"model\": \"grok-build\"` or `\"model\": \"grok-composer-2.5-fast\"` (the shipped default — the speed pick). Grok brings its own OS sandbox on macOS (profile `workspace`: read everywhere, writes confined to the task dir, temp, and `~\u002F.grok`), and its JSON output exposes no token counts — plan-billed workers report cost as included in plan.\n\n## Ringside — mission control\n\n![Ringside in the browser: a run's live results page with per-worker status and verification](docs\u002Fringside.png)\n\nRingside is a local web page — no install, no account, nothing leaves your machine. Your first run opens it automatically; every later run streams into the same tab:\n\n```bash\n.\u002Fringer.py run manifest.json   # starts Ringside and opens the tab for you\n.\u002Fringer.py hud                 # or open it any time → http:\u002F\u002F127.0.0.1:8700\n```\n\nThe top of the page is the run's live results document: what the job is, a progress bar of rounds, and \"The work\" — every deliverable each worker filed, with a plain-English line saying what the check proved and the raw check output one click away. Below it, the agents: expand a worker to see the exact brief it was handed, which engine and model are typing, and its live work stream. Past runs stay in a versioned library, and a swarm whose orchestrator *died* without finishing gets its own unmissable state — the failure mode every dashboard forgets.\n\nMultiple swarms at once is the designed-for case: run three batches under three identities and Ringside shows all three, live. `--browser` opens a simpler per-run fallback dashboard, and `--no-dashboard` runs headless.\n\nA native desktop build (Tauri, under `hud\u002F`) exists as a v0.1.1 prototype; the web dashboard is currently ahead of it — start there.\n\n## The eval loop\n\n![Timed, verified, logged](docs\u002Feval-loop.png)\n\nEvery worker attempt — pass, fail, timeout, retry — is logged with its spec, engine, duration, token count, and the raw check output. Local JSONL by default; point `[eval.postgres]` at a database to aggregate across machines. Failure rows are the point: they tell you which spec styles, engines, and task shapes actually work, so the swarm gets better on evidence instead of vibes.\n\n## Model performance log\n\n### Model identity taxonomy\n\nThe scoreboard keeps the trained model, its lab, the invoking harness, the access plan, and any explicit reasoning effort as separate fields. Reserved test names never render, and historical rows without a stamped model are quarantined instead of being credited to an engine default. See the normative [model identity taxonomy](docs\u002FTAXONOMY.md).\n\nEvery task attempt is logged **automatically and locally** to `~\u002F.ringer\u002Fruns.jsonl` — no setup, no account, nothing leaves your machine. Each row carries the per-attempt verdict straight from the EXECUTED check, plus duration, tokens, the resolved `model`, the task's `task_type` (if the manifest set one), and the `retry` number.\n\nRead it with:\n\n```bash\n.\u002Fringer.py models          # per-(model, task_type) scoreboard across the local log\n```\n\nThe scoreboard reports, per model and task_type: tasks, attempts, `pass_rate`, `first_try_pass_rate`, median duration and token count, and `last_seen`. The signal for routing is `first_try_pass_rate` — the share of tasks that passed on attempt 1 without a retry; `pass_rate` is the rescued rate after Ringer's single retry, so the gap between the two is the cost of the retry lane. Slice the log with `--log` (a different JSONL), `--task-type`, `--model`, `--engine`, `--since`, or `--json` for piping elsewhere.\n\nHistory from before the `model` \u002F `task_type` \u002F `retry` columns existed can be seeded in one pass:\n\n```bash\n.\u002Fscripts\u002Fbackfill_model_log.py \\\n  --log ~\u002F.ringer\u002Fruns.jsonl \\\n  --runs-dir ~\u002F.ringer\u002Fruns \\\n  --mapping mapping.json\n```\n\nThe `--mapping` file joins old log rows to a `task_type`. Each line uses one of three key forms, applied in order:\n\n- `run_id:task_key` — names one task in one run (most specific).\n- `run_id` — names every task in that run.\n- `name:prefix` — names every task whose key begins with `prefix`, across all runs (least specific, the usual way to cover a whole kit's keys).\n\nRows that match nothing keep their old `task_type` (empty); rows whose run-state JSON can't be found keep their old `model`.\n\n`docs\u002FMODEL-NOTES.md` is where the human-readable judgment lives on top of these numbers — the scoreboard tells you the pass rates; the notes tell you why a model shines or chokes on a given task shape.\n\n### Evidence-based routing\n\nThe scoreboard only knows models you've already run. To reason about models you *haven't* tried yet, Ringer keeps a local snapshot of the OpenRouter catalog and a change log alongside the runs log:\n\n```bash\n.\u002Fringer.py catalog                  # fetch\u002Frefresh ~\u002F.ringer\u002Fopenrouter-catalog.json\n```\n\n| Flag | What it does |\n|---|---|\n| `--refresh` | Force a re-fetch even if the snapshot is fresh |\n| `--source URL_OR_PATH` | Pull from a non-default URL or local file instead of the live OpenRouter API |\n| `--file PATH` | Read a catalog document you already have on disk, no network |\n| `--free` | Filter to models with a $0 price — promo models included |\n| `--changes` | Print the recorded add\u002Fremove\u002Fprice_change\u002Fwent_free\u002Fwent_paid events from `.changes.jsonl` |\n| `--json` | Emit the snapshot (or, with `--changes`, the event log) as JSON for piping |\n\nThe snapshot lives at `~\u002F.ringer\u002Fopenrouter-catalog.json`; the change log sits beside it as `~\u002F.ringer\u002Fopenrouter-catalog.changes.jsonl`, appending one row per added, removed, price-changed, went-free, or went-paid event between snapshots. Free promos get their own call-out (`went_free`) because a temporarily-free model is a zero-cost experiment — the cheapest way to audition a new model is to catch it while someone else is paying for it.\n\nCatalog fetches are throttled to once per 24 hours. A `run` triggers that refresh in the background on its way up; it never blocks or fails a run — if the fetch is slow or the network is down, Ringer carries on with the snapshot it has. The throttle and the auto-refresh-on-run are both documented in `.\u002Fringer.py run --help` and can be turned off there.\n\nOnce you have a catalog and a log, `models --explore` joins them into a routing recommendation:\n\n```bash\n.\u002Fringer.py models --explore                 # tiers across all task types\n.\u002Fringer.py models --explore --task-type docs # tiers for one task shape\n```\n\nModels with local evidence are sorted into tiers:\n\n- **proven** — 3+ tasks of this `task_type` logged, with `first_try_pass_rate >= 0.67`. The lane you trust with heavy work.\n- **probation** — some attempts logged but not enough volume or not enough first-try passes. Use it; don't lean on it.\n- **untested** — nothing in the log yet. Pulled from the catalog: text→text, 32k+ context window, up to 10 candidates, FREE models first then cheapest. These are your audition queue.\n\nThe promotion ladder is the point. A model enters as **untested**. You spend a small slice of suitable runs — about one task per run — auditioning cheap or free candidates on small, low-stakes work where the executed check is strong and the single retry absorbs the failure: docs sweeps, mechanical edits, persona reviews. While evidence accumulates the model sits on **probation**. At 3+ tasks with `first_try_pass_rate >= 0.67` it's **proven** for that task type and earns a lane on the heavy work. The recommendation flow is the same one this ladder implies: exploit proven models for the load-bearing tasks, and keep spending that small slice auditioning untested candidates so the bench refills itself.\n\nThe per-user philosophy, stated plainly: every user's workload is different, so the scoreboard learns what works for *your* tasks on *your* machine. A model that's proven in someone else's log is untested in yours until you've run it. The numbers are not portable between users, and the routing recommendations get personal as the log grows — which is exactly why the catalog and the change log stay local and the explore tiers are computed from your own `runs.jsonl`, not from anyone's aggregate.\n\n## Steering profiles\n\nRinger can optionally load per-model steering profiles, prepend applicable worker rules to both first-attempt and retry prompts, print driver guidance for the orchestrator, and collect one local observation row per attempt. The feature is fail-open: missing or malformed steering data never blocks a run. Setup, the profile contract, and the observation schema are documented in [`docs\u002FSTEERING.md`](docs\u002FSTEERING.md).\n\n## Hard-won invariants\n\nFour rules are baked into every worker invocation. They all cost us real debugging hours; you get them for free:\n\n1. **stdin is always closed** (`\u003C \u002Fdev\u002Fnull`) — headless CLI agents hang forever waiting on a TTY that isn't there.\n2. **Sandbox mode is always explicit** — default sandboxes silently resolve to read-only in temp directories and block every artifact write.\n3. **Verification executes the artifact** — an agent's own \"done\" is not evidence. Exit codes are.\n4. **Raw output only** — logs and eval rows carry verbatim worker output, never a summary. Anything that needs judgment reads the raw data.\n\n## License\n\n[PolyForm Shield 1.0.0](LICENSE.md) — free to use, modify, and share, including inside your own commercial work. The one thing you can't do is offer Ringer or Ringside (or a derivative that competes with them) as a product or service of your own. Commercial rights to the tool itself belong to Nate Jones Media LLC.\n\n## Requirements\n\n- Python 3.11+ (stdlib only; `psycopg` needed only for the optional Postgres eval backend)\n- At least one agent CLI (Codex works out of the box)\n- Rust toolchain, only if you're building Ringside from source\n\n![Between rounds](docs\u002Fbetween-rounds.png)\n\n---\n\nBuilt by [Jon Edwards](https:\u002F\u002Flimitededitionjonathan.com) and his agent fleet — a Claude orchestrator wrote the specs and reviewed the diffs, Codex swarms wrote the implementation, and this repo's own eval table caught its first three bugs. The tool is its own proof of concept.\n","Ringer 是一个用于并行协调多个轻量级AI代理的编排工具，通过角色分离实现高性价比的AI工程化：高性能模型负责规划与验证，低成本CLI型代理（如Codex）并行执行具体任务。核心特点是基于实际执行结果而非代理描述进行自动化验证（运行检查命令），失败时注入上下文重试，并全程记录；配套Ringside实时Web仪表盘提供所有代理状态、耗时、token消耗及历史版本追踪。适用于需要可验证、可审计、高吞吐AI代码生成或批量数据处理的工程场景，如自动化脚本生成、测试套件构建、迁移脚本开发等。",2,"2026-07-11 02:30:16","CREATED_QUERY"]