镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix(cursor): user-invoked skills hidden from the model reach the Cursor prompt - #34999

Open
juliusmarminge wants to merge 2 commits into
mainfrom
factory/issue-15606-a1794473343
Open

juliusmarminge wants to merge 2 commits into
mainfrom
factory/issue-15606-a1794473343

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Cursor leaves disable-model-invocation skills out of the model's skill catalog, and @cursor/sdk agent.send takes only a string, so the adapter's $name -> /name rewrite alone never loaded these skills (the model either could not find them or picked a similarly named one). resolveCursorSkillText in packages/provider-cursor/src/server/adapter.ts now keeps the discovered skills by name. It still rewrites $name mentions to /name, then finds every /name token (typed or rewritten). For each one that names a discovered, user-invocable skill with userInvocationOnly, it reads that SKILL.md and appends its body, with the frontmatter removed, to the prompt in a <skill name=...> block under a one-line 'The user invoked these skills' header (appendCursorInvokedSkills / cursorSlashSkillNames in skills.ts). Discovery now also runs when the message has only a typed /name. Skills the model can already see are unchanged: no file is read and the text is the same as before. Because this runs before the orchestration-instructions wrapper and in steerTurn, the skill reaches the model on the first turn and in steers. If a file is missing or unreadable, that skill is skipped without an error. New regex /(?:^|\s)\/([a-zA-Z0-9][a-zA-Z0-9:_-]*)(?=\s|$)/gu: it has a single bounded character-class run anchored to a / after start or whitespace, with no nested or alternating quantifiers. Worst case is linear in the prompt length (each start position scans one token at most once). A path like /usr/bin does not match because the lookahead needs whitespace or the end of the text after the name. No user-visible UI change.

Fixes #15606

Reproduction on main

Commit b68aedf (origin/main). Started T3CODE_DEV_SEED=0 vp run dev in a fresh worktree, paired a browser, added Cursor under Settings > Providers (authenticated via CURSOR_API_KEY), and added a scratch git project with two project skills: .cursor/skills/zebra-only (frontmatter disable-model-invocation: true, body: reply PURPLE-OKAPI-7731) and .cursor/skills/zebra-open (no flag, body: reply GREEN-TAPIR-4410). In a new Cursor thread (Composer 2.5) the $ picker listed both skills. Turn 1: picked $zebra-only from the picker and sent it. The provider event log shows the SDK received /zebra-only ... inside <t3_code_orchestration_instructions>...<user_request>, then the agent read .cursor/skills/zebra-open/SKILL.md and replied GREEN-TAPIR-4410, which is the wrong skill. Turn 2: typed /zebra-only ... by hand. The SDK received a bare /zebra-only ... at the start of the prompt, and the agent again replied GREEN-TAPIR-4410. The user-invocation-only skill's SKILL.md never reached the model either way. A unit test extending the existing Cursor steer case fails on main with expected '/grill-me My plan.' to include 'Ask one question at a time.'.

Evidence

Select $zebra-only from the skill picker and send it with “Reply with the skill’s exact response.” Then send /zebra-only Reply with the skill’s exact response. in the same thread. The requested skill has disable-model-invocation: true; its expected reply is PURPLE-OKAPI-7731. A similarly named open skill replies GREEN-TAPIR-4410.

Real web app, Chromium, light theme, 1280×800 CSS viewport; separate fresh databases and identical synthetic projects; real Cursor SDK on both commits.

Before After
b68aedfdb7 329988da19
Before: both invocations return GREEN-TAPIR-4410 After: both invocations return PURPLE-OKAPI-7731
Before recording After recording

Fixture script · Reproduction and capture notes

Recordings are 2× speed. Only the model-selector label was privacy-masked. AI-assisted; verified with the tests and tools listed above.

Not shown:

  • Mid-turn steering was not exercised; this proof covers the reported picker invocation and hand-typed slash invocation.

Tests

vp test run src/server/adapter.test.ts src/server/skills.test.ts (packages/provider-cursor): 31 passed. Same adapter test with the fix stashed: fails with expected '/grill-me My plan.' to include 'Ask one question at a time.'. vp run check:changed: format, lint, knip, typecheck (10 packages), tests (3 files, 33 tests) all pass.

Not in this change

  • No end-to-end Cursor SDK run was done; verification is the adapter unit test that drives the real prompt construction.
  • Model-invocable skills still rely on Cursor resolving /name on its own; on the first turn that /name stays inside the orchestration-instructions wrapper, which the report says may also hurt how reliably Cursor matches it.

AI-assisted; verified with the tests and tools listed above.

…15606)

AI-assisted; verified with the tests and tools listed above.
…or prompt

Cursor leaves disable-model-invocation skills out of the model's catalog, and
the SDK takes only a string, so /name alone never loaded them. The adapter now
appends the SKILL.md body of each invoked user-only skill to the prompt.

Fixes #15606

AI-assisted; verified with the tests and tools listed above.
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 12, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 329988d

Macroscope's review found this PR approvable — Explicitly invoked Cursor skills hidden from the model now have their instructions included in turn and steering prompts. Existing invocation filters remain in place, with no changes to runtime permissions or product defaults.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Baseline: b68aedf · PR result: 329988d · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The Cursor adapter now recognizes slash-skill names during prompt and steer resolution. When an invoked skill is user-invocation-only, the adapter appends its contents to the prompt. New tests cover this behavior.

Changes: Cursor skill invocation

Layer / File(s) Summary
Slash-skill parsing and prompt expansion
packages/provider-cursor/src/server/skills.ts
Adds slash-skill name parsing and a helper that strips skill frontmatter and appends skill contents in named <skill> blocks.
Adapter resolution and test coverage
packages/provider-cursor/src/server/adapter.ts, packages/provider-cursor/src/server/adapter.test.ts
The adapter discovers skills for mentions or slash names, retains enabled user-invocable skills, and appends contents for invoked skills marked userInvocationOnly. The test steers with $grill-me and checks that the skill instructions appear in the prompt.

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related PRs

  • pingdotgg/t3code#28980: Changes the Cursor adapter’s skill resolution for initial messages and steering, which this PR extends for slash-skill invocation.

Suggested reviewers: maria-rcks, yash-singh1, macroscopeapp

Merge Risk: Minimal · up to 32998

Explicitly invoked hidden Cursor skills now have their instructions added to the prompt, including in steer turns. No concrete merge-blocking defect was established. One unconfirmed point: a hidden skill that refers to sibling files by relative path may not be able to find them, since the skill's location is not included in the prompt.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title names the main change: user-invoked skills that the model cannot see (disable-model-invocation) are now added to the Cursor prompt. It follows the conventional commit format and is specific …
Linked Issues check Passed [#15606] requires that a Cursor skill with disable-model-invocation: true, invoked as /skill or $skill, has its SKILL.md loaded into the turn. The diff meets this. In adapter.ts, `resolveCurso…
Out of Scope Changes check Passed All changed code maps to the #15606 objective. skills.ts adds cursorSlashSkillNames (the slash-name regex) and appendCursorInvokedSkills (the skill block). adapter.ts changes discovery trigger…
Description check Passed The description follows the repository template closely. It has a clear Problem (Cursor skills with disable-model-invocation are not loaded when invoked via $name or /name, and the SDK takes only a st…
Full details: Title check

Explanation

The title names the main change: user-invoked skills that the model cannot see (disable-model-invocation) are now added to the Cursor prompt. It follows the conventional commit format and is specific to the Cursor provider. The 78-character length is acceptable.

Full details: Linked Issues check

Explanation

[#15606] requires that a Cursor skill with disable-model-invocation: true, invoked as /skill or $skill, has its SKILL.md loaded into the turn. The diff meets this. In adapter.ts, resolveCursorSkillText runs discovery when the text has a skill mention or a slash name. It rewrites $name to /name, finds each /name token, and for each discovered enabled, user-invocable skill with userInvocationOnly === true it reads skill.path. It then appends the contents through appendCursorInvokedSkills in skills.ts, which strips frontmatter and wraps the body in a &lt;skill name=...&gt; block. Missing or unreadable files are skipped (Effect.orElseSucceed). Skills the model already sees are not read, so their text is unchanged. The #15606 report says the ~/.agents/skills skills appear in the discovery output, so the user-level path uses existing discovery. Remaining uncertainty: the PR reports tests for project skills only, and no end-to-end Cursor SDK run was done. The unit-test coverage supports the verdict for the prompt construction path.

Full details: Out of Scope Changes check

Explanation

All changed code maps to the #15606 objective. skills.ts adds cursorSlashSkillNames (the slash-name regex) and appendCursorInvokedSkills (the skill block). adapter.ts changes discovery triggering and skill resolution. The adapter.test.ts change adds a disable-model-invocation skill steer case, which tests this objective. The change to the declined-steer assertion only narrows the check to the latest steer text, and it supports the same test. No unrelated module, UI, or configuration change appears in the reviewed diff.

Full details: Description check

Explanation

The description follows the repository template closely. It has a clear Problem (Cursor skills with disable-model-invocation are not loaded when invoked via $name or /name, and the SDK takes only a string), a Change section that explains resolveCursorSkillText, the new helper functions, the regex, and the fact that skills the model can already see are unchanged, and a Scope section that links the bug (#15606). Verification is detailed: a before/after reproduction on main, screenshots and recordings, the specific test commands with results, and a stated failure on the unfixed code. It also states what was not checked: no end-to-end Cursor SDK run and no mid-turn steering. The model and harness are named in the AI-assisted note, which satisfies the agent attribution line. Minor gaps: the Scope section does not say whether a maintainer requested the PR, and the description has a 'Not in this change' section that is not in the template. Those gaps are not critical.

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between b68aedf and 329988d.

Files selected for processing: 3

  • packages/provider-cursor/src/server/adapter.test.ts
  • packages/provider-cursor/src/server/adapter.ts
  • packages/provider-cursor/src/server/skills.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cursor provider: /skill and $skill can't invoke skills with disable-model-invocation: true (agent SDK)

1 participant