🧠 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
This commit is contained in:
2026-05-11 23:01:30 +02:00
parent 5e37331d31
commit 1b5a7638d7
8 changed files with 660 additions and 0 deletions
@@ -0,0 +1,95 @@
# Brainstorm: should dirigent's `documentation` skill move to reliquary, and in what shape?
## Source
`../dirigent/.claude/skills/documentation.md` — a flat markdown file (no folder, no frontmatter, no `name:`/`description:` header). 237 LOC. Defines a documentation philosophy + templates for CLAUDE.md, README.md, `docs/architecture/`, `docs/api/`.
## First observation: it's not actually a skill
It's missing a frontmatter block. Claude Code skills need at minimum `name:` and `description:` so the runtime knows when to surface them. Without that, this file would never auto-activate — it's effectively a static reference document the user grep'd into manually. If we port it as-is, we'd be porting a doc, not a skill.
So the real question isn't "should we copy it" — it's **"what concept inside it deserves to become a real skill, if any?"**
## What the file actually contains
Three loosely-related things bundled together:
1. **A philosophy statement** — "AI agents first, humans second", CLAUDE.md is lightweight, README is human-friendly, `docs/` is deep-dive, cargo doc is API.
2. **A folder structure prescription** for monorepo / cargo-workspace Rust projects.
3. **Four file templates** — CLAUDE.md, README.md, architecture doc, API doc.
The philosophy is interesting. The folder structure is **dirigent-specific** (cargo packages, `docs/architecture/`, `docs/api/`). The templates are generic but opinionated.
## Where each piece could go
### The philosophy → a small skill, maybe
A skill called something like **`agent-readable-docs`** could be valuable. It would activate when the user asks to "document this package", "write a README", "add a CLAUDE.md", and would advise:
- Default reader is an LLM agent, not a human.
- CLAUDE.md = short, navigational, 20-50 lines.
- README.md = human-friendly with examples.
- Long-form goes in `docs/`.
- API specs go in `docs/api/`.
This is a real **judgment-shape** skill, not a template repository. It would compose with `workpad` (which owns `docs/workpad/`, not `docs/architecture/`).
### The folder structure → not portable
The cargo-package layout in the file is dirigent-specific. Different projects (Python, Rust app, monorepo, library) want different shapes. Hardcoding "packages/`<name>`/CLAUDE.md" is wrong for anything that isn't a cargo workspace.
If we want this to be reusable, the skill must say "the user's project already has *some* layout — adapt" rather than "use this layout."
### The templates → reference, not skill
Four templates is a small enough library that it could be a `references/` folder inside an `agent-readable-docs` skill. The skill markdown points at them: "see `references/claude-md-template.md` for the structure."
Skills shouldn't paste 100 lines of template into their description — but they can host template files alongside and reference them.
## Three options, ranked
### Option 1 — Adapt as `agent-readable-docs` skill (recommended)
A new skill in `plugins/g4b_ai/skills/agent-readable-docs/`:
- `SKILL.md` — the philosophy + when to use which doc type. 60-80 LOC.
- `references/CLAUDE-md.md` — template (generic, not cargo-specific).
- `references/README-md.md` — template.
- `references/architecture-doc.md` — template.
- `references/api-doc.md` — template.
Composes with `workpad` ("workpad is for thinking-about-the-work; this skill is for documenting-the-work-itself"). Stays language-agnostic.
**Risk:** scope creep. "How to document code" is huge. Keep it tight — this skill is just about *which file goes where and what shape*, not about content quality.
### Option 2 — Leave it in dirigent
It's dirigent-specific (cargo workspace, the project's own `docs/architecture/` convention). Ports as a doc, not a skill. If you want to reuse it in dirigent forks, fine — but reliquary's plugins should be more generic.
### Option 3 — Don't port, write fresh
The existing file has the right *seed* of an idea ("agent-readable docs first") but the wrong *shape* (templates inline, cargo-coupled). If you do port it, you'd rewrite ~80% anyway. Might be cleaner to write the skill fresh, taking only the philosophy paragraph as input.
In practice this is identical to Option 1 in outcome — the difference is whether you frame it as a port or a new skill.
## Recommendation
**Option 1**, with these specific moves:
- Strip cargo-specific examples; replace with language-agnostic phrasing ("source root", not "src/lib.rs").
- Move all four templates into `references/` rather than the skill body.
- Add a frontmatter `description` that triggers on "document this", "write a README", "add CLAUDE.md", "API docs", "architecture doc".
- Cross-reference `workpad` explicitly: workpad is for working *about* the code; this skill is for docs *of* the code.
## Open question — overlap with `workpad`?
The `workpad` skill is very clear that it covers thinking-in-markdown (plans, reports, designs). Docs *of the code* (CLAUDE.md in a package, README.md, API specs) are deliberately out of `workpad`'s scope — workpad owns `docs/workpad/`, not all of `docs/`.
An `agent-readable-docs` skill fills that gap cleanly. The two compose:
- `workpad` → where do my plans, reports, journals live?
- `agent-readable-docs` → where does my package's README + agent context + API spec live?
That's a healthy split. Worth doing.
## What we'd skip
- The "Maintenance" section in the original (refactor → update CLAUDE files; new feature → update README). That's project-discipline advice, not skill content.
- The "Tips for Agents" section. Self-referential and adds noise.
- The hardcoded label `Type: Library | Binary | UI | Service`. Too narrow.
@@ -0,0 +1,144 @@
# Porting the `gitea` skill + scripts into reliquary
Hands-on design for moving dirigent's `gitea` skill (which is a thin wrapper around `scripts/gitea/*.py` in the dirigent repo) into a reliquary plugin where the scripts and the skill ship as one unit.
## Current state in dirigent
```
dirigent/
├── .claude/skills/gitea/SKILL.md # 123 LOC — thin wrapper, points at scripts
└── scripts/gitea/
├── CLAUDE.md # agent reference for scripts (~127 LOC)
├── README.md # human setup guide (~178 LOC)
├── __init__.py
├── client.py # 186 LOC — GiteaClient REST wrapper
├── close_ticket.py # 39 LOC
├── config.py # 68 LOC — env loading
├── create_ticket.py # 115 LOC
├── fetch_ticket.py # 113 LOC
├── list_tickets.py # 56 LOC
├── models.py # 66 LOC — Pydantic models
├── post_comment.py # 69 LOC
├── setup_labels.py # 43 LOC
└── start_ticket.py # 163 LOC
```
Total: ~919 LOC of Python + ~430 LOC of docs.
The skill itself does almost nothing — it tells the agent to *read* `scripts/gitea/CLAUDE.md` and *run* `uv run python -m scripts.gitea.<module>`. Everything load-bearing lives in the dirigent project root: the venv, `uv.lock`, `pyproject.toml`, and `.env`.
## The fundamental tension
The dirigent skill assumes:
1. **The Python scripts live in the project being worked on**, importable as `scripts.gitea.*` from project root.
2. **The project has uv set up and a `.env` with `GITEA_*` vars.**
3. **The user is in dirigent itself** — the skill says `dirigent workpad`, references `docs/workpad/tickets/`, and the labels list (🐛 bug, ✨ feature, 📋 workpad…) is curated for dirigent.
To turn this into a **reusable plugin skill**, none of those assumptions hold. The scripts must live with the plugin, work from anywhere, and adapt to any project's workpad layout.
## Two viable port shapes
### Option A — Scripts ship inside the plugin (recommended)
```
plugins/gitea/
├── .claude-plugin/plugin.json
├── README.md
└── skills/gitea/
├── SKILL.md
└── scripts/
├── __init__.py
├── client.py
├── config.py
├── models.py
├── fetch_ticket.py
├── create_ticket.py
├── post_comment.py
├── start_ticket.py
├── list_tickets.py
├── close_ticket.py
└── setup_labels.py
```
Invocation pattern changes:
- Skill expands `${CLAUDE_PLUGIN_ROOT}` to locate scripts.
- Each call becomes `uv run --no-project --with httpx --with pydantic --with python-dotenv python ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/fetch_ticket.py 42` — or, better, an inline-deps PEP 723 header at the top of each script so they're self-installing.
- Env vars come from `.env` in the *current working directory* (the project the user is in), not the plugin dir. `python-dotenv` already supports this.
- Workpad path comes from the `workpad` skill's resolution rules (env var → just recipe → `/docs/workpad`), not hardcoded.
**Pros:**
- Plugin is fully self-contained — install it once, use it in any repo.
- Versioned together with the skill markdown.
- No requirement that the host project has uv configured.
**Cons:**
- `uv run --no-project --with httpx ...` is slow on first run (env build). Mitigation: PEP 723 headers + `uv` cache make second-run startup fast.
- The scripts must be reworked to take a workpad root as an arg (or env var) rather than hardcoding `docs/workpad/`.
### Option B — Scripts vendored into each project (rejected)
Keep the dirigent shape: ship a "scaffolder" that copies scripts into the user's repo. This is what `superpowers`-style skills sometimes do.
**Why reject:** updates don't propagate, every project carries duplicate code, and the scripts become "the user's code now" which makes version skew permanent.
## Concrete port checklist
If we go with Option A:
### Phase 1 — copy + decouple from dirigent
1. Copy `scripts/gitea/` contents → `plugins/gitea/skills/gitea/scripts/`.
2. Drop `__init__.py` if scripts are run as files; keep it if we want `python -m`.
3. Add PEP 723 inline-dep blocks to each CLI entrypoint (`fetch_ticket.py`, `create_ticket.py`, etc.):
```python
# /// script
# requires-python = ">=3.11"
# dependencies = ["httpx", "pydantic>=2", "python-dotenv"]
# ///
```
This makes each script runnable in isolation via `uv run script.py` without a project context.
4. Rewrite imports: `from scripts.gitea.client import ...` → `from client import ...` (relative within the scripts/ dir). Or run as `python -m` with `PYTHONPATH` set.
### Phase 2 — parameterize project-specific behavior
5. Replace hardcoded `docs/workpad/tickets/` with a CLI flag `--workpad <path>` defaulting to env var `WORKPAD_FOLDER`, defaulting to `./docs/workpad`. Honor the `workpad` skill's resolution order.
6. Move the hardcoded label-emoji list out of `setup_labels.py` into a JSON/YAML file shipped with the plugin (`labels.default.json`) so users can override per-project.
7. Audit any other dirigent-isms: references to "dirigent" in error messages, the README mentioning dirigent's workpad, etc.
### Phase 3 — rewrite the skill markdown
8. `Step 0: Read Current Script Capabilities` currently points at `scripts/gitea/CLAUDE.md`. Replace with **inline** capability summary in the SKILL itself — the skill *is* the reference now; the scripts are an implementation detail.
9. Replace every `uv run python -m scripts.gitea.X` example with `uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/X.py`.
10. Connectivity check stays — just relocate the inline `python -c` snippet's imports to whatever the new module layout is.
11. Error-recovery table stays as-is. It's good.
### Phase 4 — documentation
12. README at plugin root: install instructions + Gitea token setup. Lift most of `scripts/gitea/README.md`, drop the dirigent-specific bits.
13. The skill markdown should be self-contained — don't make the agent open a second file unless absolutely necessary.
## Things to NOT do in the port
- **Don't keep both `CLAUDE.md` and `SKILL.md` for the scripts.** That split made sense in dirigent because the scripts had a life of their own outside the skill. Inside a plugin they don't. One file: `SKILL.md`.
- **Don't ship Pydantic v2 + httpx as hard plugin dependencies installed in the user's project venv.** Use PEP 723 inline deps so uv builds an isolated env per invocation.
- **Don't hardcode `closes #N` / `fixes #N` keywords** — those are Gitea behavior, not script behavior. They should stay in the skill markdown as guidance, not in code.
- **Don't copy `setup_labels.py`'s default label set verbatim.** It's tuned for one user's taste. Externalize.
## Open question — sibling skill in a "mini plugin"
The user mentioned wanting **another skill in a custom mini plugin** that builds on this. That's not designed yet — likely candidates given the workpad ecosystem:
- A `gitea-workpad-flow` skill that ties together: "fetch a ticket → write plan in workpad → post plan back as comment → branch via `start_ticket`". This is workflow glue, not API access.
- A `gitea-bulk` skill for grooming: relabel many issues, close stale ones, etc.
- A `gitea-pr` skill if/when Gitea's PR API gets used (the current scripts only touch issues).
These should be a separate plugin so the core `gitea` plugin stays purely a thin API wrapper. The workflow-glue skill *depends on* the API skill but is opinionated about flow — exactly the kind of thing that should be swappable.
## Estimated work
| Phase | Effort | Risk |
|---|---|---|
| Copy + PEP 723 conversion | ~1h | Low — mechanical |
| Parameterize workpad path + labels | ~1-2h | Medium — touches 4-5 files |
| Skill markdown rewrite | ~30min | Low |
| README + plugin manifest | ~20min | Low |
| Manual end-to-end test (real Gitea + new project) | ~1h | This is where the bugs are |
Total: **half a day of focused work** for a complete port. The `start_ticket` flow is the most likely to surface issues because it touches git state, the workpad, and the API in one call.
+16
View File
@@ -0,0 +1,16 @@
- detect tainted .venv folders: custom files and folders inside .venv, using .venv as multi-python base dir, etc. should lead to a warning, as it shows that `uv` is not fully embraced in that project.
- detect default packages for skills in main uv:
- requests or httpx
- python-dotenv
- pydantic v2+
- pytest
- pyyaml
- tomllib or tomli
- mcp
- support `SCRIPTS_DIR` (default: `'scripts/'`), `SCRIPTS_STORE` (default: `'/tmp/'`) and `SCRIPTS_UV` (default: `''`) env vars?
- detect if project itself is a python project, or uv is there to be used by the agent.
- detect uv pins (uv.toml, pyproject.toml, pip requirements)
- detect justfiles, makefiles, misefiles
-
@@ -0,0 +1,79 @@
# Orchestrator skills: dirigent's `orchestrator` vs. reliquary's `implementation-orchestration`
Comparison of two skills that both claim to govern "how the agent drives multi-step work."
| Source | File |
|---|---|
| dirigent (old) | `../dirigent/.claude/skills/orchestrator/SKILL.md` (130 LOC) |
| reliquary (current) | `plugins/g4b_ai/skills/implementation-orchestration/SKILL.md` (80 LOC) |
## TL;DR
They are not the same skill at different stages — they are **different philosophies of orchestration**:
- **`orchestrator` (dirigent)** is a *plan-execution* skill: there's a markdown plan, there's a tasks file, the agent walks phases, checks boxes, writes phase-summary files, delegates each task to a specialized "implementer" agent. It is prescriptive, ceremonial, and assumes the work is already decomposed.
- **`implementation-orchestration` (reliquary)** is a *judgment* skill: when do you delegate vs. work inline, when do you sequence vs. parallelize, how do you handle test failures and hard bugs without thrashing. It is descriptive, principle-based, and assumes the work is not yet decomposed.
The newer skill is **not a refactor of the older one** — it answers a strictly different question. Adopting the new skill does not retire the old one; if anything, the old one is the *content* you'd want when actually walking a plan, while the new one is the *meta* you'd want when deciding whether a plan is even the right move.
## Side-by-side
| Dimension | `orchestrator` (dirigent) | `implementation-orchestration` (reliquary) |
|---|---|---|
| **Trigger** | "you have a multi-phase plan in markdown — execute it" | "user said implement / build / ship / fix" — i.e. starting work, no plan required |
| **Scope** | Drive an existing plan to completion | Decide how to approach work, with or without a plan |
| **Posture toward planning** | Plan is input; if missing, write tasks.md first | Plan is optional; only worth writing for non-trivial work |
| **Delegation model** | One implementation agent per phase / task; orchestrator never implements | Mixed — inline by default, subagents when work genuinely doesn't fit |
| **Parallelism stance** | Sequential by default; parallel only for research / read-only | Sequential by default; parallel only when truly disjoint (same rule, more explicit about *why*) |
| **Test failures** | Re-engage agent with feedback | Delegate fix to subagent **but verify the diff** (calls out the "test-deletion shortcut" failure mode explicitly) |
| **Bugs** | Not covered | Two strong rules: prove-with-test before fixing; explore-before-focus |
| **Progress tracking** | Updates checkboxes in tasks.md; writes per-phase summary file | Defers to `workpad` skill; no checkbox protocol of its own |
| **Composition** | Standalone, with references to "implementation agents" by name (e.g. `rust-task-implementer`) | Explicit composition with `workpad`, `research-tree`, `superpowers` |
| **Tone** | Operational SOP ("Self-Verification Checklist", "Output Expectations") | Heuristics with rationale ("a wrong plan caught at planning time costs minutes; caught at code-review time costs days") |
| **Length** | 130 LOC, heavily structured | 80 LOC, prose-first |
## What each does well
**`orchestrator` (dirigent) strengths**
- Concrete checkbox/phase-summary protocol gives a clear paper trail when the work *is* a long plan.
- Names roles (`rust-task-implementer`, `task-writer`) — useful in a project where you've actually built those subagents.
- Self-verification checklist is genuinely good for ritualized "have I really finished this phase" moments.
**`implementation-orchestration` (reliquary) strengths**
- "Delegate the fix, but verify the diff" is the single most important orchestration rule and the old skill misses it.
- The bug-handling section ("prove before fixing, explore before focusing") is high-leverage advice that the old skill doesn't address at all.
- Composition-first design: it explicitly defers to `workpad`, doesn't reinvent placement rules.
- Acknowledges that orchestration *overhead* is itself a cost — "for changes small enough that a single agent could do the whole thing, just do it inline."
## What each is missing
**`orchestrator` is missing**
- Any treatment of bugs / unknowns. It assumes you already know what to do and just need to execute.
- Any pushback on its own ceremony. It will happily mandate phase-summary files for a 3-line fix.
- A "when *not* to use this skill" section.
- The verify-the-diff guard against subagents writing fake-green fixes.
**`implementation-orchestration` is missing**
- A concrete protocol for the "I genuinely have a 7-phase plan and need to walk it" case. It punts to `workpad` for placement but doesn't say what the *execution loop* looks like when there are 20 checkboxes to grind through.
- Named-subagent vocabulary. The old skill at least namechecks specialized implementers; the new one says "subagent" abstractly.
- A "definition of done" per phase. The old skill's self-verification checklist is useful precisely because it forces a stop.
## Recommendation
Keep `implementation-orchestration` as the primary entry-point skill — its heuristics generalize. But consider porting **two narrow pieces** from `orchestrator`:
1. **A separate `plan-walker` skill** (or section) covering: walking a checkbox plan, marking items done, writing per-phase summaries. This is the operational protocol the new skill deliberately omits. It would compose under `implementation-orchestration` ("when you have a plan, here's how to walk it") rather than replace it.
2. **A per-phase done-checklist pattern**, even if shorter than the old one. Right now there's no explicit "stop here and check" marker in the new skill, and the old skill's checklist serves that role usefully.
Not worth porting:
- The phase-summary-file mandate as a hard rule. Make it conditional on plan length.
- Hardcoded implementer-role names. The user's subagent roster will evolve; tie this to project-level config instead.
- The "celebrate when all phases complete" line. (You know.)
## Naming note
If a plan-walker skill is added, the names start to overlap awkwardly:
- `implementation-orchestration` — when and how to orchestrate
- `orchestrator` (old) — how to walk a plan
Consider renaming the ported piece to **`plan-execution`** or **`phase-walker`** to make the split obvious. Reserve "orchestration" for the meta-level.
@@ -0,0 +1,82 @@
# Verification of skill-activation-mechanics report
Date: 2026-05-11
Subject: Independent fact-check of `2026-05-11-17-skill-activation-mechanics.md` against cited sources.
## Verdict summary
| Claim | Verdict |
|---|---|
| 1. `paths:` frontmatter field exists on docs page | VERIFIED |
| 2. Full frontmatter field list | VERIFIED |
| 3. Dynamic context injection via `` !`cmd` `` plus `shell:` field | VERIFIED |
| 4. The five issue numbers exist and discuss what the report claims | VERIFIED (with one caveat — see #17204) |
| 5. `.claude/rules/` `paths` glob format, no negation | VERIFIED |
All major load-bearing claims hold up. The report is accurate.
---
## Claim 1: `paths:` frontmatter field exists — VERIFIED
Source: https://code.claude.com/docs/en/skills
The frontmatter reference table on the official Skills doc page contains a `paths` row. Exact quoted description:
> `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](/en/memory#path-specific-rules).
The report quotes this verbatim (modulo minor formatting). VERIFIED.
## Claim 2: Full frontmatter field list — VERIFIED
The docs page lists exactly these frontmatter fields in the reference table:
`name`, `description`, `when_to_use`, `argument-hint`, `arguments`, `disable-model-invocation`, `user-invocable`, `allowed-tools`, `model`, `effort`, `context`, `agent`, `hooks`, `paths`, `shell`.
This is identical to the list in the report. No invented fields. VERIFIED.
The report's one-line summaries of each field are faithful paraphrases of the official descriptions (e.g. `name` "Lowercase letters, numbers, and hyphens only (max 64 characters)"; `description` cap "truncated at 1,536 characters"; `context: fork` "forked subagent context"; `shell` "Accepts `bash` (default) or `powershell`").
## Claim 3: Dynamic context injection `` !`cmd` `` plus `shell:` field — VERIFIED
Source: same Skills docs page, section "Inject dynamic context".
Quote:
> The `` !`<command>` `` syntax runs shell commands before the skill content is sent to Claude. The command output replaces the placeholder, so Claude receives actual data, not the command itself.
And from the frontmatter table for `shell`:
> Shell to use for `` !`command` `` and ` ```! ` blocks in this skill. Accepts `bash` (default) or `powershell`. Setting `powershell` runs inline shell commands via PowerShell on Windows. Requires `CLAUDE_CODE_USE_POWERSHELL_TOOL=1`.
The docs also document fenced multi-line `` ```! `` blocks as an alternative. The workaround the report proposes (consolidating into one skill body and branching on `` !`ls` `` output) is consistent with how the docs describe the feature. VERIFIED.
## Claim 4: The five GitHub issues — VERIFIED (minor caveat on #17204)
All five issues exist at the cited URLs and discuss the claimed topic.
- **#17204** — Title: "Documentation: .claude/rules/ frontmatter format incorrect - globs works, paths with quotes/YAML list does not". Caveat: this is about `.claude/rules/` frontmatter format, not SKILL.md, and the report's wording "lists every syntax that does and does not work for `paths`/`globs`" is accurate (the issue tabulates working vs broken forms: `globs: ...` and unquoted `paths: ...` work; quoted strings and YAML lists do not). The report's broader inference — "None of the tested forms involve negation. The author would surely have tried it if it were a feature" — is supported: negation is never mentioned. Since SKILL.md `paths` "Uses the same format as path-specific rules" per the docs, citing this rules-format issue to bound SKILL.md `paths` behaviour is fair.
- **#21858** — Title: "[BUG] paths: frontmatter in user-level rules (~/.claude/rules/) is ignored". Matches report's "`paths` ignored at user level".
- **#23478** — Title: "Path-based rules (.claude/rules/ with paths: frontmatter) are not loaded on Write tool — only on Read". Matches report's "`paths` not triggered on Write tool, only Read".
- **#23569** — Title: "[BUG] Path-conditional rules (paths: frontmatter) ignored when loaded via git worktree resolution". Matches report's "`paths` ignored under worktree path resolution".
- **#16853** — Title: "[BUG] Path-scoped rules in `.claude/rules/` not automatically loaded when working with matching files". Matches report's "`paths` not auto-loading on matching file work".
All five concern `.claude/rules/` paths (the same format SKILL.md `paths` reuses), not SKILL.md directly. The report's framing as "evidence the feature is not mature enough to expect undocumented negation to work" is sound but worth noting: these are rules-side bugs cited as a proxy for skills-side maturity. VERIFIED.
## Claim 5: `.claude/rules/` `paths` glob format, no negation — VERIFIED
Source: https://code.claude.com/docs/en/memory, section "Path-specific rules".
Quoted documentation of the glob format:
> 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.
Documented patterns: `**/*.ts`, `src/**/*`, `*.md`, `src/components/*.tsx`, and brace-expansion form `src/**/*.{ts,tsx}`. All positive. No `!pattern`, `-` exclude, or any other negation operator is mentioned anywhere on the Memory page or the Skills page. VERIFIED.
---
## New findings not in the original report
1. **The Skills docs explicitly say `paths` "Uses the same format as path-specific rules"**, hyperlinking the Memory page anchor. This makes the report's reuse claim explicit (and slightly stronger than the report frames it — it is not just convention, it is a documented equivalence).
2. **#17204 is itself a bug about format parsing**: quoted strings and YAML lists in `paths:` are documented but reportedly broken in `.claude/rules/`, with only the undocumented `globs:` field and bare-unquoted `paths:` working reliably. If this same parsing bug applies to SKILL.md `paths`, the YAML-list form the docs recommend may not actually work in practice. The report does not surface this. **Worth investigating before relying on `paths: ["a", "b"]` in SKILL.md.**
3. The Skills docs also document a settings escape hatch — `disableSkillShellExecution: true` — that disables `` !`cmd` `` injection. If a managed environment sets this, workaround #2 in the report (branching skill body on `` !`ls` `` output) silently degrades. The report should flag this dependency.
@@ -0,0 +1,94 @@
# 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.
@@ -0,0 +1,145 @@
# Skill Engines Across Coding-Agent Harnesses
**Date:** 2026-05-11
**Question:** How do non-Claude coding agents handle "skills" / reusable instruction modules, and what frontmatter / activation conditions do they expose? Does the user's "boolean-condition flag-file activation" design port cross-tool, or is it Claude-only?
---
## 1. OpenAI Codex CLI
### What it does
Codex CLI is the closest cousin to Claude Code. It supports **AGENTS.md** as memory, plus a parallel set of extension surfaces: **Skills**, **Plugins**, **Hooks**, **Subagents**, **Rules**, and **MCP servers**. The skill system is explicitly modeled on the Agent Skills open standard, so SKILL.md authoring is near-identical to Claude's.
### What activation conditions it supports
- **AGENTS.md discovery** — hierarchical walk from repo root down to cwd, picking up at most one of `AGENTS.override.md`, `AGENTS.md`, or any name in `project_doc_fallback_filenames`. No frontmatter on AGENTS.md itself. ([Codex AGENTS.md guide](https://developers.openai.com/codex/guides/agents-md))
- **SKILL.md frontmatter** — required: `name`, `description`. Docs explicitly say: *"Do not include any other fields in YAML frontmatter."* UI metadata, invocation policy, and tool deps go in a sibling `agents/openai.yaml`. ([Codex Skills](https://developers.openai.com/codex/skills))
- **Path-glob activation for skills** — **NOT YET SHIPPED.** Tracked as feature request [openai/codex#19671](https://github.com/openai/codex/issues/19671), which proposes the same `paths:` frontmatter Claude already has.
- **Rules** — a `.rules` Starlark file under `rules/` directories (user / team / project layers). This is an execution-policy mechanism (used by `codex execpolicy check`), not a context-injection mechanism. ([Codex Rules](https://developers.openai.com/codex/rules))
- **InstructionsLoaded-equivalent hooks** — also not shipped; tracked as [openai/codex#21675](https://github.com/openai/codex/issues/21675) ("Codex Rules: per-session cache for additionalContext (Claude Code InstructionsLoaded parity)").
### Relevance to flag-file design
Codex has a real skill system and pre-loads `name` + `description` exactly like Claude, so description-driven activation ports cleanly. But path-scoped activation is a missing feature, and there is **no documented mechanism today for boolean conditions, file-presence triggers, or negation** on skill loading. A flag-file design would have to be encoded entirely inside the `description` string ("Use when …") and rely on the model to read it; Codex would not enforce it.
---
## 2. Google Gemini CLI
### What it does
Gemini CLI uses **GEMINI.md** as its memory file with a richer import system than AGENTS.md, plus an **Extensions** system that bundles MCP servers, prompts, custom commands, hooks, sub-agents, and (per the docs) "agent skills". ([Gemini extensions](https://google-gemini.github.io/gemini-cli/docs/extensions/))
### What activation conditions it supports
- **GEMINI.md hierarchical loading** — concatenates files found by walking the workspace tree; also discovers GEMINI.md files in directories tools touch, up to a trusted root. ([Gemini-md docs](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/gemini-md.md))
- **`@file.md` imports** — splits big GEMINI.md into smaller files, relative or absolute paths. Same syntax as Claude's `@path` imports.
- **Extension manifest (`gemini-extension.json`) fields** — `name`, `version`, `mcpServers`, `contextFileName`, `excludeTools`. **No activation conditions, no path scoping, no boolean triggers.** Extensions load globally on startup.
- **No frontmatter on GEMINI.md itself** documented.
### Relevance to flag-file design
Activation is effectively "always-on per directory" (via tree-walk) or "always-on per extension". There is **no conditional / flag-file mechanism**. The directory-discovery model is the only scoping primitive — you'd have to place a `GEMINI.md` in a specific subdir to scope advice to it.
---
## 3. Cursor / Windsurf / Aider / Continue
### Cursor (`.cursor/rules/*.mdc`)
Four activation modes via frontmatter ([Cursor rules guide](https://www.morphllm.com/cursor-rules-best-practices), [community reference](https://github.com/sanjeed5/awesome-cursor-rules-mdc/blob/main/cursor-rules-reference.md)):
- `alwaysApply: true` — every conversation
- `globs: <patterns>` — auto-attach on matching file open
- `description: …` — agent-requested (model decides from text)
- Manual `@rule-name`
Fields: `description`, `globs`, `alwaysApply`. **No boolean conditions, no negation, no file-presence triggers**, no path-negation. A proposed `mode` field for targeting Agent/Plan/Debug/Ask is still just a [feature request](https://forum.cursor.com/t/mode-frontmatter-field-in-mdc-rules-for-built-in-mode-targeting-agent-plan-debug-ask/157675).
### Windsurf (`.windsurf/rules`)
Explicit `trigger:` field with four enumerated values ([Windsurf rules guide](https://design.dev/guides/windsurf-rules/), [.windsurfrules guide](https://www.claudemdeditor.com/windsurfrules-guide)):
- `always_on`
- `manual`
- `model_decision` (description-driven)
- `glob` (with companion `globs:` field)
Hard char budget: 12,000 per workspace rule, 6,000 global. Rules exceeding budget are silently dropped. **No boolean conditions or flag-file triggers**; `trigger` is a single enum, not a composable predicate.
### Aider
A flat **CONVENTIONS.md** (any file you pass via `--read`). No frontmatter, no scoping, no skill system. Always-on or nothing. ([Aider conventions](https://aider.chat/docs/usage/conventions.html))
### Continue.dev
`.continue/rules/*.md` with YAML frontmatter supporting `name`, `globs`, `alwaysApply`, `description` — same triad as Cursor. ([Continue rules](https://docs.continue.dev/customize/deep-dives/rules)) AGENTS.md root-file support is still an [open issue](https://github.com/continuedev/continue/issues/6716).
### Bottom line for this tier
All four converge on the **same activation primitives**: always-on, manual, glob, or description-driven. **None** support boolean logic, negation, or file-existence predicates.
---
## 4. Claude Code: other activation mechanisms beyond `paths`
Citations all from [code.claude.com/docs/en/memory](https://code.claude.com/docs/en/memory), [hooks](https://code.claude.com/docs/en/hooks), and [skills](https://code.claude.com/docs/en/skills).
### What it does and what activates
- **`@path/to/file` imports in CLAUDE.md** — relative or absolute, recursive up to 5 hops. Imported files always load at session start. Not conditional.
- **`` !`<command>` `` dynamic context injection** — runs shell pre-render in skills (and the bash-and-skip-it custom command files). Output is inlined before Claude sees the skill. This **is** the closest native primitive to a flag-file: you can write `` !`test -f .reliquary/flag && echo active || echo inactive` `` and branch instructions on the result. Shell-gated, but real.
- **Path-tree CLAUDE.md walking** — ancestors load eagerly, descendants load lazily when files in them are read. The descendant case is effectively a file-presence trigger ("Claude opened a file under `foo/``foo/CLAUDE.md` loads").
- **`.claude/rules/*.md` with `paths:` frontmatter** — same glob mechanism as skills, but loads as rule rather than command. ([Path-specific rules](https://code.claude.com/docs/en/memory))
- **SKILL.md frontmatter beyond `paths`** — `name`, `description`, `when_to_use`, `argument-hint`, `arguments`, `disable-model-invocation`, `user-invocable`, `allowed-tools`, `model`, `effort`, `context: fork`, `agent`, `hooks`, `paths`, `shell`. Notably **no boolean condition field, no `requires:`, no `unless:`, no negation.**
- **`hooks.SessionStart` / `UserPromptSubmit` / `InstructionsLoaded` / 6 others** with `additionalContext` — a hook script can inspect the filesystem (`test -f`, `cat`, `git status`) and inject arbitrary context strings dynamically. This is the **most powerful conditional-activation primitive in Claude Code**: it runs deterministic shell logic and returns `additionalContext` which Claude reads as if it were a system message. ([Hooks docs](https://code.claude.com/docs/en/hooks))
- **`skillOverrides`** in `.claude/settings.local.json` — four states per skill (`on` / `name-only` / `user-invocable-only` / `off`). User-level toggle, not condition-based.
- **`skillListingBudgetFraction`** — fraction of context window (default 1%) used for skill descriptions; affects whether descriptions get truncated, not whether skills load.
- **`maxSkillDescriptionChars`** — per-entry cap (default 1,536).
- **`disableSkillShellExecution`** — disables `` !`cmd` `` injection org-wide (managed-settings escape hatch).
- **`claudeMdExcludes`** — glob-based negative filter, but at the memory-file level, not skill level.
### Relevance to flag-file design
Claude Code is the **only surveyed harness** that natively supports a boolean / file-presence activation primitive — and it does so through two channels:
1. **Inline `` !`shell` `` inside a skill** (skill is "listed" unconditionally, but its body becomes a no-op when the flag is absent).
2. **A SessionStart hook** that injects (or doesn't inject) a snippet of `additionalContext` based on `test -f .reliquary/flag`.
Neither is a frontmatter-declarative `requires-file:` field — those don't exist in any surveyed tool — but both are usable today, and the InstructionsLoaded hook in particular gives Claude something no other harness offers.
---
## Comparison table
| Tool | Memory file | Skill concept | Frontmatter activation fields | Boolean / file-presence triggers |
| --- | --- | --- | --- | --- |
| Claude Code | CLAUDE.md (+ `@imports`, tree-walk, `.claude/rules/`) | Yes (SKILL.md, full system) | `paths`, `description`, `when_to_use`, `disable-model-invocation`, `user-invocable`, `context`, `hooks`, +more | **Yes**, via `` !`cmd` `` injection and SessionStart/InstructionsLoaded hooks |
| Codex CLI | AGENTS.md (hierarchical, override files) | Yes (SKILL.md; only `name`/`description` allowed) | `name`, `description` (paths is requested, not shipped) | No |
| Gemini CLI | GEMINI.md (tree-walk, `@file` imports) | Via extensions (manifest-bundled) | `name`, `version`, `mcpServers`, `contextFileName`, `excludeTools` — extension-level only | No |
| Cursor | `.cursor/rules/*.mdc` | Rules (no separate skill) | `description`, `globs`, `alwaysApply` | No |
| Windsurf | `.windsurf/rules` | Rules (no separate skill) | `trigger` (enum: always_on / manual / model_decision / glob), `globs` | No |
| Aider | CONVENTIONS.md | None | None | No |
| Continue.dev | `.continue/rules/*.md` | Rules | `name`, `globs`, `alwaysApply`, `description` | No |
---
## Recommendation
**Of the surveyed harnesses, Claude Code is the only one that supports boolean-condition / flag-file activation today**, via two non-frontmatter routes: inline `` !`shell` `` inside a SKILL.md, and a SessionStart/InstructionsLoaded hook that conditionally returns `additionalContext`. No tool — including Claude — exposes a declarative `requires-file:` or boolean-predicate frontmatter field.
**Cross-tool portability of the user's flag-file design: limited.**
- Description-driven activation ("Use when project has a `.reliquary/` directory") works as a soft hint everywhere that has a skill/rule concept (Claude, Codex, partially Cursor/Windsurf/Continue), but the model decides — not the harness.
- Hard, harness-enforced flag-file gating is Claude-only. Codex would need either the proposed [#19671](https://github.com/openai/codex/issues/19671) (path globs) or [#21675](https://github.com/openai/codex/issues/21675) (InstructionsLoaded parity) to land before it could replicate the pattern.
- The portable lowest common denominator is: ship the skill, give it a tight `description` that names the flag file, and document a manual `/skill-name` invocation as the cross-tool fallback. Claude users additionally get a hook that auto-activates it.
If the user wants real enforcement now, lean on the Claude InstructionsLoaded hook + `disable-model-invocation: true` skills, and treat Codex/Gemini/Cursor as "best-effort, description-driven" targets.
---
## Sources
- [Claude Code memory docs](https://code.claude.com/docs/en/memory)
- [Claude Code hooks docs](https://code.claude.com/docs/en/hooks)
- [Claude Code skills docs](https://code.claude.com/docs/en/skills)
- [Codex AGENTS.md guide](https://developers.openai.com/codex/guides/agents-md)
- [Codex Skills](https://developers.openai.com/codex/skills)
- [Codex CLI features](https://developers.openai.com/codex/cli/features)
- [Codex Rules](https://developers.openai.com/codex/rules)
- [openai/codex#19671 — path globs for skills](https://github.com/openai/codex/issues/19671)
- [openai/codex#21675 — InstructionsLoaded parity](https://github.com/openai/codex/issues/21675)
- [Gemini-md docs](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/gemini-md.md)
- [Gemini extensions](https://google-gemini.github.io/gemini-cli/docs/extensions/)
- [Cursor mdc best practices (Morph)](https://www.morphllm.com/cursor-rules-best-practices)
- [Cursor mdc rules reference (community)](https://github.com/sanjeed5/awesome-cursor-rules-mdc/blob/main/cursor-rules-reference.md)
- [Cursor mode field feature request](https://forum.cursor.com/t/mode-frontmatter-field-in-mdc-rules-for-built-in-mode-targeting-agent-plan-debug-ask/157675)
- [Windsurf rules guide (design.dev)](https://design.dev/guides/windsurf-rules/)
- [.windsurfrules guide](https://www.claudemdeditor.com/windsurfrules-guide)
- [Aider conventions](https://aider.chat/docs/usage/conventions.html)
- [Continue.dev rules](https://docs.continue.dev/customize/deep-dives/rules)
- [continuedev/continue#6716 — AGENTS.md support](https://github.com/continuedev/continue/issues/6716)
@@ -0,0 +1,5 @@
Resolved. See:
- [`../reports/2026-05-11-17-skill-activation-mechanics.md`](../reports/2026-05-11-17-skill-activation-mechanics.md) — primary findings on Claude Code skill activation.
- [`../reports/2026-05-11-17-skill-activation-mechanics-verification.md`](../reports/2026-05-11-17-skill-activation-mechanics-verification.md) — independent citation-by-citation verification.
- [`../reports/2026-05-11-17-skill-engines-cross-tool.md`](../reports/2026-05-11-17-skill-engines-cross-tool.md) — comparative survey across Codex, Gemini CLI, Cursor, Windsurf, Aider, Continue, plus the non-`paths` Claude mechanisms (hooks, `` !`cmd` ``, `@imports`, `skillOverrides`, etc.).