๐ CoalTipple
August 9, 2026 ยท View on GitHub
๐ CoalTipple
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.
๐ What it is
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.
๐ค Compatibility
- 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.
๐ Install
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 Code โ plugin
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.
Other platforms โ no install (routing cannot actuate)
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.
Verify (from clone)
node scripts/verify.mjs # validates config, schemas, plugin files
node scripts/test.mjs # runs zero-dependency unit tests
๐๏ธ The Two Knobs
Routing 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.
The qualityBar Staircase
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.
๐ก๏ธ Routing the Work Safely
- 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.
Damage Control
- 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 โ Safe Routing States
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.
๐ง Memory Anchor
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.
Commands
| 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 |
โ๏ธ Configure
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.
Permissions
- 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
๐ Benchmark
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).
๐งญ Part of TheColliery
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.
๐ License
Apache License 2.0. See LICENSE for details.