๐Ÿš‚ 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.

version license status SKILL.md

Claude Code Antigravity Cursor Codex Gemini CLI Cline Windsurf Copilot CLI claude.ai

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:

DirectionWhenWhy
delegate-DOWNTask is mechanical and largeA cheaper tier does the bulk โ†’ saves tokens
escalate-UPTask is beyond the current tier's competenceA stronger tier does it right โ†’ protects quality
stay (route OFF)Task is small / no valid rankingBypasses 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 model param -- 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's Model field, 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's Model field (inherit / flash_lite / flash / pro) DOES let the agent pick a per-spawn tier at invocation time (the earlier check only looked at define_subagent, which has no such field) -- a Claude Opus 4.6 parent spawned a Gemini 2.0 Flash child by naming Model: "flash". What IS still true, confirmed the same day: no effort knob exists anywhere in the schema. CT still does not install here: the Model enum 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 model param 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-agent model (provider/model-id) ยท Devin subagent model frontmatter (+ an Adaptive auto-router) ยท Kiro a subagent model attribute ยท Copilot CLI partial (a profile pin works, but the Task-tool model param 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):

KnobAxisScale
TIERcorrectness โ€” which modelCoarse (low < mid < heavy < reasoning)
EFFORTsize โ€” output volume / iterationFine-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:

  1. The task's grade picks the starting tier (cheapest possible).
  2. The worker runs, and output is verified against the task contract.
  3. Passes โ†’ done. Fails โ†’ climb one rung. Out of attempts/fails hard โ†’ jump to top tier.
  • Tune qualityBar by 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 heavy tier based on keywords. They never fall to cheap tiers, even under quota limits โ€” and a modelTiers pin 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 with state.json journaling) 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, see fableConsent) overlaid with your modelTiers pins โ€” a constant, no enumeration. Unknown models default to heavy.
  • 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 contextFiles is empty, CoalTipple auto-loads CLAUDE.md / AGENTS.md.
  • Offers once to set up an anchor on new projects. Manage manually via /coaltipple memory.

Commands

CommandWhat it does
/coaltippleManually load the routing contract for this turn (routing is normally automatic via the hook; useful after /coaltipple off)
/coaltipple statsApproximate token savings + delegate-down / escalate-up activity this session
/coaltipple offTurn 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 updateCheck 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:

KeyDefaultWhat it does
enableRoutingtrueMaster routing switch
modeautoDirection: delegation (down) | escalation (up) | auto | off
qualityBar60Quality threshold (0โ€“100) for the staircase โ€” raise (~85) for critical logic, lower (~45) for quick drafts
delegateMinLines120Minimum task size below which down-delegation is skipped (spawn-overhead floor)
fableConsentfalseStanding 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
modelTiersunsetOptional 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 fableConsent gate 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:

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.