Claude Code Project Setup — CLAUDE.md, Settings & Permissions
A well-configured project makes every Claude Code session 10× faster. This guide covers the full setup: creating your CLAUDE.md memory file, configuring permissions in .claude/settings.json, adding hooks, and wiring it all up for team use — for solo projects, mono-repos, and everything in between.
On this page
Project Anatomy: What Claude Code Reads
When you run claude in a project directory, Claude Code loads context from several sources in order:
| Source | Location | Purpose |
|---|---|---|
| User settings | ~/.claude/settings.json | Global defaults for all your projects |
| User memory | ~/.claude/CLAUDE.md | Personal preferences across all projects |
| Project settings | .claude/settings.json | Project-wide permissions and hooks |
| Project memory | CLAUDE.md (project root) | Project context loaded every session |
| Sub-dir memory | packages/api/CLAUDE.md | Scoped context for mono-repo packages |
| Git context | git log, git status | Automatically read when in a git repo |
Project settings override user settings. Sub-directory CLAUDE.md files stack on top of the root CLAUDE.md. The result: Claude has complete, layered context without you saying a word.
Creating Your CLAUDE.md File
CLAUDE.md is the single most impactful file you can create. Claude reads it at session start — it's your project's permanent briefing document.
Create the file
touch CLAUDE.md # Or let Claude generate a draft for you: claude "generate a CLAUDE.md for this project based on what you can see"
Claude will inspect your files, package.json, README, directory structure, and produce a draft you can refine.
Fill in the essential sections
A production-ready CLAUDE.md has six sections:
# Project: [Your App Name] ## Overview [2-3 sentences: what the app does, who uses it, current stage] ## Tech Stack - **Language**: TypeScript 5.x / Node 20 - **Framework**: Next.js 14 (App Router) - **Database**: PostgreSQL via Prisma ORM - **Auth**: NextAuth.js - **Deployment**: Vercel ## Commands ```bash npm run dev # Start dev server (port 3000) npm run test # Run Jest tests npm run test:watch # Test in watch mode npm run build # Production build npm run lint # ESLint npx prisma migrate dev # Apply DB migrations ``` ## Architecture - `src/app/` — Next.js App Router pages and layouts - `src/components/` — Shared React components - `src/lib/` — Utilities, DB client, auth config - `src/server/` — Server actions and API routes - `prisma/` — DB schema and migrations ## Conventions - Use named exports (no default exports for components) - Tailwind for styling — no CSS modules - Server components by default; `'use client'` only when needed - Zod for all input validation - Error boundaries in `src/app/error.tsx` ## Current Focus [What's being built/fixed right now — update each sprint]
Commit it to git
git add CLAUDE.md git commit -m "chore: add CLAUDE.md for Claude Code project memory"
All teammates inherit your project briefing automatically on their next claude session.
Configuring .claude/settings.json
Project settings live at .claude/settings.json. This file is safe to commit to git (it contains no secrets). Create the directory and file:
mkdir -p .claude touch .claude/settings.json
A fully annotated settings.json:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npx *)",
"Bash(git status)",
"Bash(git log *)",
"Bash(git diff *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git checkout *)",
"Bash(cat *)",
"Bash(ls *)",
"Read(*)",
"Edit(*)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force*)",
"Bash(sudo *)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "npm run lint --silent 2>&1 | head -20"
}
]
}
]
},
"env": {
"NODE_ENV": "development"
}
}
After creating this file, restart Claude Code (Ctrl+C, then claude again) for the settings to take effect.
Permissions and Allowed Commands
Claude Code asks for permission before running shell commands. You can pre-approve commands so Claude works without interrupting you for routine operations.
Permission syntax
| Pattern | Matches |
|---|---|
"Bash(npm run *)" | Any npm script |
"Bash(git *)" | Any git command |
"Bash(npm run test)" | Only npm run test exactly |
"Read(*)" | Read any file |
"Edit(*)" | Edit any file |
"Edit(src/*)" | Edit files in src/ only |
"WebFetch(*)" | Allow fetching URLs |
"mcp__*" | Allow all MCP tools |
Recommended permission sets by project type
Web app (Node.js):
"allow": [ "Bash(npm run *)", "Bash(npx *)", "Bash(git status)", "Bash(git log *)", "Bash(git diff *)", "Bash(git add *)", "Bash(git commit *)", "Bash(git checkout *)", "Read(*)", "Edit(*)" ]
Python project:
"allow": [ "Bash(python *)", "Bash(pip *)", "Bash(pytest *)", "Bash(uv *)", "Bash(poetry *)", "Bash(git *)", "Read(*)", "Edit(*)" ]
Rust project:
"allow": [ "Bash(cargo build)", "Bash(cargo test)", "Bash(cargo run *)", "Bash(cargo fmt)", "Bash(cargo clippy)", "Bash(git *)", "Read(*)", "Edit(*)" ]
"Bash(rm -rf *)", "Bash(git push --force*)", and "Bash(sudo *)". Even if Claude wouldn't normally run these, the deny list is a hard guardrail that prevents accidental execution during automated workflows.
Setting Up Hooks
Hooks run shell commands automatically in response to Claude's tool use. They're defined in the hooks section of your settings.json.
Hook trigger types
| Trigger | When it fires |
|---|---|
PreToolUse | Before a tool call executes |
PostToolUse | After a tool call completes |
Stop | When Claude finishes a turn |
Notification | When Claude sends a notification |
Common hook patterns
Run linter after every file edit:
"hooks": {
"PostToolUse": [{
"matcher": "Edit",
"hooks": [{"type": "command", "command": "npm run lint --silent 2>&1 | head -20"}]
}]
}
Run tests after editing test files:
"PostToolUse": [{
"matcher": "Edit(src/**/*.test.ts)",
"hooks": [{"type": "command", "command": "npm run test --testPathPattern=\"$(basename $CLAUDE_TOOL_INPUT_FILE)\" 2>&1 | tail -30"}]
}]
Send a desktop notification when Claude finishes:
"Stop": [{
"matcher": "",
"hooks": [{"type": "command", "command": "notify-send 'Claude Code' 'Task complete' 2>/dev/null || osascript -e 'display notification \"Task complete\" with title \"Claude Code\"' 2>/dev/null || true"}]
}]
Auto-format Python after edits:
"PostToolUse": [{
"matcher": "Edit(**.py)",
"hooks": [{"type": "command", "command": "black \"$CLAUDE_TOOL_INPUT_FILE\" 2>&1"}]
}]
$CLAUDE_TOOL_INPUT_FILE is the file path for Edit hooks. $CLAUDE_TOOL_NAME is the tool that fired. Use these to write targeted hooks that only act on the affected file.
Team and Shared Project Setup
Setting up Claude Code for a team takes 5 minutes. The key insight: project config lives in the repo, so every developer gets the same setup automatically.
What to commit to git
| File | Commit? | Notes |
|---|---|---|
CLAUDE.md | ✓ Yes | Shared project context |
.claude/settings.json | ✓ Yes | Shared permissions and hooks |
.claude/settings.local.json | ✗ No | Personal overrides — add to .gitignore |
.claude/todos.md | ✗ No | Session-specific, changes constantly |
Add this to your .gitignore:
# Claude Code user-specific files .claude/settings.local.json .claude/todos.md
Onboarding a new developer
# After cloning the repo: npm install -g @anthropic-ai/claude-code # Add API key to their shell profile: echo 'export ANTHROPIC_API_KEY=sk-ant-...' >> ~/.zshrc source ~/.zshrc # That's it — all project config inherits from the committed files: cd your-project claude
Team API key management
Each developer should use their own API key for security and individual rate limits. For CI/CD or shared automation, create a dedicated "team bot" API key in your Anthropic organization console and store it in your CI secrets (e.g. GitHub Actions secrets, not in the repo).
Mono-repo Configuration
Claude Code's CLAUDE.md stacking makes mono-repos work naturally. Here's the pattern:
your-monorepo/
├── CLAUDE.md ← Root: overall structure, shared tooling
├── .claude/
│ └── settings.json ← Root: permissions for all packages
├── packages/
│ ├── api/
│ │ └── CLAUDE.md ← API package: Express routes, DB schema
│ ├── web/
│ │ └── CLAUDE.md ← Web app: React, Tailwind, auth flow
│ └── shared/
│ └── CLAUDE.md ← Shared: types, utilities, naming conventions
└── apps/
└── mobile/
└── CLAUDE.md ← Mobile: React Native, navigation structure
When you cd packages/api && claude, Claude reads:
your-monorepo/CLAUDE.md(root context)your-monorepo/packages/api/CLAUDE.md(package context)your-monorepo/.claude/settings.json(root permissions)
The root CLAUDE.md should describe the mono-repo topology. Each package CLAUDE.md should describe only that package — don't repeat root info.
npm run build:all, npm run test:all). Each package CLAUDE.md adds its own entry points, schemas, and conventions.
Setup by Project Type
Next.js / React App
CLAUDE.md highlights: - App Router vs Pages Router - Server components vs client components pattern - Where API routes live - Auth flow (NextAuth, Clerk, custom) - Env vars required (list names, not values) settings.json: "allow": ["Bash(npm run *)", "Bash(npx *)", "Bash(git *)", "Read(*)", "Edit(*)"]
Python / FastAPI / Django
CLAUDE.md highlights: - Virtual env setup: `python -m venv .venv && source .venv/bin/activate` - Package manager: pip / poetry / uv - How to run: `uvicorn main:app --reload` or `python manage.py runserver` - Test runner: pytest, coverage, fixtures location settings.json: "allow": ["Bash(python *)", "Bash(pip *)", "Bash(uv *)", "Bash(pytest *)", "Bash(git *)", "Read(*)", "Edit(*)"]
Go Service
CLAUDE.md highlights: - Module path from go.mod - Build: `go build ./...` - Test: `go test ./...` - Key packages and their responsibilities - Proto/gRPC definitions location settings.json: "allow": ["Bash(go build *)", "Bash(go test *)", "Bash(go run *)", "Bash(go vet *)", "Bash(git *)", "Read(*)", "Edit(*)"]
iOS / React Native
CLAUDE.md highlights: - `npm start` for Metro bundler - `npx expo run:ios` or Xcode scheme - Navigation structure (React Navigation, Expo Router) - State management approach settings.json: "allow": ["Bash(npm run *)", "Bash(npx expo *)", "Bash(git *)", "Read(*)", "Edit(*)"]
Complete Example: A Production-Ready Setup
Here's what a fully configured project looks like for a Next.js SaaS app:
CLAUDE.md:
# Project: Acme SaaS ## Overview B2B analytics dashboard for e-commerce teams. Next.js 14 with App Router, PostgreSQL, Stripe billing. Currently: migrating from Pages Router, ~70% done. ## Commands ```bash npm run dev # Dev server http://localhost:3000 npm test # Jest + React Testing Library npm run test:e2e # Playwright (requires running dev server) npm run db:migrate # Run pending Prisma migrations npm run db:seed # Seed dev database npm run build # Production build npm run typecheck # tsc --noEmit ``` ## Stack Next.js 14 · TypeScript · Prisma + PostgreSQL · NextAuth.js (Google/GitHub) · Stripe · Tailwind · shadcn/ui ## Architecture - `src/app/` — App Router pages (migrating from `pages/`) - `src/app/(dashboard)/` — Authenticated routes (layout checks session) - `src/components/ui/` — shadcn/ui primitives - `src/components/charts/` — recharts wrappers - `src/lib/db.ts` — Prisma client singleton - `src/lib/stripe.ts` — Stripe client + webhook handlers - `src/server/` — Server actions (prefix: `action`) ## Conventions - Server components by default. `'use client'` only for interactivity. - Zod schemas in `src/lib/schemas/` for all API input - shadcn/ui components only — never write raw HTML form elements - Data fetching in server components via `src/lib/queries/` - No `useEffect` for data — use server components + React Query for client-side ## Current Focus Migrating `pages/api/` to `src/app/api/`. Then App Router layout groups. Known issue: `/api/webhooks/stripe` must stay in `pages/api/` (NextAuth conflict).
.claude/settings.json:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npx *)",
"Bash(git status)", "Bash(git log *)", "Bash(git diff *)",
"Bash(git add *)", "Bash(git commit *)", "Bash(git checkout *)",
"Bash(git stash)", "Bash(git stash pop)",
"Read(*)",
"Edit(*)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force*)",
"Bash(sudo *)",
"Bash(git reset --hard*)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit(src/**/*.ts)",
"hooks": [{"type": "command", "command": "npm run typecheck 2>&1 | tail -15"}]
}
],
"Stop": [
{
"matcher": "",
"hooks": [{"type": "command", "command": "notify-send 'Claude Code' 'Ready' 2>/dev/null || true"}]
}
]
}
}
Frequently Asked Questions
What is CLAUDE.md and why do I need it?
CLAUDE.md is a Markdown file that Claude Code reads at the start of every session. It functions as persistent project memory — you describe your tech stack, key commands, architecture, and coding conventions. Without it, Claude has no context about your project and you'll repeat yourself every session. With a good CLAUDE.md, Claude knows your project instantly and can work with no preamble.
Where does Claude Code store project settings?
Project-level settings live in .claude/settings.json at your project root. This file controls allowed shell commands, file path permissions, tool policies, and hooks. It's safe to commit to git — it contains no secrets. User-level settings (global defaults) live in ~/.claude/settings.json.
Should I commit CLAUDE.md to git?
Yes. CLAUDE.md is pure documentation — it makes Claude instantly productive for everyone who works on the project. Commit CLAUDE.md and .claude/settings.json. Add .claude/settings.local.json to .gitignore (that file is for personal overrides).
How do I generate a CLAUDE.md automatically?
claude "analyse this codebase and generate a comprehensive CLAUDE.md file covering: project purpose, tech stack, all dev commands, directory structure, and key conventions. Output to CLAUDE.md"
Review and edit the output — Claude usually gets 80-90% right and you refine the rest.
Can I have multiple CLAUDE.md files?
Yes. Claude reads CLAUDE.md from the current directory and all parent directories up to the project root. For mono-repos, put a root CLAUDE.md with overall structure, and per-package CLAUDE.md files for package-specific context. For a user-level CLAUDE.md (applies to all your projects), put it at ~/.claude/CLAUDE.md.
How do I set up Claude Code for a team?
Commit CLAUDE.md and .claude/settings.json to the repo. Each teammate installs Claude Code (npm install -g @anthropic-ai/claude-code) and sets their own API key. They inherit the full project config automatically on first claude run. No additional setup required.
→ Deep-dive: Claude Code Memory & CLAUDE.md Guide
→ Claude Code Hooks — Automate actions on tool use
→ Claude Code Best Practices — Power user workflows