Load when you need Claude Code PLATFORM mechanics as used by this repo -- config-dir resolution and CLAUDE_CONFIG_DIR, what lives in ~/.claude, settings.json precedence and key ownership, plugin/marketplace internals (installed_plugins.json, known_marketplaces.json, marketplace manifests, CLI verbs), hook events/matchers/exit codes, skills vs commands vs agents, CLAUDE.md @import, cloud-container env vars and launch ordering, statusline wiring. Trigger phrases - "how do plugins actually install", "where does settings.json come from", "what is CLAUDE_CONFIG_DIR", "why did my hook not fire", "what runs at session start", "what is installed_plugins.json". This is the factual reference; for step-by-step operations use dotfiles-run-and-operate, for env recreation use dotfiles-build-and-env, for proving state use dotfiles-verification-toolkit.
Install
npx skillscat add taloncjones/dotfiles/claude-code-platform-reference Install via the SkillsCat registry.
Claude Code Platform Reference (as used in this repo)
Domain knowledge pack: how the Claude Code platform actually works underneath
this dotfiles repo. Every claim is grounded in a repo file (cited as path or
path:line) or a live inspection of the cloud container this was written in;
anything neither could prove is labeled inferred-from-docs. This is a
reference, not a runbook -- it tells you what the moving parts ARE so the
sibling runbooks make sense.
When NOT to use this skill
| You want to... | Use instead |
|---|---|
| Run day-to-day plugin/update/repair operations | dotfiles-run-and-operate |
| Rebuild a machine or cloud env from scratch | dotfiles-build-and-env |
| Prove a symlink/plugin/hook is actually live | dotfiles-verification-toolkit |
| Triage a broken session or failing hook | dotfiles-debugging-playbook |
| Know why a design decision was made | dotfiles-architecture-contract |
| See the history of the cloud plugin saga | dotfiles-failure-archaeology |
| Look up an env var or flag default | dotfiles-config-and-flags |
| Improve the cloud-session story | dotfiles-cloud-first-campaign |
Glossary (first use of every jargon term)
- Config dir: the directory Claude Code reads all user-level state from
(settings, plugins, credentials). Default~/.claude; overridden by theCLAUDE_CONFIG_DIRenv var. - Plugin: an installable bundle of skills/commands/agents/hooks, identified
asname@marketplace(e.g. the retired Superpowers usedsuperpowers@claude-plugins-official; the retired ECC usedecc@ecc). - Marketplace: a git repo that catalogs plugins via a
.claude-plugin/marketplace.jsonmanifest; registered per config dir. - Hook: an external command Claude Code runs on lifecycle events
(PreToolUse, PostToolUse, SessionStart, ...), registered in settings.json. - Skill: a directory containing
SKILL.md(YAML frontmatter:name,description); the description is the model-facing loading trigger. - Setup script: the pre-launch shell field in a claude.ai/code cloud
environment config; its disk writes are filesystem-snapshotted.
Config-dir resolution and CLAUDE_CONFIG_DIR
CLAUDE_CONFIG_DIR selects the config dir; unset means ~/.claude. This repo
runs TWO config dirs off one asset source:
| Dir | Account | Selected by |
|---|---|---|
~/.claude |
personal (default; desktop app, unwrapped launches) | nothing -- the fallback |
~/.claude-work |
work | claude() zsh wrapper when $PWD is under ~/Git/work |
Resolution logic lives in zsh/claude-account.zsh: CLAUDE_PERSONAL_ONLY=1,claude --personal, a personal checkout, or canonical personal ownership take
precedence over inherited work settings. Work repositories allow an explicit
personal override; otherwise they default to the work configuration.claude-account prints the selected configuration.
For the default personal account, launch with CLAUDE_CONFIG_DIR unset,
never empty. Claude Code 2.1.261 on macOS resolves the existing default login
differently when ~/.claude is supplied explicitly (verified with read-onlyclaude auth status); work/custom namespaces still use explicit absolute
paths. Preserve that distinction when dispatching headless reviewers.
Launch paths that bypass the wrapper (desktop app, IDE extensions,command claude) use their own inherited configuration. account_guard.py
warns about work credentials in personal scope; personal credentials in a
work repository are allowed. A SessionStart warning is detection, not a
pre-launch credential firewall.
Both dirs are populated by link_claude_config_dir ininstall/common/claude-links.sh -- symlinks into the repo for everything
except settings.json, which is machine-local per dir (see below).
Cloud containers get only ~/.claude (personal); there is no ~/.claude-work
story in cloud (open weak point, by design -- bootstrap-cloud.sh header).
What lives in a config dir
Live-verified layout of ~/.claude in a cloud container, 2026-07-02
(ls -la ~/.claude). "Managed" = symlinked by link_claude_config_dir
(install/common/claude-links.sh); "local" = machine-local real file/dir.
| Entry | Kind | Points to / holds |
|---|---|---|
CLAUDE.md |
managed symlink | claude/global-instructions.md -- global instructions, loaded every session |
operating-principles.md |
managed symlink | claude/operating-principles.md -- pulled in via @import (see below) |
commands/ |
managed symlink | claude/commands/ -- slash commands |
agents/ |
managed symlink | claude/agents/ -- subagent definitions |
hooks/ |
managed symlink | claude/hooks/ -- guard hook scripts |
skills/ |
managed symlink | claude/skills/ -- personal skills tracked, installer-managed/generated skills untracked, including any retired-ECC leftovers (claude/skills/.gitignore whitelist) |
rules/ |
managed symlink | claude/rules/ -- only personal/ tracked; retired-ECC-vendored language dirs untracked (claude/rules/.gitignore) |
statusline.js |
managed symlink | claude/statusline.js |
settings.json |
LOCAL file | seeded once from claude/settings.json.tmpl; plugin installers write into it |
plugins/ |
LOCAL dir | plugin state -- see next section |
projects/, sessions/, shell-snapshots/, tasks/ |
LOCAL | session/runtime state (platform-managed) |
Note the defensive behavior in link_claude_config_dir: real (non-symlink)commands/agents/hooks/rules/skills dirs are backed up as<name>.bak.<timestamp> before symlinking, and seed_machine_local_file
removes a stale settings.json SYMLINK (write-through pollution risk) and warns
when the existing file is under half the template size (corruption signal) --
install/common/claude-links.sh:23-47.
Settings files: precedence and which keys this repo uses where
Precedence chain, highest first (inferred-from-docs -- the repo cannot
prove ordering, only that both user and project layers are honored):
managed/enterprise policy > CLI flags > .claude/settings.local.json
(project, personal) > .claude/settings.json (project, committed) ><config-dir>/settings.json (user).
What this repo puts in each layer (all repo-verified):
| File | Tracked? | Keys used | Purpose |
|---|---|---|---|
claude/settings.json.tmpl |
yes | env, permissions (allow/deny/ask, defaultMode), hooks (PreToolUse, PostToolUse, SessionStart), statusLine, enabledPlugins, extraKnownMarketplaces, mcpServers |
template for the USER settings.json in both config dirs |
<config-dir>/settings.json |
no (machine-local) | same as template plus whatever plugin installers write | seeded ONCE by seed_machine_local_file; template changes need manual merge on machines. Cloud reconciles automatically via reconcile_claude_settings (bootstrap-cloud.sh) -- open weak point that machines do not |
.claude/settings.json (repo root) |
yes | enabledPlugins, extraKnownMarketplaces, hooks.SessionStart |
PROJECT settings: enabledPlugins pins Superpowers off (retired 2026-09, like ECC), no plugin is declared any more, plus the session-start.sh hook that runs bootstrap-cloud.sh for assets/settings/identity |
.claude/settings.local.json |
gitignored (.gitignore:159-160) | none committed | per-machine personal overrides only |
enabledPlugins semantics: true per name@marketplace id enables the
plugin; extraKnownMarketplaces pins each marketplace to a git source URL so
the platform can install declared plugins natively at session start,
pre-launch (.claude/settings.json; rationale in repo CLAUDE.md "Cloud
sessions"). User-layer and project-layer plugin declarations are merged
(inferred-from-docs for exact merge rules; live container shows both
layers' plugins active).
Skill-level controls (checked against upstream docs and the 2.1.278 binary,
2026-09-19): skillOverrides (on / name-only / user-invocable-only /off) hides or trims personal, project, and bundled skills, andSkill(...) permission rules restrict invocation -- but upstream states
plainly that plugin skills are NOT affected by skillOverrides; the only
control for a plugin's skills is the whole plugin (enabledPlugins,/plugin). claude plugin details <name@marketplace> prints a plugin's
component inventory and projected always-on token cost (the retired ECC
2.2.1 carried 380 skills, ~40.6k tokens per session -- the isolation-tax
decision that led to its retirement); /skill-doctor (interactive) shows
per-skill cost and usage. A same-named plugin loaded via --plugin-dir or
as a ~/.claude/skills/<name> skills-dir plugin shadows the installed
marketplace copy for that session, which is the only route to a curated
subset of a third-party plugin.
Plugin system mechanics
On-disk layout under <config-dir>/plugins/, live-verified 2026-07-02:
| Path | Role |
|---|---|
installed_plugins.json |
GROUND TRUTH of what is installed: per plugin id, installPath, version, installedAt, gitCommitSha. claude plugins install can exit 0 WITHOUT writing it -- never trust the exit code (bootstrap-cloud.sh plugin_installed, commits 722c653, f91d7d2) |
known_marketplaces.json |
registered marketplaces: source URL + installLocation + lastUpdated |
marketplaces/<name>/ |
full git clone of the marketplace repo; its .claude-plugin/marketplace.json is the manifest the install resolver checks |
cache/<marketplace>/<plugin>/<version>/ |
the installed plugin content actually loaded at launch |
Cold-start race (settled, commit 7cb28b7): a github-backed marketplace can be
REGISTERED but still mid-fetch, so claude plugins install no-ops with exit 0
because the manifest does not list the plugin yet. Plain git marketplaces
clone synchronously and win the race. This repo's bootstrap-cloud.sh used to
defeat this deterministically with ensure_plugin (manifest poll, then
install, then verify against installed_plugins.json, backoff capped at
15s); that helper was deleted along with the retired Superpowers install path
(2026-09), since this repo installs no plugin any more. The race and its
platform-level defeat pattern (poll the manifest, never trust the exit code)
remain true for anyone installing a plugin by hand.
CLI verbs used by this repo (note the mixed singular/plural -- copy exactly):
claude plugin marketplace list
claude plugin marketplace add <git-url>
claude plugin marketplace update <name>
claude plugins list
claude plugins install <name@marketplace>
claude plugins update <name@marketplace>
claude plugins uninstall <name@marketplace>(Historical sources, all since deleted along with the retired Superpowers install path: bootstrap-cloud.sh's ensure_plugin, and the retired Superpowers install function in zsh/functions.zsh, which adopted the same ensure_plugin semantics as _claude_ensure_plugin on 2026-07-02 -- the retired ECC install function used the same pattern.)
This repo declares no plugin any more: Superpowers (retired 2026-09, formerly superpowers@claude-plugins-official, https://github.com/anthropics/claude-plugins-official.git) and ECC (retired 2026-09, formerly ecc@ecc at https://github.com/affaan-m/ECC.git) are both gone.
While installed, both were registered BY URL so the clone was synchronous --
the official marketplace's platform default registration is async and absent
during a pre-launch Setup script; that pattern remains correct for any future
plugin this repo might declare.
Hooks
Registration points, exit-code contract, and the full inventory.
Exit-code semantics (verified in every repo hook): exit 0 = allow /
no-op; exit 2 = block (PreToolUse prevents the tool call; PostToolUse
surfaces the violation to the model); anything raised inside a hook is caught
and exits 0 -- fail-open by convention so a broken hook never bricks a
session (e.g. claude/hooks/emoji_guard.py, final sys.exit(0) on exception;
same pattern in block_secrets.py, commit_guard.py). protect_claude_md.py
is warn-only: it only ever exits 0 with a warning payload.
Where registered:
- USER layer --
claude/settings.json.tmplhookskey (lands in each
config dir's settings.json):
| Event | Matcher | Hooks |
|---|---|---|
| PreToolUse | Bash |
commit_guard.py, no_ai_attribution_bash.py |
| PreToolUse | Read|Edit|Write |
block_secrets.py (segment-based matching since commit 52f807d, 2026-07-02) |
| PreToolUse | Edit|Write |
protect_claude_md.py (warn-only) |
| PostToolUse | Edit|Write |
emoji_guard.py, no_ai_comments.py, format_files.py (prettier) |
| PostToolUse | mcp__plugin_atlassian |
cache_jira_url.py |
| SessionStart | startup|clear|compact |
account_guard.py |
| PermissionRequest | Bash |
scratch_policy.py (scratch-only allow or no decision; Claude only) |
- PROJECT layer --
.claude/settings.json:
| Event | Matcher | Hook |
|---|---|---|
| SessionStart | startup|resume |
$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh (cloud self-heal; no-op unless CLAUDE_CODE_REMOTE=true) |
Matchers are regexes against the tool name (PreToolUse/PostToolUse) or the
session-start source (startup, resume, clear, compact are the values
this repo matches on). Hook commands referencing ~/.claude/hooks/... work in
BOTH config dirs because hooks/ is a symlink to the same repo dir in each.
Git hooks are a separate mechanism (git core.hooksPath ->~/.config/git/hooks -> git/hooks/), not Claude Code hooks -- see
dotfiles-change-control.
Skills vs commands vs agents
| Kind | Location | File shape | Loaded when |
|---|---|---|---|
| Skill | claude/skills/<name>/SKILL.md |
YAML frontmatter, exactly name + description; description carries the triggers |
model loads it on-demand when the description matches the task (see claude/skills/ship/SKILL.md for house style) |
| Command | claude/commands/<name>.md |
frontmatter optional: all current commands are plain markdown (handoff/kickoff are skills); filename = /name |
user types /name; body becomes the prompt |
| Agent | claude/agents/<name>.md |
YAML frontmatter name + description (multi-line ok); directory currently contains only .gitkeep because review agents are plugin-owned |
dispatched by name when a project-local agent is defined |
Plugins contribute their own skills/commands/agents/hooks from their cache
dir; those load only if the plugin is in installed_plugins.json AND enabled at
launch. The claude/skills/.gitignore whitelist means the skills dir on disk
mixes tracked personal skills with untracked installer-managed/generated
ones (including any retired-ECC leftovers) -- check git ls-files claude/skills before assuming a skill is version-controlled.
CLAUDE.md and @import
claude/global-instructions.md (symlinked to <config-dir>/CLAUDE.md) loads every
session. Its last line, @operating-principles.md, is an @import: Claude Code
inlines the referenced file (resolved relative to the importing file's
directory -- both are symlinks into claude/, so it resolves) into the
session context. This is how claude/operating-principles.md applies to every
session without being duplicated. Project CLAUDE.md (repo root) stacks on top
of the global one. Claude Code ALSO natively auto-loads every .md under~/.claude/rules/ at launch (verified live in a cloud session, 2026-07-02;
an earlier "nothing auto-loads" finding here came from fresh clones where the
untracked vendored dirs did not exist): a paths: frontmatter scopes a rule
to sessions with matching files in context, no frontmatter loads every
session. Our tracked always-on layer is claude/rules/personal/; ECC rules vendoring and ECC itself are both retired (see dotfiles-architecture-contract).
Cloud containers (claude.ai/code)
Env vars, verified in this container and in repo sources:
| Var | Value in cloud | Consumer |
|---|---|---|
CLAUDE_CODE_REMOTE |
true |
gate in .claude/hooks/session-start.sh:16 -- makes the hook a no-op on real machines |
CLAUDE_PROJECT_DIR |
repo root | hook command in .claude/settings.json; fallback logic session-start.sh:21 |
Launch ordering is THE load-bearing fact (root cause commit c1c4500):
plugins load at CLI launch. Anything that installs a plugin AFTER launch
(e.g. a SessionStart hook) is dark until the NEXT session. Hence two
placements:
- PRIMARY -- pre-launch:
.claude/settings.jsondeclaresenabledPlugins+extraKnownMarketplaces; the platform installs them
natively before launch, so session 1 has them (design landed in commit
8d4507f). Alternative pre-launch placement: the environment's Setup script
field runs before launch, has roughly a 5-minute budget
(bootstrap-cloud.sh:64), and its disk writes are filesystem-snapshotted --
paid once, reused by later sessions (bootstrap-cloud.sh:21-28). Custom
base images are unsupported; the snapshot is the equivalent. - SELF-HEAL -- post-launch: the SessionStart hook (matcher
startup|resume) runs bootstrap-cloud.sh to relink assets, reattribute
git identity (platform seedsClaude <noreply@anthropic.com>; never copy
the 1Password signing block into a container --reattribute_git_identity
setscommit.gpgsign false), reconcile settings.json from the template
(reconcile_claude_settings-- needed because installers create
settings.json with only plugin keys, which skips the seed; commit 910f2bc),
and re-ensure plugins for the NEXT session.
Session lifecycle sources this repo matches on: startup (new session),resume (continued session), clear (/clear), compact (context
compaction). The self-heal runs on startup|resume; account_guard onstartup|clear|compact.
Cloud containers are personal-account only. Historical: installed_plugins.json in a 2026-09-22 snapshot of this container showed the now-retired superpowers@claude-plugins-official v6.1.0 installed at session start (an earlier snapshot also showed the now-retired ecc@ecc v2.0.0); no plugin installs in a fresh container any more, since both are retired.
Statusline
statusLine key in settings.json (from claude/settings.json.tmpl):{"type": "command", "command": "node ~/.claude/statusline.js"}. The script
is symlinked by link_claude_config_dir (install/common/claude-links.sh:132),
which also sweeps a stale statusline.sh from earlier setups. Requires node
on PATH; bootstrap-cloud.sh warns (does not abort) when node is missing. The
statusline follows the session's anchored dir (workspace.current_dir), not
shell cd -- which is why worktrees must be entered via the native worktree
tool (claude/global-instructions.md "Worktree Default").
Provenance and maintenance
Written 2026-07-02 from repo state at commit 26eae6d and live inspection of
the authoring cloud container. Volatile facts and how to re-verify:
| Fact | Re-verify with |
|---|---|
| Config-dir routing logic | grep -n "_claude_config_dir" zsh/claude-account.zsh |
| Symlink set per config dir | grep -n "ln -sf" install/common/claude-links.sh |
| User-layer hook registrations | python3 -c "import json; print(json.dumps(json.load(open('claude/settings.json.tmpl'))['hooks'], indent=2))" |
| Project-layer plugin declaration + hook | cat .claude/settings.json |
| Installed plugins + versions (live) | cat ~/.claude/plugins/installed_plugins.json |
| Registered marketplaces (live) | cat ~/.claude/plugins/known_marketplaces.json |
| Marketplace manifest lists a plugin | grep '"name"' ~/.claude/plugins/marketplaces/<name>/.claude-plugin/marketplace.json |
| Marketplace URL (official; ECC's is retired) | grep -n "REPO_URL" bootstrap-cloud.sh |
| Retry budget / backoff cap | grep -n "PLUGIN_RETR" bootstrap-cloud.sh |
| Hook exit-code behavior | grep -n "sys.exit" claude/hooks/<hook>.py |
| Hook script inventory | ls claude/hooks/*.py |
| Tracked vs untracked skills | git ls-files claude/skills vs ls claude/skills |
| @import still present | tail -1 claude/global-instructions.md |
| CLAUDE_CODE_REMOTE gate | grep -n "CLAUDE_CODE_REMOTE" .claude/hooks/session-start.sh |
| Statusline command | grep -n "statusline" claude/settings.json.tmpl install/common/claude-links.sh |
| Cited commits still exist | git show --stat -s c1c4500 8d4507f 7cb28b7 722c653 910f2bc 5b799dd 52f807d |
Dated/volatile: plugin version (superpowers 6.1.0 on 2026-07-02; the retired ecc was 2.0.0);
the settings-precedence chain and enabledPlugins merge rules are
inferred-from-docs, not repo-proven -- re-check against current Claude Code
docs before relying on the exact ordering; the CLI verb spelling
(claude plugin marketplace vs claude plugins) tracks the installed CLI and
may change across releases (claude plugin --help).