How to set up Claude Code for a new project
Status: 🟩 COMPLETE Last updated: 2026-06-19 Plain-English tagline: The first-day Claude Code configuration for a new project —
CLAUDE.mdin the repo,.claude/settings.jsonfor permissions + hooks, and the global~/.claude/for cross-project conventions. ~15 minutes; pays back forever.
Goal
By the end of this guide, your new project has:
- A
CLAUDE.mdat the repo root with project-specific conventions Claude will load every conversation - A
.claude/settings.jsonwith sensible permissions (auto-allow common safe commands) - A documented place for project-specific memories
- A connection to the global
~/.claude/setup (memories, plugins) you’ve built across projects
This setup is what makes Claude Code feel “tuned to your project” rather than “asking the same context every conversation.”
Why it matters
Without setup, every Claude Code session starts cold: Claude doesn’t know your stack, doesn’t know your conventions, doesn’t know which commands are safe to run without asking. The same instructions get repeated dozens of times.
With setup:
- Project-specific patterns (stack, file structure, conventions) are loaded automatically
- Safe commands run without permission prompts (
npm test,npm run lint) - Risky commands still pause (
git push --force,rm -rf) - Project-specific memories accumulate productively over time
For Bible Quest-style projects, a 15-minute setup at project start is recovered within the first day of use.
Prerequisites
- Claude Code installed (
npm install -g @anthropic-ai/claude-code) - A new project folder (could be a fresh
npx create-next-app) - A working
~/.claude/setup from previous projects (optional but recommended) - Knowledge of Claude Code basics
Steps
1. Run /init to scaffold CLAUDE.md
Open Claude Code in your project:
cd path/to/new-project
claudeRun the built-in init command:
> /init
Claude examines the project (reads package.json, scans the file tree, looks at any docs) and proposes a CLAUDE.md. Review and accept. The file lands at the project root.
Alternatively, write it by hand. A starting template for a Next.js project:
# Project Name
## Stack
- Next.js 16 (App Router)
- Supabase (Postgres + Auth + Storage)
- Vercel (hosting; functions pinned to syd1 for Sydney users)
- Tailwind CSS + shadcn/ui
- TypeScript everywhere; `strict: true`
## Conventions
- Server actions for mutations (not API routes)
- All data access through Supabase clients (`lib/supabase/server.ts`, `lib/supabase/client.ts`)
- RLS on every Supabase table; service role key NEVER exposed client-side
- Use shadcn/ui components; only add custom UI when shadcn doesn't have it
- Mobile-first Tailwind (default mobile; `md:` and up for desktop)
- Dark mode support from day one (semantic tokens via shadcn variables)
## Code style
- Functional components only
- `async/await` over `.then()`
- Validate inputs at boundaries with Zod
- No magic strings — extract enums or constants
## Don't
- Use any `NEXT_PUBLIC_*` env var for secrets
- Modify database migrations after they've been applied to production
- Skip `npm run build` before pushing — always verify production build
## Local dev
- Run dev server: `npm run dev`
- Run tests: `npm test` (Vitest)
- Run E2E: `npx playwright test`
- Run lint: `npm run lint`
- Type check: `npx tsc --noEmit`
## Key files
- `app/` — all routes and pages
- `lib/supabase/` — Supabase clients
- `lib/utils.ts` — shared utilities + `cn` helper
- `components/ui/` — shadcn components (don't edit directly)
- `components/` — custom components
## When working on this project
- Always run `npm run build` before declaring a feature done
- Update PROGRESS.md after shipping any meaningful feature
- Prefer server components over client components when possibleCommit this:
git add CLAUDE.md
git commit -m "Add CLAUDE.md"Every Claude Code conversation in this project will read it.
2. Create .claude/settings.json for permissions
Project-scoped settings live in .claude/settings.json at the project root.
mkdir .claudeCreate .claude/settings.json:
{
"permissions": {
"allow": [
"Bash(npm run dev)",
"Bash(npm run build)",
"Bash(npm run lint)",
"Bash(npm test)",
"Bash(npx tsc --noEmit)",
"Bash(npx playwright test)",
"Bash(git status)",
"Bash(git diff)",
"Bash(git log:*)",
"Bash(git branch:*)",
"Bash(gh pr view:*)",
"Bash(gh pr list:*)",
"Read(*)",
"Edit(*)",
"Write(*)"
],
"ask": [
"Bash(git push:*)",
"Bash(git rebase:*)",
"Bash(git reset:*)",
"Bash(npm install:*)",
"Bash(gh pr create:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force)",
"Bash(git reset --hard:*)"
]
}
}The three categories:
allow— Claude can run these without askingask— Claude pauses for confirmationdeny— Claude refuses to run
Tune to your comfort. The example above is conservative (asks before destructive git operations, blocks rm -rf). For a team project, ask more; for a solo greenfield, allow more.
3. Decide what to commit
Three patterns for the .claude/ folder in version control:
Pattern A: Commit everything (small projects, solo or trusted team)
git add .claude
git commit -m "Add .claude config"Settings + any saved prompts + skills are versioned. Easy to share.
Pattern B: Commit .claude/settings.json but gitignore the rest
.gitignore:
.claude/
!.claude/settings.json
Settings are shared; ephemeral state (logs, drafts) isn’t.
Pattern C: Gitignore everything (sensitive content possible)
.claude/
Nothing is shared. Each developer configures themselves.
For Bible Quest: Pattern A. The settings are useful for collaborators (including future-George six months later).
4. Set up project-specific memories
The full memory system lives at ~/.claude/projects/<project-folder-name>/memory/. For a project at C:\Users\georg\my-app, that becomes C:\Users\georg\.claude\projects\C--Users-georg-my-app\memory\.
Important memories to seed early:
project_tech_stack.md— what’s in use, version pins, gotchasproject_progress_log.md— newest-first log of major features shippedproject_<name>_app.md— high-level project overview
These accumulate naturally as the project grows. Don’t write them all on day one — let memory grow organically as conversations expose what’s worth remembering.
To add the first memory:
> Save a memory file: project_tech_stack.md, with the following content...
Claude creates the file in the right location and updates MEMORY.md automatically (see Add a new memory file for the manual process).
5. (Optional) Hook in to the global setup
If you have a global ~/.claude/CLAUDE.md (probably, if you’ve used Claude Code on previous projects), it loads automatically. No action needed.
To verify what’s loaded in a session, ask Claude:
> What CLAUDE.md files are loaded for this conversation?
Claude lists all loaded memory files. Should include:
~/.claude/CLAUDE.md(global)CLAUDE.md(project)~/.claude/projects/<project-folder>/memory/MEMORY.md(the memory index)
6. (Optional) Set up hooks
Hooks run automated commands on certain events. For example, “after every file edit, run npm run lint.” Add to .claude/settings.json:
{
"permissions": { /* ... */ },
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx eslint --fix \"$CLAUDE_FILE_PATHS\"" }
]
}
]
}
}(Exact hook syntax depends on Claude Code version; check current docs.)
Hooks make some workflows seamless but can also be intrusive. Add them deliberately, not aspirationally.
7. (Optional) Add useful slash commands
Custom slash commands live in .claude/commands/ as Markdown files. Each is a “saved prompt.”
Example .claude/commands/full-check.md:
Run the full quality pipeline:
1. npm run lint
2. npx tsc --noEmit
3. npm test
4. npm run build
Report any failures and propose fixes.In Claude Code: type /full-check and Claude runs this prompt.
8. Verify
In a fresh Claude Code session:
cd path/to/project
claudeClaude should:
- Have read
CLAUDE.mdautomatically - Apply the permissions from
.claude/settings.json - Reference project memories when relevant
Test:
> What's this project's stack?
Claude should answer accurately based on CLAUDE.md.
> Run npm test.
Should run without a permission prompt (because it’s in the allow list).
> Run git push --force.
Should refuse (because it’s in deny list).
Verification
A working setup looks like:
- ✅ Opening Claude Code in the project — Claude knows the stack
- âś… Running
npm run lint— no permission prompt - ✅ Running risky commands — prompts for confirmation
- ✅ Asking “what’s loaded?” — Claude lists CLAUDE.md + memories
- ✅ Asking about project conventions — Claude knows them
Common failures and fixes
”CLAUDE.md isn’t being loaded”
Make sure:
- It’s at the repo ROOT (not in a subfolder)
- It’s literally named
CLAUDE.md(case-sensitive on Linux/Mac) - The file exists when you start Claude Code
Some projects mistakenly put it in .claude/CLAUDE.md — that’s NOT the loaded one. It must be at the project root.
”Permissions aren’t applying”
Three causes:
.claude/settings.jsonsyntax is wrong. JSON parse errors silently skip the file. Validate JSON.- You’re running an OLD Claude Code version. Update:
npm install -g @anthropic-ai/claude-code@latest. - A higher-priority config overrides it. Check user-level
~/.claude/settings.jsonfor conflicts.
”Hooks aren’t firing”
Verify the matcher pattern matches the tool name. Run a hook with --verbose (if available) to see what triggered or didn’t.
”Claude knows about old conventions, not new ones”
You updated CLAUDE.md but Claude still references the old version. Two causes:
- Conversation cache — the current conversation has the OLD version. Type
/clearto reset; new conversation will read the updated CLAUDE.md. - Memory file conflict — a memory says one thing; CLAUDE.md says another. Update both.
”Different developers have different setups”
Either:
- Commit
.claude/settings.jsonso everyone gets the same - Document the expected setup in CLAUDE.md (a section called “First-time setup”)
- Use a project README section about Claude Code configuration
”I want to share my custom commands with the team”
Commit .claude/commands/*.md. They’re text files; checking them in works.
”I don’t want to share my hooks (they’re personal)”
Put project-shared settings in .claude/settings.json (commit). Put personal hooks in a per-user override location.
A concrete example: setting up Bible Quest
The Bible Quest project (C:\Users\georg\st-marks-bible-quest) has:
CLAUDE.mdat the repo root — full project conventions.claude/settings.json— committed; defines allow/ask/deny permissions~/.claude/CLAUDE.md(global) — George’s universal preferences across all projects (auto-loaded too)~/.claude/projects/C--Users-georg-st-marks-bible-quest/memory/— project-specific memory files
Memories evolve over time. Notable ones:
project_bible_study_app.md— top-level overviewproject_tech_stack.md— stack + gotchasproject_progress_log.md— chronological feature logplaybook_*.md— reusable conventions (live in~/.claude/projects/C--Users-georg/memory/)
This setup made the project workflow dramatically smoother — sessions don’t repeat “what’s the stack?” or “how do we handle auth?” every time.
What just happened, conceptually
Claude Code’s configuration cascades through three layers:
1. Global: ~/.claude/CLAUDE.md + ~/.claude/settings.json
↓
2. Project: <repo>/CLAUDE.md + <repo>/.claude/settings.json
↓
3. Conversation: current Claude conversation context (slash commands, ad-hoc prompts)
Project settings OVERRIDE global ones. Conversation context layers on top of both.
You build setup gradually:
- Day 1:
CLAUDE.mddescribing the stack - Week 1: permissions tuned for common commands
- Month 1: memories accumulate for project-specific patterns
- Month 6: refined hooks, custom slash commands, plugin integrations
The 15-minute setup is the foundation; the rest grows naturally.
See also
- Claude Code overview 🟩 🟦 — first orientation
- Claude Code deep dive 🟩 🟦 — comprehensive
- Memory system 🟩 🟦 — how memory works
- Add a new memory file 🟩 — the per-memory workflow
- settings.json 🟩 🟦
- Hooks 🟩 🟦
- Slash commands 🟩 🟦
- Plugins 🟩 🟦
- Subagents 🟩 🟦
- Dotfiles & config 🟩 — where
~/.claude/lives - Start a new Next.js project (with the playbook) 🟩 — the broader scaffold