Skip to content

Best Practices for Real-World AI Coding Workflows

The CLAUDE.md is the most impactful thing you can do. Claude reads it every session.

# Project Name
## What this project is (2-3 sentences)
Be specific: "A REST API for processing payments, built with Node.js + TypeScript.
Uses Stripe for payment processing and PostgreSQL for storage."
## Build, test, and run commands
The exact commands. Don't describe them — show them.
- Dev: `npm run dev`
- Test: `npm test`
- Lint: `npm run lint`
- Build: `npm run build`
## Hard rules (things Claude must never do)
- Never commit to main directly
- Never modify migration files once applied
- Never use `npm` — always `pnpm`
## Architecture overview
One paragraph. Where are the key directories and what's in them?
## Common patterns
Show examples, not just rules:
"Error handling: throw AppError('message', 400) — see src/types/errors.ts"
## Known gotchas
What trips up even experienced developers on this project?
  • Things obvious from the code (Claude can read the code)
  • Git history or “we changed X last week”
  • Long philosophy sections — be concrete
  • Duplicate content that’s already in docs files (use @import instead)

Spending 5 minutes on permissions saves dozens of “approve this?” prompts.

{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(pnpm *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git checkout *)",
"Bash(git push origin *)",
"Bash(gh pr *)",
"Read",
"Edit",
"Write",
"Glob",
"Grep"
],
"deny": [
"Bash(git push --force *)",
"Bash(rm -rf *)",
"Bash(sudo *)",
"Edit(.env*)",
"Edit(prisma/migrations/**)"
]
}
}

Rule of thumb: Allow the things Claude will do constantly. Deny the things that are irreversible.


3. Give Claude Enough Context, Not Too Much

Section titled “3. Give Claude Enough Context, Not Too Much”
"There's a race condition in src/services/queue.ts — fix it"
"Add input validation to the /api/users endpoint in src/handlers/users.ts"
"The app is broken" ← Claude has to guess where to start
"Make it better" ← not actionable
"This error is appearing in prod:
TypeError: Cannot read property 'id' of undefined
at PaymentService.process (src/services/payment.ts:47)
Fix it."

Before touching any files on a big refactor or new feature:

Terminal window
claude --permissions plan
> Explore the authentication flow and tell me how it works.
> Map out every file involved.

Once you understand the landscape, switch to normal mode:

Shift+Tab ← cycles to normal mode
> Now implement OAuth2 login following the patterns you found

This prevents Claude from rushing into edits based on incomplete understanding.


Don’t:

"Upgrade all dependencies, add dark mode, refactor the auth system,
and deploy to production"

Do:

Session 1: "Upgrade dependencies one by one, running tests each time"
Session 2: "Add dark mode to the settings page only"
Session 3: "Refactor auth — explore first, then implement"
Session 4: "Deploy to staging"

This keeps each session focused, reviewable, and reversible.


Never let Claude commit without reviewing the diff:

Terminal window
git diff # see what changed
git diff --staged # see what's staged

Or:

> Show me a summary of what you changed and why

Ask Claude to explain any change you don’t understand before accepting it.


For large tasks, subagents keep the main context clean:

Instead of:

> Read all 50 files in src/, then find all the bugs

Do:

> @Explore: map the entire src/ directory and give me a summary of each module

The Explore agent uses its own context window, returns a clean summary, and your main session stays light.


8. Keep Auto Memory On, Review It Occasionally

Section titled “8. Keep Auto Memory On, Review It Occasionally”

Auto memory saves Claude from re-learning things every session. But review it periodically:

Terminal window
/memory

Remove stale entries (e.g. “run npm install because of missing deps” if you’ve since fixed that).


9. Use Hooks for Enforcement, Not Reminders

Section titled “9. Use Hooks for Enforcement, Not Reminders”

If you find yourself constantly telling Claude “remember to run lint after editing”:

{
"hooks": [{
"event": "PostToolUse",
"if": { "tool": "Edit", "path": "**/*.ts" },
"run": "sh",
"args": ["-c", "npx eslint $file_path --fix 2>/dev/null || true"],
"continueOnError": true
}]
}

Now it happens automatically — you don’t need to say it.


10. Design Skills Around Outcomes, Not Steps

Section titled “10. Design Skills Around Outcomes, Not Steps”

Bad skill: lists every command with no judgment

# Deploy
Run: `npm test`
Run: `npm build`
Run: `sls deploy`

Good skill: states the outcome and lets Claude handle edge cases

# Deploy to $ARGUMENTS
Deploy the application to $ARGUMENTS safely.
Success criteria:
- All tests pass
- Build completes without errors
- Deployment health check returns 200
- Smoke test passes
Abort immediately if any step fails. Never deploy with failing tests.

Add to deny list:

{
"permissions": {
"deny": [
"Edit(.env)",
"Edit(.env.*)",
"Edit(*.pem)",
"Edit(*.key)"
]
}
}

For security-sensitive code (auth, crypto, payment), always review manually. Claude can introduce subtle vulnerabilities even with good prompting.

Use --permissions plan before running unfamiliar code

Section titled “Use --permissions plan before running unfamiliar code”

If Claude writes a shell script, review it in plan mode before running it.

Never use "defaultMode": "bypassPermissions" outside of a container you control.


.claude/settings.json ✓ shared permissions and hooks
.claude/CLAUDE.md ✓ project instructions
.claude/rules/ ✓ path-scoped rules
.claude/skills/ ✓ shared workflows
.claude/agents/ ✓ shared subagents
.mcp.json ✓ shared MCP servers
.claude/settings.local.json ✗ personal model/theme preferences
CLAUDE.local.md ✗ personal instructions
.claude.local.json ✗ personal MCP auth tokens

Team CLAUDE.md vs personal CLAUDE.local.md

Section titled “Team CLAUDE.md vs personal CLAUDE.local.md”

Team .claude/CLAUDE.md:

  • Build commands
  • Architecture overview
  • Hard rules everyone follows

Personal CLAUDE.local.md:

  • Your preferred response style
  • Your debugging preferences
  • Context about your current work focus

If Claude is going in the wrong direction, press Esc and say “actually, do it this way instead” rather than letting it finish and then correcting.

If Claude made edits you don’t want, Esc+Esc rewinds to the previous checkpoint.

After an hour or many file edits, start a new session for a new task. Long sessions accumulate context noise.

If you’ve been chatting a while and want Claude to tackle a large feature, compact first to free up context.


TaskModel to use
Exploring/searching codebaseclaude-haiku-4-5 (fast, cheap)
Writing code, fixing bugsclaude-sonnet-4-6 (balanced)
Complex architecture, security reviewclaude-opus-4-8 (most capable)
CI/CD automationclaude-haiku-4-5 (cost-efficient)

Set per-agent in the agent frontmatter, or switch mid-session with /model.


A well-configured Claude Code setup should feel like this:

  • Permission prompts are rare (you pre-approved the common ones)
  • Claude knows your conventions without being told each session (CLAUDE.md + memory)
  • Repetitive workflows run with one command (skills)
  • Complex tasks are broken into the right agents automatically
  • You review and understand every change before it’s committed
  • Tests run automatically and catch regressions

If you’re spending more time fighting Claude than building, check:

  1. Is CLAUDE.md clear and specific?
  2. Are permissions configured correctly?
  3. Are you giving tasks that are too large?
  4. Are you in the right permission mode for the task?
  • Trick: “Practice #0 is verify — never trust, always test.”
  • Do: turn the 15 into a team checklist; adopt the top 5 first.
  • They’ll trip on: adopting all 15 at once — habit-stack one per week.

Learning path:42-large-codebases.md · Index · ➡ 44-anthropic-courses.md

Written by Fenil Patel