Files
reliquary/docs/workpad/reports/2026-05-11-17-skill-activation-mechanics.md
g4borg 1b5a7638d7 🧠 Add brain-dump docs for skill adaptation
Add exploratory and design docs for porting dirigent skills to
reliquary, including:
- Explore port options for the gitea skill (in-plugin vs vendored)
- Document activation mechanics across Claude Code and cross-tools
- Include an orchestration comparison between dirigent and reliquary
  approaches
- Add research on glob negation and flag-file activation patterns
- Create uv-detection goals and skill-engines cross-tool reports
- Provide a research plan for future porting work and risk notes
2026-05-11 23:01:30 +02:00

95 lines
8.7 KiB
Markdown

# Skill activation mechanics in Claude Code
Date: 2026-05-11
Scope: How Claude Code decides when to activate a plugin skill, with focus on file-presence / glob triggers and negation.
## Bottom line for the flag-file design
The user's design — sibling skills selected by which flag-files are present, with one skill keyed on "pyproject.toml AND NOT (Justfile|Makefile|mise.toml)" — is **partially supported, with no native negation**.
- File-glob activation IS a documented feature: SKILL.md frontmatter accepts a `paths:` field (glob patterns) that limits when Claude auto-loads the skill. So "activate only when pyproject.toml is present in the working file set" is expressible.
- Glob negation (`!Justfile`, `!**/Makefile`) is **not documented and not known to work**. The `paths:` syntax is the same as `.claude/rules/` path-specific rules, which document positive patterns and brace expansion only — no exclude/negate operator.
- Activation is path-driven, not literally "file-exists-in-repo" driven: `paths` triggers when Claude is *working with* (reading/writing) a matching file in this turn, not at session start based on repo contents. This is an important distinction for the flag-file model.
- There is no priority / specificity / tie-break field. Ordering is left to the model.
Workarounds for the "bare pyproject" case:
1. Encode negation in the `description` text ("Use only when there is no Justfile, Makefile, or mise.toml") and rely on the model. Unreliable but cheap.
2. Use a single skill with `paths: ["pyproject.toml", "Justfile", "Makefile", "mise.toml"]` and let the SKILL.md body branch on what it finds (via dynamic context injection `` !`ls` ``). This consolidates the decision into one skill body and is the most robust option today.
3. Wrap activation in a hook (`InstructionsLoaded` / SessionStart) that injects different CLAUDE.md content based on flag files. Hooks have full shell access, so arbitrary boolean logic is trivial — but this is hook-land, not skill-land.
## Question-by-question findings
### 1. Activation mechanism
Activation is primarily model-driven from `description`, **and** there is one declarative file-trigger field: `paths`.
From the official frontmatter reference table on the Skills docs page:
> **`paths`** — 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. Uses the same format as path-specific rules.
So in the default case (no `paths`), the model decides based on the description that lives in the system prompt. With `paths` set, automatic loading is gated by glob match on the files Claude is working with.
`allowed-tools` is a permission/pre-approval field, not an activation field — it only affects what tools the skill may use once active. `disable-model-invocation: true` disables auto-activation entirely (only the user can `/invoke` it). `user-invocable: false` does the inverse (only the model can invoke it, hidden from `/` menu).
### 2. Glob negation
**No documented negation syntax.** The `paths` field uses the same glob format as `.claude/rules/` path-specific rules, which the memory docs describe as:
> Use glob patterns in the `paths` field to match files by extension, directory, or any combination... You can specify multiple patterns and use brace expansion to match multiple extensions in one pattern.
The documented patterns are all positive (`**/*.ts`, `src/**/*`, `src/**/*.{ts,tsx}`). Brace expansion works. No `!pattern` exclude syntax is documented anywhere in the Skills, Plugins-reference, or Memory pages.
Empirical evidence from the issue tracker corroborates this:
- anthropics/claude-code#17204 lists every syntax that does and does not work for `paths`/`globs`. None of the tested forms involve negation. The author would surely have tried it if it were a feature.
- Multiple open bugs (#21858, #23478, #23569, #16853) discuss the field still failing in mundane cases (user-level rules, Write tool, worktrees). The feature is not mature enough to expect undocumented negation to work even if hand-rolled.
Conclusion: glob negation in `paths` is not supported today. Expressing "X present AND Y absent" requires a workaround.
### 3. Manifest fields
**SKILL.md frontmatter (official, from the Skills doc table):**
| Field | Purpose |
|---|---|
| `name` | Display name. Defaults to directory name. Lowercase, hyphens, max 64 chars. |
| `description` | What the skill does and when to use it. Drives model-based activation. Up to 1024 chars. |
| `when_to_use` | Extra trigger phrases. Appended to description, counts toward the 1,536-char listing cap. |
| `argument-hint` | Autocomplete hint. |
| `arguments` | Named positional args for `$name` substitution. |
| `disable-model-invocation` | If true, only the user can invoke. |
| `user-invocable` | If false, hide from `/` menu. |
| `allowed-tools` | Tools pre-approved for this skill. |
| `model` | Model override for this turn. |
| `effort` | Effort-level override. |
| `context` | Set to `fork` to run in a subagent. |
| `agent` | Subagent type when `context: fork`. |
| `hooks` | Skill-scoped lifecycle hooks. |
| `paths` | **Glob patterns gating auto-activation.** |
| `shell` | `bash` or `powershell` for `` !`...` `` injection. |
**plugin.json / marketplace.json:** Per the Plugins reference, neither has activation-condition keys for skills. Skills are auto-discovered from the plugin's `skills/` directory and gated only by whether the plugin is enabled. Activation logic lives in SKILL.md, not at the manifest level.
### 4. Priority / specificity
**No priority field exists.** When skills share a name across scopes there is a fixed override order (enterprise > personal > project; plugin skills are namespaced and don't conflict). Beyond name-conflict resolution there is no documented mechanism for declaring one sibling skill more specific than another. The model chooses among eligible skills based on description match. If `paths` filters narrow the eligible set, that narrowing is the only "specificity" lever available.
For listing-budget pressure, `skillOverrides` and `skillListingBudgetFraction` can drop or shorten descriptions of low-priority skills, but that's about token budget, not activation priority.
## First-party skills using non-description signals
Searched anthropics/skills and anthropics/claude-plugins-official. The publicly indexed first-party skills (PDF, Excel, DOCX, PPTX, etc.) rely on description-based activation. I did not find a first-party SKILL.md using `paths` in the public repos within the time budget for this research. Plenty of community/third-party skills exist, but I cannot confirm any well-known one using `paths` from authoritative sources. **Treat `paths` as a real but under-exercised feature** — the open bug list (#17204, #21858, #23478, #23569, #16853) confirms it ships and is being used, but adoption is limited.
## Citations
- [Extend Claude with skills — Claude Code docs](https://code.claude.com/docs/en/skills) — full frontmatter table including `paths`.
- [Skill authoring best practices — Claude API docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) — frontmatter requirements, description guidance.
- [How Claude remembers your project — Memory docs](https://code.claude.com/docs/en/memory) — `paths` glob syntax via `.claude/rules/` (the format `paths` reuses). Documents positive patterns and brace expansion; no negation.
- [Plugins reference — Claude Code docs](https://code.claude.com/docs/en/plugins-reference) — plugin.json/marketplace.json schemas; no skill-activation keys at manifest level.
- [anthropics/claude-code#17204](https://github.com/anthropics/claude-code/issues/17204) — `paths` vs `globs` working/non-working forms; confirms no negation tested or supported.
- [anthropics/claude-code#21858](https://github.com/anthropics/claude-code/issues/21858) — `paths` ignored at user level.
- [anthropics/claude-code#23478](https://github.com/anthropics/claude-code/issues/23478) — `paths` not triggered on Write tool, only Read.
- [anthropics/claude-code#23569](https://github.com/anthropics/claude-code/issues/23569) — `paths` ignored under worktree path resolution.
- [anthropics/claude-code#16853](https://github.com/anthropics/claude-code/issues/16853) — `paths` not auto-loading on matching file work.
- [paddo.dev — Claude Code Path-Specific Rules](https://paddo.dev/blog/claude-rules-path-specific-native/) — third-party walk-through of the `.claude/rules/` `paths` feature introduced in 2.0.64.
- [anthropics/skills repo](https://github.com/anthropics/skills/) and [anthropics/claude-plugins-official](https://github.com/anthropics/claude-plugins-official) — reviewed for non-description activation; none confirmed.