# Use different models for planning and coding

> Set up a planner and a DeepSeek executor in OpenCode, keep their permissions separate, and compare the cost of accepted changes rather than tokens.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-11-02 | Topics: [AI](https://flaviocopes.com/tags/ai/) | Canonical: https://flaviocopes.com/planner-executor-models/

Some coding tasks need a lot of investigation before anyone should edit a file. Once the decision is made, the implementation may be quite small.

You can use different models for those two jobs. Keep a model you trust for the planning and review, then give a less expensive model a narrow implementation task.

That can reduce cost. It can also add handoff errors, repeated context, and extra review. The useful question is how much it costs to get a change you can accept.

Here is a setup using OpenCode's current agent configuration and DeepSeek's `deepseek-flash` API model, which DeepSeek documents as serving V4.1 Flash. The configuration was checked against the documentation in October 2026; I haven't run a paid model comparison for this article. Check the [current DeepSeek model alias](https://api-docs.deepseek.com/quick_start/agent_integrations/) before using it.

## Give the planner a decision to make

Start with a task where you can describe success without choosing the implementation:

```text
Investigate why the file list loses its selected row after a rename.

Read the current code and tests. Explain the cause with source
references. Propose the smallest fix and a regression test.

Do not edit files or launch an executor yet. Identify the files
that one executor would own, and anything it must leave alone.
```

The executor needs to know what caused the problem and how we will check its fix. A plan that says “improve state management” leaves almost all the important decisions for the executor.

Ask follow-up questions now. If you can't understand why the proposed change should fix the problem, adding more agents won't help.

## Connect the providers

In OpenCode, run `/connect` and choose DeepSeek, then supply your API key through the connection flow. Connect your preferred planning provider too. Use `/models` to inspect the available models. Keep credentials out of the project configuration.

Those commands and the provider catalog are documented in [OpenCode's provider setup](https://opencode.ai/v2/docs/providers/). Make sure the DeepSeek model is available before assigning work to it.

For the primary session, select the model you already trust for investigation through `/models`. Selecting an agent and selecting the session model are separate operations in OpenCode 2. Check both in the interface, especially when returning to an existing session. The [model documentation](https://opencode.ai/v2/docs/models/) explains session selection and defaults.

## Configure a bounded executor

The following is an OpenCode 2 configuration. It uses `agents` and a `permissions` array; older OpenCode examples have different fields.

Merge this into your project's `opencode.jsonc`, preserving any settings already there:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "default_agent": "planner",
  "agents": {
    "planner": {
      "description": "Investigates a task and reviews one bounded implementation",
      "mode": "primary",
      "system": "Investigate first. Propose a concrete task and acceptance checks. Do not launch the executor until the user approves the task. Review its diff and evidence before accepting it.",
      "permissions": [
        { "action": "edit", "resource": "*", "effect": "deny" },
        { "action": "shell", "resource": "*", "effect": "ask" },
        { "action": "subagent", "resource": "*", "effect": "deny" },
        { "action": "subagent", "resource": "executor", "effect": "ask" }
      ]
    },
    "executor": {
      "description": "Implements one approved task within named files",
      "mode": "subagent",
      "model": "deepseek/deepseek-flash",
      "steps": 8,
      "system": "Implement only the approved task. Stay within the named files. Ask before expanding scope. Report changed files, checks actually run, failures, and uncertainties. Never commit, push, or deploy.",
      "permissions": [
        { "action": "edit", "resource": "*", "effect": "ask" },
        { "action": "shell", "resource": "*", "effect": "ask" },
        { "action": "subagent", "resource": "*", "effect": "deny" }
      ]
    }
  }
}
```

The planner can't edit through the edit tool, and shell commands require approval. The executor has its own approval rules. Read commands before approving them: a shell command can change files too.

The child has an explicit model. Without that setting, a subagent inherits its parent's model. Its `steps` allowance bounds model steps, then requests a summary; another user message resets the allowance. It isn't a dollar cap. These behaviors are covered in the [agent documentation](https://opencode.ai/v2/docs/agents/).

Permissions don't turn prompts into an operating system sandbox. Keep separate controls around credentials, network access, and production systems. Review [OpenCode's permissions](https://opencode.ai/v2/docs/permissions/) alongside any existing global or project rules, because configuration can merge.

Start a new session so the default agent takes effect. Verify the planner and primary model are selected. The child model setting does not choose the primary model for you.

## Hand over the evidence the child needs

After approving the plan, give the planner a small execution contract:

```text
Use one executor for the approved rename fix.

It owns src/file-list.ts and test/file-list.test.ts only.
Pass the diagnosis, the relevant functions, and the expected
selection behavior. Require the existing test command plus a
regression test for renaming the selected row.

Stop if the fix needs other files. No dependency changes.
Review the result yourself and report any unresolved question.
```

Subagents start with fresh context. Include the reasoning they need, rather than assuming they saw your conversation.

For the first task, watch the child session and confirm its selected model. Check the returned diff and test output. A summary saying “tests passed” needs a corresponding command and result. If tests weren't run, keep that distinction in the handback.

Avoid starting five executors on the same files. Get one complete handoff working before introducing concurrent work.

## Measure accepted changes

A useful calculation is:

```text
cost per accepted task =
  (planning + execution + retries + review costs)
  / number of accepted tasks
```

For example, imagine ten tasks consume $3 in planning, $2 in execution, and $1 in review. If eight changes meet your acceptance checks, the model cost is $0.75 per accepted task. Those numbers are illustrative, not a benchmark.

Track elapsed time and your review time beside that figure. Include failed tasks in the cost. Otherwise the workflow looks cheaper whenever you quietly abandon its difficult results.

Repeated prompts, large tool outputs, cache behavior, and retries all affect the bill. Compare the provider's current pricing with actual usage records rather than assuming the advertised input token rate predicts the whole task.

If the stronger model spends half an hour repairing every child result, try a narrower task or a different executor. Some tasks belong entirely with the stronger model.

## Check data handling for both routes

This setup sends some project content to the planning provider and some to DeepSeek. Using a cheaper child doesn't keep its context inside the parent's provider.

Check retention and training policies for each endpoint and account. A promise not to train on prompts isn't the same as zero retention.

If you use OpenRouter instead of the direct route above, its [Zero Data Retention documentation](https://openrouter.ai/docs/guides/features/zdr) describes eligible endpoint routing and the `provider.zdr` control. That policy has a defined scope; plugins and external tools have their own data handling. Don't infer a blanket privacy promise from the model name.

Keep the first experiment small enough that you can inspect every file it touched. You can widen the workflow once the handoff, review, and cost records show that it works for your tasks.
