06

Agentic Development Best Practices

Subagent workflows, parallelization, code review, TDD, memory management.

Agentic Development Best Practices

AI agents can write code faster than any human. That speed is a double-edged sword. Without discipline, you ship bugs faster too. Best practices matter more with agents, not less — because the cost of a mistake is multiplied by the volume of code being produced. This section covers the workflows and guardrails that separate productive agentic development from expensive chaos.

Subagent-Driven Development

The core pattern of agentic development is decomposition: break work into tasks, assign each task to a fresh agent, and merge the results. A fresh agent per task avoids context pollution — the accumulated confusion that happens when one agent tries to hold too many concerns in memory at once.

bash
# Subagent-Driven Development Pattern

# Step 1: Understand — Read the spec, explore the codebase
claude "Read docs/feature-spec.md and identify all tasks"

# Step 2: Decompose — Break into independent tasks
# Key: tasks should touch DIFFERENT files to avoid conflicts

# Step 3: Execute in waves — Launch independent tasks in parallel
claude --background "Build the SearchBar component in components/ui/SearchBar.tsx"
claude --background "Add the /api/search endpoint in app/api/search/route.ts"
claude --background "Write tests for search in __tests__/search.test.ts"

# Step 4: Review — Check results when agents finish
claude "Review recent changes for integration issues and type errors"

# Step 5: Commit — After each logical unit, not batched at the end
claude /commit

The critical rule is file-level isolation. Two agents editing the same file will produce merge conflicts. Decompose by file boundary: one agent per component, one per API route, one per test file. If two tasks must touch the same file, serialize them.

Parallelization — When and How

Not everything should run in parallel. The decision tree is simple: if two tasks are independent and touch different files, parallelize them. If they share files or one depends on the other's output, serialize them. Over-parallelization causes more merge conflicts than it saves in time.

PracticeWhenWhy
ParallelizeIndependent tasks touching different filesMaximizes throughput without conflicts
SerializeTasks that share files or have dependenciesPrevents merge conflicts and race conditions
Batch reviewAfter a wave of parallel tasks completesCatches integration issues between parallel changes
Single agentSmall changes (under 50 lines)Overhead of decomposition exceeds the work itself
Fresh contextEach new task or subtaskAvoids context pollution from prior tasks
Commit per unitAfter each logical piece of workMakes rollbacks granular and review easier

AI Code Review

AI-generated code needs AI-powered review. Use specialized review agents that focus on different concerns: correctness, security, performance, and architecture. The compound-engineering plugin provides purpose-built reviewers for each of these.

bash
# Use specialized review agents for different concerns

# General code review — catches bugs, style issues, missing edge cases
claude "Review the changes in the last 3 commits as a code-reviewer"

# Security review — finds injection risks, auth gaps, data exposure
claude "Review app/api/ as a security-sentinel. Check for:
- Input validation on all endpoints
- Authentication and authorization checks
- SQL injection or XSS vectors
- Sensitive data in responses"

# Performance review — spots N+1 queries, unnecessary rerenders, memory leaks
claude "Review components/ as a performance-oracle. Check for:
- Unnecessary re-renders (missing memo, unstable references)
- Large bundle imports that could be lazy-loaded
- Missing loading and error states"

Match review depth to risk level. A UI copy change needs a quick glance. A new API endpoint handling user data needs a security-sentinel review. An architectural change needs an architecture-strategist review. Do not waste tokens reviewing every line with every agent.

Test-Driven Development with Agents

TDD is even more powerful with agents. Write a failing test that describes the behavior you want, then tell the agent to make it pass. The test acts as both a specification and a verification gate. The agent cannot "hallucinate" its way past a failing test.

typescript
# TDD with Claude Code

# Step 1: You write the failing test (the specification)
# __tests__/calculateScore.test.ts
import { calculateScore } from '../lib/scoring'

describe('calculateScore', () => {
  it('returns 0 for empty answers', () => {
    expect(calculateScore([])).toBe(0)
  })

  it('awards 10 points per correct answer', () => {
    expect(calculateScore([
      { correct: true },
      { correct: true },
      { correct: false },
    ])).toBe(20)
  })

  it('applies 1.5x multiplier for streak of 3+', () => {
    const answers = Array(4).fill({ correct: true })
    expect(calculateScore(answers)).toBe(60) // 40 * 1.5
  })
})

# Step 2: Tell Claude to make it pass
claude "Make all tests in __tests__/calculateScore.test.ts pass.
Create lib/scoring.ts with the implementation."

# Step 3: Iterate — add more tests, tell Claude to make them pass
Info

TDD flips the agent relationship: instead of reviewing AI output for correctness, you define correctness upfront and let the AI figure out the implementation. The test is your contract. The agent is the contractor.

Memory Management

Agents do not remember between sessions. Every conversation starts from scratch — unless you give them memory. CLAUDE.md is the primary memory mechanism, but it needs active maintenance. The best developers update CLAUDE.md as a reflex, not an afterthought.

text
# Memory management patterns

# After fixing a non-trivial bug:
# Add the root cause and fix to CLAUDE.md or a debugging.md
# so future agents do not repeat the investigation

# After an architectural decision:
# Document the decision and reasoning in CLAUDE.md
# "We use localStorage instead of a database because..."

# After discovering a gotcha:
# Add it to the Rules section of CLAUDE.md
# "Motion v12 requires import from 'motion/react', NOT 'framer-motion'"

# What NOT to save:
# - Temporary task state (what you are currently working on)
# - Speculative conclusions (unverified assumptions)
# - Information already in CLAUDE.md (avoid duplication)

Think of CLAUDE.md as institutional knowledge for your AI team. Every bug fix, every workaround, every "we tried X and it did not work" — these are valuable lessons that save future sessions hours of repeated investigation.

Security and Human-in-the-Loop

AI agents should never have unchecked authority over destructive operations. The human-in-the-loop (HITL) principle means that certain actions always require human approval: deployments, database mutations, force pushes, and anything touching credentials.

markdown
# Security rules to encode in CLAUDE.md

## Safety Rules
- NEVER edit .env, credentials, or secret files
- NEVER run destructive commands (--force, --hard, rm -rf)
- NEVER commit sensitive files — warn if user requests it
- NEVER skip pre-commit hooks (--no-verify)
- NEVER auto-deploy without explicit human approval
- Docker ports: bind to 127.0.0.1 only (no 0.0.0.0)

## Permission Gates
# Claude Code has built-in permission prompts for:
# - Running shell commands (Bash tool)
# - Writing or editing files
# - Making network requests
# Review these prompts carefully — they are your last line of defense
Warning

Never add --no-verify, --force, or similar flags to bypass safety checks. If a pre-commit hook fails, the correct response is to fix the issue — not to skip the hook. Agents that bypass safety checks will eventually cause a production incident.

Prompt Engineering for Agents

Prompting an agent is different from prompting a chatbot. Agents need specificity, context, and constraints. A vague prompt like "fix the bug" produces vague results. A precise prompt like "fix the TypeError in lib/scoring.ts line 42 where calculateScore receives undefined instead of an array" produces precise results.

bash
# Bad: Vague, no context, no constraints
claude "make the app better"

# Good: Specific task, clear context, explicit constraints
claude "Add error boundaries to all page-level components in app/.
Each error boundary should:
- Catch render errors and display a GlassPanel with the error message
- Include a 'Try Again' button that calls reset()
- Log errors to console in development only
- Follow the existing component patterns in components/ui/
Reference: components/ui/GlassPanel.tsx for the panel style"

# Good: Reference existing files as examples
claude "Create a new mini-game component for the quiz challenge.
Follow the same pattern as components/games/PromptDuel.tsx:
- Accept onComplete(score: 0-100) prop
- Use GlassPanel for the container
- Include a timer display
- Use Motion for enter/exit animations"

Three rules for effective agent prompts: (1) reference specific files so the agent reads them first, (2) state the acceptance criteria explicitly, and (3) name the patterns to follow. Agents are excellent pattern-followers — give them a pattern and they will replicate it consistently.

Managing Agent-Generated Tech Debt

Agent-generated code tends toward certain patterns: over-abstraction, inconsistent naming between sessions, duplicated utility functions, and verbose implementations. This is not a flaw — it is a natural consequence of each agent session starting fresh without full codebase context.

bash
# Regular cleanup tasks for agent-generated codebases

# 1. Consolidate duplicates — agents often recreate utilities
claude "Find any duplicated utility functions across lib/ and components/.
Consolidate them into the appropriate lib/ module."

# 2. Normalize naming — different sessions may use different conventions
claude "Audit all component prop interfaces for naming consistency.
Standardize: onX for callbacks, isX for booleans, xCount for numbers."

# 3. Remove dead code — agents sometimes leave unused imports or functions
claude "Find and remove all unused exports and imports across the codebase.
Run the TypeScript compiler after to verify nothing breaks."

# 4. Simplify over-abstraction — agents tend to over-engineer
claude "Review lib/utils.ts for over-abstracted functions.
If a function is only used once, consider inlining it."
Tip

The 80/20 rule of agent work: agents handle 80% of implementation quickly and correctly. The remaining 20% — integration, edge cases, consistency — requires human judgment. Plan for that 20%. Budget time for review and cleanup after every agent-heavy session.

Common Anti-Patterns

Warning

Avoid these common mistakes: (1) Over-parallelizing — launching 10 agents that edit the same files causes conflicts. (2) Skipping review — trusting agent output without reading it leads to subtle bugs. (3) Vague prompts — "make it work" produces unpredictable results. (4) No CLAUDE.md — without project context, every session starts from zero. (5) Using agents for simple changes — a 5-line fix does not need a subagent workflow. (6) Batching commits — committing everything at the end makes rollbacks impossible.

Putting It All Together

The best agentic workflows combine all of these practices into a coherent cycle. Start with a well-maintained CLAUDE.md. Decompose work into independent tasks. Launch subagents in parallel for independent work. Use TDD to define correctness upfront. Review with specialized agents. Commit after each logical unit. And feed every lesson back into CLAUDE.md for the next session.

text
# A complete agentic development cycle

# 1. Start with context
# - Read CLAUDE.md, review the plan, understand the codebase

# 2. Decompose the feature
# - Break into 3-5 independent tasks
# - Identify file boundaries (no overlap between tasks)

# 3. Write tests first (TDD)
# - Define acceptance criteria as failing tests
# - Each test file maps to one subagent task

# 4. Execute in parallel
# - Launch one agent per task
# - Main thread handles the critical path

# 5. Review the results
# - Low risk: quick scan
# - Medium risk: code-reviewer agent
# - High risk: security-sentinel + architecture-strategist

# 6. Commit and update memory
# - One commit per logical unit
# - Update CLAUDE.md with any new patterns or gotchas

# 7. Repeat for the next feature

Agentic development is not about replacing human judgment — it is about amplifying it. You provide the direction, the standards, and the review. The agents provide the speed, the consistency, and the tireless execution. Together, you build software faster than either could alone.

Further Reading

Claude Code Best Practices

Anthropic engineering team's guide to productive agentic workflows with Claude Code.

Anthropic Engineering

Compound AI Agent Design Patterns

Research on how to build reliable agent systems with decomposition, review, and feedback loops.

Anthropic Research
Vibe Voyager — The Agentic Coding Odyssey