| name | write-skill |
| description | Create or improve reusable agent skills. Use when the user wants to write a new skill, refactor an existing one, or review skill quality. Covers frontmatter, structure, invocation control, content lifecycle, and the unified dotfiles skills workflow. |
| disable-model-invocation | true |
| argument-hint | ["skill-name"] |
| allowed-tools | Bash(ls *) Read Write Edit Glob Grep |
Write Skill
You are writing or improving a reusable agent skill. Follow this guide precisely.
File location
All user-authored skills live in one canonical dotfiles directory and are linked into each harness:
Source: ~/.dotfiles/agent/skills/<skill-name>/SKILL.md
Claude: ~/.claude/skills -> ~/.dotfiles/agent/skills
Pi: ~/.pi/agent/skills -> ~/.dotfiles/agent/skills
Codex: ~/.codex/skills/<skill-name> -> ~/.dotfiles/agent/skills/<skill-name>
Never create skills directly in a harness-specific directory. Always write to ~/.dotfiles/agent/skills/<skill-name>/SKILL.md, then run ~/.dotfiles/agent/scripts/sync-agent-config.sh to refresh harness links.
If the skill needs supporting files (templates, examples, scripts), place them alongside SKILL.md in the same directory:
~/.dotfiles/agent/skills/<skill-name>/
SKILL.md # Required: main instructions
template.md # Optional: template for Claude to fill
examples/ # Optional: example outputs
scripts/ # Optional: helper scripts
Reference supporting files from SKILL.md so harnesses know they exist. Prefer relative links such as references/API.md; use harness-specific variables only when the skill truly cannot be portable.
Step 1: Determine intent
If $ARGUMENTS is provided, use it as the skill name.
Ask the user only when the answers cannot be inferred safely. Skip questions already answered:
- What does this skill do? One sentence.
- Who invokes it? Determines invocation mode:
- Both user and model (default) -- no special frontmatter
- User only (
disable-model-invocation: true) -- for workflows with side effects
- Model only (
user-invocable: false) -- for background domain knowledge
- Does it need arguments? If yes, what are they?
- Should it run in a forked context? (
context: fork) -- for isolated tasks that should not see conversation history.
Step 2: Write the frontmatter
The YAML frontmatter block controls routing. Use the smallest portable header that works across harnesses:
---
name: my-skill
description: Specific task plus trigger conditions.
---
Use extra fields only when a specific harness supports them and the skill needs them. Unknown fields may be ignored by other harnesses.
Common extended fields:
---
name: my-skill
description: >-
One-paragraph description of what
this skill does and when to use it.
when_to_use: >-
Additional trigger conditions.
argument-hint: [arg1] [arg2]
arguments: arg1 arg2
disable-model-invocation: true
user-invocable: false
allowed-tools: Bash(git *) Read Edit
model: sonnet
effort: high
context: fork
agent: Explore
paths: "src/**/*.py, tests/**"
shell: bash
---
Frontmatter rules
name: Must match the directory name. Use lowercase letters, numbers, and hyphens only.
description: This is the most important field. Harnesses use it to decide when to load the skill. Front-load the primary use case and trigger conditions.
disable-model-invocation: true: Use for anything with side effects (deploys, commits, sends messages, creates PRs, modifies external systems). Prevents Claude from invoking without explicit user request.
user-invocable: false: Use for domain knowledge that Claude should auto-load when relevant. The user never needs to type /skill-name for these.
allowed-tools: Pre-approve tools to avoid repeated permission prompts during the skill. Only grant what the skill actually needs. Use glob patterns for Bash: Bash(git *), Bash(npm *).
- Never combine
disable-model-invocation: true with user-invocable: false -- they are mutually exclusive intents.
- Portable baseline: Pi requires
name and description; Claude and Codex also route best with explicit, specific descriptions.
Invocation control summary
| Frontmatter combo | User invokes | Claude invokes | Description in context |
|---|
| (default) | Yes | Yes | Yes |
disable-model-invocation: true | Yes | No | No |
user-invocable: false | No | Yes | Yes |
Step 3: Write the content body
The markdown body after the frontmatter is what the harness follows when the skill is invoked. Apply these principles:
Structure
- Start with a one-line role statement: "You are doing X." Sets Claude's frame.
- Use numbered steps for procedural skills. Use sections for reference skills.
- Keep SKILL.md under 500 lines. Move reference material to separate files in the skill directory.
- Be imperative: "Run X", "Check Y", "Ask the user Z". Not "You could run X" or "Consider checking Y".
- Specify exit conditions: What does "done" look like? What should Claude output when finished?
Harness-specific features
Claude supports variables and dynamic context injection. Treat these as harness-specific, not portable defaults.
Use these in the markdown body:
| Variable | Description |
|---|
$ARGUMENTS | All arguments passed when invoking |
$ARGUMENTS[N] | Specific argument by 0-based index |
$N | Shorthand for $ARGUMENTS[N] |
$name | Named arg from arguments frontmatter |
${CLAUDE_SKILL_DIR} | Directory containing this SKILL.md |
${CLAUDE_SESSION_ID} | Current session ID |
${CLAUDE_EFFORT} | Current effort level |
Dynamic context injection
Run shell commands before skill content loads using !`command` syntax:
## Current branch info
!`git branch --show-current`
!`git log --oneline -5`
Multi-line version:
```!
gh pr list --state open --limit 5
```
Output replaces the placeholder before Claude sees the skill.
Content lifecycle awareness
- Invoked skill content stays in context for the rest of the session.
- After auto-compaction, the first 5,000 tokens of each skill are preserved.
- Combined budget for all re-attached skills: 25,000 tokens.
- Most recently invoked skills get priority.
- Implication: Put the most critical instructions in the first 5,000 tokens. Put reference tables and examples later -- they may be trimmed.
Step 4: Quality checklist
Before saving, verify:
Step 5: Save and verify
- Write the SKILL.md to
~/.dotfiles/agent/skills/<skill-name>/SKILL.md.
- Refresh harness links:
~/.dotfiles/agent/scripts/sync-agent-config.sh.
- Verify the skill is live:
ls -la ~/.claude/skills/<skill-name>/SKILL.md
ls -la ~/.pi/agent/skills/<skill-name>/SKILL.md
ls -la ~/.codex/skills/<skill-name>/SKILL.md
- Show the user the final file and confirm it is linked.
Common anti-patterns to avoid
- Wall-of-text descriptions: The description field is for Claude's routing, not documentation. Keep it to 2-3 sentences max.
- Mixing invocation modes: A skill should not be both background knowledge and an interactive workflow.
- Putting facts in skills: Facts about the codebase belong in CLAUDE.md. Skills are for procedures, checklists, and reference material that load on-demand.
- Duplicating tool functionality: Don't write a skill that wraps a single tool call. Skills add value when they encode multi-step procedures or domain knowledge.
- Forgetting
allowed-tools: If the skill uses tools, pre-approve them. Otherwise the user gets prompted repeatedly, which defeats the purpose.
- Overscoping: One skill, one job. If you need to combine "create component" and "write tests", make two skills.
Skill vs Other Mechanisms
- Skill: repeatable workflow, domain playbook, or reference knowledge.
- Extension/tool: new tools, slash commands, UI behavior, event hooks, or stateful behavior.
- Agent/persona: subagent role, tool allowlist, or delegation prompt.
- Project docs: persistent repo facts, architecture, and conventions.