When starting a new conversation or using Composer, Cursor automatically scans and loads an excessive number of “Skills” from the ~/.claude/skills/ directory. Even though it only reads the frontmatter rather than the full file content, the sheer volume of loaded skills consumes a significant amount of the initial context window (tokens).
Specifically, Cursor is recursively scanning hidden directories within the skills folder, loading skills meant for other Agent CLIs (like openclaw) that are not relevant to the current session.
Duplicated SKILLs will also be loaded. E.g. when you install GStack, same SKILLs from ~/.agent/skills and ~/.claude/skills will be loaded
Steps to Reproduce
Have a directory structure in ~/.claude/skills/ that contains many subdirectories or hidden folders (e.g., .hermes/ or .opencode/).
Start a new chat or Composer session in Cursor.
Observe the initial token count or check the context being sent to the model.
Notice that skills from paths like ~/.claude/skills/gstack/.hermes/skills/…/SKILL.md are being included.
Expected Behavior
Ignore hidden directories (starting with .) within the skills folder.
Hey, thanks for the detailed report and the screenshot. Confirmed: the recursive skills scanner doesn’t filter hidden directories inside ~/.claude/skills/, so anything in .hermes/, .opencode/, .gstack/, and similar subfolders from other agent CLIs gets pulled into context. I’ve reported this internally.
On dedup: normalization works for ~/.claude/skills vs ~/.cursor/skills, but GStack stores skills in ~/.agent/skills (no s at the end), and we only detect ~/.agents/skills. That’s why duplicates don’t collapse in your case. Flagged this too.
No fix yet. Workaround: turn off Include third-party Plugins, Skills, and other configs in Settings → Rules, Skills, Subagents. This will stop loading from the .claude/, .codex/, .agents/ roots entirely, including skills you might want, so if you need them you can temporarily copy specific folders into ~/.cursor/skills/.
thanks. is there a way to set this for cursor-agent as well? your response seems to be for the cursor gui and im not sure if that translates over to what cursor-agent pulls in.
I have a similar issue but more focused on ~/.cursor/skills-cursor/.
For me it’s not really about context size — it’s that agents spread their focus onto irrelevant built-ins like create-skill or create-rule even when the task has nothing to do with that. These are clearly commands, not auto-invocable workflows. I manually moved them to ~/.cursor/commands/ and that did the trick — but every Cursor update re-downloads anything missing from skills-cursor/, so the fix doesn’t survive. I’ve ended up writing a small script that purges the folder and marks it immutable with chflags uchg after each update.
What I’d love is a first-class option to disable built-ins — skills, subagents, commands, and (if you’re generous) tools. I’ve been using Cursor as my main tool for a while and have a clear sense of how I want the agents’ environment shaped; let me shape it.
@jubi - right now the toggle Include third-party Plugins, Skills, and other configs is an IDE-only setting. In ~/.cursor/cli-config.json docs Configuration | Cursor Docs there is no equivalent flag documented, it only has editor and permissions. Also, the cursor-agent CLI handles skills differently in general. There are a few parity gap reports, for example this one Cursor-agent CLI does not register skills from plugins (IDE does — parity gap) and this one Cursor CLI does not load ./claude/skills, so skills behavior in CLI vs IDE is not symmetric right now. I marked it internally as a gap. When we fix hidden-dirs filtering, we’ll also take a look at the CLI side.
@Demianight - this looks similar by symptoms, but it’s a different case overall. Built-in skills from ~/.cursor/skills-cursor/ are currently seeded automatically and re-populated on update, and that’s by design at this stage. What you want is a first-class option to disable built-ins skills/subagents/commands. That’s a reasonable feature request, but it’s broader than the hidden directories bug from the original thread. Can you open a separate thread for it? That’ll make it easier to track and prioritize separately, without mixing it with the fix for scanning .claude/skills. The chflags uchg workaround is valid for now, even if it’s a bit fragile.
Composer 2.5 gave me the cursor-agent wrapper script below. I confirmed that it works on Linux. @Demianight, it also filters out Cursor’s built-ins by default.
#!/usr/bin/env bash
# cursor-agent-skill-filter — run cursor-agent with third-party skills hidden
#
# Problem: cursor-agent auto-discovers skills from many compatibility roots
# (~/.claude/skills, ~/.codex/skills, ~/.claude/plugins, ~/.cursor/plugins,
# ~/.cursor/skills-cursor, ~/.agents/skills, plus project .claude/.codex trees).
# The IDE toggle "Include third-party Plugins, Skills, and other configs" does
# NOT apply to the CLI — there is no cli-config.json equivalent.
#
# Solution: re-exec inside a private mount namespace (unshare) and bind-mount an
# empty directory over those paths. Only user/project Cursor skills remain
# visible (~/.cursor/skills/, .cursor/skills/). skills-cursor is mounted
# read-only so Cursor's managed-skills sync cannot repopulate it at runtime.
# Claude Code / Codex sessions in other terminals are unaffected.
#
# Usage:
# cursor-agent-skill-filter [cursor-agent args...]
# cursor-agent-skill-filter --cursor-skills # also show ~/.cursor/skills-cursor/
# cursor-agent-skill-filter --all-skills # no filtering (plain cursor-agent)
#
# Environment:
# CURSOR_AGENT_ALL_SKILLS=1 same as --all-skills
# CURSOR_AGENT_CURSOR_SKILLS=1 same as --cursor-skills
# CURSOR_AGENT_SKILL_FILTER_DEBUG=1 print mount diagnostics to stderr
#
# Requirements: Linux, util-linux (unshare), user namespaces enabled
#
set -uo pipefail
all_skills=0
cursor_skills=0
passthrough=()
while [[ $# -gt 0 ]]; do
case "$1" in
--all-skills) all_skills=1; shift ;;
--cursor-skills) cursor_skills=1; shift ;;
*) passthrough+=("$1"); shift ;;
esac
done
[[ "${CURSOR_AGENT_ALL_SKILLS:-}" == 1 ]] && all_skills=1
[[ "${CURSOR_AGENT_CURSOR_SKILLS:-}" == 1 ]] && cursor_skills=1
_ALL_HIDE_TARGETS=(
"$HOME/.claude/skills"
"$HOME/.codex/skills"
"$HOME/.cursor/skills-cursor"
"$HOME/.claude/plugins"
"$HOME/.cursor/plugins"
"$HOME/.agents/skills"
)
_debug() {
[[ "${CURSOR_AGENT_SKILL_FILTER_DEBUG:-}" == 1 ]] || return 0
echo "cursor-agent-skill-filter: $*" >&2
}
_cleanup_stale_mounts() {
local target
for target in "${_ALL_HIDE_TARGETS[@]}"; do
while mountpoint -q "$target" 2>/dev/null; do
_debug "cleaning stale mount on $target"
umount "$target" 2>/dev/null || break
done
done
}
_skill_targets() {
local targets=(
"$HOME/.claude/skills"
"$HOME/.codex/skills"
"$HOME/.claude/plugins"
"$HOME/.cursor/plugins"
"$HOME/.agents/skills"
)
if [[ "$cursor_skills" -eq 0 ]]; then
targets+=("$HOME/.cursor/skills-cursor")
fi
printf '%s\n' "${targets[@]}"
}
_empty_dir=""
_mounts=()
_teardown() {
local target
for target in "${_mounts[@]}"; do
umount "$target" 2>/dev/null || true
done
if [[ -n "$_empty_dir" ]]; then
rmdir "$_empty_dir" 2>/dev/null || true
fi
}
_setup() {
_empty_dir="$(mktemp -d)"
local target
while IFS= read -r target; do
[[ -n "$target" ]] || continue
mkdir -p "$target"
if mount --bind "$_empty_dir" "$target"; then
_mounts+=("$target")
if [[ "$target" == "$HOME/.cursor/skills-cursor" ]]; then
mount -o remount,bind,ro "$target" 2>/dev/null \
&& _debug "hid (ro) $target" \
|| _debug "hid $target (ro remount failed)"
else
_debug "hid $target"
fi
else
echo "cursor-agent-skill-filter: warning: failed to hide $target" >&2
fi
done < <(_skill_targets)
}
if [[ "$all_skills" -eq 0 && "${CURSOR_AGENT_UNSHARED:-}" != 1 ]]; then
_cleanup_stale_mounts
reexec_args=()
[[ "$cursor_skills" -eq 1 ]] && reexec_args+=(--cursor-skills)
reexec_args+=("${passthrough[@]}")
exec unshare --user --mount --map-root-user -- \
env CURSOR_AGENT_UNSHARED=1 "$0" "${reexec_args[@]}"
fi
if [[ "$all_skills" -eq 0 ]]; then
trap _teardown EXIT INT TERM
_setup
_debug "skill isolation active (cursor_skills=$cursor_skills)"
fi
exec cursor-agent "${passthrough[@]}"
Hey, thanks for sharing this, @zar42stra. Nice approach. Using a user namespace for isolation plus a bind-mount over the skill routes looks like a workable solution for users on the cursor-agent CLI who need to filter out third-party skills while there’s no native toggle there yet.
A couple of caveats for anyone trying it. This is Linux-only. You’ll need util-linux for unshare. And if you want to run it without sudo, you’ll need unprivileged user namespaces enabled. On some distros, like Debian, they’re disabled by default. Also, this is an unofficial workaround, so please test it in your own environment before relying on it for work.
On the hidden directories bug, status is unchanged. The issue is being tracked, there’s no fix yet, and I can’t share an ETA. I’ll post here as soon as there’s an update.
Hey @azhang, quick update: the fix for excessive skill loading from hidden directories inside ~/.claude/skills/ and for duplicate skill loading landed in Cursor 3.17. Please update to 3.17 or newer and give it another try.
If anything from hidden folders still ends up in the initial context, or duplicates don’t collapse, for example your GStack ~/.agent/skills vs ~/.claude/skills case, drop a screenshot of the context and we’ll take another look.