DEV Community

Cover image for How Fusion works: DeepSeek V4 Pro plans, V4 Flash writes the code
Dennison Bertram
Dennison Bertram

Posted on

How Fusion works: DeepSeek V4 Pro plans, V4 Flash writes the code

Big models write better plans. Small models are cheaper and fast enough to type the code. I wanted both in one session without switching models by hand.

That's Fusion. It's one entry in FreePi, a free AI coding agent for the terminal. This post explains how it splits a task between DeepSeek V4 Pro and DeepSeek V4 Flash, how the switch happens, and when it's worth turning on. Everything here comes from the code that ships in the CLI today.

Try it: run npx free-pi-cli@latest in a terminal, then pick Fusion in /model.

Give this to your agent: freepi.ai/llms.txt

The short version

Every message you send goes through three phases:

  1. Explore. DeepSeek V4 Flash reads your code with read-only tools. It makes no edits.
  2. Plan. DeepSeek V4 Pro gets one request. It writes a step-by-step plan into the agent's todo list. It can't edit files.
  3. Build. Flash takes over again. It works through the todo list, edits files and runs tests.

So Pro answers one request per message. Flash handles every other request, including all the follow-ups after tool calls.

How you turn it on

FreePi runs the pi coding agent. Type /model and Fusion is the first entry in the list. Pick it, and the footer shows Fusion plus the model that answered the last request.

Fusion isn't the default. A new session starts on the default model the server lists first, so you pick Fusion yourself.

Fusion is a router, not a model

pi has a feature called virtual models. A virtual model shows up in /model like any other model. Before every request, it runs a route function that picks a real model to send that request to.

Fusion is a virtual model. When you pick it, nothing new runs on the server. Each request still goes out as a normal request to deepseek-v4-pro or deepseek-v4-flash.

The router keeps one piece of state per session branch, the current phase. Here's the core of it, trimmed, with one helper renamed:

switch (request.reason) {
  case "user":
    // a new message from you: start over
    return route(executor, "explore");
  case "continuation":
    // after the planner's one reply, it's all build
    if (phase !== "explore")
      return route(executor, "build");
    if (editedThisTurn(messages))
      return route(executor, "build");
    // the executor asked for a plan
    return planRequested(messages)
      ? route(planner, "plan")
      : route(executor, "explore");
}
Enter fullscreen mode Exit fullscreen mode

In pi, a "continuation" is any request in the agent loop that isn't a fresh message from you, like the request after a tool result.

Asking for a plan is a tool call

How does Flash say "I've read enough, give me a plan"? It calls a tool named fusion_plan.

The tool takes one argument, a summary of what Flash found and what the task needs. It only exists while Fusion is selected. Its result is the planner's brief:

You are now the planning model. Write a concrete
step-by-step plan (files, exact changes, tests to add
and run) and record it with the todo tool, one item
per step. Do not edit files or run commands. Another
model will carry out the plan.
Enter fullscreen mode Exit fullscreen mode

The router sees that fusion_plan result in the transcript and sends the next request to Pro. Pro sees the whole conversation, including the files Flash already read. Then it writes the plan with the todo tool. You can see that list any time with /todos.

Guardrails, because prompts alone didn't work

Fusion's instructions tell Flash to explore first and call fusion_plan before any edit. A comment in the code explains why that wasn't enough. In a live run, DeepSeek ignored the instruction and edited files directly.

So Fusion now blocks edits in code. While Fusion is selected, the CLI checks every edit and write call:

  • Before a successful fusion_plan call since your last message, the edit is blocked. The model gets back "call fusion_plan first".
  • If the planner tries to edit, it's blocked too. The planner records the plan, and the executor makes the changes.

A few more cases are handled:

  • The planner stops early. If Pro replies with text and no tool calls, the turn would end with nothing built. Fusion adds one hidden message, "The plan is recorded. Carry out the unfinished todo items now", so Flash picks up the work. This happens at most once per plan.
  • The planner request fails. The retry goes to Flash in build mode instead of trying Pro again.
  • A model is missing. If either model can't be found, every request goes to the default model instead of failing.

What stays with Flash

Plain questions skip the planner. Fusion's instructions tell Flash to answer a message that needs no file changes directly, with no fusion_plan call.

Background work also goes to Flash. A compaction summary, for example, is a request outside the agent loop, and the router always sends those to the executor.

The server picks the pair

The model ids aren't hardcoded forever. On startup the CLI calls /client-version, and the server can send a fusion field with a planner and an executor. Today it says:

{
  "planner": "deepseek-v4-pro",
  "executor": "deepseek-v4-flash"
}
Enter fullscreen mode Exit fullscreen mode

The CLI uses that pair only if both models are in the catalog it just loaded. Otherwise it falls back to its built-in pair. So I can swap the planner on the server without shipping a new CLI.

When to use it

Fusion fits tasks where a bad plan costs you more than a slow start:

  • Changes that touch several files.
  • A feature plus the tests for it.
  • Refactors where the order of steps matters.

For a one-line fix, plain DeepSeek V4 Flash is usually the better pick. Under Fusion, even a tiny edit waits for exploration and a planning request.

Trade-offs

  • The plan request costs more. Pro is the more expensive model, so its request uses more of your daily allowance than a Flash request. The /model picker shows how fast each model uses it.
  • Prompt caches don't carry over. pi's docs say switching models loses the prompt cache. Each switch between Flash and Pro sends the context without it.
  • Shell commands aren't blocked. Exploration needs bash, so Fusion leaves it alone. A shell command can still change files before the plan exists. Keep your work in git.
  • One plan per message. Pro writes the plan once. If the build goes sideways, send a new message and Fusion starts over from explore.

Wrapping up

Fusion is a small router on top of pi. Flash explores, Pro writes one plan into the todo list, and Flash builds it. Edits stay blocked until the plan exists, and failures fall back to Flash instead of stalling. Use it for multi-file work, and stay on Flash for quick fixes.

Try it free with npx free-pi-cli@latest, pick Fusion in /model, and read more at www.freepi.ai.

Top comments (0)