Skip to content
Empryo

The Marionette: a cheap model pulls the strings

When it guessed causes, fixes dropped from 3/3 to 1/3. Now it only points at files: 3/3 and 11% cheaper.

The Marionette: a cheap model pulls the strings

You type a vague one-line bug report into your coding agent. Before editing anything, the expensive model spends ten steps working out which files you meant, at frontier prices.

I wanted a cheap pre-pass to do that work. The first version made the agent worse: it fixed the bug 3 times out of 3 alone, and once with my pre-pass attached. In one run, the pre-pass wrote a requirement telling the agent to keep the bug it was sent to fix, and the agent did exactly that 🫢 The second version scored 3/3 with 11% less spend.

All numbers come from my benchmark runs in isolated Anthropic workspaces, and the recorded spend matched Anthropic's billing API to within 0.2%.

The step I wanted to cutLink to this section

Empryo starts with the Genome, a ranked map of every file, symbol and dependency, with code navigation tools on top. It's in every prompt and a big part of why Empryo tends to be cheaper and faster than agents that grep around from scratch.

However, a map of the repo is not a map of your request. Working out which few files your sentence is about is a short walk with the Genome, but it runs on the expensive model, every prompt, and a vague sentence in a big repo can take ten steps.

The Marionette gives that walk to a model that costs a fortieth as much, before the expensive one starts. It reads your prompt, explores the same code map, and passes on your exact words with a map of where this request lands.

Real capture: the compile runs, the map assembles under the prompt, the agent starts on it.

What the agent receivesLink to this section

You type:

when we close the terminal on desktop, if it was open it stays on bottom bar until i click it then it disappears from bottom bar

The agent gets it word for word, with the map attached:

  • Asks: each separate behavior you described, quoted in your words. That sentence has two. An early version caught one and fixed half the bug.
  • Locations: files, functions and line ranges, such as the terminal panel's close handler, ranked primary or nearby.
  • Connections: how those pieces are wired, for example that closing a tab never clears its minimized state. Each names the tool that found it, so nothing is a guess.
  • Memories: relevant past decisions from your project's memory.
  • Not checked: what the pre-pass didn't reach.
The map as it lands, expanded, asks, loci with line ranges, strands, memories.
The map as it lands, expanded, asks, loci with line ranges, strands, memories.

No suspected cause, no proposed fix and no acceptance criteria. The first version is the reason.

The first version guessedLink to this section

The first Marionette formed theories, suggested fixes and wrote acceptance criteria. On paper that's more value per run, since you pay for the model anyway.

I tested it on one real desktop bug with a top-tier main model, five isolated workspaces and three runs per variant, each from an empty cache.

bench pass 2 · same bug, same main model
──────────────────────────────────────────
control (no pre-pass)      3/3 fixed · $1.49
diagnosing marionette      1/3 fixed · $1.37

Cheaper, and fewer fixes, because a cheap model's guesses steer an expensive model's judgment. The main agent had the tools to find the real cause and didn't look, because it arrived believing it knew.

A better prompt doesn't fix that, because the pre-pass did exactly what its output format invited. So I removed every field where a theory could go. What's left is factual: this file, these lines, this caller, this memory, this thing I didn't check.

bench pass 3 · locator rewrite
──────────────────────────────────────────
control                    3/3 fixed · $1.49 · 18 steps
locator marionette         3/3 fixed · $1.32 · 14 steps

Judged blind on the diffs, the fixes matched the control's. The main agent took four fewer steps and spent 11% less, and the pre-pass cost $0.09 to $0.13 per prompt.

It doesn't win everywhere. On a bug the expensive model already solves alone, it only matches it for slightly less money, and you wait longer for the pre-pass. It helps most with vague prompts, large repos, two requests in one sentence, and cheaper main models that can't afford twenty exploration steps.

Is it just an explore agent?Link to this section

I tested that too. Empryo's explore agent is a read-only helper the main agent can send out mid-turn, so one variant forced it before any edits. It did well: a Sonnet scout fixed 3 of 3 at about $1.30, and a Haiku scout fixed 2 of 3 at $1.13, the cheapest variant in that round.

Same idea, different point in the turn:

  • It always runs. The main agent often skips explore on the vague prompts that need it most.
  • It runs before the turn. An explore report lands mid-conversation as tool output and costs steps and context. The map arrives with your prompt.
  • It fills a form. An explore agent writes a report. The Marionette's fixed fields have no room for a theory, and that limit is the difference between 1/3 and 3/3.
  • Some modes are faster than any agent. Two of the four skip the tool loop: index-only answers in about 0.2 seconds, fast in about twenty.
  • It uses memory, visibly. It searches your project memories, and the map shows as an expandable section under your prompt.

Explore still fits mid-turn, when the agent needs a closer look. The Marionette handles the cold start.

The measurement that changed the defaultLink to this section

I measured four modes on 11 real requests against Empryo's own repo, three trials each. Recall is whether it found the files the actual fix touched, and precision is how much of what it returned was relevant.

lanegold recallprecisionmedian latencytokens in
none (index only)83%20%0.2s0
fast83%45%~22s7.4k
assist72%48%~60s~20k
deep (full survey)––~2min~390k (mostly cached)

A plain index lookup with no model found the right files as often as the model-driven modes, in 200 milliseconds and for zero tokens. Symbols, dependencies and change history already hold most of the answer.

It only lost on precision, because a raw candidate list is noisy. So the default, fast, spends one cheap model call turning candidates into a short brief: index recall with model precision, in about 22 seconds. The full survey mode, with the main agent's tools, still exists but is no longer the default.

Round two: does the map change what the expensive model does?Link to this section

Finding files is only a stand-in. What matters for your bill is what the expensive model does with the map, so I ran an end-to-end test with Opus 5 as the main agent and diagnosis-only prompts. Four variants: Opus alone, Opus told to send an explore scout first, and Opus with a map from a Haiku or a Sonnet pre-pass.

On a request whose wording barely overlapped the code responsible:

e2e · opus-5 main · same prompt, four arms
──────────────────────────────────────────────
opus alone            gold file at step 3 · $0.681
opus + explore scout  gold file at step 2 · $0.687
opus + haiku map      gold file at step 1 · $0.367 + $0.014
opus + sonnet map     gold file at step 1 · $0.504 + $0.082

The $0.014 pre-pass put the right file in Opus's first tool call and cut its bill by 46%. The scout still paid full price, because its report arrived mid-turn.

On a second task, the Haiku pre-pass left the right file off its map, though the index had it as a candidate. Opus trusted the map with a hole in it and did worse than Opus alone. Sonnet's variant kept the file and was the only one to finish within the step limit. Two changes went on the roadmap. Firstly, the pre-pass should have to argue a file out of the map when the request names it, instead of quietly ranking it low. Secondly, when the index is unsure, a stronger model should review the same candidates instead of searching longer. There's still no field for a fix.

Using itLink to this section

Experimental and off by default. In the terminal app:

/marionette fix the race in tab restore   # run the pre-pass on one prompt
/marionette on | off | status             # run it on every prompt
/marionette none | fast | assist | deep   # pick the mode
/router                                   # pick the model it uses

In headless mode, --marionette turns it on and --marionette-mode <none|fast|assist|deep> picks the mode. By default it uses the lightweight model from your router settings. If the pre-pass fails, your prompt goes through unchanged.

In the TUI, the map builds in the transcript, then folds to one line:

The TUI lane. Same compile, same map, drawn in text.

For anyone building something similarLink to this section

If you build anything that briefs a larger model, let the cheap one tell the expensive one where to look and never what to conclude. Give it an output format with nowhere to put an opinion. If a field for one exists, it gets filled, and the model downstream believes it.

Numbers come from benchmark rounds 2 to 5: the isolated-workspace runs, a 143-run file-finding series with two pre-pass models, and the Opus 5 end-to-end test.