Skip to content

fix(server): Cursor V2 threads load project skills and rules - #13499

Merged
juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/cursor-setting-sources
Sep 24, 2026
Merged

juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/cursor-setting-sources

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Cursor V2 threads ignored the project's AGENTS.md, .cursor/rules, and skills. makeCursorAgentOptions never set local.settingSources, and @cursor/sdk 1.0.31 loads no settings layer from disk when that field is missing. The SDK's parser maps undefined to every layer off, and the docs say "Without local.settingSources, only inline servers are loaded." So T3's $skill → /skill rewrite reached an agent that had no skill catalog. The model sometimes found SKILL.md anyway by grepping the workspace.

What changed

makeCursorAgentOptions now passes settingSources: ["project", "user", "team", "mdm", "plugins"] on every create and resume. The recorded agent.open frames in the 10 Cursor transcripts gain that one field, because replay matches outbound frames exactly. Nothing else in the transcripts changed.

Why these sources

  • These are every layer the Cursor CLI loads. The CLI (2026.06.02 build, inspected on macOS) always loads enterprise /etc/cursor/hooks.json (MDM), team hooks and managed skills, user ~/.cursor, and project .cursor. T3's design intent is to honor the user's provider customizations. The Claude V2 adapter already does this by leaving the Claude SDK on its "load everything" default.
  • Listed explicitly rather than "all". In 1.0.31, "all" expands to exactly these five, but an explicit list means a new SDK layer won't be picked up silently.
  • team and mdm are org-admin layers. Their policy should apply to the user's agents. Without a team account or /etc/cursor/hooks.json they are no-ops. One visible side effect: when authenticated, the team layer syncs Cursor's built-in managed skills into ~/.cursor/skills-cursor, as the CLI does.
  • CursorTextGeneration keeps settingSources: [] for isolated commit-message and title generation. It is untouched.

Effect on T3's sandbox and approval policy

  • No layer here loosens what T3 sets. sandboxOptions.enabled and autoReview still come from the runtime policy.
  • sandbox.json is independent of this change. The SDK reads ~/.cursor/sandbox.json whenever an API key is present, and reads the per-repo .cursor/sandbox.json inside its permissions service. settingSources gates neither (CursorTextGeneration already relies on this). A per-repo sandbox.json can add writable paths, but it could do that before this change too.
  • Hooks can only block. The newly loaded hooks (.cursor/hooks.json, ~/.cursor/hooks.json, plus Claude-format hooks in .claude/settings*.json and ~/.claude/settings.json) can deny tool calls or ask for approval. Local SDK runs have no interactive approval, so "ask" becomes a deny. They cannot auto-approve anything.
  • Behavior to be aware of: project MCP servers load without approval. Project and user .cursor/mcp.json servers now start, and the SDK passes ignoreApprovals: true, so it skips Cursor's per-server approval. This matches how Claude threads load project config.
  • Behavior to be aware of: hooks can run commands. Project and user hooks run their commands like any other T3-launched agent tool. The SDK has no workspace-trust gate.

Verification

  • Live repro, before and after. Setup: @cursor/sdk 1.0.31, composer-2.5, a temp workspace with an AGENTS.md requiring the line PROJECT-RULE-MARKER-4417 and a skill at .cursor/skills/zebra-audit/SKILL.md. Prompt: "Without using any tools: list the names of the agent skills available to you that are defined in this project (or say NONE), then answer: what is 2+2?"
    • settingSources omitted (before): NONE … nothing in the context I was given lists project-defined agent skills … 2 + 2 = 4. No marker line.
    • ["project","user","team","mdm","plugins"] (after): - zebra-audit … 2+2 = 4 … PROJECT-RULE-MARKER-4417
    • With /zebra-audit as the prompt and no sources, the model still answered correctly, but only after grep/read AGENTS.md/glob **/*/read SKILL.md to find it. With sources it read the skill directly.
    • ["project"] alone also fixes the project case. Adding user + plugins surfaces ~/.agents/~/.claude user skills and account plugins. Create-to-finish time was about the same with or without team/mdm (7–11s per run).
  • cd apps/server && vp test run src/orchestration-v2/Adapters/CursorAdapterV2.test.ts: 12 passed, including the new option test.
  • cd apps/server && vp test run src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts -t cursor: 9 Cursor fixtures passed.
  • cd apps/server && vp test run src/orchestration-v2/testkit/OrchestratorReplayRecovery.integration.test.ts src/orchestration-v2/Adapters/CursorAdapterV2.testkit.test.ts src/orchestration-v2/Adapters/CursorAgentSdk.test.ts: 9 passed. This covers the provider_thread_resume resume frame.
  • cd apps/server && vp exec tsc --noEmit -p .: no errors. vp lint on the two touched .ts files: only a pre-existing unused-layer warning.
  • Not run: repo-wide checks, and no fixture re-recording. The transcript edit only adds the logged field.

Overlap

#13493 (v2/cursor-rerecord) re-records the same Cursor transcripts and adds a skill_invocation fixture that was recorded without settingSources. Whichever PR merges second needs its agent.open frames carrying "settingSources":["project","user","team","mdm","plugins"], most simply by re-recording after this change. That branch's skill_invocation recording currently shows the model finding SKILL.md by exploring the workspace, not through native skill loading.

Model: Claude Opus 5.5 (Claude Code)

🤖 Generated with Claude Code


Devin Review

@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 Sep 24, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This changes the default configuration for all Cursor V2 threads and resumes to load project, user, team, MDM, and plugin settings, including hooks and file-based MCP servers. The resulting production behavior and external configuration side effects warrant human review.

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

@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire — 4.9 KiB — 6.8 KiB ✅
Codex Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Codex Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Codex Live turn WebSocket decoded — 20.4 KiB — 29.3 KiB ✅
Codex Live turn messages — 2 — 8 ✅
Claude Total thread wire — 4.9 KiB — 6.8 KiB ✅
Claude Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Claude Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Claude Live turn WebSocket decoded — 20.8 KiB — 29.3 KiB ✅
Claude Live turn messages — 2 — 8 ✅

Baseline: unavailable · PR result: 1237269 · Source CI: failure

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: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

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

@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch from 9fc8676 to ae065ff Compare September 24, 2026 21:34
The Cursor SDK loads no on-disk settings layer unless local.settingSources
names it, so V2 Cursor threads ignored AGENTS.md, .cursor/rules, project and
user skills, hooks, and file-based MCP config. Pass every layer the Cursor
CLI loads (project, user, team, mdm, plugins) and update the recorded
agent.open frames that replay matches exactly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@juliusmarminge
juliusmarminge force-pushed the v2/cursor-setting-sources branch from 9bf862b to 1237269 Compare September 24, 2026 21:39
@juliusmarminge
juliusmarminge merged commit 8d7d885 into t3code/codex-turn-mapping Sep 24, 2026
22 of 24 checks passed
@juliusmarminge
juliusmarminge deleted the v2/cursor-setting-sources branch September 24, 2026 21:47
juliusmarminge added a commit that referenced this pull request Sep 24, 2026
…loaded

The first recording predated #13499, so the SDK loaded no project skills
and the model found SKILL.md by searching the workspace. Recorded again
with settingSources in agent.open (and an empty HOME), the SDK loads the
workspace skill natively and the model reads it straight from the `/review`
invocation before answering.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 24, 2026
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 25, 2026
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

1 participant