Adds 3 new topic files (ai-parallel-agents, api-integration, python-patterns) and extends 21 existing topic files with new gotchas and patterns surfaced from memory across tracked projects. Index updated accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
107 lines
8.9 KiB
Markdown
107 lines
8.9 KiB
Markdown
# Claude Code Skills
|
|
|
|
## Skill Structure
|
|
|
|
- Each skill lives in `skills/<skill-name>/SKILL.md`
|
|
- Skills should be project-agnostic where possible — use dynamic context injection to adapt
|
|
- After adding a new skill, run the install script to register it
|
|
- Skills only useful for one project should live in that project's `.claude/skills/` instead
|
|
|
|
## Authoring Guidelines
|
|
|
|
- **Inline by default** — only use `context: fork` if the skill genuinely doesn't need conversation history
|
|
- **Pre-fetch context** with `!`command`` injection to reduce tool calls during execution
|
|
- **Restrict tools** with `allowed-tools` to the minimum needed — reduces permission prompts
|
|
- **Use $ARGUMENTS** for user input, `$0`, `$1` etc. for positional args
|
|
- Dynamic commands in `!`command`` run at skill load time, not during Claude's execution
|
|
|
|
## Portable Path Resolution
|
|
|
|
- **Use `CLAUDE_PROJECT_ROOT` env var** for cross-project path references in `!`command`` blocks. Hardcoded absolute paths (e.g., `~/dev/claude/...`) are user-specific. Relative paths (`../`) break depending on CWD and can trigger sandbox violations when they resolve outside allowed directories.
|
|
- **Add a detection fallback.** Include a "Step 0" in skill instructions that detects the project root by walking up the directory tree to find the highest `CLAUDE.md` if the env var isn't set. This makes skills work even without prior setup.
|
|
- **Keep config paths relative to the root.** Settings files should use paths relative to `CLAUDE_PROJECT_ROOT` (e.g., `projects_dir: projects`) rather than absolute paths, so they're portable across machines.
|
|
|
|
## Skill Discovery Timing
|
|
|
|
- **Skills are discovered at session start, not dynamically.** Creating or symlink a new skill mid-session requires restarting Claude Code to use it as a slash command.
|
|
- **Broken symlinks cause silent failures under `set -e`.** `readlink -f` on a broken symlink returns empty string. The install script should validate symlinks and remove stale ones.
|
|
|
|
## `!`command`` Gotchas
|
|
|
|
- **No `$()` command substitution** — the permission checker rejects commands containing `$()`
|
|
- **No complex shell pipelines relying on subshells** — keep commands simple and self-contained
|
|
- **`allowed-tools` patterns must match the command binary** — each binary used in `!`command`` blocks needs its own pattern
|
|
- **Prefer specific tool patterns over broad ones** — `Bash(git log *)` is safer than `Bash(git *)`
|
|
- **Fallback to tool instructions for dynamic paths** — if a command needs `$ARGUMENTS` to compute a path, use a plain-text instruction telling Claude to use the Read tool instead
|
|
- **Env var expansion works** — `${CLAUDE_PROJECT_ROOT}` expands in `!`command`` blocks because they run as shell commands. This is the recommended pattern for portable cross-project paths.
|
|
|
|
## Non-ASCII in YAML Frontmatter
|
|
|
|
Skills with em dashes (`—`), smart quotes (`"`), or other non-ASCII characters in the YAML frontmatter `description` field fail to load silently — the skill appears as "Unknown skill" with no error message. The markdown body below the frontmatter can contain any characters.
|
|
|
|
AI models commonly generate em dashes instead of regular dashes. Always validate skill files (e.g., with `cat -A` or a dedicated validator) before committing.
|
|
|
|
## Profile-Independent Skills Directories
|
|
|
|
Each Claude Code profile maintains a completely independent skills directory. Skills installed in one profile (e.g., default) are unavailable in other profiles (e.g., `.claude-octopus`). Install scripts must use the profile-aware config directory path rather than hardcoded paths like `~/.claude/skills/`.
|
|
|
|
## Research Failure History Before Building Validators
|
|
|
|
When building a tool that detects known problems (like a linter rule or a validator), research all historical failures first — session logs, git commit history, issue trackers. Documentation alone misses non-obvious failure patterns. The upfront research investment produces comprehensive coverage that incremental discovery cannot match.
|
|
|
|
## Task Decomposition for Independent Agents
|
|
|
|
When breaking work into tasks for independent agents (container-based or otherwise):
|
|
- **Task prompts must be fully self-contained** — agents have no conversation history from the decomposer
|
|
- **Include explicit "read these files first" instructions** in each task prompt
|
|
- **Balance granularity** — over-decomposing creates merge overhead; under-decomposing wastes parallelism potential
|
|
- **Scope each task to one deliverable** with clear reads (inputs) and writes (outputs) to minimise conflicts
|
|
- **Use 3+ parallel research agents before architecture decisions.** Survey competing tools, best practices, and user patterns in parallel before committing to a design. Breadth of input prevents tunnel vision during planning.
|
|
|
|
## Make Review Skills Read-Only
|
|
|
|
Skills that review artifacts (plans, specs, designs) should be read-only — restrict allowed-tools to Read, Glob, Grep, and safe Bash commands. Review output informs the human rather than auto-editing, which avoids unintended changes and reduces permission prompts. Load best-practice context upfront — better to load too much reference material than to miss a relevant check.
|
|
|
|
## Separate Formatter Exit Codes from Hook Exit Codes
|
|
|
|
When integrating formatters with Claude Code hooks, keep formatter scripts and hook dispatch logic separate. Formatter scripts exit 0 (clean) or 1 (lint errors). The dispatch hook decides the final exit code semantically (e.g., exit 2 for PostToolUse feedback). This separation means the same formatter scripts work for both PostToolUse hooks and pre-commit hooks without modification.
|
|
|
|
## Pre-fetching Bounded Metadata vs. Unbounded Content
|
|
|
|
When a skill needs to examine large external artifacts (transcripts, logs, dumps), have a helper script pre-gather **metadata only** (a small JSON list: paths, sizes, headers) at skill-load time via `!`command``. Delegate the actual content extraction to a subagent invoked from the skill's instructions.
|
|
|
|
This keeps the main conversation's context small — the skill sees a compact index rather than megabytes of raw content — and lets each step pick the cheapest/strongest model for the job (metadata triage with Haiku, deep extraction with Sonnet). Never pre-fetch unbounded content via `!`command``; it bloats the system prompt and often blows past context limits.
|
|
|
|
## Shell Wrappers to Work Around `!`command`` Restrictions
|
|
|
|
When a skill needs dynamic values like `$(pwd)` in its pre-fetch command, write a thin shell wrapper script that does the substitution internally and expose the wrapper in `!`command``. The Claude Code permission checker rejects `$()` inside bang commands (see `!`command`` Gotchas above), but a wrapper invoked as a plain binary is fine.
|
|
|
|
Document the wrapper's reason-for-existence in a comment at the top of the script so it can be removed if the `$()` restriction ever lifts. Keep wrappers minimal — one responsibility each — so the indirection doesn't obscure what the skill is actually doing.
|
|
|
|
## Model Selection for Subagents by Task Type
|
|
|
|
When a skill spawns a subagent for a subtask, pick the model by cognitive demand:
|
|
|
|
| Task type | Model |
|
|
|---|---|
|
|
| Deterministic extraction, reformatting, metadata triage | Haiku |
|
|
| Judgment required — detecting backtracking, gotchas, intent | Sonnet |
|
|
| Planning, architecture, cross-file synthesis | Opus |
|
|
|
|
Document the rationale in the skill (a comment near the subagent invocation is enough) so future edits don't silently downgrade quality by picking a cheaper model without revisiting whether the task actually fits it.
|
|
|
|
## Subagent Path Discipline
|
|
|
|
Subagents inherit no cwd context from the parent skill — they start in whatever working directory the harness gives them, which is rarely where the parent was invoked. When a subagent writes output files, **pass absolute paths in its prompt** and never rely on relative paths resolving the way the parent expects.
|
|
|
|
Verify on the first real run that files land where intended; a subagent writing to a surprise cwd often fails silently (the parent looks for the file, doesn't find it, falls through to a default). `CLAUDE_PROJECT_ROOT` (see Portable Path Resolution above) is the canonical anchor — compute absolute output paths from it before handing them to the subagent.
|
|
|
|
## Separate Skill-Helper Scripts from General Scripts
|
|
|
|
Not every script in a repo is a skill helper. Maintain an explicit allowlist (e.g., a `SKILL_HELPERS` array in the installer) of scripts that get symlinked into the profile's skills-reachable dir (`$CLAUDE_CONFIG_DIR/scripts/`). Other scripts stay callable only by absolute repo path.
|
|
|
|
**Key points:**
|
|
- **Symlinks, not copies.** Edits to the repo go live immediately without reinstalling.
|
|
- **Hooks follow the same installer pattern** via their own allowlist loop — don't conflate hooks with general skill helpers.
|
|
- **Explicit allowlist beats glob.** Auto-symlinking every script means new unrelated scripts silently become skill-reachable, which is a permission-scope surprise.
|