I typed the same instruction three times in a single week. "Write tables with HTML tags." "Japanese and English versions always ship as a pair." "Run the check scripts before you push."
Halfway through the third one, my hands stopped. Claude wasn't the problem. The way I was working had hit a ceiling, and I was papering over it by repeating myself.
Claude Code mastery is usually laid out as five levels: Raw Prompting → CLAUDE.md → Skills → Hooks → Orchestration. As an indie developer running apps alongside four sites, I retraced those levels deliberately to see where I actually stood.
What I found: the steps are not equal in height. Some I cleared overnight. Others held me for months.
Levels 1 and 2: From Prompting to CLAUDE.md — a Low First Step
Level 1, Raw Prompting, is exactly what it sounds like: open Claude Code, type, get results. For a one-off fix or a quick "does this even work" check, it's plenty. There's no prize for climbing higher than you need to.
The ceiling signal here was easy to spot: you're explaining the same context every single time. That's the cue for Level 2.
Level 2 means dropping a CLAUDE.md in your project root and writing down your context and decision criteria. And here's something I had wrong.
You'll see it said that CLAUDE.md caps out at 200 lines. In practice, I never hit a hard line limit. My workspace CLAUDE.md swelled to 113 KB at one point. It still loaded fine.
The real problem was elsewhere. The longer it gets, the less reliably the rules near the bottom get followed. Nothing breaks at a threshold — it just quietly thins out. That gradual fade was the tricky part.
The fix was simple. I moved historical notes and past diagnoses into a separate archive file and kept only the rules currently in force, trimming down to 31 KB. Not to satisfy a line count, but to keep attention from diluting. Once I reframed it that way, instruction-following stabilized.
# Project Overview
Next.js 16 (App Router) + TypeScript + Cloudflare Workers
## Criteria when you're unsure
1. Every article ships as a JA + EN pair (a missing pair means a 404 on language switch)
2. Write tables as HTML <table> (remark-gfm isn't installed; pipe syntax breaks in production)
3. Clone to a working directory before pushing — never push from the workspace repo
## Never do this
- Link internally to an article that doesn't exist
- Put real API key formats in code samples (use YOUR_API_KEY)The trick was to bias the content toward decision criteria rather than procedures. The moment you start writing procedures, CLAUDE.md balloons.
Level 3: Skills — They Are Not "Zero Token Cost"
This was my first real wall. It held me for months.
I've seen skills explained with the claim that reusing one costs zero tokens. I believed that at first. It isn't true.
When a skill fires, the contents of its SKILL.md are loaded into context. What's actually zero is the human effort of retyping the same procedure — not the tokens. Get this backwards and you'll assume that adding more skills makes things lighter, which sets you up for a surprise.
Where this understanding actually pays off is in how you write the description. My first one was a single line: "Updates articles." It never fired. Claude had nothing to reason from about when to reach for it.
---
name: claudelab-content-update
description: |
Use when creating or updating articles on Claude Lab.
Trigger on "write an article", "update this", "push it",
and whenever a JA+EN pair, quality checks, or log entries are needed.
---
1. Prepare the repo — clone to a working directory (never touch the workspace repo directly)
2. Write the Japanese version — content/articles/ja/{category}/{slug}.mdx
3. Write the English version — content/articles/en/{category}/{slug}.mdx (written natively, not translated)
4. Verify the counts match — find content/articles/ja -name "*.mdx" | wc -l must equal the en side
5. Run the check scripts — a single violation means no pushSpelling out the trigger conditions in the description, and structuring the body as numbered steps. Those two changes alone got my skills actually firing.
They also explained why I'd been stuck between Level 2 and Level 3: I'd been mixing rules and procedures together in CLAUDE.md. Decision criteria belong in CLAUDE.md; anything with an order of operations belongs in SKILL.md. Once I drew that line, both files got shorter.
Level 4: Hooks — Build the Brakes Before the Engine
Hooks let you inject your own processing at lifecycle moments: before and after a command runs, when a file changes, when a prompt comes in. You configure them in .claude/settings.json.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "$HOME/bin/guard-dangerous-command.sh" }
]
}
]
}
}Block dangerous commands. Auto-lint before a commit. That's the shape of it.
That said, I don't route my quality checks through Hooks. I keep them as standalone scripts and run them explicitly before every push.
The reason is legibility on failure. Hooks stop you automatically, which is genuinely useful — but I found it harder to keep a record of which check rejected which file and why. When I want something a human can read back later, calling a script explicitly suits me better.
python3 _scripts/article_gate.py <ja.mdx> <en.mdx> # content density
python3 _scripts/templating_gate.py <repo> --check ... # verbatim overlap with other posts
python3 _scripts/frontmatter_integrity.py <repo> # broken YAML
python3 _scripts/redirect_integrity.py <repo> # redirect contradictionsEverything has to exit 0 before I push, in a separate command. Hooks or explicit scripts — neither is the right answer universally. Choose based on what you want left behind when something fails.
Level 5: Orchestration — Dynamic Workflows Lowered the Step
This was wall number two. Running things in parallel isn't the hard part. The hard part is losing visibility into what happened once you do.
In July 2026, Dynamic Workflows became generally available in Claude Code. Claude plans the work itself, runs hundreds of parallel subagents within a single session, and verifies its own output before reporting back. It's available in the CLI, desktop, and VS Code extension, as well as through the API (Introducing Dynamic Workflows in Claude Code — Anthropic blog).
There are two ways in. Ask Claude directly to assemble a workflow, or enable the Claude Code–specific ultracode setting from the effort menu, which raises effort to xhigh and lets Claude decide for itself whether a workflow is warranted. The Dynamic workflow size setting in /config (small / medium / large) gives you a knob for roughly how many agents to spin up.
Reaching this level used to mean splitting agents, assigning roles, and designing synchronization yourself. Now Claude handles the planning and the verification. The step genuinely got lower.
| Level | Ceiling signal | Next move |
|---|---|---|
| 1: Raw Prompting | Explaining the same context every time | Write decision criteria into CLAUDE.md |
| 2: CLAUDE.md | It's bloating with procedures | Move ordered work out into SKILL.md |
| 3: Skills | Skills never fire | Spell out trigger conditions in the description |
| 4: Hooks | Catching the same mistakes by hand | Build verification first (Hooks or scripts — pick by what record you need) |
| 5: Orchestration | Long waits from running serially | Hand planning and verification to Dynamic Workflows |
Even so, what kept me from clearing Level 4 to Level 5 wasn't the tooling. I hadn't built a way for failures to leave a trace before I went parallel. Run things one at a time and you can see where they fall over. Go parallel and that visibility disappears.
Build the gates and the logs first, then parallelize. Reversing that order was all it took.
Choosing Your Next Step
Retracing all five, my honest takeaway is that you don't need to climb them in order. The moment you feel a ceiling in how you work today is the cue to move.
- Explaining the same context repeatedly? Write one CLAUDE.md. For deeper structure, see "Designing CLAUDE.md for Stable Output — Hierarchy, Sub-Agents, and External Memory"
- CLAUDE.md bloating? Move procedures into SKILL.md, and spell out the trigger conditions in the description
- Catching the same mistakes by hand? Write one verification script. For permission design, "Claude Code Tool Permissions: Custom Allow/Deny Policies" is a useful companion
- Waiting too long on serial runs? Try Dynamic Workflows. For Hooks and parallel operations in depth, see "Claude Code Mastery — Hooks, Orchestration & Multi-Agent Operations"
If you do one thing today, add three lines under a "Never do this" heading in the CLAUDE.md of whatever project you have open. Decision criteria worked better for me when I subtracted rather than added.
For what it's worth, I didn't climb these levels cleanly. I stalled twice, blamed the tooling, and found out both times that the problem was where I'd put things — a fairly ordinary lesson in solo development, where nobody else is around to point it out. If that saves someone else a detour, it was worth writing down.