Project configuration allows you to customize Claude Code’s behavior for specific repositories, creating consistent workflows shared across your team.
Project Structure
Claude Code uses a .claude/ directory in your project root:
project-root/
├── .claude/
│ ├── CLAUDE.md # Project context and conventions
│ ├── settings.json # Project settings
│ ├── settings.local.json # Local overrides (gitignored)
│ ├── .mcp.json # MCP server configuration
│ ├── commands/ # Custom slash commands
│ │ ├── deploy.md
│ │ └── test-all.md
│ ├── agents/ # Custom agents
│ │ ├── security-audit.md
│ │ └── perf-analyzer.md
│ ├── skills/ # Custom skills
│ │ └── api-design/
│ │ ├── SKILL.md
│ │ └── examples/
│ └── hooks/ # Event hooks
│ └── hooks.json
├── .gitignore
└── ...
CLAUDE.md - Project Context
The CLAUDE.md file provides project-specific context to Claude:
Location
Or at project root:
What to Include
Project Overview :
# Project: E-commerce Platform
A Node.js/TypeScript e-commerce backend with:
- REST API using Express
- PostgreSQL database
- Redis caching
- JWT authentication
- Stripe payment integration
Architecture :
## Architecture
- **Controllers** ( `src/controllers/` ): Handle HTTP requests
- **Services** ( `src/services/` ): Business logic
- **Models** ( `src/models/` ): Database schemas (TypeORM)
- **Middleware** ( `src/middleware/` ): Auth, validation, error handling
- **Utils** ( `src/utils/` ): Shared utilities
Data flow: Controller → Service → Model → Database
Code Conventions :
## Code Style
### Naming
- Classes: PascalCase ( `UserService` )
- Functions: camelCase ( `getUserById` )
- Files: kebab-case ( `user-service.ts` )
- Constants: UPPER_SNAKE_CASE ( `MAX_RETRIES` )
### Patterns
- Use async/await, never .then()
- Dependency injection via constructor
- All exported functions must have JSDoc
- Prefer named exports over default
### Error Handling
```typescript
try {
const result = await operation ();
return result ;
} catch ( error ) {
logger . error ( 'Operation failed' , { error , context });
throw new AppError ( 'User-friendly message' , 500 );
}
Testing
Unit tests: *.test.ts next to source files
Integration tests: __tests__/ directories
Minimum 80% coverage required
Use Jest for all testing
**Technology Stack**:
```markdown
## Tech Stack
### Backend
- Runtime: Node.js 18+
- Language: TypeScript 5.0
- Framework: Express 4.x
- ORM: TypeORM 0.3
### Database
- Primary: PostgreSQL 14
- Cache: Redis 7
### External Services
- Payments: Stripe API
- Email: SendGrid
- Storage: AWS S3
Common Tasks :
## Common Tasks
### Running Tests
```bash
npm test # All tests
npm test -- --watch # Watch mode
npm test -- --coverage # With coverage
Database
npm run db:migrate # Run migrations
npm run db:seed # Seed data
npm run db:reset # Reset (dev only)
Development
npm run dev # Start dev server
npm run build # Build for production
npm run lint # Run ESLint
**Constraints**:
```markdown
## Constraints
- No console.log in production code (use logger)
- No `any` types in TypeScript
- All API endpoints require authentication
- All database queries must use parameterized queries
- All user input must be validated (use Joi schemas)
- All secrets in environment variables, never hardcoded
Complete Example
# E-commerce API Project
Node.js/TypeScript REST API for e-commerce platform.
## Architecture
Layered architecture:
- **Routes** ( `src/routes/` ): Endpoint definitions
- **Controllers** ( `src/controllers/` ): Request handling
- **Services** ( `src/services/` ): Business logic
- **Repositories** ( `src/repositories/` ): Data access
- **Models** ( `src/models/` ): TypeORM entities
## Code Conventions
### File Organization
- Feature-based: `src/features/users/` , `src/features/products/`
- Each feature has: routes, controller, service, repository, model, tests
### TypeScript
- Strict mode enabled
- No `any` types (use `unknown` and type guards)
- Interfaces for all public APIs
- Types in `*.types.ts` files
### Async/Await
```typescript
// Good
async function getUser ( id : string ) : Promise < User > {
const user = await userRepository . findById ( id );
if ( ! user ) throw new NotFoundError ( 'User not found' );
return user ;
}
// Bad - don't use .then()
function getUser ( id : string ) : Promise < User > {
return userRepository . findById ( id )
. then ( user => {
if ( ! user ) throw new NotFoundError ( 'User not found' );
return user ;
});
}
Error Handling
Use custom error classes: AppError, NotFoundError, ValidationError
Always log errors with context
Return user-friendly messages, log technical details
try {
const result = await riskyOperation ();
return result ;
} catch ( error ) {
logger . error ( 'Operation failed' , {
error ,
userId ,
operation: 'riskyOperation'
});
throw new AppError ( 'Could not complete operation' , 500 );
}
Testing
Coverage requirement: 80%
Test file naming: *.test.ts
Use descriptive test names: should return 404 when user not found
Mock external services
Use factories for test data
API Design
REST Conventions
Use plural nouns: /users, /products
Nested resources: /users/:id/orders
Query params for filters: /products?category=electronics&sort=price
Request/Response
// Success response
{
"data" : { ... },
"meta" : { "timestamp" : "2024-01-01T00:00:00Z" }
}
// Error response
{
"error" : {
"message" : "User-friendly error" ,
"code" : "VALIDATION_ERROR" ,
"details" : []
}
}
Database
Migrations
Always create migrations for schema changes
Never edit existing migrations
Test migrations up and down
Queries
Use query builders or parameterized queries
Add indexes for foreign keys
Use transactions for multi-table operations
Security
All endpoints authenticated (except auth endpoints)
Use bcrypt for passwords (cost factor: 12)
JWT tokens expire in 1 hour
Refresh tokens in HTTP-only cookies
Rate limit: 100 requests/minute per IP
Input validation with Joi schemas
Sanitize all user input
No secrets in code (use .env)
Environment Variables
Required in .env:
NODE_ENV = development
PORT = 3000
DATABASE_URL = postgresql://...
REDIS_URL = redis://...
JWT_SECRET = ...
STRIPE_SECRET_KEY = ...
Commit Messages
Follow Conventional Commits:
feat(users): add password reset endpoint
fix(auth): handle expired tokens correctly
docs(api): update authentication docs
test(products): add integration tests
Dependencies
Keep dependencies up to date (review monthly)
No deprecated packages
Audit with npm audit before committing
Document why each dependency is needed
## Project Settings
### settings.json
Project-wide settings shared via git:
```json
{
"model": "claude-sonnet-4.6",
"permissions": {
"allow": [
"Read",
"Grep",
"Glob",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(npm test:*)",
"Bash(npm run:*)"
],
"ask": [
"Edit",
"Write",
"Bash(git commit:*)",
"Bash(git push:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)"
]
},
"verbose": false,
"theme": "auto",
"spinnerVerbs": ["Building", "Testing", "Deploying"]
}
settings.local.json
Personal overrides (not committed):
{
"theme" : "dark" ,
"verbose" : true ,
"permissions" : {
"allow" : [
"Edit" ,
"Write"
]
}
}
Add to .gitignore:
.claude/settings.local.json
.claude/.mcp.json # If contains credentials
Custom Commands
Create project-specific workflows:
Deploy Command
.claude/commands/deploy.md:
---
description : Deploy to production
allowed-tools : Bash(git:*), Bash(npm:*)
---
# Production Deployment
Deploy application to production:
1. Verify on main branch: ! `git branch --show-current`
2. Ensure clean working directory: ! `git status --porcelain`
3. Run tests: ! `npm test`
4. Build: ! `npm run build`
5. Tag version: ! `git tag -a v$(node -p "require('./package.json').version") -m "Release"`
6. Push tag: ! `git push --tags`
7. Deploy: ! `npm run deploy:prod`
Stop if any step fails.
Database Reset
.claude/commands/db-reset.md:
---
description : Reset development database
allowed-tools : Bash(npm:*)
---
# Database Reset
**WARNING: This will destroy all data!**
1. Confirm with user first
2. Drop database: ! `npm run db:drop`
3. Create database: ! `npm run db:create`
4. Run migrations: ! `npm run db:migrate`
5. Seed data: ! `npm run db:seed`
Report status after each step.
Custom Agents
Specialized project agents:
API Documentation Generator
.claude/agents/api-docs.md:
---
description : Generate API documentation from code
model : claude-sonnet-4.6
tools : [ "Read" , "Grep" , "Write" ]
---
# API Documentation Generator
Generate API documentation:
1. Find all route files in `src/routes/`
2. Extract from each route:
- HTTP method and path
- Request parameters (path, query, body)
- Response schema
- Error codes
- Authentication requirements
3. Generate Markdown documentation
4. Write to `docs/api.md`
Follow OpenAPI 3.0 structure for consistency.
Database Migration Creator
.claude/agents/create-migration.md:
---
description : Create database migration from schema changes
model : claude-opus-4.6
tools : [ "Read" , "Write" , "Bash" ]
---
# Migration Creator
Create migration for: $ARGUMENTS
1. Analyze current schema in `src/models/`
2. Determine required changes
3. Generate TypeORM migration
4. Create migration file: `src/migrations/TIMESTAMP-{description}.ts`
5. Include up and down migrations
6. Test migration locally
Follow TypeORM migration patterns from existing migrations.
Event Hooks
Automate workflows with hooks:
.claude/hooks/hooks.json:
{
"hooks" : [
{
"name" : "lint-on-edit" ,
"events" : [ "PostToolUse" ],
"command" : "npm run lint:fix" ,
"match" : {
"tool" : "Edit" ,
"file" : "src/**/*.ts"
}
},
{
"name" : "test-before-commit" ,
"events" : [ "PreToolUse" ],
"command" : "npm test" ,
"match" : {
"tool" : "Bash" ,
"pattern" : "git commit:*"
},
"blocking" : true
},
{
"name" : "security-check" ,
"events" : [ "PreToolUse" ],
"command" : "./scripts/security-check.sh" ,
"match" : {
"tool" : "Bash" ,
"pattern" : "npm install:*"
},
"blocking" : true
}
]
}
MCP Configuration
Connect external tools:
.claude/.mcp.json:
{
"mcpServers" : {
"github" : {
"command" : "npx" ,
"args" : [ "-y" , "@modelcontextprotocol/server-github" ],
"env" : {
"GITHUB_TOKEN" : "${GITHUB_TOKEN}"
}
},
"postgres" : {
"command" : "python" ,
"args" : [ "-m" , "mcp_server_postgres" ],
"env" : {
"DATABASE_URL" : "${DATABASE_URL}"
}
}
}
}
Don’t commit credentials! Use environment variables and add .mcp.json to .gitignore if it contains secrets.
Best Practices
Document conventions : Keep CLAUDE.md updated with project patterns
Share commands : Commit useful commands to help the whole team
Use local settings : Personal preferences go in settings.local.json
Version control : Commit .claude/ to git (except .local.json)
Test hooks : Use blocking: false while developing hooks
Troubleshooting
CLAUDE.md Not Loaded
Issue : Claude doesn’t follow project conventions
Solutions :
Check file location: .claude/CLAUDE.md or project root
Verify file is not too large (stays within context limits)
Reference explicitly: “Follow guidelines in @CLAUDE.md”
Commands Not Appearing
Issue : Custom commands don’t show in autocomplete
Solutions :
Check files are in .claude/commands/
Verify .md extension
Check frontmatter syntax
Restart Claude Code
Hooks Not Executing
Issue : Event hooks don’t fire
Solutions :
Verify hooks.json syntax
Check event names
Test command manually
Check match patterns
Look for errors in output
Next Steps
Settings Configure global and project settings
Task Automation Create commands, agents, and hooks
Environment Variables Use environment-based configuration
Git Workflows Automate version control