anomalyco / anomalyco/opencode

V2: subagent frontmatter skill allows ignored (global deny wins)

Open
#50,149 0 comments 0 reactions 0 assignees View on GitHub

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 permissions apply before agent-specific rules, so later agent rules can refine them"
  • /v2/docs/skills — loading a skill "Checks the selected agent's skill permission"; "Place the same rules under agents.<id>.permissions to 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
  1. Global config ~/.config/opencode/opencode.json:
{ "permissions": [
    { "action": "skill", "resource": "*", "effect": "deny" },
    { "action": "skill", "resource": "other-skill", "effect": "allow" }
] }
  1. Create ~/.config/opencode/skills/my-test-skill/SKILL.md with frontmatter name: my-test-skill and a description (ID is path-derived, so name matching the directory is irrelevant to the bug).

  2. 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.
  1. From the primary agent, launch my-reviewer and let it run its instruction.
  2. Observed: my-test-skill missing from the subagent's skill catalog; the skill call returns {"error":{"type":"permission.rejected","message":"Permission denied: skill"}}.
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.