A tipple is the sorting-and-rail-switching station of a coal mine — this one switches rails for prompts across models.
A model/effort router for Claude Code — delegate a task you can do but that is large and cheap down to a cheaper tier to save tokens, and hand a task beyond your reach up to a stronger tier for quality.
Not the cheapest router by claimed savings — a cross-provider or empirical router can point to a bigger number on someone else's benchmark. The real difference is MECHANISM, not degree: CoalTipple's qualityBar staircase is inspectable and local — the contract lives in SKILL.md, the tier ladder and fall logic in classify.mjs, the config in your own file, all readable in this repo — not an empirical claim measured on someone else's workload that you have to trust. Newer entrants like Not Diamond Code (announced 2026-08-04) report large self-measured savings (their own figure: 20–65%) on their own benchmarks; we make no comparable claim, and place no number beside theirs. One mechanism difference that IS verifiable by reading this repo: CoalTipple's routing decision runs entirely in the agent's own context on local files — zero external network calls for the decision itself — unlike Not Diamond Code's own-documented architecture, where a local proxy sends per-step derived metadata to a remote optimization service for every routing call. That is a property of HOW the decision is made, not a claim about which result is better.
Tier key: non-actuating — the platform cannot run CT's routing AS SHIPPED (most have no per-worker model-pick at all; Antigravity is the one exception with a real per-spawn tier pick that still doesn't map onto CT's design — see the caution below) · candidate — a worker model-pick is documented but unverified live (monthly review, not a supported install). Further candidates (Zed · OpenCode · Devin · Kiro) are listed in Install.
Benchmark · Contributing · Changelog · Security · Privacy · Releases
Part of TheColliery — siblings: CoalMine (quality canaries) · CoalBoard (consensus & debate board) · CoalHearth (session warm-resume) · CoalFace (fan-out discipline) · CoalWash (memory defrag) · CoalLedger (docs health).
Caution
Claude Code only. CoalTipple's routing only actuates where an agent can pick a spawned worker's model + effort. Today that is Claude Code. Antigravity does NOT ship CT -- invoke_subagent DOES take a per-spawn Model tier (proven by a live spawn, 2026-08-04), but that tier selects a GOOGLE model regardless of the parent's vendor, and no effort knob exists anywhere in its schema. CT's never-down gate, qualityBar staircase, and Claude alias floor don't map onto a cross-vendor Google tier ladder -- a different, unbuilt product, not a missing spawn param. Other platforms (Codex, Cursor, ...) are under monthly review.
A tipple is the sorting-and-rail-switching station of a coal mine. This tool switches rails for prompts across models (alongside CoalMine).
You are main. CoalTipple decides, per task, whether to:
| Direction | When | Why |
|---|---|---|
| delegate-DOWN | Task is mechanical and large | A cheaper tier does the bulk → saves tokens |
| escalate-UP | Task is beyond the current tier's competence | A stronger tier does it right → protects quality |
| stay (route OFF) | Task is small / no valid ranking | Bypasses routing to prevent overhead |
Routing logic lives inside SKILL.md — the model reads and routes natively. No background daemon.
- Claude Code (validated live across the 2.1.x line): Built Claude-Code-first and run end-to-end across all model tiers (Haiku, Sonnet, Opus). Routing degrades safe on any CC version — an unfamiliar model classifies strong, a failed spawn falls, and the platform resolves each alias to its current best model at spawn-time (the ranking is the alias floor + pins — nothing to enumerate).
- Routing actuates on Claude Code only: CT needs a platform where an agent can pick a spawned worker's model + effort. CC's Agent/Task tool takes a
modelparam -- that is the requirement. - Subagent-capable != qualifies: a model choice alone isn't enough either -- Antigravity DOES let the agent pick a per-spawn model tier (
invoke_subagent'sModelfield, proven live 2026-08-04), but that tier is a cross-vendor Google model regardless of the parent's own vendor, and carries no effort knob. CT's never-down gate, qualityBar staircase, and Claude alias floor don't map onto that shape -- a different, unbuilt product, not a missing spawn param -- so CT is gated to CC. Other platforms (Cursor · Zed · OpenCode · Devin · Kiro · Copilot CLI, …) are under monthly review — see Install → Other platforms for the current matrix.
CoalTipple installs on Claude Code only — routing actuates only where an agent can pick a spawned worker's model + effort, and Claude Code's Agent/Task tool is the one that takes a model parameter.
claude plugin marketplace add TheColliery/CoalTipple
claude plugin install coaltipple@coaltipple
# Restart Claude Code to load the /coaltipple commands (stats | off | memory | update)Optional per-project config override, first-found wins: <project>/.claude/coal/coaltipple.json → .agents/coal/coaltipple.json → .gemini/coal/coaltipple.json → legacy .claude/.coaltipple.json.
There is deliberately no file-copy or install.mjs path for other agents: none gives CT what it needs to ship as designed -- most have no worker model-pick at all, and the one exception (Antigravity) picks a cross-vendor tier with no effort knob (see Compatibility for the full reason).
- Antigravity — does not ship CT, but not for the reason previously stated here. The 2026-06-16 note that AG has "no per-spawn model parameter" was wrong, or went stale -- we cannot tell which from here. Re-verified 2026-08-04 by reading the live tool schema and running a real spawn:
invoke_subagent'sModelfield (inherit/flash_lite/flash/pro) DOES let the agent pick a per-spawn tier at invocation time (the earlier check only looked atdefine_subagent, which has no such field) -- a Claude Opus 4.6 parent spawned a Gemini 2.0 Flash child by namingModel: "flash". What IS still true, confirmed the same day: no effort knob exists anywhere in the schema. CT still does not install here: theModelenum selects a GOOGLE tier regardless of the parent's own vendor -- a cross-vendor handoff, not a cheaper same-family worker -- and CT's never-down gate, qualityBar staircase, and Claude alias floor (haiku<sonnet<opus<fable) don't map onto that shape. A tier-only, cross-vendor AG lane would be a different, unbuilt product under CT's name, not a missing install step. - Codex · Gemini CLI · Cline · Windsurf — no worker model-pick → not supported.
- Cursor — reports a worker
modelparam but it is unverified; a monitored candidate under monthly review (verify the spawn schema first), not a supported install today. - Zed · OpenCode · Devin · Kiro · Copilot CLI — candidates — docs-verified 2026-07-13; a live spawn-schema verify on a real install is REQUIRED before any adapter (the Antigravity burn rule: docs-claimed ≠ actuating). What the docs show: Zed
agent.subagent_model· OpenCode per-agentmodel(provider/model-id) · Devin subagentmodelfrontmatter (+ an Adaptive auto-router) · Kiro a subagent model attribute · Copilot CLI partial (a profile pin works, but the Task-toolmodelparam has an open upstream bug and a cost-guard silently downgrades sub models). - Adapter design, locked ahead of any verify: pre-provisioned pins — define per-tier pinned subagents (the Codex pattern: per-agent config files carrying a pinned model), so routing = picking the agent, no per-spawn model param needed; it ships only after a live schema verify on a real install.
- claude.ai — the ZIP-upload skill path is for read/analyze skills only; CoalTipple actuates model routing, so it does not apply.
node scripts/verify.mjs # validates config, schemas, plugin files
node scripts/test.mjs # runs zero-dependency unit testsRouting adjusts two independent knobs (always raise effort before tier):
| Knob | Axis | Scale |
|---|---|---|
| TIER | correctness — which model | Coarse (low < mid < heavy < reasoning) |
| EFFORT | size — output volume / iteration | Fine-grained (low → max) |
- TIER tracks difficulty/sensitivity; EFFORT tracks output size. A short cryptographic function wants a high tier but low effort. A large mechanical template wants a cheap tier but high effort.
qualityBar (0–100, default 60) defines the acceptable quality threshold:
- The task's grade picks the starting tier (cheapest possible).
- The worker runs, and output is verified against the task contract.
- Passes → done. Fails → climb one rung. Out of attempts/fails hard → jump to top tier.
- Tune
qualityBarby risk: raise (~85) for critical logic; lower (~45) for quick drafts. - This is the inspectable, local mechanism named above — the contract and the code that implements it live in this repo, not a benchmark number you have to trust.
- No Down-Delegation for Sensitive Tasks: Cryptography, auth, payments, and security paths are forced to the
heavytier based on keywords. They never fall to cheap tiers, even under quota limits — and amodelTierspin naming a known-weaker model (e.g.haiku) can never satisfy that floor either. - Overhead Floor: Tasks below
delegateMinLines(default 120) stay on main to avoid spawn overhead. - Prose Preservation: User-facing writing and translation stay on main to protect voice.
- Verify, Do Not Eyeball: Output merges require passing objective checks (
qaOnMerge: strict/standard/off). - Workers are Leaves: By policy a worker is given a bounded task contract and returns to main rather than spawning its own workers — routing stays depth-0 whether or not the platform allows nesting.
- Isolation: Uses git worktree-isolation (or local
.claude/.coaltipple/proposed/sandbox withstate.jsonjournaling) to protect files from mid-run failures. - Rate Limits: Automatically falls back to the next available tier on limit-hits, but never below a sensitive task's minimum tier.
- Side Effects: Commands with external side-effects (e.g. bash mutations, commits) are never delegated.
The Lock guarantees CoalTipple is only ever in one of two states: routing correctly or routing off.
- Always Buildable: The ranking is the alias floor
haiku < sonnet < opus < fable(→low/mid/heavy/reasoning;reasoning=fable, the top rung above opus — a real-money spawn that is consent-gated, seefableConsent) overlaid with yourmodelTierspins — a constant, no enumeration. Unknown models default toheavy. - Validity-Gated: Checks ranking schema, hash, and completeness before writing.
- Fails Safe: Bypasses routing if the model ranking is broken.
- Spawn-Time Resolution: The platform resolves each alias to its current best model at spawn-time, and a failed spawn falls to the next available tier — so the floor never goes stale and there is no refresh cadence.
Workers start context-fresh. A memory anchor file gives a fresh worker project context.
- If
contextFilesis empty, CoalTipple auto-loadsCLAUDE.md/AGENTS.md. - Offers once to set up an anchor on new projects. Manage manually via
/coaltipple memory.
| Command | What it does |
|---|---|
/coaltipple |
Manually load the routing contract for this turn (routing is normally automatic via the hook; useful after /coaltipple off) |
/coaltipple stats |
Approximate token savings + delegate-down / escalate-up activity this session |
/coaltipple off |
Turn routing off for this session — work as a normal single agent |
/coaltipple memory [on|off|set <file>] |
Set up or change the memory anchor a fresh worker reads |
/coaltipple update |
Check for a newer CoalTipple version and offer to apply it, or set how updates are handled |
Everything is tunable in .coaltipple.json — a global ~/.claude/.coaltipple.json overlaid per key by the first-found project config (<gitroot>/.claude/coal/coaltipple.json → .agents/coal/coaltipple.json → .gemini/coal/coaltipple.json → legacy .claude/.coaltipple.json; project wins), so you can tune or shut off a globally-installed skill per project (off-switch: enableRouting: false) — a skill you don't need in a given project stops loading (and burning tokens) there. Ships zero-config with optimal defaults. The high-impact keys:
| Key | Default | What it does |
|---|---|---|
enableRouting |
true |
Master routing switch |
mode |
auto |
Direction: delegation (down) | escalation (up) | auto | off |
qualityBar |
60 |
Quality threshold (0–100) for the staircase — raise (~85) for critical logic, lower (~45) for quick drafts |
delegateMinLines |
120 |
Minimum task size below which down-delegation is skipped (spawn-overhead floor) |
fableConsent |
false |
Standing consent to route to Fable 5 (the top rung above opus, a real-money spawn) without asking each time. Unset/false = ask once per fable escalation (once / always-this-project / no); no caps the climb at the top non-fable rung (opus today — read from the ranking). Set per-project: configure.mjs --project --fableConsent true |
modelTiers |
unset | Optional pins overlaying the alias floor (e.g. { "reasoning": ["future-top-model"] }) — the one human override for a model the agent cannot see; an unavailable pin falls safely down the ladder at spawn-fail |
Full key reference: every key + default lives in scripts/lib/config-schema.mjs and the commented template platform-configs/.coaltipple.json — or run node scripts/configure.mjs --help.
- Reads its own config/ranking and your project; writes only its own scratch state (a ranking cache, an update-check stamp) — never a target file.
- The one defining right: picking the model a spawned worker runs at — the whole mechanism. A worker gets strictly LESS: a bounded task contract, no re-spawning, no shell/network of its own.
- Never network, exec, or delete by itself; always asks before spending real money (the
fableConsentgate before Fable 5) or anything else beyond read+scratch — you, main, execute it on your own tools.
Full series matrix + the must-fail set: Permission Matrix
We evaluate the final output correctness after the main escalates one rung, and the token savings of delegating mechanical bulk down — each dated, on small honest samples, in the linked record so a copied number cannot drift.
- ON-vs-OFF (paired, 2026-07-03, v1.0.23): the same 4 tasks at every tier (36 runs, K=3, Haiku 4.5/Sonnet 5/Opus 4.8) — routing ON scored 4/4 task quality on both baselines; OFF scored 3/4 on both, failing a DIFFERENT task each (an Opus main fails the boring spec's letter; a Sonnet main fails the sensitive legal nuance). From an Opus main ON is also ~23% cheaper; from a Sonnet main it is cost-neutral and removes a liability-shifting translation error.
Full harnesses, per-task scoring, the quality-vs-tier matrix, routing-savings history, and every honest-scope caveat live in the series umbrella: TheColliery/.github/benchmarks/CoalTipple (RESULTS.md · ROUTING-SAVINGS.md).
CoalTipple is the series' model/effort router, and it shares its engineering doctrine with six siblings:
- CoalMine — quality canaries
- CoalBoard — consensus & debate board
- CoalHearth — session warm-resume
- CoalFace — fan-out discipline
- CoalWash — memory defrag
- CoalLedger — docs health
Install one, it stands alone; install all, they compose without conflict.
That doctrine: Phoenix-13 hooks (zero-dependency, no network, fail-silent, no child processes, deterministic), single-source-of-truth config schemas, and a strict no-overkill discipline — full series at TheColliery.
Zero-dependency, offline by default, no API keys — "by default" because the consent-gated self-update check (/coaltipple:update) goes online; the hook never does.
Apache License 2.0. See LICENSE for details.