Skip to content

[FEATURE]:pin a session's model so an agent cannot use another one #55654

Open

Description

@rapasyonok1337

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

What happens now. The user picks the model for a session, but an agent can quietly use a different one: it runs opencode run --model <other> through the shell tool, or calls the session model endpoint from Code Mode. No warning, a different provider and price.

What I want. A supported way to pin a session or an agent to one model, so the agent cannot move to another on its own. Any of these would do:

  • a model permission action, so permissions can restrict model selection;
  • an agent option that rejects model overrides;
  • ignoring --model when a session model is pinned.

Related. #51071 covers the same class of problem for the subagent tool's model argument. This request is about the other vector - an agent overriding the model through the shell/CLI, and Code Mode calling the local API - plus a general way to pin the session model rather than a single tool check.

Workaround I use now. A plugin denies shell commands that contain a model override, and a config rule turns Code Mode off for agents.

// opencode.jsonc
{
  "plugins": ["./plugins/model-guard"],
  "permissions": [{ "action": "execute", "resource": "*", "effect": "deny" }]
}
// plugins/model-guard/index.ts
import { Plugin } from "@opencode/plugin"

const LAUNCH = /\bopencode(?:-cli)?(?:\.exe|\.cmd)?\b/i
const OVERRIDE = /(^|\s)(--model|-m)(\s|=)/i
const SWITCH_API = /\/api\/session\/[^\s]*\/model\b/i

export default Plugin.define({
  id: "model-guard",
  async setup(ctx) {
    await ctx.permission.hook("evaluate", (event) => {
      if (event.action !== "shell") return
      const hit = event.resources.find(
        (r) => SWITCH_API.test(r) || (LAUNCH.test(r) && OVERRIDE.test(r)),
      )
      if (!hit) return
      event.effect = "deny"
      event.message = "switching models is blocked; use the model selected for this session"
    })
  },
})

Two gaps in that workaround: shell matching is text-based and therefore best effort, and a plugin cannot deny execute on its own - setting effect: "deny" for execute in permission.hook("evaluate") had no effect, only the config permissions rule did.

Env: OpenCode 2.0.27, Windows 10, desktop app.

Activity

  1. opencode-agent commented on Oct 15, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed request and for sharing your workaround!

    To restate it: you want a supported way to pin a session's or agent's model, so an agent can't switch to another model on its own, whether through opencode run --model in the shell or by calling the session-model API from Code Mode. Ideally this would be enforced through permissions or an agent option.

    You're right about the execute gap. Whether Code Mode is available is decided from the configured permission rules alone. That check doesn't go through the plugin permission.hook("evaluate"), so a plugin can't deny execute; only a config rule can. Since there is also no hook when a session's model changes, a plugin can only match shell text, as yours does, so a reliable version needs support in OpenCode itself. I've passed this on to the maintainers, who will consider it.

    Related issues:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions