opencode.tools adds the execute / session_move hint even when Code Mode is denied · Issue #57711 · anomalyco/opencode · GitHub
Skip to content

opencode.tools adds the execute / session_move hint even when Code Mode is denied #57711

Open

Description

@DaniilSokolyuk

Description

When Code Mode is turned off with a permission rule ({ "action": "execute", "resource": "*", "effect": "deny" }), Tool.snapshot doesn't build the execute tool (codeModeEnabled = !whollyDisabled("execute", rules)), but the built-in opencode.tools plugin still adds this system part to every context, compaction and generate request:

When you create a worktree outside the current working directory and intend to use it as your primary working directory, consider using execute to call tools.opencode.session_move and make the worktree the session's working directory.

The model is told to use a tool it isn't offered (and tools.opencode.* are Code Mode only, so they aren't reachable either).

Expected: skip the hint when execute is wholly denied for the session's agent.

Related: #48749 (the hint now also reaches compaction and generate requests).

Plugins

Own plugins via the SDK (embedded host); the hint comes from the built-in opencode.tools.

OpenCode version

@opencode/core 2.0.32

Steps to reproduce

  1. Config with "permissions": [{ "action": "*", "resource": "*", "effect": "allow" }, { "action": "execute", "resource": "*", "effect": "deny" }].
  2. Send a prompt.
  3. The request has no execute tool, but its system prompt still contains the execute / tools.opencode.session_move hint.

Activity

  1. opencode-agent commented on Oct 21, 2026

    @opencode-agent
    Contributor

    Thanks for the clear report. I was able to reproduce this on 2.0.32 with a simulated model and your permissions (allow *, deny execute). After sending a prompt, the main request offers no execute tool (only glob, grep, patch, question, read, shell, skill, subagent, webfetch, websearch), but its system prompt still contains the execute / tools.opencode.session_move worktree hint.

    It still happens on the latest dev (4d59657). The hook in the built-in opencode.tools plugin adds the hint without checking whether execute is denied. The script below reproduces it by checking the outgoing request body.

    Related: #48749 (why the hint also reaches compaction and generate requests).

    Reproduction script (drive.ts)
    // Repro for anomalyco/opencode#57711: with `execute` wholly denied, the request
    // has no `execute` tool but its system prompt still carries the
    // `execute` / `tools.opencode.session_move` worktree hint.
    import { Effect, Stream } from "effect"
    import { Llm, OpenCodeDriver } from "opencode-drive"
    
    const HINT = "tools.opencode.session_move"
    const results: Array<{ index: number; tools: string[]; hint: boolean }> = []
    
    const toolNames = (body: any): string[] =>
      (body?.tools ?? []).map((t: any) => t?.name ?? t?.function?.name ?? "?")
    
    export default OpenCodeDriver.use(
      {
        ...(process.env.OC_DEV ? { opencode: { dev: process.env.OC_DEV } } : {}),
        config: {
          permissions: [
            { action: "*", resource: "*", effect: "allow" },
            { action: "execute", resource: "*", effect: "deny" },
          ],
        },
      } as any,
      ({ ui, llm }: any) =>
        Effect.gen(function* () {
          yield* llm.serve((request: any, index: number) => {
            const text = JSON.stringify(request.body)
            const entry = { index, tools: toolNames(request.body), hint: text.includes(HINT) }
            results.push(entry)
            console.log("REQUEST", JSON.stringify(entry))
            return Stream.make(Llm.text("ok done"))
          })
          yield* ui.submit("hello")
          yield* ui.waitFor("ok done")
          // the main agent request is the one that offers tools (skip background requests)
          const r = results.find((e) => e.tools.length > 0)!
          console.log(
            `RESULT execute tool offered: ${r.tools.includes("execute")}; session_move hint in system prompt: ${r.hint}`,
          )
          if (!r.tools.includes("execute") && r.hint) console.log("BUG REPRODUCED")
        }) as Effect.Effect<void, unknown, never>,
    )

    Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions