Cursor SDK local runtime does not appear to load filesystem skills

Where does the bug appear (feature/product)?

Somewhere else…

Describe the Bug

When using @cursor/sdk with the local runtime, project skills defined under .cursor/skills/…/SKILL.md do not appear to be loaded, even when local.settingSources includes “project”.

The same project skill is visible to the Cursor IDE session, but an SDK local agent created with Agent.prompt() does not follow it. The SDK run behaves as if the skill does not exist.

Steps to Reproduce

Create a minimal project with this skill file:

---
name: canary
description: If this skill is loaded, respond with CANARY-SEEN.
---

# Canary

When asked whether canary is available, respond exactly:

CANARY-SEEN

Do not add any other text.

Create this SDK script:

import { Agent } from '@cursor/sdk'

const cwd = process.cwd()
const prompt = 'Do you have the canary skill? Do not search the filesystem.'

if (!process.env.CURSOR_API_KEY) {
  throw new Error('CURSOR_API_KEY is required')
}

console.log('[repro] cwd:', cwd)

const result = await Agent.prompt(prompt, {
  apiKey: process.env.CURSOR_API_KEY,
  model: { id: 'composer-2' },
  local: {
    cwd,
    settingSources: ['project'],
  },
})

console.log('[result]', JSON.stringify(result, null, 2))

Run:

npm install @cursor/sdk
CURSOR_API_KEY=... node cursor-sdk-skill-repro.mjs

Expected Behavior

The SDK local agent should load .cursor/skills/canary/SKILL.md and respond:

CANARY-SEEN

The prompt explicitly says not to search the filesystem, so this should only happen if the skill was loaded into the agent context.

Actual Behavior

The SDK local agent does not see the project skill. It responds that no canary skill is loaded/active.
Actual output from the repro:

{
  "id": "run-e15ac563-6938-4c33-adfc-e222af41f75a",
  "status": "finished",
  "result": "I’m **not** searching your filesystem here.\n\nFrom what’s visible **in this chat’s instructions and context**, there is **no “canary” skill** loaded or referenced, so **I don’t have it active for this session**. If it exists in your Cursor setup, it would need to be attached or surfaced by your project/settings for me to behave under it automatically.",
  "model": {
    "id": "composer-2"
  },
  "durationMs": 13309
}

Operating System

MacOS

Version Information

SDK version: @cursor/[email protected]

For AI issues: which model did you use?

composer-2

For AI issues: add Request ID with privacy disabled

SDK run id: run-e15ac563-6938-4c33-adfc-e222af41f75a

I do not see a separate request id in the SDK output.

Additional Information

I could not find explicit documentation saying that the Cursor SDK local runtime supports project skills from .cursor/skills.
The typescript sdk docs mention local.settingSources and say "project" loads project settings from .cursor/. They also document several project-level filesystem features such as MCP config, hooks, and subagents. However, I did not find a clear statement about whether project skills are expected to be loaded by SDK local agents.
So this report may be either:

  1. a bug: SDK local runtime should load .cursor/skills, but currently does not; or
  2. a documentation gap: project skills are intentionally unsupported in SDK local runtime, but this limitation is not documented clearly.

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

One more data point: the same `.cursor/skills/canary/SKILL.md` works correctly when using Cursor CLI from the same project directory.

Could someone from the Cursor team take a look when possible? I would really appreciate any guidance on whether this is expected behavior or a bug in the SDK local runtime.

Hi @_1161118 Thanks for the report and sorry for the delay in getting back to you. I spent some time this morning reproducing the bug and I have a grasp on exactly the issue you’re facing. Thank you for your detailed reproduction steps. I can reproduce your “skill not seen” symptom, and it comes down to how the SDK local runtime scopes skill discovery.

It resolves the real (canonical) path of both your workspace root and each SKILL.md, then drops any skill that resolves outside the root. So if your .cursor/skills dir, the SKILL.md, or a parent directory is a symlink pointing outside the workspace, the skill lands “outside” and gets silently filtered out. A plain, non-symlinked .cursor/skills/<name>/SKILL.md under the root loads fine with settingSources: ['project'] — I confirmed both the working and the failing (symlinked) cases.

This is a real bug on our side, specific to the SDK local runtime (the IDE loader already follows symlinks; that handling didn’t carry over). We’re tracking it internally, and I’ll let you know when it’s fully sorted out.

the Workaround: use real skill files under the workspace root, not symlinks. If you keep a shared library, copy it in instead of symlinking (cp -RL dereferences symlinks into real files). Passing a subdirectory as cwd is fine on its own and doesn’t drop skills.

Thanks for looking into this. Just to clarify a few things from my side:

  1. The original repro I posted was not using symlinks. The skill file was a regular .cursor/skills/canary/SKILL.md file under the workspace root.
  2. At the time I filed the report, that repro was consistently failing: the SDK local runtime did not see the canary skill, while Cursor CLI did.
  3. I reran the same repro today, still with @cursor/[email protected], and it now works: the SDK local runtime loads the canary skill correctly.

So the symlink issue you described sounds like a real SDK local runtime bug, but it does not seem to be the same issue I originally hit. It looks like the non-symlink project skill loading behavior may have changed since I filed the report…
Nevertheless, I’m happy that the original repro works now. Thanks for taking the time to investigate and for the detailed follow-up.

Awesome, thanks for following up! Glad it’s working now