Let agents opt out of the app default layer; fix PLUGIN_DIRS collapsing to one dir - #59
Open
simurg79 wants to merge 2 commits into
Open
Let agents opt out of the app default layer; fix PLUGIN_DIRS collapsing to one dir#59simurg79 wants to merge 2 commits into
simurg79 wants to merge 2 commits into
Conversation
An app's `default.agent.md` is force-merged into every session -- both its prompt and its `tools:`. The only escape hatch was the internal `pilotswarm-system-agent` prompt-layer kind, which app agents cannot reach, so authoring one agent that did not want the app-wide instructions meant weakening the default for every other agent in the deployment. Agents can now declare `inheritAppDefaults: false`. Such an agent is composed from the framework base plus its own prompt and tools only, and it is dropped from the prompt layer manifest. Omitting the field inherits, so every existing agent is unchanged. The flag is resolved from the bound agent definition at prompt-composition time rather than persisted on the session row, matching how agent redefinition is expected to take effect on the next turn -- so no migration is needed and no session can carry a stale copy of the decision. A single `inheritsAppDefaults()` resolver gates all four consumption points (session prompt, subagent prompt, app-default tool merge, layer manifest) so they cannot drift apart. This is a composition choice, not a security boundary: invariants that must hold for every session still belong in the framework base layer, which cannot be opted out of. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PLUGIN_DIRS is documented and parsed as a comma-separated list, and the SDK worker loads every entry (worker.ts Tier 4 iterates config.pluginDirs). The TUI/portal bootstrap did not: resolvePluginDir() returned dirs[0] and then overwrote process.env.PLUGIN_DIRS with that single path, so every dir after the first was discarded before the worker ever saw it. The failure is silent and the blast radius is bad: an overlay dir holding default.agent.md would simply not load, dropping the app default prompt and its force-merged tools with no warning. resolvePluginDirs() now returns the full list, --plugin accepts a comma-separated value, and system.md is resolved across all dirs (first match wins). Branding still reads only the first dir, so single-dir configurations resolve to exactly the same values as before. The same truncation in web/bin/serve.js --plugin handling is fixed too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
What
Two changes that together let an app author an agent which does not inherit the app's
default.agent.mdlayer.1.
inheritAppDefaultsfrontmatter (feature)An app's
default.agent.mdis force-merged into every session — both its prompt and itstools:. The only escape hatch waspromptLayering.kind === "pilotswarm-system-agent", which app agents cannot reach. So the only way to author an agent that did not want those instructions was to weaken the default for everyone.Agents can now opt out:
An opted-out agent composes from the framework base plus its own prompt and tools only.
feat/capability-profiles-phase1covers the skills/tools half (allowedSkills,toolPolicy); this stays orthogonal to it.This is a composition choice, not a security boundary — invariants that must hold for every session still belong in the framework base layer, which cannot be opted out of.
2.
PLUGIN_DIRSno longer collapses to one directory (bug fix)PLUGIN_DIRShas always been documented and parsed as a comma-separated list, and the SDK worker loads every entry — butbootstrap-env.jsresolved it down todirs[0]and then wrote that single path back overprocess.env.PLUGIN_DIRS, destroying the config before embedded workers read it.Any deployment configuring two plugin dirs silently lost all but the first, with no error. For an overlay holding
default.agent.md, that means the app default layer vanishes silently.--pluginnow also accepts a comma-separated list.system.mdis resolved across all plugin dirs (first match wins).Same one-line collapse existed in
packages/app/web/bin/serve.jsand is fixed there too.Why together
The second is a prerequisite for using the first the obvious way: putting the app default in its own plugin dir so opting out is visibly opting out of a named layer rather than out of something buried among the ordinary agents.
Tests
packages/sdk/test/unit/agent-inherit-app-defaults.test.mjs— 11 new testspackages/app/tui/test/bootstrap-env-plugin-dirs.test.mjs— 6 new teststsc --noEmitclean, TUI plugin-dir tests 6/6, all on top of 0.5.28Note for the maintainer
No version bump or CHANGELOG heading is claimed — both entries are filed under
## Unreleased. (An earlier local cut of this work claimed 0.5.27, which was taken upstream in the meantime; that commit was dropped.)