Skills preloading keeps 17+ file descriptors open unnecessarily
Environment
- Claude Code version: 2.1.34
- OS: macOS Darwin 24.6.0 (Apple Silicon)
- Number of skills: 17 (216KB total)
- Process uptime: 25 minutes
- Memory usage: 310MB
Problem
Claude Code CLI preloads all skills at startup and maintains open file descriptors for every SKILL.md file throughout the session, even when skills are not being used. This is unnecessary and wasttes system resources.
Evidence
File Descriptors Analysis
$ lsof -p 55537 | wc -l
98
The process has 98 open file descriptors, including:
$ lsof -p 55537 2>/dev/null | grep "SKILL.md" | wc -l
17
All 17 skills have their SKILL.md files open simultaneously:
50r REG /Users/santifer/code/project2/.claude/skills/claudable-stack/SKILL.md
52r REG /Users/santifer/code/project2/.claude/skills/clean-image/SKILL.md
54r REG /Users/santifer/code/project2/.claude/skills/ship-it/SKILL.md
56r REG /Users/santifer/code/project2/.claude/skills/design/SKILL.md
... (13 more)
Skills Being Preloaded
brand-ops, career-ops, claudable-design, claudable-stack,
claudable-workflow, clean-image, content, design, diagram-prompt,
linkedin-post, perf-boost, readme-pro, seo-strategist, ship-it,
substack-cover, substack-post, tech-translate
Root Cause
The TUI appears to:
- Index all skills during startup (reasonable for autocomplete)
- Keep SKILL.md files open instead of reading + caching + closing (unnecessary)
- Never close the file descriptors during the session
Expected Behavior
Skills indexing should:
- Read all SKILL.md files during startup
- Cache metadata in memory (name, description, content)
- Close file descriptors after reading
- Optionally: implement lazy loading (load skills on first invocation)
Impact
- Wasted file descriptors: 17 FDs for skill files that are rarely accessed
- Memory overhead: Kernel maintains open file state
- Scalability: Users with 50+ skills (as seen in #22427) would have 50+ FDs open
- Resource exhaustion risk: Systems with ulimit constraints could hit FD limits
Comparison with Related Issue
Issue #22427 reports 23GB memory leak with 1,071 skill files. While that focuses on memory, the root cause may be similar: aggressive preloading/caching without proper resource cleanup.
Proposed Solution
Option A (minimal fix): Read → Cache → Close
// Pseudocode
for (const skill of skills) {
const fd = open(skill.path);
const content = read(fd);
skillCache.set(skill.name, parseSkill(content));
close(fd); // ← Add this
}
Option B (lazy loading): Only load skills when invoked
// Load metadata only (name, description) for autocomplete
// Load full content on first use: /skill-name or Skill(skill="name")
Reproduction
- Create 15+ skills in
.claude/skills/ - Start
claudeCLI - Check open file descriptors:
``bash``
lsof -p $(pgrep claude) | grep "SKILL.md"
- Observe all SKILL.md files are open
- Files remain open throughout session (even when unused)
Related Issues
- #22427 - Memory leak with 1,071 skills (23GB RAM)
- #11045 - Skills context overflow (requests hidden skills feature)
- #21567 - Terminal renderer CPU spin (different but resource-related)
System Details
$ ps -p 55537 -o pid,%cpu,%mem,vsz,rss,etime
PID %CPU %MEM VSZ RSS ELAPSED
55537 28.8 2.0 484534928 310864 00:25:54
---
Note: This issue focuses specifically on file descriptor management. Memory leak investigation would be a separate (but related) issue.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗