feat(summon): make skill supporting files individually loadable via load()#7583
feat(summon): make skill supporting files individually loadable via load()#7583wpfleger96 merged 6 commits intomainfrom
Conversation
ceb8105 to
ec8e9fd
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec8e9fd48b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
ec8e9fd to
ec435d8
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec435d83a4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
I think #7457 might help here? |
|
@tlongwell-block so #7457 enables the Slackbot to see that the skill's supplemental/reference material exists, but it's still unreachable/unusable the skill is structured like: and the agent can and the model does try this, but it fails with: because currently if we're going to abstract the |
|
I think this is ok @wpfleger96 - downside is that this is less "progressive loading" which is one of the tenets of skills. So downside is if there are skills which are mountains and mountains of .md files, it will blow out context. tagging @tlongwell-block who would be aware of this limitation and may have thoughts. I think it is ok but I don't know how bloated skills are (the ones I have seen in squareup/agents I think may end up a bit bloated, but I guess you only load one or two). |
c1b502d to
d784c78
Compare
|
@michaelneale @tlongwell-block 🙃 sorry I totally botched this PR, my intention was to preserve progressive disclosure here not break it! I just pushed a new change to address this - now instead of inlining supporting files on load, each supporting file is now individually addressable via load(): Loading the base skill still just loads My intention here was to make skill supplemental files reachable for geese without filesystem access, but not break skill progressive disclosure! What do y'all think |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d784c78378
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
6ff5592 to
8afe5cd
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8afe5cd747
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec87472f52
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Supporting files were only listed as paths with "use file tools to read these" — but environments without the developer extension (e.g. slackbots) have no file-reading tools, making reference files unreachable. Now .md/.mdx supporting files are read and included inline alongside the SKILL.md content, consistent with how SKILL.md itself is already read and included. Non-markdown files continue to be listed as paths.
… auto-inlining The previous approach read all markdown supporting files into context on every load(source: "skill-name") call, breaking progressive disclosure — a core skill design tenet. Skills like oncall-buddy-help with large reference directories would blow out context on every load. The real problem: environments without filesystem access (Slackbot) couldn't reach supporting files at all since they had no tools to read them directly. The fix is to make each supporting file individually loadable via load(source: "skill-name/relative/path") rather than dumping everything upfront. load(source: "skill-name") now lists supporting files with their load() names so the LLM knows how to progressively pull in what it needs. Includes symlink safety check (canonicalize + starts_with) to prevent path traversal via malicious skill directories.
…file resolution On Windows, Path::to_string_lossy() uses backslash separators but load() paths use forward slashes. Normalize discovered file paths to use forward slashes before comparison and in user-facing output so load(source: "skill/references/ops.md") matches consistently.
When a matched supporting file can't be read (permissions, non-UTF8), resolve_source now returns an error describing the actual failure instead of returning None which surfaced as a misleading "not found" message. Changed the return type to Result<Option<Source>, String> to distinguish "not found" from "found but failed to read".
baa58a7 to
e060917
Compare
Fixes TOCTOU race in path traversal check by reading from the
canonicalized path instead of the original, eliminating the window
for symlink swaps between check and read. Also distinguishes
canonicalize failures ("file not found") from traversal violations
("resolves outside skill directory") in error messages.
Adds kind filter to error path so a recipe sharing a skill's name
doesn't produce "Skill 'x' has no supporting files". Blocks
delegate() on supporting file paths since raw file content shouldn't
be used as recipe instructions. Validates skill names don't contain
'/' during parsing to prevent ambiguous resolution. Normalizes
user-supplied relative paths for Windows compatibility. Caps the
available-files error list at 10 entries.
Adds security tests for symlink traversal (#[cfg(unix)]), path
traversal input, and slash-in-name rejection.
0a84c0b to
7f9ef5b
Compare
|
/goose |
|
Summary: This PR enables individual loading of skill supporting files via 🟡 Warnings
🟢 Suggestions
✅ Highlights
Review generated by goose |
* main: (45 commits)
fix: resolve {{ recipe_dir }} in nested sub-recipe paths during secret discovery (#7797)
Add @DOsinga as CODEOWNER for documentation (#7799)
feat: Add summarize tool for deterministic reads (#7054)
fix(api): use camelCase in CallToolResponse and add type discriminators to ContentBlock (#7487)
feat: ACP providers for claude code and codex (#6605)
chore(deps): bump express-rate-limit from 8.2.1 to 8.3.0 in /evals/open-model-gym/mcp-harness (#7703)
feat(openai): capture reasoning summaries from responses API (#7375)
Fix some dependencies (#7794)
fix: improve keyring availability error detection (#7766)
feat: add MiniMax provider with Anthropic-compatible API (#7640)
feat: add Tensorix as a declarative provider (#7712)
fix(security): remove insecure default secret from GOOSE_EXTERNAL_BACKEND (#7783)
refactor: Convert Tanzu provider to declarative JSON config (#7124)
replaces https://github.com/block/goose/pull/7340/changes (#7786)
feat(summon): make skill supporting files individually loadable via load() (#7583)
Keep toast open on failed extension (#7771)
fix(ui-desktop): unify path resolution around GOOSE_PATH_ROOT (#7335)
fix: pass OAuth scopes to DCR and extract granted_scopes from token response (#7571)
fix: write to real file if config.yaml is symlink (#7669)
fix: preserve pairings when stopping gateway (#7733)
...
* main: (69 commits)
fix: resolve {{ recipe_dir }} in nested sub-recipe paths during secret discovery (#7797)
Add @DOsinga as CODEOWNER for documentation (#7799)
feat: Add summarize tool for deterministic reads (#7054)
fix(api): use camelCase in CallToolResponse and add type discriminators to ContentBlock (#7487)
feat: ACP providers for claude code and codex (#6605)
chore(deps): bump express-rate-limit from 8.2.1 to 8.3.0 in /evals/open-model-gym/mcp-harness (#7703)
feat(openai): capture reasoning summaries from responses API (#7375)
Fix some dependencies (#7794)
fix: improve keyring availability error detection (#7766)
feat: add MiniMax provider with Anthropic-compatible API (#7640)
feat: add Tensorix as a declarative provider (#7712)
fix(security): remove insecure default secret from GOOSE_EXTERNAL_BACKEND (#7783)
refactor: Convert Tanzu provider to declarative JSON config (#7124)
replaces https://github.com/block/goose/pull/7340/changes (#7786)
feat(summon): make skill supporting files individually loadable via load() (#7583)
Keep toast open on failed extension (#7771)
fix(ui-desktop): unify path resolution around GOOSE_PATH_ROOT (#7335)
fix: pass OAuth scopes to DCR and extract granted_scopes from token response (#7571)
fix: write to real file if config.yaml is symlink (#7669)
fix: preserve pairings when stopping gateway (#7733)
...
Summary
load(source: "skill-name/relative/path")— e.g.load(source: "oncall-buddy-help/references/technical-ops.md")load(source: "skill-name")) now lists available supporting files with theirload()names rather than inlining their content.mdfilesProblem
Skill environments without filesystem access (e.g. Block-internal Goose Slackbot deployments) had no way to reach supporting reference files. The previous approach — listing paths with "Use the file tools to read these files" — only worked for environments with the developer extension.
Behavior
Now outputs:
The LLM can then selectively load only the reference it needs, preserving progressive disclosure while remaining fully functional in filesystem-restricted environments.