
On March 31, Anthropic accidentally shipped a source map file in their Claude Code npm package — and for a brief window, the complete TypeScript source (512,000 lines across ~1,900 files) was publicly accessible. The community archived it before Anthropic could pull it down.
I spent a few days going through the built-in skills: simplify, batch, skillify, and a dozen others. Most of the community attention went to the hidden feature flags and the easter egg pet system. What caught my eye was less flashy: the way Anthropic’s engineers write their own skills differs from what the official docs teach.
Claude Code Skills has two official references — the Skills docs and the Agent Skills Best Practices guide. Both are worth reading. Neither prepares you for what the built-in skills actually look like.
This post distills 10 patterns that are in the source but not in the docs. Each one shows a ❌ typical doc-style approach vs ✅ the actual built-in skill approach. If you write SKILL.md files for Claude Code, these patterns change how you structure them.
1. Write Trigger Conditions in description/when_to_use, Not Just Feature Descriptions
The description and when_to_use fields are officially described as ways to help “Claude decide when to apply” the skill — which is true but vague. What the docs don’t spell out is that these fields need to work like a classifier: positive trigger conditions AND explicit exclusion conditions.
# ❌ Doc style — only describes the feature
description: "Help build apps with Claude API"
# ✅ Built-in skill style — clear trigger/no-trigger boundaries
description: >
Build apps with the Claude API or Anthropic SDK.
TRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`, or user asks to use Claude API.
DO NOT TRIGGER when: code imports `openai`/other AI SDK, general programming tasks.
# ❌ Vague when_to_use
when_to_use: "When the user wants to run recurring tasks"
# ✅ Built-in skill style — trigger phrase examples + exclusion conditions
when_to_use: >
When the user wants to set up a recurring task, poll for status, or run
something repeatedly (e.g. "check the deploy every 5 minutes", "keep running
/babysit-prs"). Do NOT invoke for one-off tasks.
Treat when_to_use as a classifier prompt — give the model concrete criteria to judge by, not just a description of what the skill does.
2. Every Step Needs Explicit Success Criteria
The Agent Skills guide mentions “checklists” but doesn’t emphasize what actually matters: every step needs an exit condition. Without one, models tend to move on before they’re finished, or skip steps they consider “obvious.”
# ❌ Doc style — only says what to do
### Step 1: Gather context
Read the relevant config files and understand the current state.
### Step 2: Make changes
Update the configuration based on user requirements.
# ✅ Built-in skill style — each step has a completion gate
### Step 1: Gather all memory layers
Read CLAUDE.md and CLAUDE.local.md from the project root.
**Success criteria**: You have the contents of all memory layers and can compare them.
### Step 2: Classify each entry
For each entry, determine the best destination.
**Success criteria**: Each entry has a proposed destination or is flagged as ambiguous.
Think of **Success criteria** as a gate: the model checks the condition before it’s allowed to move to the next step.
3. Large Skills Should Selectively Load Reference Docs, Not Inject Everything
Reference files are easy when you have two or three. With eight, scattered conditional-load instructions fall apart — the model has to track multiple if branches, and it’s easy to miss one.
Built-in skills solve this with a structured task → document routing table instead:
# ❌ Doc style — simple conditional loading
If you encounter an API error, read `references/api-errors.md`.
# ✅ Built-in skill style — structured task index
## Quick Task Reference
**Single text classification/summarization:**
→ Read `references/basic-api.md`
**Chat UI or streaming display:**
→ Read `references/basic-api.md` + `references/streaming.md`
**Function calling / tool use / agents:**
→ Read `references/basic-api.md` + `references/tool-use-concepts.md` + `references/tool-use.md`
**Error handling:**
→ Read `references/error-codes.md`
When you have more than 2-3 reference files, a routing table works better than scattered conditional instructions. The model matches the task type and loads exactly what it needs.
4. Use Tables for Decision Branches, Not Prose
Decision logic in prose is fragile. The model has to parse nested conditions from natural language, which means it’s susceptible to edge cases and missed branches.
# ❌ Prose-based decisions
If the entry is about project conventions that all contributors should follow,
put it in CLAUDE.md. If it's personal preferences for this user only, put it
in CLAUDE.local.md. If it's org-wide knowledge, put it in team memory.
# ✅ Tabular decisions
| Destination | What belongs there | Examples |
|--------------------|----------------------------------|----------------------------------|
| **CLAUDE.md** | Project conventions for all | "use bun not npm", "test: bun test" |
| **CLAUDE.local.md**| Personal instructions for you | "prefer concise responses" |
| **Team memory** | Org-wide cross-repo knowledge | "staging is at staging.internal" |
| **Stay in memory** | Temporary or uncertain notes | Session-specific observations |
Tables let the model match conditions like a lookup — far less prone to missed branches than natural language if-else.
5. Orchestrate Parallel Agents for Complex Tasks Instead of Single-Threading
The Claude Code docs mention context: fork for running in a sub-agent, but don’t show how to orchestrate multiple agents in parallel. For review and validation tasks, this is exactly what the built-in skills do.
# ❌ Single-threaded approach
## Steps
1. Review code for reuse opportunities
2. Review code for quality issues
3. Review code for efficiency problems
4. Fix all issues
# ✅ Parallel agent orchestration (actual simplify.ts pattern)
## Phase 2: Launch Three Review Agents in Parallel
Use the Agent tool to launch all three agents concurrently in a single message.
Pass each agent the full diff.
### Agent 1: Code Reuse Review
Search for existing utilities that could replace newly written code...
### Agent 2: Code Quality Review
Review for: redundant state, parameter sprawl, copy-paste, leaky abstractions...
### Agent 3: Efficiency Review
Review for: unnecessary work, missed concurrency, hot-path bloat, memory leaks...
## Phase 3: Fix Issues
Wait for all three agents to complete. Aggregate findings and fix each issue.
When a task has independent sub-dimensions (code review is a clean example: reuse, quality, and efficiency don’t depend on each other), splitting into parallel agents cuts wall-clock time significantly. The gain compounds when the dimensions are truly orthogonal.
6. Front-Load Input Validation Instead of Letting the Model Figure It Out
Neither official document mentions input validation in skills. The result is that skills written by the book tend to discover their own precondition failures mid-execution — after the model has already done work it now has to abandon.
For pure Markdown skills, prerequisite checks belong at the very top:
# ❌ No validation — model attempts execution then fails
---
name: batch
---
# Batch Skill
Break the work into independent units and spawn workers...
# ✅ Front-loaded validation
## Prerequisites — check BEFORE doing anything
1. Verify this is a git repository (`git rev-parse --git-dir`). If not,
tell the user: "This requires a git repo because it uses worktrees for isolation."
2. Verify the argument is not empty. If empty, show usage:
"Provide an instruction. Examples: /batch migrate from react to vue"
3. Only proceed if both checks pass.
“When NOT to execute” belongs at the top, not buried in step 4.
7. Progressive Interview Beats One-Shot Information Gathering
skillify.ts uses a 4-round interview pattern that neither official document describes. One-shot information gathering — asking the user to provide everything upfront — produces either incomplete answers or decision fatigue.
# ❌ One-shot information dump
Please provide: skill name, description, steps, arguments, execution mode,
save location, trigger conditions, and any gotchas.
# ✅ Progressive rounds
### Step 2: Interview the User
Use AskUserQuestion for ALL questions!
**Round 1: High level confirmation**
- Suggest a name and description. Ask to confirm or rename.
**Round 2: More details**
- Present the high-level steps as a numbered list.
- If the skill needs arguments, suggest them.
- Ask: inline or fork?
- Ask: save to this repo or personal?
**Round 3: Breaking down each step**
For each major step, ask:
- What does this step produce that later steps need?
- What proves this step succeeded?
- Should the user confirm before proceeding?
**Round 4: Final questions**
- Confirm trigger conditions and suggest trigger phrases.
IMPORTANT: Don't over-ask for simple processes!
The final line — “Don’t over-ask for simple processes!” — is as important as the rounds themselves. Without it, the model applies the full interview to cases where two questions would have been enough.
8. Worker/Sub-Task Prompts Must Be Fully Self-Contained
Forked agents can’t see the conversation that spawned them. This is the fact that built-in skills (particularly batch.ts) build around explicitly — and that neither official document mentions.
# ❌ Assumes worker knows the context
Spawn workers to implement each unit of the plan.
# ✅ Explicitly requires self-contained worker prompts
For each agent, the prompt must be fully self-contained. Include:
- The overall goal (the user's instruction)
- This unit's specific task (title, file list — copied verbatim from your plan)
- Any codebase conventions you discovered
- The e2e test recipe from your plan
- The worker instructions below, copied verbatim:
(full worker instruction template)
Your skill must explicitly instruct: “copy all needed information into each worker prompt.” Never say “based on previous findings” — the worker has no previous findings to reference.
9. Use Precise Patterns for allowed-tools, Not Blanket Permissions
The allowed-tools field is documented, but the docs give no guidance on how to write it well. Blanket permissions like Bash trigger confirmation prompts for every command; precise patterns suppress them for expected operations while preserving them for anything unexpected.
# ❌ Too broad
allowed-tools: [Bash, Read, Write, Edit]
# ✅ Least privilege + precise patterns
allowed-tools:
- Read
- Grep
- Glob
- Bash(git:*) # only git commands
- Bash(npm:*) # only npm commands
- Bash(mkdir:*) # only mkdir commands
Bash(pattern:*) is a prefix wildcard that only matches commands starting with that prefix. Use it to express exactly what your skill needs — nothing more.
10. A Practical Guide for Choosing fork vs inline
The Claude Code docs only say “set to fork to run in a sub-agent” with no selection guidance. The built-in skills follow a clear decision rule:
| Choose inline (default) | Choose fork |
|---|---|
| Need mid-process user interaction | Self-contained, no user input needed |
| Need to modify current conversation context (e.g., switch model) | Task is independent with its own completion criteria |
| Output needs further discussion in the conversation | Output is a final report/result |
| Example: skillify (multi-round interview) | Example: simplify (review + fix) |
The decision hinge: if your skill has “ask the user to confirm” steps anywhere, don’t use fork. In fork mode, the agent cannot interact with the user at all.
Summary
| # | Pattern | Doc Coverage | One-Line Rule |
|---|---|---|---|
| 1 | Bidirectional trigger conditions | Vaguely mentioned | when_to_use needs both “TRIGGER when” + “DO NOT TRIGGER when” |
| 2 | Per-step success criteria | Not mentioned | Add **Success criteria** to every step |
| 3 | Task-to-file routing table | Principle mentioned | Replace scattered conditional loads with a structured index |
| 4 | Tabular decision branches | Not mentioned | Use Markdown tables for multi-option decisions, not prose |
| 5 | Parallel agent orchestration | Not mentioned | Split review tasks into parallel agents in the prompt |
| 6 | Front-loaded validation | Not mentioned | Write Prerequisites checks at the top — stop early on failure |
| 7 | Progressive interview rounds | Not mentioned | Gather complex requirements in rounds, add “Don’t over-ask” |
| 8 | Self-contained worker prompts | Not mentioned | Forked agents can’t see chat history — copy everything in |
| 9 | Least-privilege tool patterns | Field listed only | Use Bash(git:*) instead of blanket Bash |
| 10 | fork vs inline selection | Briefly mentioned | Need user interaction → inline; self-contained → fork |