Summary
A plugin-defined agent whose manifest declares tools: { question: true } cannot actually call the built-in question tool. The inherited default permission question: "deny" (from the defaults block in packages/opencode/src/agent/agent.ts) is not overridden by the manifest tools: entry at agent-resolution time, so the tool is disabled for the agent.
Environment
- opencode:
1.18.5
- OS: Linux
OPENCODE_EXPERIMENTAL_CODE_MODE=true (reproduces with codemode off as well)
- The
adv agent is defined via a plugin manifest (~/.local/share/Advance/plugin/agents/adv.md) with tools: { ..., question: true, ... } and no explicit question permission override.
Reproduction
- Define a plugin agent with a manifest that includes
tools: { question: true } and no permission entry for question.
- Run
opencode debug agent <plugin-agent-name>.
- Inspect the resolved
tools dict and the permission list.
Observed (opencode debug agent adv)
The model never receives the question tool in its function list.
Root cause
packages/opencode/src/agent/agent.ts — the shared defaults permission includes:
const defaults = Permission.fromConfig({
// ...
question: "deny",
plan_enter: "deny",
plan_exit: "deny",
// ...
})
The built-in build and plan agents explicitly override it:
permission: Permission.merge(defaults, Permission.fromConfig({ question: "allow", ... }), user)
But plugin-defined agents inherit defaults as-is. The manifest's tools: { question: true } does not propagate to an agent-level permission allow, so the inherited deny wins.
Expected behavior
A manifest declaring tools: { question: true } should produce an effective agent-level permission allow for question, overriding the inherited default deny — mirroring the override the built-in build/plan agents apply explicitly. The tools: map and the permission defaults should not silently disagree.
Workaround
Add an explicit permission override in the agent's config (opencode.jsonc):
Verified: with the override, opencode debug agent <name> reports question: true and permission gains { permission: "question", action: "allow", pattern: "*" } (merged last, wins over the default deny).
Additional context
Summary
A plugin-defined agent whose manifest declares
tools: { question: true }cannot actually call the built-inquestiontool. The inherited default permissionquestion: "deny"(from thedefaultsblock inpackages/opencode/src/agent/agent.ts) is not overridden by the manifesttools:entry at agent-resolution time, so the tool is disabled for the agent.Environment
1.18.5OPENCODE_EXPERIMENTAL_CODE_MODE=true(reproduces with codemode off as well)advagent is defined via a plugin manifest (~/.local/share/Advance/plugin/agents/adv.md) withtools: { ..., question: true, ... }and no explicitquestionpermission override.Reproduction
tools: { question: true }and nopermissionentry forquestion.opencode debug agent <plugin-agent-name>.toolsdict and thepermissionlist.Observed (
opencode debug agent adv){ "tools": { "question": false, // ← disabled despite manifest `question: true` "execute": true, // ... }, "permission": [ { "permission": "*", "action": "allow", "pattern": "*" }, { "permission": "question", "action": "deny", "pattern": "*" } // ← inherited default wins ] }The model never receives the
questiontool in its function list.Root cause
packages/opencode/src/agent/agent.ts— the shareddefaultspermission includes:The built-in
buildandplanagents explicitly override it:But plugin-defined agents inherit
defaultsas-is. The manifest'stools: { question: true }does not propagate to an agent-level permissionallow, so the inheriteddenywins.Expected behavior
A manifest declaring
tools: { question: true }should produce an effective agent-level permissionallowforquestion, overriding the inherited defaultdeny— mirroring the override the built-inbuild/planagents apply explicitly. Thetools:map and the permission defaults should not silently disagree.Workaround
Add an explicit permission override in the agent's config (
opencode.jsonc):Verified: with the override,
opencode debug agent <name>reportsquestion: trueandpermissiongains{ permission: "question", action: "allow", pattern: "*" }(merged last, wins over the default deny).Additional context
OPENCODE_EXPERIMENTAL_CODE_MODE=falsetoo — so the codemode flag itself is not the trigger; it only made the absence visible.tools: { question: true }without an explicit permission override.plan_enter/plan_exitlikely share the same shape (alsodenyindefaults).