fix(skills): unify runtime inclusion and available_skills exposure policy#60852
Conversation
Greptile SummaryThis PR fixes a layering bug where skills passing The legacy fallback in Confidence Score: 5/5Safe to merge — the only findings are P2 style/scaffolding concerns with no runtime impact. All P0/P1 criteria are met: the core behavioral fix is correct and well-tested, legacy compatibility is preserved via the isSkillVisibleInAvailableSkillsPrompt fallback chain, and formatters are now correctly policy-free. The sole P2 note about unused SkillExposure fields does not affect any live code path. src/agents/skills/types.ts and src/agents/skills/workspace.ts — the includeInRuntimeRegistry and userInvocable fields on SkillExposure are set but not read by runtime decision logic. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/skills/workspace.ts
Line: 488-494
Comment:
**`includeInRuntimeRegistry` is set but never read**
`exposure.includeInRuntimeRegistry` is always written as `true` here, but no runtime code reads it to make decisions — `shouldIncludeSkill()` in `config.ts` handles actual runtime gating independently. A future caller setting this to `false` on a manually constructed `SkillEntry` would see no effect. The field name implies it gates runtime registry inclusion, but currently it does not.
Similarly, `exposure.userInvocable` mirrors `invocation.userInvocable`, but `command-specs.ts` (line 85) reads `entry.invocation?.userInvocable`, not `entry.exposure?.userInvocable`. If these two fields ever drift on a manually composed entry, `exposure.userInvocable` would be silently ignored.
Consider either wiring these fields into their respective decision paths or documenting them as reserved/forward-looking scaffolding to prevent misuse.
How can I resolve this? If you propose a fix, please make it concise.Reviews (2): Last reviewed commit: "fix(skills): add changelog entry for pro..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba4872ec7c
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
3b01f98 to
35fcc2e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9420e81933
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@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: d485a43d2c
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@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: 482bfa506b
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
482bfa5 to
80171ae
Compare
|
@greptileai review |
There was a problem hiding this comment.
Pull request overview
This PR fixes a skills pipeline inconsistency by unifying the policy for which runtime-eligible skills are exposed in the session <available_skills> prompt, preventing skills from being usable at runtime but omitted from the prompt due to later-layer filtering.
Changes:
- Introduces
SkillExposureonSkillEntryand uses it to drive<available_skills>visibility decisions upstream. - Removes formatter-layer visibility filtering so prompt formatters render exactly the skills they are given.
- Updates/extends tests to validate aligned runtime inclusion vs prompt exposure behavior (including legacy entries).
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/agents/skills/workspace.ts | Adds exposure-aware prompt visibility filter; ensures compact/full formatters don’t re-filter skills. |
| src/agents/skills/types.ts | Defines SkillExposure and adds optional exposure to SkillEntry. |
| src/agents/skills/skill-contract.ts | Stops filtering out disableModelInvocation skills inside the formatter. |
| src/agents/skills/compact-format.test.ts | Updates formatter expectations and adds exposure-driven visibility test coverage. |
| src/agents/skills.test.ts | Adds regression test ensuring runtime-eligible skills remain visible in <available_skills> even with disable-model-invocation. |
| src/agents/skills.resolveskillspromptforrun.test.ts | Adds legacy behavior test when exposure metadata is absent. |
| src/agents/skills.loadworkspaceskillentries.test.ts | Validates newly loaded entries set exposure to keep prompt visibility aligned with runtime eligibility. |
| CHANGELOG.md | Documents the user-visible behavior change/fix. |
e7e5e2f to
2b48b3a
Compare
|
Merged via squash.
Thanks @KimGLee! |
…licy (openclaw#60852) Merged via squash. Prepared head SHA: 2b48b3a Co-authored-by: KimGLee <[email protected]> Co-authored-by: altaywtf <[email protected]> Reviewed-by: @altaywtf
…licy (openclaw#60852) Merged via squash. Prepared head SHA: 2b48b3a Co-authored-by: KimGLee <[email protected]> Co-authored-by: altaywtf <[email protected]> Reviewed-by: @altaywtf
…licy (openclaw#60852) Merged via squash. Prepared head SHA: 2b48b3a Co-authored-by: KimGLee <[email protected]> Co-authored-by: altaywtf <[email protected]> Reviewed-by: @altaywtf
…licy (openclaw#60852) Merged via squash. Prepared head SHA: 2b48b3a Co-authored-by: KimGLee <[email protected]> Co-authored-by: altaywtf <[email protected]> Reviewed-by: @altaywtf
…licy (openclaw#60852) Merged via squash. Prepared head SHA: 2b48b3a Co-authored-by: KimGLee <[email protected]> Co-authored-by: altaywtf <[email protected]> Reviewed-by: @altaywtf
Summary
Closes #60716.
This fixes a semantic split in the skills pipeline where a skill could remain runtime-eligible/configured but disappear from the session
<available_skills>prompt due to a later formatter-layer filter.Before this change:
shouldIncludeSkill()insrc/agents/skills/config.tsresolveWorkspaceSkillPromptState()insrc/agents/skills/workspace.tsformatSkillsForPrompt()insrc/agents/skills/skill-contract.tsThat layering allowed one concrete inconsistent state:
shouldIncludeSkill(...) === true<available_skills>becausedisable-model-invocationwas applied again later while building/rendering the promptRoot cause
The problem came from prompt visibility being controlled in a different layer than runtime inclusion.
More specifically:
src/agents/skills/config.tsdecided whether a skill was included from the runtime/config/eligibility perspectivesrc/agents/skills/workspace.tsthen removedentry.invocation?.disableModelInvocation === trueentries before prompt generationsrc/agents/skills/skill-contract.tsalso treated formatter input as visibility-policy input instead of pure render inputSo the bug was not just "a bad filter" — it was that business visibility policy was split across multiple layers.
What changed
SkillExposureonSkillEntry