If claude-code-best-practice is the encyclopedia, this is the field guide.
An opinionated, production-tested Claude Code configuration for solo developers managing multiple apps.
Not a tutorial — a real setup that runs daily across 10+ personal projects,
shared so you can steal the parts that work for you.
The Story · What's Inside · Key Decisions · Quick Start · Adapting · Philosophy
I'm not a developer. I've spent 20 years close to code without writing much of it — I understand architecture, I can debug a concept, but I don't read diffs. I haven't looked at a line of code in my projects for months.
What I do is build things. I maintain a portfolio of 10+ personal apps — budget trackers, reading lists, encyclopedias, games, tools for my family. Different stacks, different audiences, different deployment targets. One development environment: Claude Code.
After months of trial, error, and way too many hours watching Claude Code attempt the same failing fix for the fifth time, I built a system. Commands that orchestrate agents. Agents that remember what they learned. Skills that preload project conventions. Hooks that nudge without blocking.
This repo is that system, anonymized and documented. It's opinionated because opinions are what's missing from most "best practices" repos — I'll tell you what I chose and why I chose it over the alternative.
As Boris Cherny, who created Claude Code, put it: "Every engineer uses their tools differently." This is my way.
┌───────────────────────────────────────────────────────────┐
│ You type a command │
│ /audit /cleanup /new-app /next /sync /tech-debt │
│ /sync-setup │
└─────────────────────────────┬─────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────┐
│ Agents │
│ │
│ implementer ───── sonnet │
│ troubleshooter ── inherit (never weaker than the caller) │
│ docs-checker ─── sonnet (audits README, CLAUDE.md) │
│ portfolio-sync ─ sonnet (cross-repo coherence) │
│ portfolio-audit haiku (compliance checks) │
│ dummy-visitor ── sonnet (bilingual naive-visitor review) │
│ │
│ ┌────────────┐ ┌──────────────────────────────────┐ │
│ │ Memory │ │ Skills (preloaded knowledge) │ │
│ │ per agent │ │ • portfolio-conventions │ │
│ │ per project│ │ │ │
│ └────────────┘ └──────────────────────────────────┘ │
└─────────────────────────────┬─────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────┐
│ Hooks │
│ │
│ stale-readme-guard "Docs still current?" (advisory) │
│ auto-format ─────── "Format the file" (advisory) │
│ portfolio-yml-validate "Manifest valid?" (advisory) │
│ portfolio-drift ─── "Docs staged with code?" (advisory) │
│ secret-scan ─────── "API key in source?" (blocking) │
│ push-build-gate ─── "Build clean before push?" (blocking)│
└───────────────────────────────────────────────────────────┘
Tip
For a visual, interactive version of this architecture, open the workflow guide.
Commands (7) — entry points that orchestrate everything
| Command | What it does | When to use it |
|---|---|---|
/sync |
Portfolio-wide manifest sync + JSON generation | Weekly maintenance |
/audit |
Parallel docs-checker + portfolio-audit | Before releases, compliance sweeps |
/new-app |
Full scaffold with portfolio compliance from day one | Starting a new project |
/next |
Executes the next unblocked task from a multi-phase plan track, then stops | One session per phase of a large plan |
/cleanup |
Disk hygiene sweep of ~/.claude first, then stale plans, plugin audit, memory compaction |
Weekly housekeeping |
/tech-debt |
Monthly triage → deep review → auto-fix | Monthly health check |
/sync-setup |
Sync this repo from live ~/.claude/ config (anonymize + audit) |
After workflow changes |
Agents (6) — the workers, each with a specific role and model
The model selection matters. I don't pay opus prices for a compliance check that haiku handles perfectly. Heavier, cross-file work doesn't live on a fixed agent — it escalates by dispatch, at the model tier the task calls for.
Skills (1) — preloaded knowledge and user-invocable utilities
- portfolio-conventions: condensed version of cross-project standards (naming, signature, dark mode, docs, manifest format, quality gates, display order). Loaded into
troubleshooterandportfolio-sync.
The other four skills I used to run here are gone — their content was either already inferable by the agents that needed it, or better placed directly in the global CLAUDE.md's quality section, where it can't drift out of sync with a separate file.
Why skills instead of just writing longer agent prompts? Because skills are reusable across agents, versionable independently, and don't bloat agents that don't need them.
Hooks (6) — 4 advisory + 2 blocking
- secret-scan (PreToolUse → Write|Edit): blocks writes containing API key patterns (
sk-,AKIA,ghp_, etc.), excludes.env.example(blocking) - push-build-gate (PreToolUse → Bash
git push): runs the build before the push goes out and blocks on failure or compiler warnings (blocking) - auto-format (PostToolUse → Write|Edit): runs Prettier / Ruff / rustfmt on the edited file if the project has the corresponding config — silent if not (advisory)
- portfolio-yml-validate (PostToolUse → Write|Edit
*.portfolio.yml): checks required fields, slug = folder name, numericsort_order, validsurface_type(advisory) - portfolio-drift (PreToolUse → Bash
git commit): warns when dependency/deploy files are staged but.portfolio.yml/ README.md aren't (advisory) - stale-readme-guard (PreToolUse → Bash
git push): checks unpushed commits for deploy/dep changes without a README.md update (advisory)
Most hooks are advisory — in a system where I don't review code, I need Claude Code to exercise judgment, not pass checklists. There are two blocking exceptions now: secret scanning, because accidentally committing an API key is irreversible, and the push build gate, because shipping a broken build is a different kind of irreversible — it's live the moment it deploys.
The CLAUDE.md at the root is the backbone — ~80 lines of rules that apply to every project. The most important ones:
Important
The 3-level escalation cascade. Each level forces a different approach. No retrying the same level twice. Every fix attempt requires a stated root cause hypothesis — no "let me try a different approach" without a new theory.
flowchart LR
A["🐛 Bug"] --> B["L1: Direct fix
hypothesis → fix"]
B -->|works| Z["✅ Done"]
B -->|"still broken"| C["L2: Systematic debugging
investigate → hypothesize → fix → verify"]
C -->|works| Z
C -->|"still broken"| D["🛑 STOP"]
D --> E["L3: Troubleshooter
inherit · structural diagnosis"]
E --> F["📋 New plan"]
F --> G["🔧 Implementer
executes plan"]
G --> Z
style D fill:#dc2626,color:#fff
style E fill:#8B5CF6,color:#fff
style G fill:#3B82F6,color:#fff
style Z fill:#10B981,color:#fff
Warning
Bug triage before code. When I report a bug, Claude Code must rule out environment issues first — stale cache, service worker, old build. The most common "bugs" in my portfolio weren't bugs at all.
Note
Docs in the same commit as code. README, CLAUDE.md, and .portfolio.yml updates ship with the feature, not as an afterthought. If the commit changes behavior, it changes documentation.
The elegance check. Before presenting non-trivial work, pause and ask: "Is there a more elegant way?" I don't review code — Claude Code is the entire quality bar.
The generalization check. Before implementing a specific request, consider whether it's a special case of a more general pattern. If the general solution is roughly the same effort, implement the general version. If not, implement the specific case cleanly — it's easier to generalize clean code later than to simplify over-engineered code.
These aren't arbitrary choices. Each one came from a specific failure. Read the full story for the context behind each decision.
| Decision | Alternative I considered | Why I went this way |
|---|---|---|
| 3-level escalation cascade | Binary "2 fails → architect" | The old binary rule skipped a crucial step: structured debugging. Level 2 (systematic debugging skill) catches tricky-but-not-architectural bugs without invoking opus. |
| Troubleshooter never codes | One agent diagnoses and implements | When the same agent diagnoses and codes, it's biased toward solutions it can implement quickly rather than the right solution. |
| Advisory hooks + 2 blockers | All advisory or all blocking | Most hooks should nudge, not gate. The exceptions: secret scanning (an irreversible leak) and the push build gate (an irreversible bad deploy) both block. |
| Property-based tests for invariants | Unit tests only | Unit tests verify examples. Property tests verify laws — "transfers preserve totals" catches edge cases no human would write. |
| Model selection per task | Always use the best model | Haiku is perfect for audits. Sonnet handles 80% of implementation. Opus is for architecture and complex cross-file work. Matching model to task is a quality decision, not just a cost one. |
| Agent memory over lesson files | Flat markdown files per project | Files had no structure, no auto-injection, no compaction. Agent memory is read at startup, written automatically after corrections, and split when it grows too large. |
| Skills as preloaded context | Dynamic tool calls | Skills need to be available before the agent starts thinking. Dynamic loading means the agent might not know what it needs to know when making its first decision. |
| One manifest per repo (.portfolio.yml) | Central inventory document only | Drift. A central doc goes stale the moment you rename an app. A manifest in the repo travels with the code and gets updated in the same commit. |
Note
The setup is fully modular — you can copy everything, cherry-pick individual pieces, or just read and adapt the patterns to your own system.
git clone https://github.com/w2ur/claude-code-setup.git
cp -r claude-code-setup/commands/ ~/.claude/commands/
cp -r claude-code-setup/agents/ ~/.claude/agents/
cp -r claude-code-setup/skills/ ~/.claude/skills/
cp -r claude-code-setup/hooks/ ~/.claude/hooks/
cp claude-code-setup/CLAUDE.md ~/.claude/CLAUDE.mdThen edit CLAUDE.md and the agent files to replace w2ur, {portfolio-site}, and other placeholders with your own values.
The setup is modular. Want just the escalation system? Copy the global CLAUDE.md's bug-handling cascade, the implementer agent, and the troubleshooter agent. Want just the maintenance workflow? Copy /cleanup and /tech-debt. Each piece works independently — the full system is better, but partial adoption works fine.
Browse the files, understand the patterns, and build your own version. The philosophy doc explains the "why" behind each choice — that's often more valuable than the "what."
This system was built for a very specific situation — here's how to adapt it to yours
If you have 1-3 apps: You don't need half of this. Drop portfolio-sync and portfolio-audit — they exist because I have 10+ repos to keep in sync. Keep the implementer and troubleshooter agents, the escalation cascade in the global CLAUDE.md, and the two blocking hooks. That alone is a massive upgrade over bare Claude Code.
If you work in a team: The escalation rules still apply — they're about AI behavior, not team size. The implementer/troubleshooter split actually maps well to teams where juniors implement and seniors review. The memory system needs thought, though — per-developer or shared? I haven't solved that one.
If you have a different stack: My skills are specific to my projects. Throw them out and write your own. The architecture (commands → agents → skills + hooks) doesn't care what language you write in.
If you use a monorepo: The portfolio-sync agent assumes separate repos. You'd need a monorepo-aware version. Everything else works as-is.
Caution
- Application code. Zero lines of app code. Just configuration.
- Personal data. Public apps are mentioned by name (they're live on the internet anyway). Private apps, personal URLs, and paths are anonymized.
- A universal solution. This works for me. Parts of it will work for you. All of it, probably not — and that's fine.
This repo stays in sync with my actual ~/.claude/ setup via /sync-setup — a command that runs a Python sync script to copy, anonymize, and audit for data leaks. After any workflow change (new agent, renamed command, new hook), I run /sync-setup and the repo updates itself. See scripts/ for details.
Known gap: the global CLAUDE.md also references three helper shell scripts under ~/.claude/scripts/ (dev-scanner.sh, disk-hygiene.sh, cleanup-cron.sh) that aren't published in this repo yet.
If something looks outdated, it probably means I changed my setup and haven't synced yet. Open an issue — it's a good nudge.
This is a personal setup, not a framework. I'm not accepting PRs that change the architecture or philosophy. But I welcome:
- Bug reports: if something is broken, inconsistent, or unclear
- Questions: open an issue, I'll answer and improve the docs
- Adaptations: if you built something interesting on top of this, I'd love to hear about it
- claude-code-best-practice — the comprehensive reference (encyclopedic, community-maintained)
- Anthropic's Claude Code docs — official documentation
- William Revah on LinkedIn — where I write about building apps with AI, cognitive biases, and whatever else I'm curious about
MIT — copy, adapt, share. Attribution appreciated but not required.
Built by William — someone who doesn't read code but ships 10+ apps anyway.
Read the philosophy for the full story.