feat(opencode): filter instruction files by reader audience - #38957
Open
iceteaSA wants to merge 1 commit into
Open
feat(opencode): filter instruction files by reader audience#38957iceteaSA wants to merge 1 commit into
iceteaSA wants to merge 1 commit into
Conversation
1 task
iceteaSA
force-pushed
the
instruction-audience
branch
from
July 26, 2026 12:22
3472beb to
9f30f79
Compare
iceteaSA
marked this pull request as ready for review
July 26, 2026 14:35
iceteaSA
force-pushed
the
instruction-audience
branch
from
July 26, 2026 14:50
9f30f79 to
8d0fddb
Compare
Adds an opencode.audience frontmatter directive so an instruction file can declare who it is for: a role (main / subagent / all) and an agent glob, matched as OR across entries and AND within one. Reader role is derived structurally from whether the session has a parent, so a primary-mode agent dispatched as a child is correctly a subagent. Absent metadata means included everywhere, byte-identical; an unknown key under opencode is fatal and names the file, because a typo like `audiance` parses as valid YAML and failing open would silently reinstate the delivery the directive exists to prevent. Filtering covers system-prompt assembly, nearby-file resolution through the read tool, and the prompt attachment path. The V2 SessionCore assembly path is a separate implementation and is not covered.
iceteaSA
force-pushed
the
instruction-audience
branch
from
August 2, 2026 11:45
8d0fddb to
136a4f0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #38961
Related: #4096 (context control for subagents — shapes context volume from the dispatch side; this shapes ownership from the file side).
Type of change
What does this PR do?
Lets an instruction file declare who it is for, so a nested
AGENTS.mdwritten for the orchestrator does not get delivered to every subagent:roleismain/subagent/all;agentis a glob. Entries OR together, keys within one entry AND together. A file with noopencode:metadata is included everywhere, byte-identical to today — no behaviour change unless you opt in.Three decisions worth calling out, because each has a wrong-looking-but-tempting alternative:
Reader role is structural, not configured. It comes from
session.parentID == null, not from the agent'smode. Amode: "primary"agent dispatched as a subagent is a subagent — deriving role from config would get that backwards, and the whole point is to reason about the delivery, not the label.An unknown key under
opencode:is fatal and names the file.audiance:is valid YAML, so a permissive schema cannot distinguish a typo from an absent directive — and failing open silently reinstates exactly the delivery the directive was written to prevent.opencode: {}is treated as absence and included, since an empty map asserts nothing.Filtering happens on every delivery path, not just the obvious one.
buildSystem()is the path people think of; two others leak without it, and both were found by inspection rather than by a failing test:Instruction.resolve()— nestedAGENTS.mdsurfaced through the read tool. Needed a reader onTool.Context, supplied by the production constructors and failing closed when absent.createUserMessage'sfile:attachment path — hardcodedrole: "main", so a subagent leaked main-only instructions whenever a dispatch carried an@filereference.AudienceErroris delivered as a typed failure rather than a defect, so a malformed file surfaces as a normal error at the call site.Known limitation, documented in
rules.mdx: the V2 SessionCore assembles system context through a separate path (packages/core/src/instruction-context.ts) with no audience filtering. That is bounded today because V2 has no task tool, so every V2 session is structurallymain— but it stops being bounded the moment V2 gains dispatch.packages/corecannot import frompackages/opencode, so sharing the filter means moving it into core; that is a larger change than this PR should carry.How did you verify your code works?
packages/opencode/test/session/instruction-audience.test.tscovers parsing,role/agentmatching, wildcard semantics, OR/AND composition, directive stripping, and malformed-metadata failures.instruction.test.ts: neutering the audience filter leaks wrong-audience project files; neutering the origin filter leaks config files into project scope. Each failure names which filter died.resolve(), and through an@fileattachment — each failing before the fix and passing after.bun testinpackages/opencode: 3243 pass / 0 fail (dev baseline 3207).bun typecheckclean inpackages/opencodeandpackages/core.packages/web/src/content/docs/rules.mdx, including the V2 limitation above.Screenshots / recordings
Not a UI change.
Checklist