Claude Code Configuration & Workflows
Claude Code is not just a chatbot pasted into a terminal. It is a fully configurable agentic coding environment that reads your project conventions, follows scoped rules, executes custom skills, and integrates into CI/CD pipelines. The difference between a developer who simply types prompts and one who configures Claude Code properly is the difference between dictating to a stranger and collaborating with a teammate who already knows your codebase. This section covers every configuration surface in depth.
1. The CLAUDE.md Hierarchy
CLAUDE.md files are the primary mechanism for giving Claude Code persistent context about how you work. They are plain Markdown files placed at specific locations in your filesystem, and Claude reads them automatically at the start of every session. Think of them as the README that Claude actually reads — every time, without being asked.
There are three levels, and they follow a clear precedence rule: more specific overrides more general. A directory-level instruction beats a project-level instruction, which beats a user-level instruction. This mirrors how CSS specificity works — the closest rule wins.
User Level: ~/.claude/CLAUDE.md
This file applies to every project you open with Claude Code. It captures your personal preferences — coding style, language defaults, formatting opinions, and behavioral instructions that follow you everywhere.
# Personal Coding Preferences
## Language & Style
- I prefer TypeScript over JavaScript in all new files.
- Use `const` by default; only use `let` when reassignment is necessary.
- Prefer named exports over default exports.
- Use early returns to reduce nesting — never nest more than 3 levels deep.
## Formatting
- Use 2-space indentation in TypeScript, JavaScript, JSON, and YAML.
- Use 4-space indentation in Python and Rust.
- Always add trailing commas in multi-line arrays and objects.
- Prefer single quotes in JS/TS; double quotes in Python.
## Communication
- When explaining changes, be concise. Skip obvious descriptions.
- If a refactor touches more than 5 files, summarize the blast radius first.
- Never add comments that restate what the code already says.
## Git
- Write commit messages in imperative mood ("Add feature" not "Added feature").
- Keep the first line under 72 characters.
- Always include a blank line between the subject and body.
Project Level: ./CLAUDE.md
This file lives at the root of your repository. It captures conventions specific to this codebase — architecture patterns, build commands, testing strategies, and domain-specific rules. Every team member who uses Claude Code on this project benefits from the same instructions.
# Project: InvoiceTracker API
## Architecture
- This is a Node.js REST API using Express and Prisma ORM.
- All routes live in src/routes/ and follow the pattern: src/routes/{resource}.routes.ts
- Business logic lives in src/services/ — routes must NOT contain business logic directly.
- Database models are defined in prisma/schema.prisma — never edit the DB directly.
## Build & Run
- Install: `npm install`
- Dev server: `npm run dev` (runs on port 3001)
- Production build: `npm run build && npm start`
- Database migrations: `npx prisma migrate dev`
## Testing
- Test framework: Vitest
- Run all tests: `npm test`
- Run specific test: `npx vitest run src/services/__tests__/invoice.test.ts`
- Tests must pass before any commit. Run them after making changes.
## Conventions
- All API responses use the envelope format: `{ success: boolean, data?: T, error?: string }`
- Errors are handled by the global error middleware in src/middleware/errorHandler.ts
- Input validation uses Zod schemas co-located with routes.
- Environment variables are accessed through src/config/env.ts — never use process.env directly.
## Do NOT
- Do not install new dependencies without asking first.
- Do not modify the CI workflow files in .github/workflows/.
- Do not change the Prisma schema without discussing migration strategy.
Directory Level: ./src/api/CLAUDE.md
Directory-level files provide hyper-specific instructions for a particular folder. These are powerful for enforcing local conventions that do not apply globally — input validation rules in the API layer, pure-function constraints in utility folders, or strict typing requirements in shared packages.
# Route Handler Rules - Every route handler MUST validate its input using the co-located Zod schema. - Never import from src/services/ files that belong to a different domain. For example, invoice.routes.ts may import from invoice.service.ts but NOT from user.service.ts. Cross-domain calls go through the event bus in src/events/. - All route files export a single Express Router instance as the default export. - Always include request logging middleware for POST, PUT, and DELETE operations.
# Utility Function Rules - Every function in this directory must be a pure function — no side effects, no I/O. - Every function must have explicit TypeScript return types (no inference). - Every function must have at least one unit test in the adjacent __tests__/ folder. - Do not import from any src/ directory other than src/types/.
2. Rules with YAML Frontmatter
While CLAUDE.md files give broad context, the .claude/rules/ directory provides a more structured, granular mechanism. Each rule is a separate Markdown file with optional YAML frontmatter that controls when the rule activates. This is particularly useful for path-scoped instructions — rules that apply only when Claude is editing certain types of files.
Rules are stored in .claude/rules/ at the project root. Each file contains optional YAML frontmatter delimited by ---, followed by the rule body in Markdown.
--- description: Enforce strict TypeScript conventions globs: - "**/*.ts" - "**/*.tsx" --- # TypeScript Strict Mode Rules - Always enable `strict: true` in tsconfig. If you create a new tsconfig, include it. - Never use `any` type. Use `unknown` and narrow with type guards. - All function parameters and return types must be explicitly annotated. - Prefer `interface` over `type` for object shapes that may be extended. - Use `readonly` for properties that should not be reassigned after construction. - Prefer `as const` assertions over enum for string unions.
--- description: Python file naming and style conventions globs: - "**/*.py" --- # Python Conventions - Use snake_case for all variables, functions, and file names. - Use PascalCase only for class names. - All modules must include a module-level docstring. - Type hints are required on all public function signatures. - Use pathlib.Path instead of os.path for filesystem operations. - Prefer f-strings over .format() or % formatting.
---
description: Automatically run tests when test files are modified
globs:
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.spec.ts"
---
# Test File Rules
- After editing any test file, run the corresponding test suite to confirm it passes.
- Use `npx vitest run {filepath}` for individual test files.
- If a test fails, fix the test or the source code — do not skip or comment out tests.
- Test descriptions should follow the pattern: "should {expected behavior} when {condition}".
--- description: Database migration safety rules globs: - "prisma/**" - "drizzle/**" - "**/migrations/**" --- # Migration Safety - NEVER drop a column or table without explicit user confirmation. - All migrations must be reversible — include both `up` and `down` operations. - After generating a migration, read the SQL and summarize what it does before proceeding. - Test migrations against a local database before marking the task complete.
globs field uses standard glob patterns. A rule with globs: ["**/*.py"] only activates when Claude is working on Python files. Rules without a globs field apply universally. The description field helps Claude understand the rule's intent — write it clearly, as Claude uses it to determine relevance.3. Custom Skills
Skills are reusable, multi-step workflows stored in the .claude/skills/ directory. While rules provide passive instructions that Claude follows when relevant, skills are active procedures that Claude executes when invoked. Think of rules as guardrails and skills as playbooks.
Each skill is a Markdown file with YAML frontmatter defining its name, description, and optional constraints like allowed tools or execution context.
---
name: deploy
description: Build, test, and deploy the application to the staging environment
context: fork
allowed-tools:
- Bash
- Read
- Grep
---
# Deploy Skill
Execute the following steps in order. Stop immediately if any step fails.
## Step 1: Pre-flight Checks
- Run `git status` and confirm the working tree is clean. If there are uncommitted changes, warn the user and stop.
- Confirm we are on the `main` or `staging` branch. If not, warn and stop.
## Step 2: Run Tests
- Execute `npm test` and wait for completion.
- If any tests fail, report the failures and stop. Do not deploy with failing tests.
## Step 3: Build
- Run `npm run build`.
- Verify the `dist/` directory was created and contains output.
## Step 4: Deploy
- Run `npm run deploy:staging`.
- Capture and report the deployment URL.
## Step 5: Verify
- Run `curl -s {deployment_url}/health` and confirm a 200 response.
- Report the deployment status to the user.
--- name: review description: Perform a structured code review on staged changes context: fork allowed-tools: - Read - Grep - Glob - Bash --- # Code Review Skill Review the current staged changes (`git diff --cached`) against the following checklist: ## Security - [ ] No hardcoded secrets, API keys, or credentials - [ ] User input is validated and sanitized before use - [ ] SQL queries use parameterized statements (no string concatenation) ## Quality - [ ] Functions are under 50 lines; if longer, suggest extraction - [ ] No duplicated logic — check if similar code exists elsewhere with Grep - [ ] Error cases are handled explicitly (no silent catches) ## Testing - [ ] New functions have corresponding tests - [ ] Edge cases are covered (null, empty, boundary values) ## Style - [ ] Naming is clear and follows project conventions - [ ] No commented-out code left in place - [ ] Imports are organized and unused imports removed Output a structured review with findings grouped by category.
When to Create a Skill vs. a Rule
The distinction matters. Use it as a decision filter:
- Rule — A passive constraint or convention. "Always validate inputs in route handlers." Claude follows it automatically when the context matches.
- Skill — An active, multi-step procedure. "Deploy to staging." Claude executes it when the user invokes it with a slash command.
- If the instruction is "whenever you see X, do Y" — that is a rule.
- If the instruction is "when I ask you to do X, perform steps A, B, C" — that is a skill.
context: fork option runs the skill in a forked context, preventing it from polluting the main conversation history. This is ideal for self-contained workflows like deployment or code review. The allowed-tools field restricts which tools the skill can use — a security measure that prevents a review skill from accidentally writing files.4. Built-in Tools Deep Dive
Claude Code has a fixed set of built-in tools that it uses to interact with your filesystem, search your codebase, and execute commands. Understanding which tool to use when is critical for getting fast, accurate results. Using the wrong tool wastes tokens, slows responses, and can produce incomplete answers.
| Tool | Purpose | When to Use | When NOT to Use |
|---|---|---|---|
| Read | Read contents of a specific file by path | You know the exact file path. You need to see the full contents or a specific line range. | You are searching for something across many files. Use Grep or Glob instead. |
| Grep | Search file contents by regex pattern | Finding where a function is called, locating error messages, searching for patterns across the codebase. | You already know which file to look at (use Read). You need to find files by name, not content (use Glob). |
| Glob | Find files matching a name pattern | Finding all test files, locating config files, discovering which modules exist in a directory. | You need to search inside file contents (use Grep). You already know the file path (use Read). |
| Edit | Make targeted find-and-replace edits in a file | Changing a function name, updating an import, fixing a bug on a specific line, adding a parameter. | Creating a new file from scratch (use Write). Rewriting most of a file (use Write). |
| Write | Create a new file or completely overwrite an existing one | Writing a new component, creating a config file, generating a complete test suite from scratch. | Making small changes to an existing file (use Edit — it is faster and shows a clearer diff). |
| Bash | Execute any shell command | Running tests, git operations, installing packages, checking system state, building the project. | Searching files (use Grep/Glob). Reading files (use Read). These built-in tools are faster and more reliable than shell equivalents. |
The Search Strategy Pattern
A common workflow when investigating unfamiliar code follows this three-step pattern:
- Glob first to find relevant files:
Glob("**/auth*.ts")— "Show me all files related to authentication." - Grep to search within them:
Grep("validateToken", glob="**/auth*.ts")— "Find where token validation happens." - Read to examine the match:
Read("src/middleware/auth.ts", offset=42, limit=20)— "Show me the implementation."
This funnel — from broad discovery to targeted reading — minimizes wasted tokens and gets Claude to the relevant code quickly. When you prompt Claude with "find and fix the authentication bug," a well-configured Claude Code follows this pattern automatically. But if you prompt with "fix the bug in src/middleware/auth.ts line 45," it skips straight to Read and Edit.
5. Plan Mode
Plan Mode tells Claude to think before acting. Instead of immediately editing files and running commands, Claude first proposes a structured plan — which files to modify, what changes to make, and in what order — and waits for your approval before executing any of it.
When to Use Plan Mode
- Complex refactors — Renaming a widely-used interface, migrating from one library to another, restructuring directories.
- Unfamiliar codebases — When you have just cloned a repo and want Claude to explore before changing anything.
- Destructive operations — Deleting files, dropping database tables, force-pushing branches.
- Multi-file changes — When a single logical change touches more than three or four files, the plan helps you verify completeness.
- Learning situations — When you want to understand what Claude would do, so you can learn the codebase through its analysis.
When to Skip Plan Mode
- Simple, well-understood edits — "Add a createdAt field to the User model." The change is small and obvious.
- Single-file changes — Fixing a typo, updating a constant, adding an import.
- Tasks where you already specified the exact change — "Change the timeout from 5000 to 10000 in src/config.ts."
How It Works
You activate Plan Mode by pressing Shift+Tab to toggle between Plan and Act modes in the Claude Code interface. When in Plan Mode, Claude can still read files and search the codebase — it just will not write, edit, or execute commands until you approve the plan. After reviewing the plan, you can approve it to let Claude execute, modify it by giving feedback, or reject it entirely.
6. Hooks: PreToolUse and PostToolUse
Hooks let you inject custom logic before or after Claude uses a tool. They are defined in your Claude Code settings (typically ~/.claude/settings.json or .claude/settings.json at the project level) and run as shell commands. The hook receives context about the tool invocation via stdin as JSON and can block the operation by returning a non-zero exit code.
PreToolUse Hooks
These fire before a tool executes. They can inspect the planned action and block it if it violates a policy. If the hook exits with a non-zero status, the tool call is aborted and Claude sees the rejection reason.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "python3 .claude/hooks/block_dangerous_commands.py"
},
{
"matcher": "Edit",
"command": "python3 .claude/hooks/check_file_locked.py"
}
]
}
}
#!/usr/bin/env python3
"""
PreToolUse hook: Block dangerous Bash commands.
Receives tool invocation JSON on stdin.
Exit 0 to allow, exit 1 to block.
"""
import sys
import json
BLOCKED_PATTERNS = [
"rm -rf /",
"rm -rf ~",
"git push --force",
"git reset --hard",
"DROP TABLE",
"DROP DATABASE",
"> /dev/sda",
]
data = json.load(sys.stdin)
tool_input = data.get("tool_input", {})
command = tool_input.get("command", "")
for pattern in BLOCKED_PATTERNS:
if pattern.lower() in command.lower():
print(f"BLOCKED: Command contains dangerous pattern '{pattern}'", file=sys.stderr)
sys.exit(1)
sys.exit(0)
PostToolUse Hooks
These fire after a tool completes. They are useful for logging, auditing, or triggering side effects like running a linter after every file edit.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"command": "python3 .claude/hooks/lint_on_write.py"
},
{
"matcher": "Edit",
"command": "python3 .claude/hooks/lint_on_write.py"
}
]
}
}
#!/usr/bin/env python3
"""
PostToolUse hook: Run ESLint after any file write/edit.
"""
import sys
import json
import subprocess
data = json.load(sys.stdin)
tool_input = data.get("tool_input", {})
file_path = tool_input.get("file_path", "")
# Only lint JS/TS files
if file_path.endswith((".ts", ".tsx", ".js", ".jsx")):
result = subprocess.run(
["npx", "eslint", "--fix", file_path],
capture_output=True, text=True
)
if result.returncode != 0:
print(f"Lint issues found in {file_path}:", file=sys.stderr)
print(result.stdout, file=sys.stderr)
# Non-zero exit here informs Claude of the lint failure
sys.exit(1)
sys.exit(0)
git push --force, that command will not execute regardless of what Claude tries. This is the strongest guardrail available.7. CI/CD Integration
Claude Code can run in headless mode — no interactive terminal, no human in the loop. This unlocks powerful CI/CD workflows: automated code review on pull requests, test generation, documentation updates, and migration assistance. The key is the --print flag (or -p), which tells Claude to process a single prompt, output the result, and exit.
Headless Mode Basics
# Single prompt, printed output, non-interactive claude -p "Review the changes in this PR for security issues" --output-format json # Pipe input for context git diff main...HEAD | claude -p "Review this diff for bugs and security issues" # Use a specific model claude -p "Generate unit tests for src/auth.ts" --model claude-sonnet-4-20250514
GitHub Actions: Automated PR Review
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for accurate diffs
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Run Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# Get the diff between the PR branch and base
DIFF=$(git diff origin/${{ github.base_ref }}...HEAD)
# Run Claude in headless mode
REVIEW=$(echo "$DIFF" | claude -p \
"Review this pull request diff. Check for:
1. Bugs and logic errors
2. Security vulnerabilities
3. Performance issues
4. Style violations
Output a concise markdown review." \
--output-format text)
# Post the review as a PR comment
gh pr comment ${{ github.event.pull_request.number }} \
--body "$REVIEW"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Session Isolation
Each CI run operates in its own isolated context. There is no shared conversation history between runs, no cached state, and no cross-contamination. This means:
- Each run starts fresh — Claude has no memory of previous CI invocations.
- Your CLAUDE.md and
.claude/rules/files are still read and respected. - Environment variables (like
ANTHROPIC_API_KEY) must be available in the CI environment. - The
--allowedToolsflag can restrict which tools Claude may use in CI, preventing it from running arbitrary Bash commands in your pipeline.
# Restrict Claude to read-only tools in CI claude -p "Review this code" \ --allowedTools "Read,Grep,Glob" \ --output-format text
--allowedTools to enforce the principle of least privilege.8. Agent Definitions
Agents live in the .claude/agents/ directory and represent specialized personas that Claude can adopt for specific workflow contexts. While skills are step-by-step procedures (like recipes), agents are broader role definitions that shape how Claude thinks, what it prioritizes, and how it communicates throughout an entire session.
--- name: security-auditor description: Reviews code with a security-first mindset allowed-tools: - Read - Grep - Glob - Bash --- # Security Auditor Agent You are a security-focused code reviewer. Your primary concern is identifying vulnerabilities, unsafe patterns, and security anti-patterns. ## Focus Areas - **Injection attacks**: SQL injection, XSS, command injection, path traversal - **Authentication/Authorization**: Missing auth checks, privilege escalation, insecure token handling - **Data exposure**: Sensitive data in logs, overly permissive API responses, PII leakage - **Dependency risk**: Known vulnerable packages, outdated dependencies ## Behavior - When reviewing code, always check imports for known-vulnerable packages. - Search the codebase for related security controls before suggesting changes. - Classify findings by severity: CRITICAL, HIGH, MEDIUM, LOW. - Provide a fix for every finding — never just report a problem without a solution. ## Output Format For each finding: 1. **Severity**: [CRITICAL/HIGH/MEDIUM/LOW] 2. **Location**: file path and line number 3. **Description**: What the vulnerability is 4. **Fix**: Concrete code change to remediate
---
name: api-designer
description: Designs and implements REST APIs following best practices
allowed-tools:
- Read
- Grep
- Glob
- Edit
- Write
- Bash
---
# API Designer Agent
You are an API design specialist. You follow REST conventions strictly and
prioritize consistency, discoverability, and backward compatibility.
## Design Principles
- Use plural nouns for resource names: /users, /invoices, /payments
- Use HTTP methods correctly: GET reads, POST creates, PUT replaces, PATCH updates, DELETE removes
- Always version the API: /api/v1/
- Return consistent envelope format: { success, data, error, meta }
- Use proper HTTP status codes: 201 for creation, 204 for deletion, 422 for validation errors
## When Designing a New Endpoint
1. Check existing endpoints for consistency in naming and response format
2. Define the Zod validation schema first
3. Implement the route handler
4. Add the service layer logic
5. Write integration tests
6. Update the API documentation
Agents vs. Skills: When to Use Each
The difference is one of scope and identity:
- Skill: A discrete procedure. "Run the deploy workflow." It has a beginning, a defined sequence of steps, and an end. It is a verb.
- Agent: A persistent persona. "Be the security auditor for this session." It shapes how Claude approaches every task during the session. It is a noun — a role.
- Use a skill when you have a repeatable task with clear steps that runs and completes.
- Use an agent when you want Claude to adopt a different lens or expertise domain for an extended interaction.
- Agents can invoke skills. A security-auditor agent might call the "review" skill as part of its work.
Configuration Quick Reference
| Mechanism | Location | Scope | When It Activates |
|---|---|---|---|
| CLAUDE.md (User) | ~/.claude/CLAUDE.md | All projects | Every session, automatically |
| CLAUDE.md (Project) | ./CLAUDE.md | Current project | Every session in this project |
| CLAUDE.md (Directory) | ./src/folder/CLAUDE.md | Specific directory | When working in that directory |
| Rules | .claude/rules/*.md | Glob-scoped or universal | When glob pattern matches the current file |
| Skills | .claude/skills/*.md | On-demand | When invoked via slash command |
| Agents | .claude/agents/*.md | Session-wide persona | When activated by the user |
| Hooks | .claude/settings.json | Pre/Post tool execution | Automatically on matching tool calls |
| CI/CD (Headless) | Pipeline config | Per-run | When triggered by CI event |
Mastering these configuration surfaces transforms Claude Code from a generic assistant into a project-aware collaborator that enforces your team's standards, follows your conventions, and executes complex workflows reliably. The initial investment in writing good CLAUDE.md files, rules, and skills pays compound returns on every subsequent interaction.