A while back I wrote about how I use Fable 5 without going token-bankrupt:
I put Fable 5 in the orchestrator seat — scoping, design, delegation, final review — while the hands-on implementation, testing, shipping, and code review are done by Opus and Sonnet subagents. The expensive model plans and judges; the cheaper models execute. This ran beautifully for most tasks.
There's just one problem. As you probably know, Fable 5 access via subscription ends on July 7. (I'm praying it comes back to subscription someday… 🙏)
The orchestration setup itself works without Fable 5 — but if the model at the top, the one cutting scope and judging everything, gets downgraded, output quality drops with it.
Here's the thing though: Opus and Sonnet are not bad models. Used correctly, they produce genuinely good output. What matters is writing down what to do, how to do it, and what to do when something fails. So before losing access, I decided to document how Fable 5 actually works and hand it down to Opus/Sonnet — as skills.
This post is about what I did and how. Finding a "replacement for Fable" seemed hopeless, so the goal became something else: raise the whole team's capability so that quality holds even with Opus in the orchestrator seat.
The gap between Fable 5 and Opus/Sonnet is not intelligence
To keep using a pseudo-Fable after the shutdown, I started by examining what the difference actually is.
When Opus/Sonnet produce output I didn't intend during everyday engineering, the failures turn out to follow recognizable patterns. For example:
- Slapping
"use client"at the top of a Next.js page because one button needs anonClick- …which drops the entire page and its import tree onto the client
- Writing
fetchwith no cache option- The defaults are opposite between Next.js 14 and 15, but "it works" was only checked on the dev server — hello, production caching surprise
- Skipping input validation in a Server Action because it's "only called from my form"
- It's actually a public POST endpoint anyone can hit with arbitrary arguments
- Fetching initial data inside
useEffect- An
awaitin a Server Component would do it, without the request waterfall and the layout flash
- An
- "Fixing" a failing test by rewriting the assertion
- Don't touch the assertion until you've proven, with evidence, that the code side is the wrong one
- Saying "this should work now" without running anything
- Run it first, then conclude whether it works
What matters here: none of these are knowledge gaps. Ask Sonnet directly — "is a Next.js Server Action dangerous without input validation?" — and it answers correctly. The knowledge is in there. What's missing is the correct procedure.
Fable 5 runs these checks implicitly, without being asked, and pushes back when something's off. With Opus/Sonnet, those checks have to be written down explicitly.
Raw reasoning differences are real, of course. But for routine implementation, review, and debugging, most of the observable quality gap comes down to discipline, sequencing, and verification — and all three can be written as skills.
"Be careful" prompts don't work
My first attempt at Fable-izing Opus/Sonnet was writing "be careful, always verify, follow best practices" into the prompt. Result: nothing happened (obviously, in hindsight). A sentence that doesn't change the model's next move doesn't change its behavior.
So the first rule of documenting Fable's working method was a ban list. No line may contain:
"be careful" / "follow best practices" / "think hard" / "ensure quality"
Every line has to be executable or checkable — runnable as a command, defined as a threshold, expressed as if/then, or greppable as a pattern. It must be unambiguous what the reader does next.
I documented Fable 5's working method along five axes
Before getting into the "how": I maintain ccteams, a CLI that installs pre-built Claude Code subagent teams with one command.
From v0.2.x, every team ships with two skills: a shared working method and a per-team playbook. Here's what actually went into them, in order.
1. Fix the work routine
The classic Opus/Sonnet mistake is starting to write immediately — leaning on training data or earlier context ("Go is usually written like this", "this library's API was like that") without checking the repository in front of it.
So each playbook opens with a numbered procedure that forces pre-writing behavior:
Read
go.mod(and its version) before using a language feature
Read the lockfile for the actually-installed version before trusting library docs
Read two neighboring files before picking a pattern
grepbefore writing a helper (it usually already exists under a different name)
In short, it pre-commits the model to one principle: don't decide from memory — read the repo and decide.
2. Define the failure patterns and their fixes
What mid-tier models lack isn't knowledge — it's that they carry wrong assumptions, and proceed on the premise that the plausible implementation is the correct one. Crushing that tendency is the priority.
So for each team, I defined the common failure patterns in a fixed format:
symptom → wrong instinct → correct move
so that when Opus/Sonnet hits the symptom, it knows exactly how to correct course.
From the ccteams Next.js playbook:
One button needs an onClick → put
"use client"at the top of the page → extract the button into its own leaf component, mark only that file client, keep the page a Server Component.
From the Go playbook:
Handler hits an error → call
http.Error(w, msg, 500)and keep going → addreturnimmediately after.http.Errorwrites and returns; your handler doesn't — the success path below writes a second body onto a committed 500 response.
There are 10–15 of these per team (Go team, React Native team, Rails team, and so on). Naming the wrong instinct explicitly lets the model recognize the exact moment it's about to make the mistake. You're patching the decision point, not the knowledge base.
3. Define the decision branches
A frontier model's edge is judgment. Judgment itself can't be transplanted — but 80–90% of the recurring cases can be compiled into explicit branches. From the Go playbook:
Before launching any goroutine — three questions, "nobody" is a forbidden answer:
- Who cancels it?
- Who waits for it?
- Where does its error go?
If any answer is "nobody", don't launch it.
Why this one? Because a goroutine is trivial to launch and hard to clean up. When a mid-tier model casually writes go doWork(), the typical outcomes are:
- Nobody stops it → it keeps running after the program should be done, or lives forever (goroutine leak = memory leak)
- Nobody waits for it →
mainexits first and the work silently never completes - The error has nowhere to go → failures inside the goroutine get swallowed, and no one ever notices
This is exactly the kind of thing that goes wrong when vibe-coding Go, so it's defined specifically for the Go team.
There's also a team-independent rule shared by everyone:
State your hypothesis before touching code. A fix without a confirmed root cause is a guess.
This blocks the classic mid-tier move of applying a plausible-looking fix before the root cause is confirmed.
For debugging specifically — where "patch the symptom's location and feel done" accidents are constant — the debug team has a dedicated gate:
Before writing any fix, you must be able to say: "X causes Y, because Z" — where X and Y are observed, and Z explains why this exact symptom appears. If you can't fill in Z, you have a correlation, not a cause.
In other words: no causal sentence, no fix phase. You get sent back to re-verify the hypothesis.
This is the pattern across ccteams: for each team, the decision branches that stop that team's characteristic accidents are written out explicitly.
4. Define the verification method
Verification is cheap compared to generation. Which means: a mid-tier model plus a strong verification harness beats a mid-tier model alone, by a wide margin. So every playbook contains an exact, ordered verification recipe.
Not "please test it" — but which commands, in which order, and what each failure means. For Go: go build ./... → go vet ./... → go test -race ./... (with -race marked non-negotiable). The frontend playbook includes checks no linter will ever run for you: a keyboard-only walkthrough, and resize tests at 320/768/1280px.
On top of that, the shared working method demands execution as the basis for claims. A typical mid-tier shortcut is returning code that has never been run, with a cheerful "this should work". To kill that:
The diff is a claim; execution is evidence. Only after actually running build/test/lint and reading their output is the claim backed.
And to enforce it, every claim in a report must carry a label — VERIFIED (ran it) / REASONED (read the code) / ASSUMED (unchecked) — with silent upgrades forbidden. You can no longer pass off "should work" as "works".
5. Absorb failures one at a time with a learning loop
Everything above was written by Fable in advance — rules based on predicting "a mid-tier model will probably get this wrong". Not bad, but predictions are predictions. Rules grounded in mistakes that actually happened in your project are obviously stronger.
So the working method includes a learning loop: the more you use the team, the more it optimizes itself to your project.
The rule itself is simple: when a mistake surfaces that the playbook didn't anticipate, turn it into a catalog entry, and add it as a rule after human approval.
From v0.2.2, running ccteams use automatically creates .claude/skills/team-lessons/SKILL.md. Once created, this file is never overwritten — not by team switches, not by ccteams updates. It exists to accumulate your project's own failure patterns and their fixes.
When an unanticipated mistake occurs, the AI works out the symptom → wrong instinct → correct move and asks you whether it should be recorded. On approval, the agent appends the entry to team-lessons/SKILL.md.
The result is a team that gets smarter with every failure it absorbs.
That said, bloat is unavoidable on a long-running project. As first-line countermeasures there's a duplicate check (sharpen an existing entry instead of appending a near-copy) and the human approval gate itself — but long-term operation is an open question I'm still thinking about.
Making sure it actually reaches the subagents
Claude Code skills are on-demand: they get invoked when the model decides they're relevant. Which means a "working method" skill is never used unless something makes it relevant — and the subagents actually doing the work never invoke skills on their own, period.
To solve this, I planted it in two places.
1. Embed it in the agent definitions
Every agent's system prompt now begins with FIRST ACTION: Read .claude/skills/<team>-playbook/SKILL.md and follow it. But "read this" alone is sometimes ignored — so as a fallback, the 5–6 most load-bearing rules from the playbook are also embedded inline in the system prompt itself.
2. Embed it at delegation time
The orchestration rules obligate the orchestrator to paste a compressed digest of the shared working method, verbatim, into every delegation prompt.
And as the last line of defense, in case both get slipped past: the orchestrator is instructed to check every report against named gates and reject on failure. "The build output isn't quoted? Sent back." Even if delivery fails completely, work that ignored the discipline doesn't get accepted.
Why not just paste the full text everywhere? Because the more instructions you add, the lower the compliance per instruction. So the always-loaded portion is 5–6 lines, each agent carries ~10 inline lines, and the full ~200 lines are read on demand.
Sounds like a lot of setup, right?
ccteams (v0.2.x and later) already ships with Fable 5's working method handed down to Opus/Sonnet, exactly as described above. If you just want a good team quickly — or a template to study — give it a try:
npm install -g ccteams
ccteams list
ccteams use go-api # or next-ts, python-fastapi, rails, django, debug — pick your team
# restart Claude Code
If this saved you some setup time, a star on the repository would make my day. Issues and impressions from trying it are very welcome too!
Afterword
My initial plan was to define rules for the orchestrator only. That turned out to be a dead end — because the one getting weaker is the orchestrator. Fable could catch subagents' mistakes at report time with high precision and send them back; no amount of orchestrator-side rules reproduced that behavior on a weaker model.
Rejection is also more expensive than prevention. So I shifted the weight onto preventing mistakes in the first place — raising the whole team — rather than catching them at the top.
I reverse-engineered, shipped, and tested it, and the results were satisfying: bugs that Opus used to miss are now getting caught. For routine work, I'd say this setup has closed most of the gap between Fable and the other models.
What it can't cover is Fable's unique strength: handling the unanticipated. Noticing "something is off" when nothing on any checklist says so; grasping the structure of a genuinely novel problem at a glance. That doesn't transfer through anything you can write in a skill.
That remaining gap is what the learning loop above chips away at — one absorbed failure at a time.
"Make Opus/Sonnet behave like Fable 5" is an idea you see floated a lot, but I rarely found articles that go into the details — so I actually did it and wrote them down. I hope some of it is useful to you.
Top comments (0)