Claude Code: harness-specific frontmatter and hooks
This page covers Claude Code-specific behaviors, frontmatter extensions, and patterns that do not apply to other harnesses. The cross-platform-safe core lives in the rest of the docs; this page is for authors targeting Claude Code specifically. Source: https://code.claude.com/docs/en/skills (Anthropic’s official Claude Code docs);LANDSCAPE 2.1; REVIEWER G3, G4, G10.
Per-scope priority
Claude Code resolves skill names from four scopes in this order:- Enterprise. Managed settings deployed organization-wide.
- Personal.
~/.claude/skills/<skill-name>/SKILL.md. - Project.
.claude/skills/<skill-name>/SKILL.mdin the project root. - Plugin.
<plugin>/skills/<skill-name>/SKILL.md(namespaced as<plugin-name>:<skill-name>).
~/.claude/skills/wiki/ (personal) shadows a skill at .claude/skills/wiki/ (project) and any plugin-provided wiki skill.
Plugin skills are namespaced (plugin-name:skill-name); they cannot shadow each other across plugins, but they CAN be shadowed by personal or project skills with the same bare name (the personal/project name resolves before the plugin namespace).
The plugin-skill-shadowed-by-personal-skill case is the karpathy-wiki development pattern: the personal ~/.claude/skills/karpathy-wiki/ is a symlink to the plugin’s checked-out directory. Edits to the plugin source land immediately for the personal scope without going through plugin reinstall.
SessionStart-hook injection pattern
Source:LANDSCAPE 2.1; REVIEWER G2; superpowers issue #1220.
The SessionStart hook reads SKILL.md, escapes for JSON, and emits the body as hookSpecificOutput.additionalContext. The agent receives the entire body before its first turn. This guarantees the iron laws are in context every turn but costs the full SKILL.md size in input tokens every session.
The empirical anchor: superpowers issue #1220 measured ~17.8k tokens of SessionStart-hook injection over 57 hours across 13 firings of using-superpowers. That is ~1,370 tokens per firing on average; the skill body is the floor.
The pattern is justified for the bootstrap skill (using-superpowers is the canonical exception), where the iron laws of the entire ceremony must be in context from turn 1. It is rarely justified elsewhere; description-triggered loading is the cheaper default for most skills.
When you do use SessionStart-hook injection:
- Keep the injected body small. The cost is paid every session whether the skill is invoked or not.
- Document the injection in the skill’s prose so users know the cost.
- Measure the injection cost on a representative session sample. The 17.8k / 57 hours / 13 firings number is the right shape; substitute your own.
${CLAUDE_PLUGIN_ROOT} substitution gotcha
Source: REVIEWER G3; /Users/lukaszmaj/wiki/concepts/claude-code-plugin-root-substitution.md.
The token ${CLAUDE_PLUGIN_ROOT} is a config-time substitution in plugin.json and hooks.json; Claude Code expands it to the plugin’s installed path when reading those files.
The token does NOT propagate to the Bash tool. A SKILL.md that says bash "${CLAUDE_PLUGIN_ROOT}/scripts/foo.sh" fails for personal-symlink installs (the literal string reaches Bash, expands to empty, command becomes bash /scripts/foo.sh which does not exist).
Three workarounds:
- Use
${CLAUDE_SKILL_DIR}instead. This token IS available in bash injection commands. - Use a relative path.
bash scripts/foo.shworks if the skill’s working directory is the skill’s base directory. - Compute the path explicitly. Read the base directory from the harness preamble at the top of the skill’s body,
cdinto it, then invoke. Karpathy-wiki uses this pattern.
docs/08-packaging-as-plugin.md for the full discussion.
Invocation taxonomy: disable-model-invocation and user-invocable
Source: REVIEWER G10.
Claude Code documents a clean dichotomy on these two frontmatter fields:
disable-model-invocation: true: only the user can invoke. The agent cannot auto-fire. Use for side-effecting workflows:/deploy,/release,/commit.user-invocable: false: only the agent can invoke. The user cannot type/skill-name. Use for background knowledge / discipline skills the user should not need to think about.
| disable-model-invocation | user-invocable | Behavior | Example |
|---|---|---|---|
| false (default) | true (default) | Both agent and user can invoke | The default; karpathy-wiki uses this combination implicitly |
| true | true (default) | User only | /deploy, /release |
| false (default) | false | Agent only | Background discipline skills users should not directly invoke |
| true | false | Neither | Effectively disabled; rarely useful |
docs/03-three-questions.md). Decide explicitly; do not let the defaults answer for you.
paths: glob as activation gate
The paths: field accepts glob patterns that limit when a skill auto-loads. From Anthropic’s docs: “Glob patterns that limit when this skill is activated. Accepts a comma-separated string or a YAML list. When set, Claude loads the skill automatically only when working with files matching the patterns.”
Example:
docs/05-authoring/frontmatter.md for the field reference; docs/07-mechanism-vs-decoration.md for the broader pattern.
Sources
LANDSCAPE2.1 (Claude Code skill loading mechanisms; SessionStart hook).LANDSCAPE1.3 (Anthropic Claude Code docs).REVIEWERG3 (${CLAUDE_PLUGIN_ROOT}substitution gotcha; the three workarounds).REVIEWERG4 (per-scope priority).REVIEWERG10 (disable-model-invocation/user-invocabletaxonomy).
docs/04-token-economics.md (the SessionStart-hook injection cost), docs/08-packaging-as-plugin.md (the plugin manifest and the substitution gotcha).