Goal

Copy a working Claude Code setup: config files, plugins, skills, MCP servers, and the habits that make them pay off. Written from my own daily setup — everything here is running, not theoretical.

Quick start (TL;DR)

  • Put a short CLAUDE.md in ~/.claude/ (how you want Claude to work) and one per repo (how this project works)
  • Add marketplaces, install plugins: superpowers, ponytail, batman, caveman, obsidian, ghost, claude-office, LSP plugins
  • Drop extra standalone skills straight into ~/.claude/skills/<name>/SKILL.md — no marketplace needed
  • Enable MCP servers you actually use (Context7 for docs, Playwright for browser work, Perplexity for search, an image-gen server if you want visuals)
  • Set effortLevel: high and a status line in ~/.claude/settings.json
  • Put must-follow code rules in ~/.claude/rules/*.md with paths: globs (loads only when a matching file is touched), procedures in skills
  • Add one PostToolUse hook that formats and lints after every edit
  • Run /doctor once — past ~78 skills the listing silently drops descriptions
  • Keep sessions short — quality drops past ~100k context. Compact between chunks.

See also: ai coding for the overall workflow, prompting for how to phrase the asks.


1) The two config layers

Claude reads instructions from several places and merges them. The two that matter:

FileScopePut here
~/.claude/CLAUDE.mdevery project you touchyour working style, permissions, plugin habits
<repo>/CLAUDE.mdone repo, checked into gitfolder structure, conventions, commands, scope rules

Rule of thumb

Global = how I work. Repo = how this codebase works. If a new teammate would need to know it, it belongs in the repo file (and gets committed). If it is only true for you, keep it global.

Generate a first draft of a repo file with /init, then cut it down. Long CLAUDE.md files get skimmed; short ones get followed. Target under 200 lines.

What actually loads, and when

This is the part most setups get wrong. There are three mechanisms and they behave differently:

MechanismLoadsUse for
CLAUDE.mdevery session, in fullfacts true of every task
@path/to/file.md importevery session, in fullorganising a long file — not saving context
.claude/rules/*.md with paths:only when a matching file is readrules for one language or folder
Skill (SKILL.md)only when invoked or judged relevantprocedures, checklists, recipes

@ imports do not save context

@file.md is expanded and loaded at launch, every time, no matter what the surrounding prose says. Writing “if .codegraph/ exists → @codegraph.md” loads it in every project, indexed or not. Imports split a file for human readability; they cost exactly the same tokens. To load conditionally you need a path-scoped rule or a skill.

Path-scoped rules are the underused one. Frontmatter globs, and the harness — not the model — decides:

---
paths:
  - "src/**/*.{ts,tsx}"
---
- All API endpoints validate input
- Use the standard error response format

User-level rules live in ~/.claude/rules/ and apply everywhere; project rules in .claude/rules/. Rules without a paths: field load unconditionally, same as CLAUDE.md.

Where to put a code standard

Must-follow rules → a path-scoped rule (deterministic). Multi-step procedure → a skill (loads on demand, costs nothing until used). Don’t rely on a skill alone for anything that must always apply — see the invocation-rate trap in §2b.

My global CLAUDE.md (trimmed)

## Core Principles
- Answer first, investigate second. Check fundamentals (installed? configured?)
  before debugging details.
- Maximum effort on issues. Run extra commands, search the web —
  don't offload to the user.
- Believe claims or disprove with evidence. Never silently assume.
- Ask before writing. If intent or requirements are unclear, ask first.
- Flag uncertainty explicitly. Say so before proceeding, not after.
- Context windows >100k degrade quality. Break large tasks into chunks
  and ask to compact between them. Spawn sub agents when possible.
 
## Editing Rules
- Edit in place. Never overwrite or recreate existing files.
- Integrate additions inline with existing formatting style.
- Don't touch unrelated code.
 
## Permissions
No sudo. If required, ask me to run it in a separate terminal.
 
## Plugins
- Note any MCP tool or script that gives Claude a real capability (search, image
  gen, music gen...) here, one line each, so it gets reached for instead of
  reinvented or described in prose. Update this the day you wire something new up.

The lines doing the most work: ask before writing, flag uncertainty, don’t touch unrelated code, and keeping a running list of what Claude can actually do (not just how it should behave). Those kill most of the “it rewrote my file”, “it confidently guessed”, and “it described an image instead of generating one” failures.


2) Plugins — what I run and why

Plugins ship skills (instructions Claude loads on demand), slash commands, hooks (deterministic scripts that fire on session start/end, before/after tools), and subagents.

Install flow:

# in Claude Code
/plugin marketplace add <github-org>/<repo>
/plugin            # → Discover → pick the plugin → install

The behaviour-shaping ones (biggest daily impact)

  • ponytail — forces the laziest solution that works. Runs a ladder: does this need to exist at all → is it already in the codebase → does stdlib do it → native platform feature → already-installed dependency → one line → only then write code. Kills speculative abstractions and one-implementation interfaces. Extra commands: /ponytail-review (review a diff only for over-engineering), /ponytail-audit (whole repo: what to delete), /ponytail-debt (collect the ponytail: shortcut comments it left behind).
  • batman — watches wasted time, not wasted code. Flags building what already exists, features nobody asked for, being stuck too long, drifting off the stated goal. /batman-new before a new project (does this exist already? why should it exist? → writes WHY.md), /batman-report for where the week actually went, from session transcripts. Note: I’m still experimenting with this one.
  • caveman — compresses Claude’s prose ~75% (drops articles, filler, hedging) while keeping every technical detail. Auto-disables for security warnings and destructive-action confirmations. /caveman lite|full|ultra. Also /caveman:compress <file> to shrink a bloated CLAUDE.md and cut input tokens.

The workflow ones

  • superpowers — a library of process skills: brainstorming (before any creative work), systematic-debugging (before proposing a fix), writing-plans / executing-plans, test-driven-development, requesting/receiving code review, verification-before-completion (no “it works” without running the command), using-git-worktrees. This is the one that turns Claude from “generates code” into “follows a process”.
  • claude-office — our vault automation. Session-start hook pulls git and injects your identity + open todo count; session-end hook commits your folder. /check-in, /aggregate, /retro, /document, /setup-identity.

The domain ones

  • obsidian — writing correct Obsidian-flavoured markdown (callouts, wikilinks, properties), .base files, JSON Canvas, and defuddle which strips a web page down to clean markdown (cheaper and cleaner than raw fetch).
  • ghost — security scanning: scan-deps (CVEs in lockfiles), scan-secrets (leaked keys), scan-code (SAST — injection, XSS, SSRF), validate (is this finding real or a false positive), report (combined prioritised output). Use it as the final pass before shipping.
  • frontend-design — aesthetic direction for new UI so it doesn’t read as templated defaults.
  • typescript-lsp / pyright-lsp — give Claude real language-server data (go-to-definition, type errors) instead of grep guesses. Install the one matching your stack; refactors get noticeably more reliable.

Don't install everything

Every enabled plugin costs context at session start. I keep a few disabled (false in enabledPlugins) rather than uninstalled, and flip them on when a project needs them.


2b) Skills without a marketplace

Not every useful skill needs a plugin/marketplace wrapper. Claude Code reads any folder under ~/.claude/skills/<name>/SKILL.md directly — no install step, no marketplace registration.

# sparse-clone just the skill folders you want from a skills repo, then:
cp -r <repo>/skills/<name> ~/.claude/skills/

I pulled a batch this way from softaworks/agent-toolkitsession-handoff, skill-judge, requirements-clarity, commit-work, crafting-effective-readmes, agent-md-refactor, writing-clearly-and-concisely, react-dev, excalidraw, web-to-markdown, domain-name-brainstormer, backend-to-frontend-handoff-docs, ship-learn-next, perplexity (the last one’s just the tool-selection doc; the actual search capability is the MCP server below).

Skill vs. plugin

Use the marketplace/plugin path when you also want slash commands, hooks, or subagents bundled with it. A bare SKILL.md drop-in is enough when all you need is “load this instruction set when relevant.”

The two traps nobody warns you about

1. Skills often just don’t get invoked. Vercel’s agent evals (Jan 2026) measured a documentation skill against the same content inlined in AGENTS.md:

ConfigurationPass rate
Baseline, no docs53%
Skills, default53%
Skills, with explicit instructions79%
AGENTS.md docs index100%

The skill was never invoked in 56% of cases even though it was available. The counterweight: ETH Zurich’s AGENTbench (Feb 2026) found always-on AGENTS.md content often lowered pass rates through attention dilution. Both are true, and the way out is content that is loaded conditionally but deterministically — which is what path-scoped rules are for. Vercel’s evals were single-shot, which structurally penalises skills (they never get a conversational turn in which to fire), so this isn’t “skills are broken” — it’s “don’t let a must-follow rule live only in a skill.”

2. Too many skills silently disables some of them. Claude Code injects a listing of every skill name + description at startup, capped at skillListingBudgetFraction1% of the context window by default. Over budget, it drops descriptions starting with your least-used skills. No error, no warning. A skill with no description can’t auto-trigger.

I hit this: 78 skills, ~13,900 characters of descriptions, against a budget near 8,000.

/doctor    # authoritative number + worst contributors
/skills    # toggle off anything unused; disabled skills stop counting
{ "skillListingBudgetFraction": 0.02 }

Pruning beats raising the budget. Keep descriptions 100–150 characters with the trigger words you actually type front-loaded; each entry is capped at 1,536 chars regardless.

A code-work skill

The one skill worth writing yourself early. Mine is ~/.claude/skills/writing-code/SKILL.md: which process skill owns each phase, the documentation standard, the definition of done, and how subagent/context budget gets spent. Detail that isn’t needed every time — the full documentation rules — sits in references/documentation.md beside it and loads only when docs are actually being written.

Paired with ~/.claude/rules/code.md, which is path-scoped to source extensions and carries only the non-negotiables and the definition of done. Skill for the procedure, rule for the guarantee. See coding for the documentation quadrants it points at.


3) MCP servers

MCP servers give Claude live tools instead of stale training data or prose descriptions.

  • Context7 — fetches current library/framework docs. Worth it for anything version-specific (Next.js, Prisma, Tailwind…). My rule in CLAUDE.md: always resolve docs via Context7 before answering a version question, even when Claude “knows” the answer.
  • Playwright — real browser control: navigate, click, fill forms, screenshot, read console errors. Use it for UI verification rather than asking Claude to eyeball code.
  • anneal-memory — cross-session memory for durable preferences and debugging lessons.
  • Perplexity (@perplexity-ai/mcp-server) — web-grounded search/research/reasoning: perplexity_search for URLs/facts, perplexity_ask for quick cited answers, perplexity_research/perplexity_reason for deep multi-source or analytical work. Needs a Perplexity API key.
    claude mcp add perplexity --scope user --env PERPLEXITY_API_KEY="<key>" -- npx -y @perplexity-ai/mcp-server
  • Image generation (mcp-image) — generates real images via Gemini Nano Banana (default) or OpenAI gpt-image-2 (IMAGE_PROVIDER=openai). Auto-optimises short prompts into a full Subject–Context–Style description before generating.
    claude mcp add mcp-image --scope user \
      --env GEMINI_API_KEY="<key>" --env IMAGE_OUTPUT_DIR="<absolute path>" \
      -- npx -y mcp-image

    "Free tier" nuance 429, limit: 0 error on image models specifically — that's not a broken key, it's Google routing unbilled projects into a zero-quota bucket. Link a Cloud Billing account (still free under the monthly allowance) to unlock it. If you don't want a card on file at all, Pollinations.ai generates Flux images from a plain URL, no key, no signup — lower quality/control, but genuinely free.

    A fresh Gemini API key can come back with a

New MCP servers only register their tools at session startclaude mcp list will show a server as connected the moment you add it, but the tools themselves don’t appear until you restart the session.

Enable per-project in .claude/settings.local.json:

{ "enabledMcpjsonServers": ["playwright", "anneal_memory", "perplexity", "mcp-image"] }

3b) When there’s no MCP server for it

Not every capability has a ready-made MCP wrapper. Music generation (Google Lyria 3) didn’t at time of writing — rather than build a whole server for one endpoint, ponytail’s ladder says: reuse the key you already have, hit the REST API directly, one script.

#!/usr/bin/env bash
# lyria-music.sh "<prompt>" <output.mp3> [clip|pro]
key=$(python3 -c "import json; print(json.load(open('$HOME/.claude.json'))['mcpServers']['mcp-image']['env']['GEMINI_API_KEY'])")
curl -sS -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "Content-Type: application/json" -H "x-goog-api-key: $key" \
  -d "{\"model\": \"lyria-3-${3:-pro}-preview\", \"input\": \"$1\"}" \
| python3 -c "import json,base64,sys; d=json.load(sys.stdin); [open('$2','wb').write(base64.b64decode(c['data'])) for s in d['steps'] for c in s.get('content',[]) if c.get('type')=='audio']"

clip = 30s ($0.04), pro = full song ($0.08). Paid per call, no free tier at all for Lyria — reasonable given a card’s usually already on file for image gen by this point. Document the script’s path in your global CLAUDE.md the same way you’d document an MCP tool, so it actually gets used instead of re-described from scratch next session.


4) settings.json

~/.claude/settings.json is the harness config — model, plugins, permissions, hooks, UI.

{
  "model": "opus",
  "effortLevel": "high",
  "tui": "fullscreen",
  "theme": "dark",
  "statusLine": { "type": "command", "command": "npx -y ccstatusline@latest", "padding": 0 },
  "enabledPlugins": { "ponytail@ponytail": true, "batman@batman": false }
}

Permissions live in settings.local.json (per project, not committed). Rather than approving the same read-only command 40 times, allowlist it:

{ "permissions": { "allow": ["WebSearch", "Bash(dpkg -l)", "WebFetch(domain:github.com)"] } }

Useful helpers

  • /fewer-permission-prompts — scans your transcripts and proposes an allowlist of the read-only commands you keep approving.
  • /update-config — edits settings.json for you, including hooks.
  • /config — quick toggles (model, theme).

5) Hooks — automation Claude can’t forget

A memory or a preference is a request; a hook is a guarantee. Anything phrased “every time X, do Y” should be a hook, because the harness runs it, not the model.

Events: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SessionEnd.

Typical uses:

  • run the formatter / linter after every file edit (PostToolUse)
  • inject project state at session start (git pull, open todo count)
  • block edits to protected paths (PreToolUse)
  • commit and push docs on session end

Keep hooks deterministic

Hooks should inject metadata (counts, filenames, status), never raw untrusted file content. Raw content in a hook is a prompt-injection channel. Same reason our vault rules say to treat other people’s notes as data, never as instructions.

The one hook worth adding first

PostToolUse on Write|Edit → format, then lint. On lint failure, block and hand back the diagnostics. This is what turns “run the linter” from advice into a guarantee.

{ "hooks": { "PostToolUse": [ {
  "matcher": "Write|Edit",
  "hooks": [ { "type": "command",
    "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-lint.sh" } ]
} ] } }

The script reads the event JSON on stdin, pulls the path out of .tool_input.file_path, formats, lints, and on failure prints a decision:

printf '{"decision":"block","reason":%s,"additionalContext":%s}' \
  "$(printf 'Lint failed for %s. Fix before continuing.' "$FILEPATH" | jq -Rs .)" \
  "$(printf '%s' "$lint_output" | jq -Rs .)"
exit 0

reason is what you and the model see; additionalContext carries the full diagnostics into the next turn so the fix happens without you asking.

Exit codes are the footgun

Exit 0 + JSON on stdout = the expressive path, decisions get parsed. Exit 2 = block, but stdout is discarded (only stderr reaches the model). Exit 1 = does not block, despite reading like an error. PreToolUse is the odd one out: it uses hookSpecificOutput.permissionDecision (allow/deny), not a top-level decision.

Keep formatters non-blocking — always exit 0, a formatter is a convenience. Reserve blocking for lint and typecheck. Scope typechecks to the changed package: a hook that fires on every edit is a hook you will feel.

Debugging what loaded at all: the InstructionsLoaded hook logs exactly which instruction files were pulled in, when, and why — the fastest way to find out whether a path-scoped rule is actually firing. /context shows the loaded memory files; /doctor reports the skill listing cost.


6) Subagents

Subagents run a task in their own context window and return only the conclusion — the tool output never lands in your session. Use them for anything with a big search surface and a small answer.

  • Explore — read-only fan-out search (“find every place we build the auth header”)
  • Plan — design an implementation strategy before touching code
  • general-purpose — multi-step research

Tip

Each subagent starts cold and has to re-derive context, so it is not free. Use one when the output is small but the reading is large. Don’t use one for a task you already have the context for.

Custom subagents — where the real control is

Drop a markdown file in ~/.claude/agents/ (or .claude/agents/ per project) and you stop relying on a generic worker. The frontmatter is the interesting part:

FieldDoes
skillsInjects the full content of the named skills at startup — not just the description. Removes the invocation gamble entirely.
modelhaiku for narrow, high-volume agents; opus where judgement matters
tools / disallowedToolsA reviewer that cannot write, whatever it decides
maxTurnsHard stop on a runaway loop
memoryuser/project/local — a persistent notes directory, so the agent accumulates codebase knowledge across sessions. project is the recommended scope.
isolation: worktreeIts own git worktree, auto-cleaned if it changed nothing
permissionMode, mcpServers, hooksPer-agent permissions, server scoping, lifecycle hooks
---
name: code-reviewer
description: Reviews a diff for correctness and convention drift
model: haiku
tools: Read, Grep, Glob
memory: project
skills:
  - writing-code
---
Review the diff. Check your memory for patterns you've flagged before.
Return: file, line, the defect, and the concrete fix. Nothing else.

Two facts that contradict what most people assume:

  • CLAUDE.md and your rules do load into custom subagents. Only the built-in Explore and Plan skip them (to stay small). So when you use those two, restate any constraint they must respect — “ignore vendor/” — in the delegation prompt itself. There is no setting to change which agents skip it.
  • Subagents can’t spawn subagents by default. Set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH if you want nesting.

Parallel subagents race on files

Partition the work on disjoint directories before fanning out. Two agents editing the same file is a silent corruption, not an error. Practical ceiling for code work is around 3–5 in parallel; beyond that you can’t supervise what they did.

Delegate with a schema, not a topic

“Research the auth flow” returns a narrative you have to re-read, which defeats the point. State the question and the output shape: “list every file that builds an auth header — path, line, which helper it calls.” A vague prompt means the reading gets done twice.


7) Slash commands worth knowing

CommandDoes
/initdraft a CLAUDE.md for the current repo
/code-reviewreview your working diff
/review <PR#>review a GitHub PR
/security-reviewsecurity pass on pending changes
/simplifyapply reuse/simplification cleanups to changed code
/loop 5m <cmd>run something on an interval (poll a deploy, babysit PRs)
/schedulecron-scheduled cloud agents
/runlaunch the project’s app to see a change actually working
/compactsummarise the session and free context

8) The habits that matter more than the config

  1. Plan first, code second. Brainstorm → spec → acceptance criteria → implement one slice. Plan mode exists for this.
  2. Keep context under ~100k. Quality visibly degrades past that. Break work into chunks and compact between them.
  3. Demand evidence. “Show me the command output” beats “it works”. The verification-before-completion skill enforces this.
  4. Small commits, branches for experiments. Cheap to throw away a bad direction.
  5. Read the diff. Beautiful formatting with wrong information is worse than ugly formatting with right information — same rule as writing guides.
  6. Docs are shared state. If you learned something the repo doesn’t record, put it in the repo’s CLAUDE.md or a guide here. Pick the quadrant before writing — tutorial, how-to, reference, or explanation — and never mix two in one document. See coding > Documentation.
  7. Verify what loaded, don’t assume. /context for memory files, /doctor for the skill listing, InstructionsLoaded for the full trace. Every “it ignored my instructions” I’ve chased was a loading problem, not a compliance problem.
  8. When you wire up a new capability (MCP server, script, key), write it down the same day. An unrecorded capability gets re-described in prose or re-built from scratch next session instead of used.

Getting started from zero

  1. Install Claude Code, run it in a repo, run /init.
  2. Write a 20-line ~/.claude/CLAUDE.md — start from mine above, cut what you disagree with.
  3. Add superpowers and ponytail. Live with those two for a week before adding more.
  4. Add Context7 + the LSP plugin for your stack.
  5. Add batman and caveman once the basics feel natural.
  6. Add hooks last, when you notice yourself repeating the same instruction every session.
  7. Add live capabilities (search, image/music gen) only when you’ll actually reach for them — wire the MCP server or script, then log it in your global CLAUDE.md so it gets used.