Skills preloading keeps 17+ file descriptors open unnecessarily

Resolved 💬 4 comments Opened Feb 6, 2026 by santifer Closed Mar 6, 2026

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:

  1. Index all skills during startup (reasonable for autocomplete)
  2. Keep SKILL.md files open instead of reading + caching + closing (unnecessary)
  3. Never close the file descriptors during the session

Expected Behavior

Skills indexing should:

  1. Read all SKILL.md files during startup
  2. Cache metadata in memory (name, description, content)
  3. Close file descriptors after reading
  4. 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

  1. Create 15+ skills in .claude/skills/
  2. Start claude CLI
  3. Check open file descriptors:

``bash
lsof -p $(pgrep claude) | grep "SKILL.md"
``

  1. Observe all SKILL.md files are open
  2. 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.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗