Claude Code loading & discovery — research notes
What this is. Source-verified notes on how and when Claude Code loads CLAUDE.md, skills, commands, settings, and plugins — gathered to ground the Vrataski three-mode (Standalone / Jacket / Mimic) distribution design. Facts below were read from the raw doc markdown (
curlofcode.claude.com/docs/en/*.md), not a WebFetch summary, on 2026-06-21. Source lines cited where it matters.
Sources
code.claude.com/docs/en/memory.md(captured separately asclaude-code-memory-docs.md)code.claude.com/docs/en/skills.mdcode.claude.com/docs/en/permissions.mdcode.claude.com/docs/en/plugins.md+plugins-reference.md
1. CLAUDE.md / memory (recap from memory.md)
- Load order: walk up the tree from cwd; managed → user (
~/.claude/CLAUDE.md) → project (./CLAUDE.mdor./.claude/CLAUDE.md) → local (CLAUDE.local.md). Concatenated root→cwd; closer-to-cwd read last. - Subdirectory
CLAUDE.mdloads ON DEMAND when Claude reads a file there — not at launch. - Imports:
@path(relative-to-the-file or absolute /~/), max depth 4 hops, skipped inside backticks & code fences, external imports prompt a one-time approval dialog. - Additional dirs do NOT load CLAUDE.md by default. Set
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1to loadCLAUDE.md,.claude/CLAUDE.md,.claude/rules/*.md,CLAUDE.local.mdfrom an--add-dirdirectory.
2. Skills (skills.md)
- Where skills live (override order enterprise > personal > project):
- Personal:
~/.claude/skills/<name>/SKILL.md— all projects. - Project:
.claude/skills/<name>/SKILL.md— this project only. - Plugin: namespaced
plugin-name:skill-name.
- Personal:
- Parent + nested discovery (line 112, 134–136): project skills load from
.claude/skills/in cwd and every parent up to the repo root. Skills in nested.claude/skills/BELOW cwd load ON DEMAND when Claude reads/edits a file in that subdir. A name clash keeps both — the nested one gets a directory-qualified name (apps/web:deploy). - Timing: descriptions loaded at startup (progressive disclosure); full body on invoke. Subagents with preloaded skills get full content at startup.
--add-diris the skills exception (line 158):.claude/skills/inside an--add-dir//add-dirdirectory IS loaded automatically. Thepermissions.additionalDirectoriesSETTING grants file access only and does NOT load skills. ← load-bearing distinction.- Live reload (line 128): edits/adds/removes under
~/.claude/skills/, project.claude/skills/, or an--add-dir.claude/skills/take effect mid-session. Creating a new top-level skills dir that didn't exist at launch needs a restart.
3. Commands (skills.md line 16, 110, 160)
- "Custom commands have been merged into skills." A
.claude/commands/deploy.mdand a.claude/skills/deploy/SKILL.mdboth create/deploy. Existing.claude/commands/keep working; skill wins on a name clash. Skills add: supporting-file dir, invoke-control frontmatter, and model-auto-invocation. - Commands are NOT loaded from additional directories (line 160) — only skills are the
add-dir exception. So a command expressed as a
commands/*.mdfile won't travel via--add-dir; the same thing expressed as a skill will. - Command nesting:
.claude/commands/foo/bar.mdnamespacing is limited; skills carry the robust directory-qualified naming.
4. settings.json
- Precedence (high→low): managed → CLI flags → local (
.claude/settings.local.json) → project (.claude/settings.json) → user (~/.claude/settings.json). - Project
.claude/settings.jsonauto-applies on CWD (subject to the workspace trust dialog on first entry).allowed-toolsin project skills +autoMemoryDirectoryetc. also gated by that trust dialog. permissions.additionalDirectories≠--add-dirflag. The setting = file read/edit access only. The flag = file access plus the skills + CLAUDE.md(-with-env-var) exceptions.
5. Plugins (plugins.md / plugins-reference.md)
- Structure:
.claude-plugin/plugin.jsonmanifest +skills/,commands/(legacy),agents/,hooks/hooks.json,.mcp.json,bin/, etc. - Local install paths (no remote marketplace needed):
claude --plugin-dir ./path(or.zip) — loads a local plugin for that session (dev/testing). Repeatable; local copy beats an installed same-name plugin for the session.claude --plugin-url <zip-url>— fetch a remote zip per session.- Skills-directory plugin (the elegant one): drop a
.claude-plugin/plugin.jsoninto a skill folder and it loads as<name>@skills-dir, bundling agents/hooks/MCP too.claude plugin init <name>scaffolds one at~/.claude/skills/<name>/(auto-loads next session, all projects). In a project.claude/skills/it auto-loads project-scoped after the workspace trust dialog. - Marketplace:
/plugin marketplace add+/plugin installfor sharing (later/public).
- Scope:
~/.claude/skills/<x>@skills-dir= global; project.claude/skills/plugin = that project only;--plugin-dir= that session only.
What this means for the three modes (design inputs — NOT yet decided)
The naive plan breaks: "drop Vrataski in .jacket/ + add it to additionalDirectories
setting + gitignore it" gives file access but loads NOTHING — not skills, not commands, not
CLAUDE.md. The additionalDirectories setting is the wrong lever.
Levers that actually activate a toolkit dropped in a subdirectory:
| Mechanism | Skills | Commands | CLAUDE.md/docs | Persistent? | Cost |
|---|---|---|---|---|---|
additionalDirectories setting |
❌ | ❌ | ❌ | yes (file access) | useless for activation |
--add-dir flag |
✅ | ❌ | ✅ w/ env var | per-launch (or scripted) | needs flag every session |
Skills-dir plugin (.claude-plugin/plugin.json in .claude/skills/) |
✅ | via skills | ❌ (docs separate) | ✅ project-scoped (trust dialog) | commands must be skills; docs need another path |
@import appended to host CLAUDE.md |
❌ | ❌ | ✅ | ✅ | docs only, no skills |
Nested .claude/skills/ under .jacket/ |
✅ on-demand only | — | — | weak (only when Claude touches .jacket/ files) |
not reliable from session start |
Implication: Jacket almost certainly needs two wires, not one — (a) a skills-dir
plugin (or --add-dir) to activate skills/commands, and (b) an @import in the host
CLAUDE.md (or the --add-dir + env var) to load the root docs. "Commands merged into skills"
also nudges the whole refactor toward expressing Vrataski commands AS skills, since only
skills travel via the add-dir/plugin paths.
Correction to an earlier in-session claim: I'd said nested .claude/ below the project root
isn't discovered. That's wrong — nested .claude/skills/ are discovered (on demand); it's
nested commands and the additionalDirectories setting that don't load.
Prior art & landscape (research 2026-06-21)
Monolith-vs-layered verdict: the ecosystem median is one monolithic instruction file per
tool at the project root (CLAUDE.md, .cursorrules, .github/copilot-instructions.md,
.windsurfrules); reuse-across-projects = copy-paste or a single global file. Tight
personal/shared-substrate/project separation as independent repos is early-adopter, not
fringe — two-layer (global personal + project) is now common/platform-blessed; the 3+-tier
discipline is uncommon-but-emerging.
AGENTS.md(agents.md): cross-tool convention, 60k+ repos, read by Cursor/Aider/Codex/ Copilot/Zed/Devin/Junie/etc. Nested/modular within a repo (nearest-file-wins), but no notion of a portable personal layer or shareable toolkit — solves cross-tool + intra-monorepo, not cross-project reuse. Input for our ownAGENTS.md(subproject 0).- Jacket prior art —
yzhao062/anywhere-agents(https://github.com/yzhao062/anywhere-agents): drops a gitignored.agent-config/into any repo, host otherwise untouched, uninstall = delete dir. Beat-for-beat Jacket. Differences: it writes into host.claude/+~/.claude/(less self-contained) and pulls live from upstream (vs. our frozen vendored copy). Has a source-vs-consumer self-detection test — directly relevant to the INSTALL.md "am I a pending jacket?" idea. → study from source when designing Jacket. - Mimic is the most idiosyncratic — no established convention for "reach in from outside."
Works from the main loop (toolkit is cwd, reaches target via file access/
--add-dir); the wall is subagents inherit parent cwd — open feature request https://github.com/anthropics/claude-code/issues/31940 (per-subagent cwd/additionalDirectories).
Parked (future, not this design)
- ⏸️ Jacket self-update — keeping a deployed
.jacket/in sync with upstream Vrataski. Brad has ideas; deferred. Decision for now: Jacket vendors a frozen copy (no live-pull), self-updating is a later enhancement. (Contrast: anywhere-agents live-pulls.)