Fable Joins the Fanout
The orchestrator has been fanning out to Gemini, Grok, ChatGPT and Groq for months. There was a Claude-shaped hole in it.
Not because Claude was hard to add — because adding her meant paying per token to the Anthropic API on top of the Claude Code subscription I already run every day. Two meters for the same brain felt wrong.
Tonight it stopped being wrong.
The Problem
The orchestrator is my multi-provider ask tool. Type a question, it fans out to every provider in parallel, prints their answers side by side. It's how I triangulate anything I'm uncertain about — comparison shopping between models before I trust an answer.
Claude was the obvious missing seat. And the obvious way to add her was the Anthropic API — a key in a file, the SDK, done in twenty minutes.
But I already pay for Claude Code. I don't want to pay for the same model twice just to see her opinion in the same terminal.
The Insight
Claude Code has a --print mode. claude -p --model fable "prompt" — no interactive session, no editor, no context. You get one response, straight to stdout, using whichever auth Claude Code already has. Which for me is my subscription.
That means the meter I want to spend on IS the meter that fires when I use this flag. No second billing surface.
So the "provider" for the orchestrator doesn't need an API client at all. It needs a subprocess call.
The Build
A small provider module. Shell out to the CLI, capture stdout, wrap it in the same dict shape every other provider returns.
def query(prompt, *, model=None, max_tokens=None):
if not shutil.which("claude"):
return {"provider": "fable", "error": "claude CLI not on PATH"}
result = subprocess.run(
["claude", "-p", "--model", model or "fable",
"--output-format", "json", prompt],
capture_output=True, text=True,
encoding="utf-8", errors="replace",
timeout=300,
)
if result.returncode != 0:
return {"provider": "fable", "error": f"exit {result.returncode}"}
parsed = json.loads(result.stdout)
return {
"provider": "fable",
"model": "claude-fable-5",
"text": parsed.get("result", result.stdout),
}
Register it in the provider dict. Add fable to the argparse choices. That's the whole change.
The Result
> py -3.12 ask.py --list
Available providers:
gemini: ready
grok: ready
claude: not configured
chatgpt: ready
groq: ready
fable: ready
She's live. Solo call:
> py -3.12 ask.py -p fable "Introduce yourself in one sentence."
Routing to FABLE...
============================================================
FABLE (claude-fable-5)
============================================================
I'm Claude, an AI coding agent from Anthropic running on the
Claude Fable 5 model (the new Mythos-class tier above Opus)...
And in fanout mode she now fires alongside every other provider automatically. Same subprocess, same pattern, no new secrets on disk.
The Interesting Bit
Look at Fable's first sentence again: "the new Mythos-class tier above Opus."
A few days ago someone in a group chat mentioned Anthropic had rolled out "Mythos" alongside Fable. I couldn't place the name — nothing in the current model line I knew of used it. I flagged it as unverified and moved on.
Fable just named it herself, unprompted, in her introduction. Not internal information — it's how she describes her own tier when asked who she is. But it was the first primary source I'd seen for the word.
Small thing, but it's the shape of these tools that keeps surprising me: sometimes you build a channel to ask a question, and the channel itself is the answer.
What I Learned
- The right meter is often the meter you're already paying. Before adding a new billing surface for anything, check whether the tool you already use exposes a headless mode.
- Subprocess is a legitimate integration surface. Not everything needs an SDK. A CLI with a
--printflag and stable JSON output is an API in a plainer coat. - Reuse the existing pattern. The orchestrator's provider contract is a function that returns a dict with
provider,model, andtext. Match the contract, drop into the dict, and the rest of the pipe just works.
What's Next
The provider stub takes a model argument, so the same channel can hit Opus, Sonnet or Haiku by alias. That's the next small step — each becoming their own entity in the fanout when I want a direct comparison across the Claude family, all on the same subscription.
The council grew tonight. Debugged with Claude Code. Published at indigo-nx.com.