5.8 KiB
Skill mechanics
The skill-specific branch of writing-for-agents: what changes when the document is a
skill. Everything else about writing it is the universal reference in SKILL.md.
Where a skill lives
A personal skill lives once, at ~/.agents/skills/<name>/, with Claude Code pointed at it by a
symlink:
ln -s ../../.agents/skills/<name> ~/.claude/skills/<name>
~/.agents/skills/ is the cross-runtime home: Codex, Copilot CLI, and Gemini CLI read it directly.
Writing a second copy into ~/.claude/skills/ gives you two files that drift, and the drift is
silent because each harness only ever reads its own. One home, one symlink per harness that needs it.
A skill that only makes sense inside one repo lives once at
<repo>/.agents/skills/<name>/. Point Claude Code at that source with a
<repo>/.claude/skills/<name> symlink.
Frontmatter
---
name: writing-for-agents # letters, numbers, hyphens only; matches the directory name
description: Use when ... # the skill's top-level context pointer
disable-model-invocation: true # Claude Code only; omit unless the skill is user-invoked
---
The whole frontmatter block caps at 1024 characters, so the description is the budget. Write it in the third person: it is injected into the system prompt, not read as a reply.
The description is a context pointer, so every pointer rule in SKILL.md applies to it in full: name
the material and its trigger branches, front-load the leading word, one trigger per branch, and never
summarize the process.
Codex metadata
Each skill also carries agents/openai.yaml beside its SKILL.md, holding Codex's skill-picker
metadata and, for a user-invoked skill, its half of the invocation setting:
interface:
display_name: Writing for Agents
short_description: Reference for writing skills, AGENTS.md/CLAUDE.md, and pointed-at docs.
policy:
allow_implicit_invocation: false # user-invoked only; omit for model-invoked skills
Invocation is set in two places, and they must agree. disable-model-invocation: true governs
Claude Code; policy.allow_implicit_invocation: false governs Codex. A skill is user-invoked in both
harnesses or neither. Setting only the Claude Code half leaves the skill quietly model-invocable in
Codex, which is the same drift as two copies of the file, one field wide.
Invocation
Two choices, trading the two loads:
| Model-invoked | User-invoked | |
|---|---|---|
| Who can fire it | The agent, you, or another skill | Only you, typing /name |
| Claude Code | Omit disable-model-invocation |
disable-model-invocation: true |
| Codex | Omit the policy block |
policy.allow_implicit_invocation: false |
| Description | Model-facing, carries trigger branches | Human-facing one-liner, triggers stripped |
| Cost | Permanent context load | Zero context load, paid in cognitive load |
Model-invocation always includes your reach: a description only ever adds agent discovery, it never removes yours. So the question is only whether the agent must reach the skill on its own, or another skill must. If it only ever fires by hand, make it user-invoked and pay no context load.
A model-invoked skill whose content is all reference is also the one home for shared reference: several skills can invoke it, so the material lives in one place.
Shared reference that two user-invoked skills both need can live in neither, since with no descriptions neither can fire the other. Push it to a plain file outside the skill system and point at it from both.
Calling one skill from another
Write the dependency as an explicit instruction to call the tool, not a bare slash-name left for the model to interpret:
Call the Skill tool with "grilling".
The tool takes one skill per call. A step needing two is two calls, and saying "call it with X and Y" reads as a single call taking both. Say instead:
Call the Skill tool twice, for "grilling" and "domain-modeling".
This only works on model-invoked skills. A user-invoked skill can never be reached this way. When
a step's precondition is a user-invoked skill, phrase it as an instruction for the human: "tell the
user to run /ticket", never as a tool call.
Router prose that just names skills for a human to pick from is not invoking anything, so it keeps
/name labels as plain text.
Splitting by invocation
The invocation cut, alongside the branch and sequence cuts in SKILL.md: split off a model-invoked
skill when you have a distinct leading word that should trigger it on its own, a word you actually
use in your prompts, or when another skill must reach it. You pay context load for the new
always-loaded description, so that independent reach has to be worth it.
Router skills
When user-invoked skills multiply past what you can remember, that piled-up cognitive load is cured by a router skill: one user-invoked skill naming the others and when to reach for each, so you have one name to remember instead of many. It can only hint, never fire them, since user-invoked skills have no description for anything but you to reach.
Write the router when you notice yourself forgetting a skill exists, not before. A router over three skills is furniture.
Done when
- The skill exists once under
~/.agents/skills/, with a symlink from~/.claude/skills/. namematches the directory and uses only letters, numbers, and hyphens.- The description names the material and its triggers, in the third person, under the 1024-character frontmatter cap.
- The invocation choice is deliberate: model-invoked because the agent or another skill must reach it, user-invoked otherwise.
- The invocation choice is written in both harnesses' fields, or in neither.
- Every cross-skill dependency is a named Skill tool call to a model-invoked skill, or an instruction for the human where the target is user-invoked.