Home / Paper / Agent Teams in Claude Code: Multi-Agent Orchestration for Complex Software Projects

Agent Teams in Claude Code: Multi-Agent Orchestration for Complex Software Projects

v1.031 min read
Claude CodeAgent TeamsSub-agentsGit WorktreesCLAUDE.mdHooks
Agent Teams in Claude Code — Multi-Agent Orchestration

Abstract

A practical analysis of Claude Code's multi-agent architecture: how to orchestrate teams of independent AI sessions, configure specialized sub-agents, leverage git worktrees for parallelism, and design effective CLAUDE.md files. Based on the hands-on experience of an SEO consultant and AI developer who routinely uses teams of 3-5 agents for research, writing, and review in parallel.

This paper is also available in Italian

Leggi in italiano →

1. The Problem: Why AI Agent Teams Are Needed

Anyone who has used an AI coding assistant on a non-trivial project knows the moment when the conversation grows too long, the context saturates, and the agent starts losing the thread. For a single file or an isolated function, AI is extraordinary. For a refactoring that touches frontend, backend, and tests simultaneously, a single session is not enough.

In my daily work as an SEO consultant and AI developer, I regularly face tasks that require parallel, independent competencies: document research, code writing, quality review, and deployment — all on the same project, all in the same sprint. Delegating everything to a single Claude Code session means accumulating context until it breaks.

The fundamental problem is the context window. It is the most valuable resource of an LLM, and its performance degrades as it fills up. Every file read, every command executed, every response generated consumes context. When you reach ~95% capacity, automatic compaction kicks in, but by then you have already lost the detail of decisions made in the early stages of the conversation.

The solution is not a model with more context. The solution is an architecture that distributes work across independent agents, each with its own dedicated context, communicating only when necessary. Exactly like a team of human developers.

Meta: This Paper as an Example

This paper was written using exactly the architecture it describes: a team of 3 Claude Code agents — a researcher, a writer, a brand-reviewer — coordinated by a team lead, each with their own task in the shared list. A practical meta-example of everything that follows.

2. Agent Teams Architecture in Claude Code

2.1 System Components

An Agent Team in Claude Code is composed of four fundamental components that collaborate to distribute work effectively.

ComponentRolePersistence
Team LeadMain session that creates the team, spawns teammates, and coordinates workSession duration
TeammatesSeparate Claude Code instances working on assigned tasksUntil explicit shutdown
Task ListShared task list with statuses, dependencies, and assignments~/.claude/tasks/{team-name}/
MailboxMessaging system for peer-to-peer communication between agentsSession duration

Unlike sub-agents, which execute within a single session and can only report back to the main agent, teammates are fully independent Claude Code instances. Each teammate has its own context window, loads the same project context (CLAUDE.md, MCP servers, skills), but does not inherit the lead's conversation history.

2.2 Architecture Diagram

┌─────────────────────────────────────────────────┐
│                   TEAM LEAD                      │
│  ┌──────────┐  ┌──────────┐  ┌───────────────┐  │
│  │ Create   │  │ Assign   │  │ Synthesize    │  │
│  │ Team     │→ │ Tasks    │→ │ Results       │  │
│  └──────────┘  └──────────┘  └───────────────┘  │
└────────┬──────────────┬──────────────┬───────────┘
         │              │              │
    SendMessage    SendMessage    SendMessage
         │              │              │
   ┌─────▼─────┐  ┌─────▼─────┐  ┌────▼──────┐
   │ Teammate  │  │ Teammate  │  │ Teammate  │
   │ #1        │←→│ #2        │←→│ #3        │
   │ (Own      │  │ (Own      │  │ (Own      │
   │  context) │  │  context) │  │  context) │
   └─────┬─────┘  └─────┬─────┘  └─────┬─────┘
         │              │              │
         └──────────────┼──────────────┘
                        │
              ┌─────────▼─────────┐
              │  TASK LIST        │
              │  (shared)         │
              │  ~/.claude/tasks/ │
              └───────────────────┘
Agent Team Architecture: Lead, Teammates, and Shared Task List

2.3 Enabling and Requirements

Agent teams are an experimental feature, disabled by default. They require Claude Code v2.1.32 or later and are enabled via an environment variable.

settings.json
// settings.json (project or user level)
{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  }
}

Token Consumption Warning

Teams use significantly more tokens than a single session. Each teammate is a separate Claude instance with its own context window. Usage scales linearly with the number of active teammates. For sequential tasks or those with many dependencies, sub-agents are more efficient.

2.4 When to Use Agent Teams

Not every task justifies the coordination overhead of a team. I have identified four scenarios where teams excel over single sessions or sub-agents.

ScenarioWhy Teams Are BetterExample
Parallel research and reviewMultiple agents investigate different aspects simultaneously, share and discuss resultsCode review with security, performance, and test coverage reviewers
New modules or featuresEach teammate owns a separate piece without file interferenceFrontend + backend + tests implementation in parallel
Debugging with competing hypothesesTest different theories in parallel and converge on the answer5 teammates investigate 5 hypotheses, scientific debate
Cross-layer coordinationChanges across different layers, each with clear ownershipDB schema + API route + UI + migration

3. The Task System and Coordination

3.1 Task Lifecycle

The heart of coordination is the shared task list. Each task goes through three states: pending, in_progress, completed. Tasks can have dependencies (blockedBy) that prevent starting until dependencies are completed.

pending ──→ in_progress ──→ completed
   │                              ▲
   │         blockedBy            │
   └── (awaits dependencies) ────┘

File locking for auto-claiming:
  Teammate A completes Task #1
       ↓
  Teammate A looks for pending unowned tasks
       ↓
  File lock acquired → Task #2 assigned
       ↓
  No race condition
Task lifecycle with file locking

3.2 Assignment Modes

Tasks can be assigned in two ways, and in practice I have found that combining both is most effective.

  1. Lead assignment: ask the lead which task to assign to which teammate. Useful for tasks requiring specific expertise or a precise order.
  2. Auto-claiming: after completing a task, the teammate automatically picks up the next pending, unassigned, unblocked task. File locking prevents race conditions when multiple teammates finish simultaneously.

In my experience, the best pattern is to assign initial tasks explicitly (to give each teammate the right context in the spawn prompt), then let auto-claiming handle the subsequent flow.

3.3 Inter-Agent Communication

Communication happens through the mailbox system with the SendMessage tool. Each teammate can send messages to any other teammate (addressing by name) or broadcast to the entire team.

agent-communication.ts
// Direct message to a specific teammate
SendMessage({
  to: "researcher",
  message: "Research is ready, you can start writing",
  summary: "Research completed"
})

// Broadcast to the entire team (use sparingly!)
SendMessage({
  to: "*",
  message: "Critical issue found — stop all work",
  summary: "Critical block"
})

// Shutdown request
SendMessage({
  to: "researcher",
  message: {
    type: "shutdown_request",
    reason: "Task completed, closing session"
  }
})

Broadcasting: Use Sparingly

Broadcasting sends a separate message to every teammate. The cost scales linearly. Use it only for critical situations requiring everyone's immediate attention. For normal communication, always prefer direct messages.

3.4 Team Startup Prompt

The most natural way to start a team is to describe the task and structure in natural language. Claude creates the team, spawns teammates, and coordinates the work automatically.

team-startup-prompt.txt
// Example prompt for starting a parallel review team
"Create an agent team to review PR #142. Spawn three reviewers:
- One focused on security implications
- One checking performance impact
- One validating test coverage
Have each one review and report their findings."

// Example for debugging with competing hypotheses
"Users report the app exits after a message.
Spawn 5 teammates to investigate different hypotheses.
Have them talk to each other to refute each other's theories,
like a scientific debate."

4. Team Visualization and Control Modes

4.1 In-Process vs Split Panes

Claude Code supports two visualization modes for teams, with different trade-offs.

ModeHow It WorksRequirementsWhen to Use
In-processAll teammates in the main terminal. Shift+Down to navigate.None (works everywhere)Simple setup, small teams (2-3 teammates)
Split panesEach teammate in a separate terminal pane.tmux or iTerm2Larger teams, when simultaneous visibility is needed
teammate-mode.json
// Configuration in settings.json
{
  "teammateMode": "in-process"  // or "split-panes", "auto"
}

// "auto" (default): split panes if already in tmux, otherwise in-process

// Per-session flag
// $ claude --teammate-mode in-process

4.2 Direct Interaction with Teammates

Each teammate is a full Claude Code session. You can interact directly without going through the lead, which is a fundamental difference from sub-agents.

ActionIn-processSplit panes
Navigate between teammatesShift+Down / Shift+UpClick in the pane
Send messageType after selecting the teammateType in the pane
View outputEnter on the selected teammateDirectly visible
Interrupt actionEscapeEscape in the pane
Task listCtrl+TCtrl+T in any pane

4.3 Plan Approval

You can require teammates to plan before implementing, giving the lead (or the user) the ability to approve or reject the plan with feedback.

// In the teammate spawn prompt
"Spawn an architect teammate to refactor the auth module.
Require plan approval before they make changes."

// The teammate enters Plan Mode, analyzes with read-only operations,
// proposes a plan, and the lead approves or rejects with feedback.
// Only after approval can the teammate modify files.

4.4 Shutdown and Cleanup

Teammate shutdown is collaborative: the lead sends a request, the teammate can approve or reject (if still working). For team cleanup, always use the lead.

// Shutdown a specific teammate
"Ask the researcher teammate to shut down"
// The lead sends shutdown_request, the teammate approves/rejects

// Cleanup the entire team
"Clean up the team"
// Verifies all teammates are stopped, then removes the team
// FAILS if there are still active teammates

5. Sub-Agents: Types and When to Use Them

5.1 Fundamental Difference: Sub-Agents vs Teams

The distinction between sub-agents and teammates is crucial for choosing the right architecture. Sub-agents are focused workers that operate within a session and return a summary. Teammates are independent sessions that communicate peer-to-peer.

AspectSub-AgentTeammate
ContextOwn window; results return to the callerOwn window; fully independent
CommunicationOnly to the main agent (response)Peer-to-peer with any teammate
CoordinationMain agent manages everythingSelf-coordination via shared task list
Token costLower: results synthesized in the main contextHigher: each teammate is a separate instance
Best forFocused tasks where only the result mattersComplex work with discussion and collaboration
IsolationOptional (worktree)Separate session by design

When to Switch from Sub-Agents to Teams

Transition point: when parallel sub-agents hit the main session's context limits, or when they need to communicate with each other, it is time to switch to agent teams.

5.2 Built-in Sub-Agents

Claude Code includes several built-in sub-agents, each optimized for a specific type of work.

AgentModelToolsWhen to Use
ExploreHaiku (fast)Read-only (no Write/Edit)File discovery, code search, codebase exploration. Levels: quick, medium, very thorough
PlanInherits from mainRead-onlyCodebase research for implementation planning
General-purposeInherits from mainAllComplex research, multi-step operations
Claude Code GuideHaikuRead, Glob, Grep, WebFetch, WebSearchQuestions about Claude Code features
statusline-setupSonnetRead, EditIDE status line configuration

The model choice is strategic: Explore uses Haiku for speed (it is a read-only operation that does not require complex reasoning), while Plan inherits the main model because planning quality directly impacts implementation.

5.3 Creating Custom Sub-Agents

The real power of sub-agents emerges when you create custom agents, defined as Markdown files with YAML frontmatter in .claude/agents/ (project) or ~/.claude/agents/ (user).

.claude/agents/code-reviewer.md
---
name: code-reviewer
description: Expert code review specialist. Use immediately after writing or modifying code.
tools: Read, Grep, Glob, Bash
model: sonnet
permissionMode: default
---

You are a senior code reviewer ensuring high standards.

Review checklist:
- Code is clear and readable
- Functions and variables are well-named
- No duplicated code that should be abstracted
- Proper error handling for edge cases
- No exposed secrets or credentials
- Input validation at system boundaries
- Good test coverage for new functionality
- Performance considerations addressed

5.4 Frontmatter: All Available Fields

FieldRequiredTypeDescription
nameYesstringUnique identifier (lowercase and hyphens)
descriptionYesstringWhen Claude should delegate to this agent
toolsNolistAvailable tools (inherits all if omitted)
disallowedToolsNolistExplicitly denied tools
modelNoenumsonnet, opus, haiku, inherit (default: inherit)
permissionModeNoenumdefault, acceptEdits, dontAsk, bypassPermissions, plan
maxTurnsNonumberMaximum number of agentic turns
skillsNolistSkills to preload into the sub-agent context
mcpServersNolistMCP servers available to this agent
hooksNoobjectSpecific lifecycle hooks (PreToolUse, PostToolUse)
memoryNoenumPersistent memory: user, project, local
backgroundNobooleantrue to always run in background
isolationNoenumworktree for temporary git worktree

5.5 Resolution Priority

When multiple definitions of the same sub-agent exist, priority follows a precise order.

PriorityLocationScope
1 (highest)CLI flag --agentsCurrent session
2.claude/agents/Current project
3~/.claude/agents/All projects
4 (lowest)Plugin agents/ directoryWhere the plugin is enabled

5.6 Foreground vs Background

Sub-agents can run in foreground (blocking, permission prompts passed to user) or background (concurrent, permissions pre-approved, rest auto-denied). The background: true flag in the frontmatter forces background execution for every invocation.

// Sub-agent in foreground (default)
// - Blocking: main agent waits for the result
// - Useful when the result is needed before proceeding

// Sub-agent in background
// - Concurrent: main agent continues working
// - Automatic notification on completion
// - Ideal for independent tasks (tests, linting, research)

// Example: parallel launch of multiple sub-agents
// Main agent launches 3 searches and continues working
Agent({ prompt: "Find auth files", subagent_type: "Explore", run_in_background: true })
Agent({ prompt: "Find test files", subagent_type: "Explore", run_in_background: true })
Agent({ prompt: "Find config files", subagent_type: "Explore", run_in_background: true })

6. Git Worktrees: Isolation and Parallelism

6.1 The File Conflict Problem

When multiple agents work on the same repository, file conflicts are inevitable. Two sessions modifying the same file simultaneously produce unpredictable results. Git worktrees solve this problem at the root: each session works on an isolated copy of the repository, with its own branch.

6.2 How They Work in Claude Code

worktree-usage.sh
# Start parallel sessions with named worktrees
claude --worktree feature-auth     # Worktree "feature-auth"
claude --worktree bugfix-123       # Worktree "bugfix-123"
claude --worktree                  # Auto-generated name

# Worktrees are created at:
# <repo>/.claude/worktrees/<name>
# On branch: worktree-<name>

Each worktree is a complete copy of the working directory with its own Git branch. Changes in one worktree do not affect others. Upon completion, if there are no changes, the worktree is automatically removed; if there are changes, Claude asks whether to keep it.

6.3 Worktrees in Sub-Agents

Sub-agents can use worktree isolation with the isolation: "worktree" parameter. This is particularly useful when a sub-agent needs to make experimental changes without risking corruption of the main repository.

worktree-subagent.ts
// Launch sub-agent with worktree isolation
Agent({
  prompt: "Try refactoring the auth module using the Strategy pattern",
  isolation: "worktree",
  run_in_background: true
})

// The sub-agent works on an isolated copy
// If changes work → branch and path returned in the result
// If no changes → worktree automatically removed

6.4 Common Pattern: Writer/Reviewer

One of the most effective patterns I use is the Writer/Reviewer model with separate worktrees: one session implements changes, the other reviews in real time.

Session 1 (Writer)                   Session 2 (Reviewer)
claude --worktree impl               claude --worktree review
         │                                     │
    Implement feature                    Review code
    Write tests                          Check quality
    Commit on worktree-impl              Feedback to writer
         │                                     │
         └────── git merge ───────────→ Main branch
Writer/Reviewer Pattern with Git Worktrees

7. CLAUDE.md: The Contract Between Developer and AI

7.1 What It Is and Why It Matters

The CLAUDE.md file is the persistent context loaded at the start of every Claude Code session. It is the "contract" between the developer and the AI: it defines the rules, conventions, commands, and quirks of the project that Claude needs to know. Every teammate and every sub-agent loads the same CLAUDE.md, ensuring consistency in conventions.

The golden rule: keep CLAUDE.md under 200 lines. A file that is too long degrades performance because it consumes precious context on every request. If it grows, move content to skills (loaded on demand) or .claude/rules/ files (loaded by pattern).

7.2 What to Include vs What to Exclude

IncludeExclude
Non-obvious build/test/lint commandsThings derivable from the code
Non-standard style rulesStandard language conventions
Test execution instructionsDetailed API documentation
Repository etiquette (commit message style, PR format)Frequently changing information
Key architectural decisionsLong explanations (use @import)
Environment quirks (serverless fonts, proxies)File-by-file descriptions
Gotchas and non-obvious behaviorsSelf-evident practices in the codebase

7.3 Structure of an Effective CLAUDE.md

After many projects, I have converged on a structure that works reliably. The key is being surgical: every line must earn its place in the file.

CLAUDE.md
# CLAUDE.md

## Commands
```bash
npm run dev          # Dev server (localhost:3000)
npm run build        # Production build
npm run lint         # ESLint
npm run test         # Jest with coverage
```

## Architecture
**Next.js 16 App Router + Sanity CMS + Tailwind CSS.**
Content in Sanity (project: 5ipkzs9u, dataset: production).
Static pages with ISR (revalidate = 3600).

## Key Patterns
- Dynamic params: Next.js 15+ requires `await params`
- Images: always <Image> with alt + title from Sanity
- PortableText: use portableTextComponents everywhere

## Anti-patterns
- NEVER use `as any` for window.dataLayer (type in global.d.ts)
- NEVER commit .env files
- NEVER use npm (project uses pnpm)

Necessity Test

The test for every line in CLAUDE.md: "If I removed this line, would Claude make an error?" If the answer is no, the line doesn't belong. The /init command generates a good starting point, but it always needs pruning.

7.4 Locations and Cascading

CLAUDE.md files can exist at multiple levels and are additive:

  1. ~/.claude/CLAUDE.md — global rules for all projects
  2. <project-root>/CLAUDE.md — project-specific rules (in git)
  3. <directory>/CLAUDE.md — subdirectory rules (local override)

All levels are loaded and contribute to the context. External files can be imported with the @path/to/file syntax in CLAUDE.md.

8. Prompt Engineering Best Practices for Claude Code

8.1 The Verification Principle

Giving Claude a way to verify its work is the single highest-leverage action. Claude performs dramatically better when it can run tests, compare screenshots, and validate output.

StrategyWeak PromptEffective Prompt
Verification criteria"implement email validation""write validateEmail with specific tests, run after implementation"
Visual verification"make the dashboard prettier""[screenshot] implement this design, screenshot the result, compare"
Root causes"the build is failing""the build fails with [specific error], fix it and verify it compiles"

8.2 Explore → Plan → Implement

The most reliable workflow I have found clearly separates three phases. It is not just good advice — it is an explicit mode switch in Claude Code.

Phase 1: EXPLORE (Plan Mode, Shift+Tab)
    Claude reads files, modifies nothing
    Understands structure, dependencies, patterns
         │
         ▼
Phase 2: PLAN
    Detailed implementation plan
    Ctrl+G to open in text editor
    Review and approve the plan
         │
         ▼
Phase 3: IMPLEMENT (Normal Mode)
    Claude codes while verifying against the plan
    Tests after every significant change
         │
         ▼
Phase 4: COMMIT
    Descriptive message
    PR with context
Explore → Plan → Implement → Commit Workflow

For small, well-defined tasks (fixing a specific bug, adding a field), skipping the plan is legitimate. But for any change that touches more than 2-3 files, the plan pays for itself in time saved.

8.3 Specific vs Generic Context

Prompt quality determines output quality. Vague prompts produce generic answers; specific prompts produce correct code on the first try.

TypeWeak PromptEffective Prompt
Scope"add tests for foo.py""test for foo.py disconnected user case, avoid database mocks"
Sources"why is the API behaving strangely?""look at the git history of ExecutionFactory to understand the change"
Patterns"add widget""look at HotDogWidget.php, follow the same pattern for the new widget"
Symptoms"fix login bug""login fails after session timeout, check src/auth/session.ts"

Provide rich context

  • @ to reference specific files: @src/utils/auth.js
  • Paste images with Ctrl+V for mockups and screenshots
  • Provide documentation URLs that Claude can fetch
  • Pipe data from commands: cat error.log | claude -p "explain"
  • Let Claude explore the codebase autonomously when the context is unclear

8.4 Aggressive Context Management

The context window is a finite resource. Actively managing it makes the difference between an agent that works and one that loses its thread.

  1. /clear frequently between unrelated tasks — this is the most underrated action
  2. /compact <instructions> for manual compaction with instructions on what to preserve
  3. Esc + Esc → "Summarize from here" for partial compaction
  4. CLAUDE.md: "When compacting, preserve the full list of modified files" to maintain tracking
  5. /btw for quick questions that don't stay in the main context
  6. Sub-agents for heavy investigations that read many files — the result is synthesized

8.5 Thinking Mode and Adaptive Reasoning

Extended thinking is enabled by default with Opus 4.6 and adaptive reasoning. You can control the effort level and reasoning budget.

  • Effort level: configurable via /model or CLAUDE_CODE_EFFORT_LEVEL
  • ultrathink: keyword in prompt to force high effort
  • Option+T / Alt+T: toggle on/off during the session
  • MAX_THINKING_TOKENS: variable to limit reasoning budget
  • Ctrl+O: verbose mode to see reasoning

9. Memory System: Persistence Across Conversations

9.1 How Memory Works

Claude Code includes a file-based memory system that persists across conversations. Memory is organized by types (user, feedback, project, reference) and indexed in a MEMORY.md file that is loaded in every session.

~/.claude/projects/{project}/memory/
├── MEMORY.md              ← Index (loaded every session)
├── user_role.md           ← Who the user is
├── feedback_testing.md    ← User corrections
├── project_sprint.md      ← Project state
└── reference_linear.md   ← Where to find information

Each file has frontmatter:
---
name: user_role
description: User role and competencies
type: user
---
[memory content]
Memory System Structure

9.2 Memory Types

TypeWhen to SaveExample
userDetails about the user's role, preferences, competencies"The user is a senior developer with 10 years of Go, first time with React"
feedbackUser corrections or guidance applicable in the future"Don't mock the database in tests — previous incident where mock/prod divergence masked a broken migration"
projectInformation about ongoing work, decisions, deadlines"Merge freeze from 2026-03-05 for mobile release"
referencePointers to external resources (Linear, Grafana, Slack)"Pipeline bugs tracked in Linear project INGEST"

9.3 What NOT to Save

It is important to know what does not belong in memory, because an overfull memory degrades the index and consumes context unnecessarily.

  • Code patterns and conventions — derivable by reading the code
  • Git history and who changed what — git log/blame are authoritative
  • Debugging solutions — the fix is in the code, the context in the commit
  • Things already in CLAUDE.md — avoid duplication
  • Current task details — use the task system, not memory

9.4 Memory in Sub-Agents

Custom sub-agents can have their own persistent memory, configured in the frontmatter with the memory field. Memory is isolated by scope (user, project, local) and by agent name.

.claude/agents/code-reviewer.md
---
name: code-reviewer
description: Expert code reviewer
tools: Read, Grep, Glob, Bash
memory: project
---

# The reviewer's memory persists across sessions
# Scope project: .claude/agent-memory/code-reviewer/
# The reviewer can remember previously seen problematic patterns,
# project-specific style preferences,
# and recurring feedback.

10. Hooks and Deterministic Automation

10.1 What Are Hooks

Hooks are deterministic scripts that run automatically in response to events in the agentic cycle. Unlike instructions in CLAUDE.md (which the LLM may interpret variably), hooks are guaranteed: they always fire, execute predetermined code, and produce predictable results.

The key distinction: hooks have zero context cost (unless they return output). They do not consume the context window, making them ideal for frequent automations like linting, formatting, and validation.

10.2 Hook Types

HookWhen It FiresExample Use
PreToolUseBefore a tool executesValidate Bash commands, block non-SELECT queries
PostToolUseAfter a tool executesESLint after every file edit
NotificationOn notification eventsDesktop notification when Claude is done
TeammateIdleWhen a teammate is about to go idleExit code 2 to send them back to work
TaskCompletedWhen a task is about to be completedExit code 2 to prevent premature completion
SubagentStartWhen a sub-agent startsLogging, startup metrics
SubagentStopWhen a sub-agent finishesLogging, resource cleanup

10.3 Hooks in Sub-Agents

Custom sub-agents can define their own hooks in the frontmatter, enabling automation specific to the agent type.

.claude/agents/db-reader.md (frontmatter)
---
name: db-reader
description: Execute read-only database queries safely
tools: Bash
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate-readonly-query.sh"
  PostToolUse:
    - matcher: "Edit|Write"
      hooks:
        - type: command
          command: "./scripts/run-linter.sh"
---
scripts/validate-readonly-query.sh
#!/bin/bash
# scripts/validate-readonly-query.sh
# Hook that blocks write queries in the db-reader sub-agent

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Block any modification query
if echo "$COMMAND" | grep -iE \
  '\b(INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE)\b' > /dev/null; then
  echo "Blocked: Only SELECT queries are allowed" >&2
  exit 2  # Exit code 2 = block the action
fi

exit 0  # Exit code 0 = proceed

10.4 Quality Gates for Teams

The TeammateIdle and TaskCompleted hooks serve as quality gates for agent teams. They allow preventing a teammate from going idle too early or a task from being completed without necessary checks.

settings.json
// settings.json — Quality gate hooks
{
  "hooks": {
    "TeammateIdle": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/check-teammate-done.sh"
            // Exit code 2 → sends the teammate back to work
          }
        ]
      }
    ],
    "TaskCompleted": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/validate-task-output.sh"
            // Exit code 2 → prevents completion
          }
        ]
      }
    ]
  }
}

11. Multi-Agent Orchestration Patterns

11.1 Pattern: Research → Write → Review

This is the pattern I used to write this very paper. A team of 3 agents with sequential dependencies.

Task #1: Researcher                  Task #2: Writer
(gathers documentation)               (writes the paper)
         │                                     │
    Reads 5 URLs                       Awaits Task #1
    Extracts content                   Reads research
    Saves to docs/                     Writes paper .ts
         │                                     │
    completed ─── unblocks ──→         in_progress
                                               │
                                          completed
                                               │
                                    ─── unblocks ──→
                                               │
                                    Task #3: Brand Reviewer
                                    (verifies brand consistency)
Research → Write → Review Pipeline

11.2 Pattern: Debugging with Competing Hypotheses

When a bug is complex and possible causes are multiple, launching several agents investigating different theories is extremely effective. Each agent has a specific theory, and they can communicate peer-to-peer to refute each other's hypotheses.

concurrent-debug.txt
// Prompt for the team lead
"Users are reporting intermittent API latency.
Spawn 4 teammates to investigate in parallel:

1. 'db-investigator': Analyze slow queries, missing indexes, lock contention
2. 'network-investigator': Check DNS, connection pool, timeouts
3. 'memory-investigator': Look for memory leaks, GC pauses, cache eviction
4. 'code-investigator': Profile hot paths, N+1 queries, serialization

Have them talk to each other to rule out hypotheses.
Update a results document with the consensus."

11.3 Pattern: Multi-Layer Feature

For features that span multiple layers (database, API, frontend, tests), each teammate owns a layer and works in parallel.

TeammateLayerResponsibilityFile Ownership
db-architectDatabaseSchema, migration, indexessupabase/migrations/*, lib/db/*
api-developerBackendAPI routes, validation, business logicapp/api/*, lib/services/*
ui-developerFrontendComponents, forms, renderingcomponents/*, app/(pages)/*
test-writerTestingUnit tests, integration tests, e2e__tests__/*, cypress/*

Avoiding File Conflicts

The most important rule for multi-layer teams: each teammate must own a different set of files. If two teammates modify the same file simultaneously, conflicts arise that require manual resolution. Plan file ownership before starting the team.

11.4 Pattern: Fan-Out by File

For repetitive operations across many files (framework migration, API updates, formatting), fan-out automates the work.

fan-out-migration.sh
# Fan-out: React → Vue migration across all components
for file in $(cat components-to-migrate.txt); do
  claude -p "Migrate $file from React to Vue. \
    Follow the pattern in @src/components/Button.vue." \
    --allowedTools "Edit,Bash(git commit *)" &
done
wait  # Wait for all parallel processes to complete

# Each invocation is a separate session with its own context
# No saturation risk: one file per session

12. Common Workflows with Real Examples

12.1 Exploring an Unfamiliar Codebase

When I start working on a new project — whether it is a Next.js site for a client or a Sanity CMS integration — the first step is always a guided exploration session. Claude Code excels at this, especially using the Explore sub-agent which runs on Haiku for speed.

codebase-exploration.sh
# Exploration session
$ claude

> give me an overview of this codebase

> explain the main architecture patterns used

> what are the key data models?

> how is authentication handled?

> trace the login process from front-end to database

# For deeper explorations, Claude automatically delegates
# to the Explore sub-agent (Haiku)
# which reads files without consuming the main context

12.2 Bug Fixing with Verification

The most effective bug fixing workflow I have found follows a precise pattern: share the error, request analysis, apply the fix, verify.

bug-fix-workflow.sh
# 1. Share the specific error
> I'm seeing "TypeError: Cannot read property 'id' of undefined"
> when calling POST /api/users with an empty body.
> The error is in src/api/users.ts:42.

# 2. Claude analyzes, suggests fix
# 3. Apply and verify
> apply the fix and run the test suite to verify

# 4. If the fix introduces regressions
> the fix works for the empty body case but now the test
> "should create user with valid data" fails. Fix it.

12.3 Creating Pull Requests

Claude Code can manage the entire PR lifecycle, from summarizing changes to creating the PR with gh.

# Summarize the changes
> summarize the changes I've made to the authentication module

# Create the PR
> create a pr

# Claude uses gh pr create with appropriate title and body.
# The session is automatically linked to the PR.
# In the future: claude --from-pr 142 to resume.

12.4 Claude as a Unix Utility

Claude Code integrates seamlessly into the Unix pipeline: it accepts input from stdin, produces output on stdout, and supports structured formats.

unix-pipeline.sh
# Unix pipeline: error log analysis
cat build-error.txt | claude -p 'explain the root cause' > analysis.txt

# Structured JSON for automation
claude -p "list all TODO comments in src/" --output-format json

# Streaming JSON for long processes
claude -p "refactor all components" --output-format stream-json

# Custom linter in package.json
{
  "scripts": {
    "lint:claude": "claude -p 'you are a linter. Check src/ for...'"
  }
}

12.5 Resuming Conversations

The ability to resume conversations is fundamental for projects spanning multiple sessions. Claude Code offers several modes.

# Resume the most recent conversation
claude --continue

# Interactive selector with preview
claude --resume

# Resume session linked to a PR
claude --from-pr 142

# Give descriptive names to sessions
/rename "refactoring auth module"
ShortcutAction in Selector
↑ / ↓Navigate between sessions
→ / ←Expand/collapse details
EnterSelect session
PPreview conversation
RRename session
/Search sessions
AToggle directory/all projects
BFilter by git branch
EscExit

13. The Claude Code Extensibility Ecosystem

13.1 Extension Overview

Claude Code is not a monolithic tool but an extensible platform. Extensions plug into different parts of the agentic cycle, from persistent configuration to deterministic automation.

FeatureWhat It DoesLoadingContext Cost
CLAUDE.mdPersistent context in every sessionSession start (auto)Every request
SkillsReusable instructions and workflowsStart + on demand (/<name>)Low (descriptions only by default)
MCPConnection to external servicesSession startEvery request (tool schema)
Sub-agentsWorkers in isolated contextWhen spawnedIsolated from main session
Agent TeamsIndependent coordinated sessionsOn team creationIsolated per teammate
HooksDeterministic scripts on eventsOn triggerZero (no output by default)

13.2 Effective Combinations

Extensions are not mutually exclusive — the most powerful combinations emerge from joint use.

PatternHow It Works
Skill + MCPMCP provides the connection to the external service, the skill teaches how to use it in the project context
Skill + Sub-agentThe skill spawns specialized sub-agents for parallel work
CLAUDE.md + SkillsCLAUDE.md for "always active" rules, skills for on-demand reference
Hook + MCPHook triggers actions on external services via MCP after specific events
Sub-agent + WorktreeSub-agent works in complete isolation on a copy of the repo

13.3 Skills: Reusable Knowledge

Skills are SKILL.md files in .claude/skills/ with YAML frontmatter. They can be reference (loaded when relevant) or invocable (activated with /<name>).

.claude/skills/deploy/SKILL.md
---
name: deploy
description: Deployment checklist for the project
user-invocable: true
---

# Deployment Checklist

1. Verify all tests pass: `npm run test`
2. Production build: `npm run build`
3. Check bundle size with `npx next-bundle-analyzer`
4. Create git tag: `git tag v$(date +%Y.%m.%d)`
5. Push with tags: `git push --tags`
6. Verify deploy on Vercel dashboard

13.4 Layering and Priority

When the same extension is defined at multiple levels, the precedence rule varies by type.

  • CLAUDE.md: additive — all levels contribute
  • Skills and sub-agents: override by name (managed > user > project)
  • MCP servers: override by name (local > project > user)
  • Hooks: merge — all fire for their events

14. Feature Comparison and Architectural Choices

14.1 Skill vs Sub-Agent

AspectSkillSub-Agent
What it isReusable instructions in MarkdownIsolated worker with its own context
Main advantageKnowledge sharing across contextsContext isolation from the main session
InvocationAutomatic (by description) or manual (/<name>)Automatic (by description) or explicit
Context costLow (description only in context by default)Isolated (does not impact main context)
Best forReference, checklists, repeatable workflowsHeavy tasks, parallel research, testing

14.2 CLAUDE.md vs Skill

AspectCLAUDE.mdSkill
LoadingAutomatic, every sessionOn demand or by relevance
Can include filesYes, with @pathYes, with @path
Invocable workflowsNoYes, with /<name>
Model visibilityAlwaysDescription always, content on invocation
Best for"Always do X" rulesReference, repeatable workflows

14.3 Sub-Agent vs Teammate

The choice between sub-agent and teammate depends on the nature of the work and the level of collaboration required.

AspectSub-AgentTeammate
ContextOwn, results to callerOwn, fully independent
CommunicationOnly to main agentPeer-to-peer with everyone
CoordinationMain agent manages allSelf-coordination via task list
Token costLowerHigher (separate instance)
DurationSingle task timeUntil explicit shutdown
Best forFocused, fast tasksWork with discussion and collaboration

When to Make the Switch

Transition point from sub-agents to teams: when parallel sub-agents hit the main session's context limits, or when they need to communicate with each other to make shared decisions.

14.4 MCP vs Skill

AspectMCPSkill
What it providesProtocol for external services (tools)Knowledge and workflows (instructions)
Contribution typeAccess to tools and dataReference and procedures
Context costTool schema on every requestLow (description only)
ExampleDatabase queries, browser, SlackDeploy checklist, API conventions

15. Anti-Patterns and Common Mistakes

15.1 The Five Most Costly Anti-Patterns

After months of intensive Claude Code use — from refactoring my website to building AI pipelines — I have identified five recurring anti-patterns that consume time and tokens disproportionately.

Anti-Pattern 1: The Kitchen Sink Session

Symptom: a single session accumulates tasks of different natures — bug fixes, refactoring, new features, documentation — until the context saturates and Claude loses its thread.

Solution: /clear between unrelated tasks. Every task deserves a clean context. The cost of a /clear is zero; the cost of a polluted context is high.

Anti-Pattern 2: Correcting More Than Twice

Symptom: the first attempt does not work, you correct it, the second fails, you correct again. Each correction injects failed approaches into the context, worsening subsequent iterations.

Solution: after two failed corrections, /clear and start over with a better prompt. The third correction on the same polluted context almost never works.

Anti-Pattern 3: Excessive CLAUDE.md

Symptom: a 500+ line CLAUDE.md with detailed instructions for every file. The model ignores rules at the bottom; context is consumed unnecessarily on every request.

Solution: prune ruthlessly. Move content to skills (on demand) and .claude/rules/ (by pattern). Target: under 200 lines, every line justified.

Anti-Pattern 4: Trust Without Verification

Symptom: accepting Claude's implementation without ever running tests or visually verifying. "Looks right" is not a criterion.

Solution: always include verification criteria in the prompt. "Implement X and then run the tests" is always better than "Implement X."

Anti-Pattern 5: Infinite Exploration

Symptom: Claude reads hundreds of files looking for something, consuming context without reaching an answer.

Solution: limit the scope with specific directives, or delegate to the Explore sub-agent (which has its own isolated context and uses Haiku for speed).

16. Metrics and Performance

16.1 Context Consumption by Feature

~95%

Compaction threshold

Automatic compaction activates at ~95% of context capacity

≤200

CLAUDE.md lines

Recommended limit for the persistent context file

≤10%

MCP tool search

Context budget allocated for MCP tool schemas

3-5

Recommended teammates

Optimal team size to balance parallelism and overhead

16.2 Team Sizing Guidelines

ParameterRecommended ValueRationale
Team size3-5 teammatesBeyond 5, coordination overhead exceeds benefits
Tasks per teammate5-6 tasksSelf-contained units with clear deliverables
Files per teammateNon-overlapping setsAvoids merge conflicts and race conditions
Minimum versionv2.1.32Required for agent teams APIs

16.3 Trade-Off: Tokens vs Time

Agent teams consume significantly more tokens than a single session, but they can substantially reduce wall-clock time when work is parallelizable.

Single Session:
  Task A (20min) → Task B (15min) → Task C (10min)
  Total: 45 minutes, ~50K tokens

Team of 3 Teammates:
  Task A (20min) ─┐
  Task B (15min) ─┼── Parallel
  Task C (10min) ─┘
  Total: ~20 minutes, ~120K tokens

Trade-off: 2.4x tokens, but 2.25x faster
Token vs Time Trade-off with Agent Teams

17. Case Study: This Paper as a Meta-Example

17.1 Team Setup

This paper was written using exactly the multi-agent architecture it describes. A team of 3 Claude Code agents, coordinated by a team lead, collaborated to produce the content.

RoleTeammateTaskPrimary Tools
ResearcherresearcherGather documentation from 5 Claude Code URLsWebFetch, Write
WriterwriterWrite the complete paper in TypeScriptRead, Write, all
Brand Reviewerbrand-reviewerVerify consistency with Claudio's brandRead, Edit

In the screenshot below you can see the actual setup: the main terminal (team lead) in the center, with the three teammates visible in the side panels — each working autonomously on their own task.

17.2 Workflow

Team Lead (creates team and tasks)
         │
    Task #1 → Researcher
         │     Reads 5 documentation pages
         │     Saves to docs/paper-02-research.md
         │     Notifies writer via SendMessage
         │
    Task #2 → Writer (blocked by #1)
         │     Reads the research
         │     Reads paper 01 as reference
         │     Writes 02-agent-teams-claude-code.ts
         │     Notifies brand-reviewer
         │
    Task #3 → Brand Reviewer (blocked by #2)
               Verifies tone, consistency, quality
               Applies changes directly
Team workflow for this paper

17.3 What Worked

  1. Context separation: the researcher could read thousands of lines of documentation without saturating the writer's context.
  2. Explicit dependencies: blockedBy prevented the writer from starting before research was complete, avoiding work on partial data.
  3. Direct communication: the researcher notified the writer via SendMessage upon completion, with no need for polling.
  4. Specialization: each agent had a system prompt focused on its role, with specific instructions for the expected output type.

17.4 Lessons Learned

  • The teammate spawn prompt must include all necessary context — they do not inherit the lead's conversation history.
  • Sequential tasks (as in this case) benefit less from parallelism than independent tasks. For a linear paper, the sequential pipeline was still the right choice.
  • The output file format (TypeScript with helper functions) had to be explicitly specified in the writer's prompt, with reference to paper 01 as a template.

18. Permissions and Security in Multi-Agent Teams

18.1 Permission Inheritance

Teammates inherit the lead's permission settings at spawn time. If the lead uses --dangerously-skip-permissions, so do the teammates. This makes it crucial to configure permissions correctly before starting a team.

Permission Security

Do not use --dangerously-skip-permissions in production or with teams that interact with external systems. Every teammate will have the same authorizations as the lead. Prefer granular permissionMode in custom sub-agents.

18.2 Authorization Modes

ModeBehaviorWhen to Use
defaultPrompt user for every non-whitelisted actionInteractive development, first use
acceptEditsAuto-accept file changes, prompt for the restCoding sessions where file edits are trusted
dontAskAuto-deny non-pre-approved requestsBackground agents, CI/CD
bypassPermissionsSkip all checksOnly in isolated sandbox without Internet
planRead-only, no modificationsAnalysis, exploration, review

18.3 Sandbox and Isolation

For automated or CI/CD sessions, Claude Code supports OS-level sandboxing with /sandbox. Combined with --dangerously-skip-permissions in an environment without Internet access, it enables fully unattended execution in safety.

19. Known Limitations and Roadmap

19.1 Current Team Limitations

Agent teams are an experimental feature with concrete limitations that are important to know before adoption.

  • No session resumption with in-process teammates — if the terminal closes, teammates are lost
  • Task state may lag in propagation between teammates
  • Teammate shutdown can be slow (collaborative negotiation)
  • One team per session — teams cannot be nested
  • The lead is fixed — a teammate cannot be promoted to lead
  • Permissions are set at spawn time — not modifiable at runtime
  • Split panes require tmux or iTerm2 — not available on all setups

19.2 Where Things Are Heading

Despite current limitations, the direction is clear: multi-agent teams will become the standard way to tackle complex projects with AI. The patterns that work today — context separation, shared task lists, peer-to-peer communication — are foundational and will continue to evolve.

20. Conclusions

Multi-agent orchestration in Claude Code is not a nice-to-have feature — it is a paradigm shift in how we work with AI coding assistants. The difference between using a single session and coordinating a team of specialized agents is comparable to the difference between having a single developer and a full team.

The key lessons I have drawn from hands-on experience with agent teams come down to three.

First: context is the most valuable resource. Every architectural choice in Claude Code — sub-agents, teams, worktrees, skills — revolves around effective context management. Understanding this principle guides all operational decisions.

Second: specialization beats generalization. A sub-agent with a focused prompt and limited tools produces better results than a general session with access to everything. Restriction is a feature, not a limitation.

Third: deterministic automation is complementary to AI, not a substitute. Hooks guarantee actions that the LLM might forget (linting, validation, notifications). AI handles reasoning; hooks handle discipline.

The future of AI-assisted development is not a single omniscient agent. It is an ecosystem of specialized agents collaborating, each excelling in its domain, coordinated by an architecture that distributes work and manages context intelligently. In my daily experience — from building this website to the carousel generation pipeline, to writing this very paper — multi-agent teams have already concretely changed the way I work. The foundations are solid and usable today.

Appendix: Commands and Shortcuts Cheat Sheet

A.1 Essential CLI Commands

CommandDescription
claude --worktree <name>Parallel session with isolated git worktree
claude --teammate-mode <mode>Team visualization mode (in-process/split-panes/auto)
claude --continueResume most recent conversation
claude --resumeInteractive conversation selector
claude --from-pr <n>Resume session linked to PR
claude --permission-mode planStart in Plan Mode (read-only)
claude -p "prompt"Non-interactive execution (pipe-friendly)
claude -p "prompt" --output-format jsonStructured JSON output

A.2 Keyboard Shortcuts

ShortcutAction
Shift+TabCycle modes: Normal → Auto-Accept → Plan Mode
Shift+Down / Shift+UpNavigate between teammates (in-process)
Ctrl+TShow team task list
Ctrl+GOpen plan in text editor
Ctrl+OVerbose mode (see reasoning)
Alt+T / Option+TToggle thinking mode on/off
EscInterrupt current action
Esc + EscCheckpoint: rewind conversation/code

A.3 In-Session Commands

CommandDescription
/clearClear context (essential between tasks)
/compact <instructions>Manual compaction with instructions
/btwQuick off-context question
/initGenerate initial CLAUDE.md
/agentsView and create sub-agents
/permissionsConfigure command whitelist
/modelChange model and effort
/rewindGo back to previous checkpoint
/renameName the session

Want to build something like this?

If you have a technical project requiring advanced AI architectures, let's talk.