Anatomy of a Claude Code Setup
I’ve been using Claude Code as my primary development tool for a few months now. Over that time I’ve built up a setup with custom skills, MCP servers, hooks, and project-specific instructions. But getting there meant understanding a fundamental split in how Claude Code organizes configuration: what’s yours versus what’s the project’s.Anthropic’s .claude directory reference and their blog post on CLAUDE.md files are the official starting points. This post is a more opinionated companion: how I think about the split, and what my actual config looks like.
This post walks through the mental model, then shows what I actually have configured. If you’re just getting started with Claude Code, this should save you some trial and error.
The big picture
Everything Claude Code knows about you and your project lives in two directories. Both are called .claude/, but they’re in different places and serve different purposes.
~/.claude/ in your home directory is your personal configuration. It follows you across every project. Your preferred model, your global permissions, your personal skills and workflows. This never touches git.
.claude/ inside a project is the project’s configuration. Most of it gets committed to git and shared with anyone who clones the repo. Project skills, team permissions, shared hooks.
Here’s what that looks like on disk. Notice how both levels have similar files (settings, skills, CLAUDE.md) but at different scopes:
The color coding tells the story. Amber is personal config that never leaves your machine. Green is committed to git, shared with the team. Purple is the escape hatch: project-level files that stay local to you.
CLAUDE.md: instructions at every level
CLAUDE.md is the most visible piece of configuration. It’s a markdown file with instructions for Claude. There are multiple scopes, and they all load together, additively.See the Memory docs for the full technical reference on how CLAUDE.md files load.
An important detail: CLAUDE.md files are read from disk at session start, but their content is injected into every single request to the model, not just the first one. They’re delivered as a user message (you can see them as <system-reminder> tags if you look at the raw context). This is why they survive /compact: when the conversation history gets compressed, CLAUDE.md is re-read from disk and re-injected fresh. Your instructions never get lost.
That also means every line in your CLAUDE.md costs context on every turn. Keep it lean.
Global (~/.claude/CLAUDE.md): instructions that apply in every project. Mine is short. It has two rules: always quote paths with double quotes in shell commands (never backslash-escape spaces), and use the chrome-devtools MCP for browser automation. That’s it. Every line here costs context in every project, so keep it minimal.
Project (CLAUDE.md at the repo root): this is where the bulk of your instructions live. For this blog, mine covers the design system (color tokens, typography, aesthetic direction), the deployment workflow (always push after committing, use port 3050), which skills to invoke for which tasks, and the component library API. It’s the project’s brain dump.
Local (CLAUDE.local.md): personal notes that stay on your machine. The gitignored counterpart to the project CLAUDE.md. Useful for things like “I’m currently refactoring the auth service” or “always use my local API on port 8080.” I don’t use this one yet, but it’s there when I need it.
Anthropic recommends keeping each file under 200 lines. When your project CLAUDE.md gets long, you can split it into .claude/rules/, where each file is a standalone rule that loads either unconditionally or only when Claude opens matching files. Path-scoped rules use YAML frontmatter:
---
paths:
- "src/api/**/*.ts"
---
# API design rules load only for matching filesSkills: where the real power is
Skills are where my workflow has shifted the most. I used to spend most of my time manually prompting Claude: describing what I wanted, reviewing the output, course-correcting. Now a lot of that is encoded in slash commands. Type /review and two subagents spin up to check my code. Type /demoand a video gets recorded. The interaction has moved from “tell Claude what to do each time” to “build the workflows once, then trigger them.”Full reference at code.claude.com/docs/en/slash-commands. Each skill is a directory with a SKILL.md entrypoint, and they exist at both levels.
Global skills (~/.claude/skills/) are available in every project. These are your personal workflows. Here are the ones I use most:
/suggest— Analyzes the current context and suggests the highest-leverage next steps. My most-used skill by far. Great for when you finish a task and aren’t sure what to pick up next./review— Spawns two parallel subagents (one for bugs and correctness, one for consistency and integration) then synthesizes their findings. Way more thorough than asking Claude to “review this” in a single pass./demo— Records an MP4 video walkthrough of recent changes using the browser. Detects which routes changed, plans interactions, records the screen. Useful for async reviews./diagram— Creates SVG diagrams with a built-in multi-step review loop: structural coordinate check, browser screenshot, two independent visual review agents. Overkill for casual diagrams, but the output quality is high./reflect— End-of-session retrospective. Where Claude struggled, what could improve in the codebase for agentic workflows, and memory suggestions. I run this at the end of long sessions./setup-browser— Sets up thechrome-devtoolsMCP in a new project. Updates.mcp.json, adds the right entries to CLAUDE.md, checks for ffmpeg. One command and the project has browser access.
That last one is a pattern worth calling out: skills that set up other parts of your config. Since most of my projects are web apps, I find myself configuring browser access, screenshot tooling, and dev server conventions in almost every repo. Instead of doing that manually each time, a skill handles the whole setup. It’s automation insidethe tool that’s already automating your coding.
Project skills (.claude/skills/) are specific to a repo. For this blog, I have a create-visualization skill that encodes the entire design language (color tokens, element patterns, animation specs, 16 explicit “do not” rules learned from past mistakes). There’s also adapt-blog-post for converting Obsidian markdown into the blog’s React page format, and frontend-design for when I’m building new components.
The split is intuitive. If a skill is about how you work, it goes in ~/.claude/skills/. If it’s about how this project works, it goes in .claude/skills/.
Settings, MCP, and hooks
The same global-vs-project pattern applies to everything else. I’ll keep this brief because each of these deserves its own deep dive, but here’s the shape of it.The features overview page has a great comparison table of when to use CLAUDE.md vs skills vs hooks vs MCP.
Settings
Three settings.json files, from highest to lowest precedence: .claude/settings.local.json (your personal project overrides, gitignored), .claude/settings.json (team settings, committed), and ~/.claude/settings.json (your global defaults).Full reference at code.claude.com/docs/en/settings. There’s a JSON Schema at json.schemastore.org/claude-code-settings.json for editor autocomplete.
Scalar settings (like model) are overridden: most specific wins. Array settings (like permissions.allow) accumulate across all scopes. So your global git permissions and the project’s npm permissions both apply in the same session.
In my global settings, I set Opus as my default model, block npm install and bun add(I prefer to manage dependencies manually), and allow a long list of read-only commands so I don’t get prompted for basics like git log.
MCP servers
MCP (Model Context Protocol) connects Claude to external tools. Project servers go in .mcp.json at the repo root. Personal servers go in ~/.claude.json. Both are available in the session simultaneously. Use ${ENV_VAR} syntax in .mcp.json for secrets, since that file is committed.Full reference at code.claude.com/docs/en/mcp.
For this blog, I have chrome-devtools configured as a project MCP server for browser debugging and screenshots. In another project, I run a custom database inspector MCP. Each project gets exactly the tools it needs.
If you’ve read the ReAct post, this should ring a bell: MCP servers are the observationchannel. They give Claude a way to inspect live data, check the output of running code, query a database. Instead of the agent working from memory alone, it can ground its decisions in what’s actually happening. I’ve found this accelerates coding significantly, and I’ll write more about that in a future post.
Hooks
Hooks are scripts that fire at lifecycle events (session start, after a tool use, when Claude stops). Unlike CLAUDE.md guidance, hooks are deterministic: they always run. They’re configured in settings.json at any scope.Reference at code.claude.com/docs/en/hooks.
I have a global SessionStart hook that detects when Claude launches inside a git worktree and renames the terminal tab accordingly. Small quality-of-life thing, but it helps when I’m running multiple agents in parallel.
Notice the claude --worktreecommand in the video below: the session starts in an isolated git worktree, and the hook automatically renames the terminal tab to match. When you’re juggling three or four agents across different worktrees, being able to glance at a tab name and know which one is which makes a real difference.
The .local escape hatch
Every shared config file has a local counterpart. This is the pattern that makes team collaboration work without stepping on each other.
CLAUDE.mdis committed.CLAUDE.local.mdis gitignored..claude/settings.jsonis committed..claude/settings.local.jsonis gitignored.
The local files have higher precedence than their shared counterparts. Want to use a different model than the team default? Put it in settings.local.json. Have a personal workflow note? Put it in CLAUDE.local.md. None of this leaks into git.
settings.local.json is automatically added to your global gitignore the first time Claude creates one. But you should also add the others to your project’s .gitignore explicitly:
# Claude Code personal config
CLAUDE.local.md
.claude/settings.local.json
.claude/agent-memory-local/Getting started
If you’re setting up Claude Code for the first time, here’s the order I’d suggest:
- Run
/initin your project to generate a starter CLAUDE.md. It analyzes your codebase and gives you a reasonable starting point.SetCLAUDE_CODE_NEW_INIT=1for an interactive flow that also sets up skills and hooks, not just CLAUDE.md. - Add your most-used permission rules to
~/.claude/settings.json. At minimum, allow read-only git commands so you don’t get prompted forgit login every project. - Create a
~/.claude/CLAUDE.mdwith your personal coding preferences. Keep it short. Two or three rules that apply everywhere. - For team projects, add
CLAUDE.local.mdand.claude/settings.local.jsonto your.gitignore.
After that, it’s iteration. As you notice yourself repeating instructions, move them into CLAUDE.md or rules. As you build multi-step workflows, turn them into skills. The configuration grows with your usage.
- The .claude directory reference — interactive explorer of every file
- Features overview — when to use CLAUDE.md vs skills vs hooks vs MCP
- Using CLAUDE.md files — Anthropic’s practical guide
- Best practices — team workflows and configuration guidance