anomalyco / anomalyco/opencode
V2: subagent frontmatter skill allows ignored (global deny wins)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- Avg merge
- 7h 2m
- Merged PRs (30d)
- 384
Description
Description
Agent frontmatter permissions rules with action: "skill", effect: "allow" have no effect for subagents in V2. The child session appears to evaluate only the parent/global ruleset, so a global { "action": "skill", "resource": "*", "effect": "deny" } (the allowlist pattern from the permissions docs) hides and rejects skills that the subagent explicitly allows in its own frontmatter.
The docs describe the opposite behavior:
- /v2/docs/permissions — "Lower-priority configuration is loaded first, global rules are appended next, and agent rules are appended last" (last matching rule wins)
- /v2/docs/agents — "Global
permissionsapply before agent-specific rules, so later agent rules can refine them" - /v2/docs/skills — loading a skill "Checks the selected agent's
skillpermission"; "Place the same rules underagents.<id>.permissionsto apply them only to one agent"
Observed on v2.0.11: the skill is absent from the subagent's available-skills catalog (the catalog mirrors the primary's global-allow view — 37 skills — rather than anything derived from the subagent's own frontmatter), and the skill tool call fails with {"error":{"type":"permission.rejected","message":"Permission denied: "skill"}}.
Steps to reproduce
- Global config
~/.config/opencode/opencode.json:
{ "permissions": [
{ "action": "skill", "resource": "*", "effect": "deny" },
{ "action": "skill", "resource": "other-skill", "effect": "allow" }
] }
-
Create
~/.config/opencode/skills/my-test-skill/SKILL.mdwith frontmattername: my-test-skilland a description (ID is path-derived, sonamematching the directory is irrelevant to the bug). -
Create
~/.config/opencode/agents/my-reviewer.md:
---
description: Loads a skill
mode: subagent
permissions:
- { action: skill, resource: my-test-skill, effect: allow }
---
Call the skill tool with id "my-test-skill" and report the exact result.
- From the primary agent, launch
my-reviewerand let it run its instruction. - Observed:
my-test-skillmissing from the subagent's skill catalog; theskillcall returns{"error":{"type":"permission.rejected","message":"Permission denied: skill"}}. - Expected: the agent-level allow is the last matching rule, so the skill is advertised and loads without approval.
Proposed solution
Include the subagent's own permission rules in the child session's derived ruleset, appended after the global rules per the documented merge order. The V1 lineage of this bug is analyzed in #33223 (deriveSubagentSessionPermission reads input.subagent.permission only for task/todowrite checks and never includes it in the output) — worth checking whether the V2 derivation inherited the same shape. Related: #26758, #27497 (fixes #27201, #27654), #35238.
Plugin suggestion
While unfixed, a plugin-side workaround is currently impossible because the derived child-session permission set is never surfaced. Exposing a permission-derivation hook (e.g. an event/execute-style hook receiving the child session's effective permission set before the first tool call) would let deployments audit or patch derived rules, and would enable the "permission derivation receipt" test suggested in #33223's comments (fail when a subagent rule was silently dropped).
Plugins
@prevalentware/opencode-goal-plugin@^0.1.48 plus a local secret-masking plugin; neither touches permissions. The repro above requires no plugins.
OpenCode version
v2.0.11
Operating System
Ubuntu 24.04.5 LTS (x86_64)
Terminal
Reproduced headless via the agent API (no TUI involved).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the V2 child-session permission derivation and compare it with deriveSubagentSessionPermission discussed in #33223. Done means the child ruleset includes the subagent's rules after global rules, and the reproduction advertises and loads my-test-skill without rejection.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authorization
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100