The Marionette
A prompt-compiler pre-pass: a cheap model walks the code graph before the main agent moves and attaches a map — files:lines, wiring, memories — to your prompt.
Every Empryo prompt already carries the Genome: the whole repo as a ranked dependency graph. The marionette adds the second half — a map of *this request*. A cheap model surveys the same graph before the main agent sees your prompt, and attaches what it found: the files this sentence is about, with line ranges, how they wire together, and which past decisions apply.
The Genome says what the repo is. The marionette says which rooms you just pointed at. The agent starts warm instead of resolving that on frontier tokens.
Your prompt is never rewritten. The map rides under it.
Using it
/marionette fix the race in tab restore # compile this prompt only
/marionette fix it --steps 12 --time 90s # bound the survey
/marionette on | off | status # always-on toggle, per scopeAlways-on also lives in Settings → Router → Behaviors on desktop, and headless runs take --marionette / --marionette-mode <lane>.
The map
While the compile streams, the map assembles folded under your prompt — expand it to read:
| section | contents |
|---|---|
| asks | each distinct behaviour you asked for, quoting your words |
| loci | file.ts:120-180 · symbol · role, ranked primary/adjacent |
| strands | wiring between the loci — callers, co-changes, blast radius |
| memories | past decisions that apply, by id |
| unmapped | what the survey did not reach, stated plainly |
Every strand names the tool that produced it (navigate, genome_impact, …) — nothing in the map is a guess. By design the schema has no field for a diagnosis: in benching, a pre-pass that proposed fix shapes anchored the main agent onto wrong ones (1/3 fixed vs 3/3 for the plain agent). The locator version — mechanical observations only — restored 3/3 at 18 → 14 main-agent steps and −11% median spend.
Lanes
Set per scope with /marionette none|fast|assist|deep or "marionetteMode" in config:
| lane | what runs | recall | latency | cost (haiku) |
|---|---|---|---|---|
none | index retrieval only, no model | 83% | 0.2s | free |
fast *(default)* | retrieval + one model pass | 83% | ~20s | ~$0.02 |
assist | retrieval + short tool loop | 72% | ~60s | ~$0.05 |
deep | full read-only survey agent | — | ~2min | $0.09–0.13 |
Routing
The marionette lane in /router picks its model (taskRouter.marionette). Unset, it falls back to the spark slot — cheap by default. The pre-pass carries the same read-only intelligence belt as subagents (LSP, code graph, impact analysis, memory search — never a mutation tool), and a failed compile always degrades to your raw prompt: the pre-pass can never kill a turn.
Why not just dispatch an explore agent?
Explore is chosen by the main agent mid-turn; the marionette is guaranteed, runs *before* the turn on a clean context, emits a constrained schema instead of free prose, can skip the tool loop entirely (none/fast), and surfaces project memories. Explore remains the right tool once the agent discovers it needs eyes on a subsystem — the marionette owns the cold start.