mirror of
https://github.com/mattpocock/skills.git
synced 2026-09-13 02:48:06 +07:00
Five skills (to-spec, wayfinder, to-tickets, triage, code-review) told the agent to call the Skill tool on setup-matt-pocock-skills as a missing-config precondition. It's user-invoked, so per .agents/invocation.md no other skill — user- or model-invoked — can ever reach it that way. PR #878 turned the old soft "/skill"-style prose into a literal "Call the Skill tool with ..." instruction without checking invocation type, which made this fire more reliably in the wrong direction. Reworded all five as instructions to tell the human to run it instead. diagnosing-bugs had the same problem handing its post-mortem off to improve-codebase-architecture, with no human anywhere in that loop to catch the failed call. Removed the hand-off outright rather than softening it, since it rarely fired in practice; Phase 6 is now "Cleanup" only. Added a carve-out to .agents/invocation.md's "Dependencies between them" section — the section PR #878 introduced — so future "call the Skill tool" instructions can't repeat this against a user-invoked target. Fixes #453.
27 lines
3.8 KiB
Markdown
27 lines
3.8 KiB
Markdown
# Model-invoked vs user-invoked
|
|
|
|
Every `SKILL.md` in this repo is a skill. The one axis that splits them is **invocation** — who can reach it:
|
|
|
|
- **User-invoked** — reachable **only by the human typing its name**. Set `disable-model-invocation: true` in the frontmatter (Claude Code) and `policy.allow_implicit_invocation: false` in `agents/openai.yaml` (Codex). The `description` is **human-facing**: a one-line summary read by a person browsing slash-commands. Strip trigger lists ("Use when the user says…").
|
|
- **Model-invoked** — reachable by **model or user**. The default: omit `disable-model-invocation` and the `policy` block from `agents/openai.yaml`. The `description` is **model-facing** and keeps rich trigger phrasing ("Use when the user wants…, mentions…, asks for…") so auto-invocation fires. The test for whether a skill should stay model-invoked: _could the model usefully reach for this autonomously?_ (Reuse is the reason to extract a skill, not the test.)
|
|
|
|
Each harness excludes a user-invoked skill from the model's reach in its own way, so nothing but the human can fire it — no other skill can. A user-invoked skill may invoke model-invoked skills, but it can never reach another user-invoked skill.
|
|
|
|
Every skill also carries an `agents/openai.yaml` beside its `SKILL.md`. It holds Codex UI metadata — `interface.display_name` and `interface.short_description` for the skill picker — and, for user-invoked skills, the `policy.allow_implicit_invocation: false` that pairs with `disable-model-invocation`. Keep the two in sync: a skill is user-invoked in both harnesses or neither.
|
|
|
|
Bucket `README.md`s and the top-level `README.md` group entries into **User-invoked** and **Model-invoked**.
|
|
|
|
## Dependencies between them
|
|
|
|
Dependencies are expressed as an explicit instruction to **call the Skill tool** with the named skill (`Call the Skill tool with "grilling"`), not deep `../other-skill/FILE.md` cross-references, and not a bare `/skill`-style mention left for the model to interpret. Naming the tool is what gets it fired: most harnesses expose skill invocation as a tool the model calls, and spelling that out gets a higher hit rate than dropping a `/name` into prose and hoping it's read as a command. Dropping the leading `/` also keeps this harness-neutral rather than less — a skill name on its own carries no assumption about which harness's trigger syntax it belongs to. Shared reference docs live inside the skill that owns them; other skills reach that material by calling the Skill tool with it, not by linking across folders.
|
|
|
|
This is about **operative** instructions — a skill's own steps telling the agent to go run another skill right now. Router prose that just names skills for a human to pick from (`ask-matt`, bucket `README.md`s) isn't invoking anything, so it keeps `/skill`-style names as plain labels.
|
|
|
|
The Skill tool takes one skill per call. A step that needs two skills is two calls, not one call with two names — say so (`Call the Skill tool twice, for "grilling" and "domain-modeling"`), not "call it with X and Y," which reads as a single call taking both.
|
|
|
|
This whole convention only holds when the named skill is **model-invoked**. A user-invoked skill can never be reached this way, full stop — per the invariant above, no other skill can call it, including by naming it to the Skill tool. When a step's precondition is a user-invoked skill (e.g. `setup-matt-pocock-skills`), phrase it as an instruction for the human to act on — "tell the user to run `/setup-matt-pocock-skills`" — never as a Skill tool call.
|
|
|
|
## Passive vs active domain work
|
|
|
|
Merely _reading_ `CONTEXT.md` for vocabulary is a one-line prose pointer, not the `domain-modeling` skill. Only the active build/sharpen discipline (challenge terms, edge-case scenarios, write ADRs, update `CONTEXT.md` inline) is `domain-modeling`.
|