Understanding Claude Skills Discovery in Large Monorepos
When working with Claude Code in a monorepo, understanding how skills are discovered and loaded into context is crucial for organizing your project-specific capabilities effectively.
Important Difference from CLAUDE.md
Skills do NOT have the same loading behavior as CLAUDE.md files. While CLAUDE.md files walk UP the directory tree (ancestor loading), skills use a different discovery mechanism focused on nested directories within your project.
How Skills Are Discovered
Standard Skill Locations
Skills are loaded from these fixed locations based on scope:
| Location | Path | Applies to |
|---|---|---|
| Enterprise | Managed settings | All users in organization |
| Personal | ~/.claude/skills/<skill-name>/SKILL.md | All your projects |
| Project | .claude/skills/<skill-name>/SKILL.md | This project only |
| Plugin | <plugin>/skills/<skill-name>/SKILL.md | Where plugin is enabled |
Automatic Discovery from Nested Directories
When you work with files in subdirectories, Claude Code automatically discovers skills from nested .claude/skills/ directories. For example, if you are editing a file in packages/frontend/, Claude Code also looks for skills in packages/frontend/.claude/skills/.
This supports monorepo setups where packages have their own skills.
Example Monorepo Structure
Consider a typical monorepo with separate packages:
/mymonorepo/
├── .claude/
│ └── skills/
│ └── shared-conventions/SKILL.md # Project-level skill
├── packages/
│ ├── frontend/
│ │ ├── .claude/
│ │ │ └── skills/
│ │ │ └── react-patterns/SKILL.md # Frontend-specific skill
│ │ └── src/
│ │ └── App.tsx
│ ├── backend/
│ │ ├── .claude/
│ │ │ └── skills/
│ │ │ └── api-design/SKILL.md # Backend-specific skill
│ │ └── src/
│ └── shared/
│ ├── .claude/
│ │ └── skills/
│ │ └── utils-patterns/SKILL.md # Shared utilities skill
│ └── src/Scenario 1: Just Started Claude at Root (No Files Edited Yet)
When you run Claude Code from /mymonorepo/ and have not edited any files yet:
cd /mymonorepo
claude
# Just started - no files edited yet| Skill | In Context? | Reason |
|---|---|---|
shared-conventions | Yes | Project-level skill in root .claude/skills/ |
react-patterns | No | Not discovered -- have not worked with files in packages/frontend/ |
api-design | No | Not discovered -- have not worked with files in packages/backend/ |
utils-patterns | No | Not discovered -- have not worked with files in packages/shared/ |
Scenario 2: After Editing Files in a Package
After you ask Claude to edit packages/frontend/src/App.tsx:
| Skill | In Context? | Reason |
|---|---|---|
shared-conventions | Yes | Project-level skill in root .claude/skills/ |
react-patterns | Yes | Discovered when editing files in packages/frontend/ |
api-design | No | Still not discovered -- have not worked with files in packages/backend/ |
utils-patterns | No | Still not discovered -- have not worked with files in packages/shared/ |
Key insight
Nested skills are discovered on-demand when you work with files in those directories. They are not preloaded at session start.
Description vs Full Content
Skill descriptions are loaded into context so Claude knows what is available, but full skill content only loads when invoked. This is an important optimization:
- Descriptions: Always in context (within character budget)
- Full content: Loaded on-demand when skill is invoked
TIP
Subagents with preloaded skills work differently -- the full skill content is injected at startup.
Priority Order (When Skills Share Names)
When skills share the same name across levels, higher-priority locations win:
| Priority | Location | Scope |
|---|---|---|
| 1 (highest) | Enterprise | Organization-wide |
| 2 | Personal (~/.claude/skills/) | All your projects |
| 3 (lowest) | Project (.claude/skills/) | This project only |
Plugin skills use a plugin-name:skill-name namespace, so they cannot conflict with other levels.
Why This Design Works for Monorepos
Package-specific skills stay isolated -- Frontend developers working in
packages/frontend/get frontend-specific skills without backend skills cluttering context.Automatic discovery reduces configuration -- No need to explicitly register package-level skills; they are discovered when you work in those directories.
Context is optimized -- Only skill descriptions load initially, and nested skills are discovered on-demand.
Teams can maintain their own skills -- Each package team can define skills specific to their domain without coordinating with other teams.
Character Budget Considerations
Skill descriptions are loaded into context up to a character budget (default 15,000 characters). In large monorepos with many packages and skills, you may hit this limit.
- Run
/contextto check for warnings about excluded skills - Set
SLASH_COMMAND_TOOL_CHAR_BUDGETenvironment variable to increase the limit
Best Practices
Put shared workflows in root
.claude/skills/-- Repository-wide conventions, commit workflows, and shared patterns.Put package-specific skills in package
.claude/skills/-- Framework-specific patterns, component conventions, testing utilities unique to that package.Use
disable-model-invocation: truefor dangerous skills -- Deployment or destructive skills should require explicit user invocation.Keep skill descriptions concise -- Descriptions are always in context (up to the character budget), so verbose descriptions waste context space.
Use namespacing in skill names -- Consider prefixing with package names (e.g.,
frontend-review,backend-deploy) to avoid confusion.
Comparison: Skills vs CLAUDE.md Loading
| Behavior | CLAUDE.md | Skills |
|---|---|---|
| Ancestor loading (UP directory tree) | Yes | No |
| Nested/descendant discovery (DOWN directory tree) | Yes (lazy) | Yes (automatic discovery) |
| Global location | ~/.claude/CLAUDE.md | ~/.claude/skills/ |
| Project location | .claude/ or repo root | .claude/skills/ |
| Content loading | Full content | Description only (full on invocation) |