agentsclimarketplace

Coaltipple

Skill TheColliery/CoalTipple/plugin/skills/coaltipple

Safe, quality-gated model+effort router for Claude Code - delegates cheap work down to save tokens, escalates hard/sensitive work up through a verify staircase, never-down gate, and fail-safe Lock, up to a consent-gated Fable 5 top rung. Not the cheapest router; the safest one inside Claude.

Install
npx -y skills add TheColliery/CoalTipple --skill coaltipple

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Model/effort router — delegate a task you CAN do but that is large+cheap DOWN to a cheaper tier to save tokens (delegate-down), and hand a task beyond your competence UP to a stronger tier for quality (escalate-up). Use when a task has a large cheap subtask worth offloading, or when it exceeds the current model's competence. Claude Code only -- the platform's spawn tool must accept a worker model parameter (Antigravity etc. cannot actuate this); support reviewed monthly.

SKILL.md

26.2 KB, as published. Nobody here has run it

CoalTipple — routing contract

[!CAUTION] PLATFORM GATE -- actuates on Claude Code ONLY. Routing spawns a worker at a CHOSEN model + effort, which needs a spawn tool that accepts a worker model parameter. Works: Claude Code (Agent/Task takes model). BROKEN: Antigravity -- invoke_subagent/define_subagent expose no model param + no effort knob (low/mid/high are model names), so a worker silently runs the parent's model. On any platform without an agent-selectable worker model, do NOT pretend to delegate-down or escalate-up -- the spawn cannot change tier; routing is a silent no-op. Not on Claude Code -> this skill does not apply. (Reviewed monthly.)

Degrades safe on any CC version: an unknown model classifies as a strong tier (never cheap), a failed spawn falls to the next available, and the platform resolves each alias to its current best model at spawn-time — a CC update never breaks routing.

You are main (depth-0): you decide routing + spawn everything yourself. Workers are leaves BY POLICY — give a worker a bounded task-contract (its done-criteria make it RETURN, never open-endedly spawn its own workers); a worker that fails RETURNS its result for main to re-route. This holds whether or not the platform caps nesting — robustness rides on bounded task-contracts + the spawn-fail-fall (Step 3), never on the platform forbidding a worker to spawn.

This contract is English so any model can read it; user-facing output follows the user's language (translate prose, technical terms verbatim — see Always).

Step 0 — A valid ranking must exist first (the Lock)

Routing needs a tier ranking. It is dead simple — no introspection, no model-list enumeration, no refresh cadence:

  • The ranking IS the alias floor + your pins. Tiers = the Claude aliases haiku < sonnet < opus < fablelow / mid / heavy / reasoning (fable = the top rung above opus — a real-money spawn, consent-gated before use; see Step 2), overlaid with .coaltipple.json modelTiers pins. The platform resolves each alias to its current best model AT SPAWN-TIME, so the floor never goes stale. Read the GLOBAL shared ranking ~/.claude/.coaltipple/ranking.json (a cheap file read). You do NOT enumerate the live model list.
  • Unknown model → heavy, never cheap. Any model you do not recognize from the floor/pins is a STRONG tier (the safe over-provision). Routing keys off this tier STRUCTURE, not an exact list — a vendor 5→10-model shuffle never breaks it.
  • modelTiers pins are the one human override for a model released after your cutoff (you cannot see it): the user names it in .coaltipple.json and it wins front-of-tier.
  • A failed spawn FALLS (resolveWorker, Step 3): availability is knowable ONLY at spawn-time, never from a catalog.
  • If a ranking genuinely cannot be built → routing OFF: just work normally. The skill never breaks — it routes, or routing is off.

→ Rebuild recipe (only when ranking.json is missing / corrupt / incomplete — rare), the pin/fall mechanics, and why every degradation mode is safe: read references/lock.md. A normal route just reads the file; it never rebuilds.

Step 1 — Grade the task (deterministic, not self-assessment)

Grade 1–5 by the rubric — size + sensitive-path + keyword, never "it feels easy" (a cheap model is overconfident):

GradeSignal
1read / search / format
2≤1 file, <500 lines, not sensitive
32–3 files / 500–1000 lines
4>3 files / ≥1000 lines / sensitive path (auth, crypto, payments, migrations) — forces ≥4 even at 1 file
5concurrency / mutex / race / crypto-logic / timing-attack / proof — forces 5 regardless of size

Size = content size (general-purpose): code counts lines/files · text/translation/research/docs count words/chars (same thresholds). Difficulty (keyword/sensitive) ALWAYS overrides size — a tiny-but-hard task (1 line of crypto, a short legal-contract translation) = high grade.

Keyword groups are config-tunable (.coaltipple.json keywords) — honor them: built-in groups (concurrency/crypto/security/coding, math, knowledge, domain, creative, audit) each carry a grade floor + optional sensitive (never-down) and preserveVoice flags. Fold in BOTH the built-ins AND the user's overrides: a prompt matching a group's words floors the grade to its grade and inherits its flags (an omitted group keeps the built-in). The conductor's 0-token hint reflects only the built-ins, so YOUR read of the config is the authority. Match a group by the task's INTENT in ANY language — a bug-scan / audit / security-review matches audit by MEANING, not a literal English word (the English words are only examples + the conductor hint).

Read WHY the grade is high — it sets the DIRECTION (the grader's reasons tell you which):

  • High by DIFFICULTY (sensitive path / hot keyword) → escalate-UP: you need a stronger tier for correctness.
  • High by SIZE alone (reasons show only size: N, no sensitive/keyword — a 40-file rename, 48 CRUD handlers, bulk codegen/translation) → a high-EFFORT signal, NOT high-tier → delegate-DOWN to a cheap tier + high effort. The size threshold inflates the grade to stop you under-routing big complex work; once you see the work is MECHANICAL, route it DOWN. Never escalate-up / climb-the-staircase on bulk-mechanical work just because breadth bumped the grade — bulk is the EFFORT knob, difficulty is the TIER knob.
    • EXCEPTION — a whole-repo audit / bug-scan / security-review / code-review is high-by-DIFFICULTY, NOT size: it spans many files (looks size-driven) but finding REAL issues needs CAPABILITY — a cheap tier returns a confident shallow all-clear. Route it UP, or keep it on a capable main; NEVER delegate-down-to-cheap, and if YOU are the floor (Haiku) NEVER self — escalate UP. Bug-finding is the TIER knob, not the EFFORT knob.

If the conductor injected a hint, respect it.

qualityBar (config 0–100) — the acceptable-quality bar: grade picks the starting tier (Step 2); qualityBar is the line the result must clear, or routing climbs the ladder (Step 3). Default 60.

  • Plain meaning: "accept work of quality ≥ qualityBar%". 90 = critical, must be exact · 60 = competent/serviceable (default) · 40 = cheap-and-cheerful.
  • 0 = anything passes → stay at the starting tier, never climb. 100 = almost nothing passes below the top → climb to the top (except a task the lower tier already does perfectly — trivial → no climb). The extremes emerge from the climb mechanism; nothing is hardcoded.

Step 2 — Route (decide)

HARD GATE, before grade or anything else — sensitive = NEVER delegate-DOWN, and this does NOT depend on your grade (the single most important safety rule): if the task touches anything sensitive/security — crypto, timing-attack, constant-time, auth, authorization, payment, secret, token, password, session, security (the grader + conductor flag these, plus any .coaltipple.json keywords group you marked sensitive) — then delegate-DOWN is FORBIDDEN, whatever number you graded it. Do NOT gate this on grade ≥4/5: a weaker main UNDER-grades sensitive work and slips past a grade-gated rule. (Observed live: a main graded a hand-rolled constant-time compare medium and delegated it DOWN — "known pattern, save tokens"; the under-grade bypassed the safety rule and shipped hand-rolled crypto to a weaker model.) The keyword is the gate, not your grade. For sensitive work: escalate UP, keep it on main, or use a vetted built-in (crypto.timingSafeEqual) — never delegate-down, never hand-roll security on a cheaper tier (a plausible-but-wrong timing leak PASSES your tests). Holds under a QUOTA / limit-hit too: if the safe tier is quota-blocked, a sensitive task WAITS for reset, stays on a capable main, or hands back — it does NOT fall to a cheaper tier (the limit-hit fallback floors sensitive work at its safe-minimum — see Damage control). A modelTiers pin cannot lower this floor: a KNOWN-weaker alias (haiku/sonnet) pinned into a high tier never satisfies the gate — skip it and take the next known-strong model in that tier (resolveWorker enforces this on the fall); only an UNKNOWN, unseeable pin (a model released after your training cutoff) is trusted there. (fable is a KNOWN top rung — it qualifies for a sensitive slot by capability, and never-down still holds.)

The keyword flags are ENGLISH-ONLY, so on a NON-ENGLISH task YOU are the sensitive-gate authority: a Thai/CJK/Arabic/Cyrillic prompt — OR a Latin-script one (Spanish/French/German/Portuguese/Indonesian) — meaning "constant-time compare" / "auth bypass" matches NO English literal, so no flag fires and the grade reads trivial; a grade-gated reading would let the never-down backstop vanish. Do NOT rely on the flag for a non-English prompt: apply the never-down gate by the task's MEANING / intent. The conductor's resident routing contract reminds you to grade sensitivity by MEANING in ANY language, and it adds a per-turn nudge ONLY when it detects a non-Latin SCRIPT (Thai/CJK/…) — a Latin-script non-English prompt trips neither the keyword flags nor that script nudge, so YOUR read of the intent is the real gate. The gate fires on MEANING; the keyword is only its English fast-path.

mode (config, default auto) sets the DIRECTIONS you may route — honor it (the sensitive HARD GATE overrides it):

  • auto (default) = route BOTH directions per grade.
  • delegation = budget mode — delegate-DOWN allowed, escalate-UP SUPPRESSED (miss the bar → do it yourself / hand back, don't climb).
  • escalation = quality mode — escalate-UP allowed, delegate-DOWN SUPPRESSED (never push work down to save tokens).
  • off = routing OFF — do it yourself (the conductor also short-circuits its forcer on mode:"off").
  • Override: a SENSITIVE task obeys the hard gate under ANY mode; escalate-UP for sensitive work is always permitted even in delegation mode (safety beats the budget knob).

Per-domain disableRouting (config) — routing OFF for a matched domain: if the graded task's domain (coding / text / math / research) is in disableRouting, OR the list includes 'all', routing is OFF for THIS task — do it yourself. Map the task to its domain by nature (code→coding; translation/docs/prose→text; proofs→math; citation/claim→research). (The conductor only short-circuits on 'all'; per-domain matching needs the graded domain, so it is YOUR check.)

Double-hook stand-down (CoalBoard may fire the same turn): a stakes signal (security/crypto/migration/money) present, or CoalBoard already convening, means do NOT escalate independently — defer to CB: it leads, you become its tier-lever (its lenses run at the tier you'd have picked), one consent, never double-prompt. At the top tier you can't climb further anyway, so yield there too — CB's go-wide is the only escalation left. No CoalBoard installed / fired this turn → this rule is INERT: the sensitive hard-gate above governs alone (escalate UP as usual — CB is an optional sibling, never assumed).

Two knobs: TIER (coarse, burns Opus quota) × EFFORT (fine, cheap, low→max). Escalate cheapest-first, EFFORT → VERSION → TIER: raise EFFORT (same model, think/iterate harder), then VERSION (a stronger model of the SAME tier, e.g. Opus 4.6→4.8 — cheaper + closer than a tier jump), then TIER. Exhaust each lever before the next; never skip to a higher TIER while a stronger same-tier version is untried (Opus quota is scarce; once hit it is hard-blocked).

GradeMoveTier · Effort
1–2delegate-down (only if large — see floor) else do it yourselflow · low–med
3do it yourself or delegatemid · med→max before raising tier
4escalate-up (if difficulty-driven) / delegate-down (if size-driven + mechanical; but if YOU are the floor this is SELF, no "down" exists)heavy · effort by SIZE · sensitive → never down
5escalate-up / do it yourselfstrongest · effort by SIZE (small = low, deep/large = max)
  • The tier column = the CEILING, not the START — climb the staircase to it: escalate ONE rung at a time and verify each (Step 3); a lower rung often clears the bar (cheap tiers are more capable than they look). Reach the ceiling only when a lower rung FAILS verify; jump straight to the top on far-below / out-of-attempts (maxTotalAttempts) OR when the failure mode is subtle / un-verifiable — crypto (timing leaks), numerical precision, security — where a cheaper tier's plausible-but-wrong output would PASS your check. Rule: climb when verify is your safety net; JUMP to the reliable tier when verify can't catch the failure. Don't pre-jump to the top just because the grade is high (that over-provisions TIER). (A sensitive/hard grade still forces escalation OFF the current cheap tier — climb at least one rung; delegating sensitive DOWN is already forbidden above.)
  • Fable = the top rung (reasoning), and it costs real money → ASK before you spawn it: whenever the RESOLVED worker is a fable-family model — isFableModel, a SUBSTRING match catching the alias fable AND a pinned concrete id like claude-fable-5 (a climb/jump to the top, or a grade-5 reasoning start) — and fableConsent (config) is not already true, ASK the user ONCE in their language before spawning — once (this spawn only) · always (persist: node scripts/configure.mjs --project --fableConsent true) · no. On no, do NOT climb into fable — stay at the current tier: the rung below fable (the top NON-fable tier — opus/heavy today, but READ it from the ranking, never hardcode opus, since a future model landing between opus and fable would become the new cap). Declining the money CAPS the climb here even if qualityBar is unmet — run the worker at that tier and accept its result, don't climb further. That rung is exactly where a blocked fable re-resolves (resolveWorker, the SAME fall an unavailable fable takes), so a grade-5 reasoning START with no rung-below drops there too: block the RESOLVED model (the exact name that tripped the ask — a pinned claude-fable-5, NOT merely the literal fable, which would re-resolve + re-serve the pin) and keep declining while isFableModel stays true. No cost math, no money-gate — one worker, one ask. Sensitive work keeps its never-down floor (the cap holds at its safe floor tier heavy, never below). A blocked/unavailable fable spawn falls the same way with no ask.
  • EFFORT tracks OUTPUT-SIZE/iteration, NOT difficulty — the two knobs are independent: TIER is the correctness lever (difficulty → which model); EFFORT is the size lever (how much to produce/iterate). A hard task with SMALL output = strong TIER + LOW effort: a 10-line constant-time compare gets a strong tier (heavy/opus) for safety but LOW effort — it's 10 lines (don't jump a tiny crypto fn to the top fable rung; that over-provisions TIER). Reserve max for genuinely LARGE / deep work (a formal proof, a big refactor). Burning max on a tiny hard fn is the over-provisioning trap — the TIER already bought correctness; effort only sizes the work.
  • Effort rubric (by OUTPUT SIZE): low = a lookup / ≤30 lines / 1-2 sentences · medium = a function + tests / a short proof / a paragraph · high = a multi-case proof / a multi-file change / a long document · max = a formal proof all-cases / a big refactor / an exhaustive sweep.
  • Effort is the ALWAYS-ON lever (it pays even when TIER cannot move): at the top tier, or with only one tier available (cheaper tiers off, or a single-model user), you cannot escalate TIER but STILL optimize by scaling EFFORT per task (low for easy, high for hard). Most routers only pick a tier (worthless with one tier); CoalTipple's effort lever delivers savings at ANY fixed tier. A self-executing top main IS still routing: it pins the tier and tunes effort.
  • Delegate-down FLOOR (most important): spawning a worker has a high fixed overhead (~tens of thousands of tokens — measured). Delegate down only for a task big enough that doing it yourself would cost far more than the overhead (≥ delegateMinLines, default 120). Small-to-medium → do them yourself (offloading loses tokens). delegateMinLines is a CODE-line proxy — cheap-per-line work (translation, formatting, plain text) burns far fewer tokens/line, so it needs proportionally MORE than its raw line count before delegating pays. Judge real effort vs overhead, not the line count.
  • Budget gate before you fan out (the proactive limit-hit guard) · spawning is the biggest spend you control: a worker pays off only when the task clears the floor AND there is clear BUDGET HEADROOM. Near a session/quota limit, or right after a limit-hit, the cheapest correct route is often NO worker: collapse to inline-self. Above all, do NOT fan out SEVERAL workers at once for marginal-value, context-light, mechanical work (a multi-file grep/compare, a small audit, a consistency sweep) the main can do inline — N spawns × ~tens-of-thousands near a budget edge IS the limit-hit, and a worker that dies on the limit returns NOTHING (partial findings unrecoverable). resolveWorker is the REACTIVE fall once a spawn is blocked; THIS is the proactive gate before you spawn at all.
  • If YOU are the floor tier (cheapest — e.g. main is Haiku): no tier exists below you, so delegate-DOWN is off the table. A big size-driven mechanical task (the one the grade table routes "delegate-down" for a higher main) has NO down-target → it collapses to SELF: do it yourself and CALL it self (a "delegate-down to myself" label is the self-contradiction that then slips the work UP to a costlier tier). Cheap/mechanical work you can do → do it yourself. Work beyond your competence (hard / sensitive / too-big-context) → escalate UP (don't keep a hard task on the floor just because "it isn't sensitive" or you hold the context). At the floor: self-for-cheap, up-for-hard.
  • Context floor (the worker starts FRESH) — distinguish two kinds of "big context":
    • Accumulated CONVERSATION context (files read, decisions, the user's intent, the back-and-forth) — NON-transferable; a fresh worker can't see it. Work whose correctness depends on it → keep on main (compressing it into a contract is lossy + expensive). This is the real context-floor.
    • On-disk / re-readable INPUT (a codebase, a large document, logs) — a worker CAN read it itself from a path in the contract. A large on-disk input is NOT a reason to keep work on main — it's a reason to pick a worker with a big-enough context VARIANT (Step 0): choose TIER by difficulty, VARIANT by input size, independently. (Example: "refactor a 180k-token codebase" → the 180k is on-disk → delegatable → a hard refactor on a heavy tier + a 256k variant = an Opus-256k worker. Exception: if you ALREADY hold the input in a large-context main, keeping it there is free.)
  • ULTRACODE (max effort + multi-agent fan-out) = the top rung, for genuinely broad + independent work only; workers run a cheap tier, you orchestrate (cap concurrent at maxConcurrentSubagents, default 4 — they share one rate limit). fast-mode is not a routing choice — attach it only on an explicit human latency request, and only if fastModeOnLatencyRequest (default true); never as a routing rung.
  • Voice: when preserveVoiceForUserFacing (default true), never delegate the final user-facing deliverable to a cheaper model — INCLUDING a translation, summary, or research write-up (the prose IS the deliverable), even when bulky (reviewing it to protect voice + terminology costs about as much as redoing it). Bulk MECHANICAL work (renames, formatting, codegen) is not "deliverable prose" and stays delegate-able.

Step 3 — If you delegate

  1. Task contract (required when requireTaskContract, default true): give the worker goal + constraints + interface + done-criteria. A thin brief makes a cheap worker build the wrong thing with confidence. Keep it compact.
  2. Spawn at the chosen tier/effort — lead the spawn's description/label with the chosen model + effort so the human sees what is running (e.g. [haiku·low] scaffold 48 handlers, [opus·max] formal proof, [sonnet·high] refactor auth; CC renders the description as the task chip). Require a compact diff/summary, not whole files. The worker MUST be BOUNDED — never spawn an open-ended worker that can loop: the done-criteria (item 1) makes it terminate (a "keep improving" brief runs forever). subagentTimeoutSeconds (default 150) catches a STALL; the done-criteria prevents the LOOP.
  3. Spawn-fail-fall — the never-fail availability loop (drives resolveWorker): a spawn can ERROR instantly (0-token) because the model is unavailable / disabled / out of quota / gone ("X is currently unavailable" — proven live with fable). Availability is knowable ONLY here, at spawn-time. On error: (a) add that model to a blocked set; (b) call resolveWorker(ranking, desiredTier, {blocked, floorTier}) (classify.mjs — walks desiredTierfloorTier, skipping blocked); (c) spawn the returned worker; (d) repeat (a)–(c) on each fresh unavailable error; (e) if resolveWorker returns null (everything blocked to the floor), STOP — for a SENSITIVE task the floorTier is its safe-minimum, so null means hand back / wait for reset and NEVER breach never-down by falling cheaper. Guarantee: routing reaches a working model OR hands back cleanly — never stuck on an unavailable model, never falls sensitive work below its floor. (This is the DOWN-for-availability move; the quality climb below is the UP-for-quality move — opposite directions, don't conflate.) Mechanics + the limit-hit/quota fallback detail: references/damage-control.md.
  4. Verify against qualityBar: rigor follows qaOnMerge (strict / standard / off; default standard) — off skips merge-verify (trust mode), strict = exhaustive. Output may "look right but be wrong" — never trust it blindly, never let the worker grade itself. Measure against external criteria = the contract done-criteria + a domain-appropriate objective check (code: build/test/lint/type-check · text/translation: every segment present + consistent + format preserved · research: every claim has a real, authoritative source, verified with the web/doc tools you have yourself · math: check the steps / substitute back). RUN the check — actually execute the tests/build/parse; do NOT eyeball the code. A cheaper main especially defaults to eyeballing: it catches obvious misses but mis-judges subtle bugs (live: low and mid mains both read a buggy 1.5h as 5400 by eye; only running it revealed the true 18000). Eyeballing is not verifying. Clears the bar → done.
    • Below the bar → climb the staircase: near the bar + attempts remain → escalate one rung (the next lever in EFFORT/VERSION/TIER order — a stronger same-tier VERSION first, then the next TIER; don't retry the same model, don't skip a tier while a stronger same-tier version is untried). Far below (the next rung won't clear it), or out of maxTotalAttempts (default 2) → jump straight to the top tier (don't die by a thousand cuts). At the top and still failing → hand back to the user.
    • competence-introspection: if you know from the start the task exceeds your ceiling → escalate immediately, don't waste an attempt.
  5. Never let a cheap main QA an expert's work — if you escalated up, let the strong worker own both the hard task and the integration.

Memory anchor · Damage control · Self error-report

These run only on a specific, infrequent path — keep the rules out of the per-route hot path:

  • Memory anchor (a fresh worker gets project context beyond the bare contract): when you are about to delegate context-dependent work, find the anchor — contextFiles if set, else the platform's auto-loaded CLAUDE.md/AGENTS.md. If none exists AND memoryOffer is auto AND you have not offered this session → read references/damage-control.md (Memory anchor) for the lazy-offer + write-policy. Changed anytime via /coaltipple memory.
  • Damage control (bound the blast radius of a mid-run death — a silent stall, a limit-hit/unavailable fallback, the .proposed/ sandbox + state.json journal, worktree-isolation, the never-retry-a-side-effect rule): the load-bearing safety invariant stays in the gates above (sensitive never falls below its floor on a limit-hit — HARD GATE + Step 3.3). The mechanics fire only when a delegation is actually failing → references/damage-control.md.
  • Self error-report (CoalTipple misbehaves — a contradictory instruction, a loop/dead-end, a clearly-wrong route, the Lock refusing a valid ranking, a config key off-spec): STOP, summarize what went wrong, OFFER to file at github.com/TheColliery/CoalTipple/issues (never auto-submit). Detail: references/damage-control.md.

Always

Honor the MERGED config (every value is tunable): global ~/.claude/.coaltipple.json (your defaults) overlaid by project .claude/.coaltipple.json (per-key override; a project file is OPTIONAL — absent = global + schema defaults). Consent-gate token spend — never fan out costly work silently. Respond in the user's language (auto-detect, or the language config): translate the prose, but never translate technical terms — commands, paths, identifiers, tier/model names, severity labels, config keys stay verbatim. /coaltipple off turns routing off; /coaltipple stats shows approximate savings (an estimate — there is no cost API); /coaltipple memory [on|off|set <file>] sets up or disables the memory anchor; /coaltipple update checks for a newer version.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.