Skill Engine
Tools give Claude new capabilities. Skills give Claude new knowledge. A tool executes an action. A skill changes how Claude thinks about a problem.
Skills vs Tools
| Tool | Skill | |
|---|---|---|
| Form | Registered function with schema | Markdown template |
| Effect | Changes what the agent CAN do | Changes what the agent KNOWS |
| Execution | Runs code, returns result | Injected as text into conversation |
| Example | Bash runs a shell command | /verify injects: “Your job is not to confirm — it’s to try to break it.” |
| Persistence | Stateless per call | Active for duration of invocation scope |
The /verify skill doesn’t run any verification code. It injects a structured prompt that reframes the agent’s role. Claude then uses its existing tools (Bash, FileRead, etc.) with entirely different instructions. Same tools, different behavior.
5 Sources
| Source | Location | Scope | Priority |
|---|---|---|---|
| Bundled | Compiled into CLI | All sessions | Lowest |
| User | ~/.claude/skills/ | All projects | Low |
| Project | .claude/skills/ | Current project | Medium |
| MCP | Remote MCP servers | Session | High |
| Managed | Enterprise policy path | Organization | Highest |
When the same skill name appears in multiple sources, the higher-priority source wins. Project skills override user skills. Enterprise policy overrides everything.
16 bundled skills ship with the CLI: 11 always-on, 5 feature-gated (enabled via config or flags).
3 Discovery Modes
Monorepo pattern: A skill at packages/auth/.claude/skills/auth-specialist.md only loads when the agent opens files inside packages/auth/. A skill at packages/payments/.claude/skills/ stays hidden until you work in that package. Each package carries its own expertise without polluting the global context.
SKILL.md Anatomy
---name: migration-reviewerdescription: > Reviews database migrations for safety, reversibility, and naming convention compliance.when_to_use: > When the agent opens or creates files matching **/migrations/**paths: - "**/migrations/**" - "**/db/migrate/**"allowed-tools: - FileRead - Grep - Basharguments: - name: dialect description: "SQL dialect: postgres | mysql | sqlite" default: postgrescontext: inline # inline | forkhooks: PostToolUse: "npm run lint:migrations"---
You are a database migration specialist reviewing for the ${dialect} dialect.
Current branch: `!git branch --show-current`Pending migrations: `!ls migrations/ | grep -v _applied`
Before reviewing any migration:1. Check filename follows pattern: YYYYMMDD_HHMMSS_description.sql2. Verify every destructive operation has a corresponding rollback3. Confirm indexes are created CONCURRENTLY to avoid table locksKey frontmatter fields:
| Field | Purpose |
|---|---|
paths | Gitignore-style patterns for conditional activation |
allowed-tools | Restrict which tools are available during this skill |
arguments | Template variables substituted into the markdown body |
context: inline | Inject into current conversation |
context: fork | Spawn a subagent with this skill as its system prompt |
hooks | Per-skill lifecycle events (e.g. auto-lint after every write) |
Shell-in-Prompt
Skills can embed inline shell commands using backtick syntax in the markdown body. Before injection, the system executes them and substitutes the output:
In SKILL.md: Current branch: `!git branch --show-current` Pending migrations: `!ls migrations/ | grep "\.sql$"`
Injected into conversation: Current branch: main Pending migrations: 20240301_120000_add_users.sql 20240315_093000_add_sessions.sqlThe agent receives live context without having to run commands itself — dynamic, zero-cost context injection at skill load time.
Security Boundaries
MCP skills cannot execute shell commands. The !command syntax is blocked for any skill sourced from a remote MCP server. Remote/untrusted code cannot reach the local shell — only bundled, user, and project skills can use shell-in-prompt.
Gitignore protection. Before loading any skill directory, the system calls isPathGitignored(). Skills inside node_modules/ or any .gitignore-d path are silently skipped. This prevents supply-chain injection: an npm package cannot ship malicious .claude/skills/ that auto-load into your session.
Protected: node_modules/**/.claude/skills/ ← gitignored, skippedProtected: .git/**/.claude/skills/ ← gitignored, skippedAllowed: packages/auth/.claude/skills/ ← not gitignored, loadedAllowed: ~/.claude/skills/ ← user-owned, loadedMagic Docs
Claude Code includes an auto-documentation system: files marked with # MAGIC DOC: are automatically updated by a background agent as your code evolves. The agent is sandboxed to file editing only — no shell, no network access.
Full details → Hidden Features
Why This Matters to You
- How to write better SKILL.md → use
pathsfor targeted activation so skills only appear when relevant; useallowed-toolsto sandbox what the skill can do - How monorepo skills work → directory walk discovers
.claude/skills/in ancestor directories; deeper = higher priority; each package defines its own expertise - Why MCP skills can’t run shell commands → remote untrusted code has no shell access; only local skills (bundled, user, project) can use
!commandsyntax - How shell-in-prompt works → backtick commands execute at skill load time, output substituted before injection; agent gets live context for free
- How to prevent unwanted skill loading → add the directory to
.gitignore; the system respects it automatically
See also: Plugin Engine — Multi-Agent System — Tool Orchestration