Files
best-practices/skills-development.md
Paul O'Reilly 3efe153ca1 Populate best practices from claude-foundations
Migrates 20 topic files from claude-foundations/best-practices/ to this
standalone repo. Adds BESTPRACTICES.md index, CLAUDE.md conventions, and
updated README.md. Container agents clone this repo to /best-practices.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:46:13 +13:00

4.5 KiB

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 onesBash(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