Skip to main content

Compositions

Agent teams gain production-grade behavior when composed with other Claude Code primitives. Each composition addresses a specific gap: hooks enforce quality, skills package workflows, MCP connects external data, memory enables learning, worktrees prevent conflicts, and CLAUDE.md sets team conventions.

Teams + Hooks: Quality Gates

Hooks are the enforcement mechanism for team workflows. Three hook events target team coordination specifically.

TeammateIdle

Fires when a teammate is about to go idle. Exit code 2 keeps the teammate working.

{
  "hooks": {
    "TeammateIdle": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'INPUT=$(cat); NAME=$(echo \"$INPUT\" | jq -r \".teammate_name\"); if [ \"$NAME\" = \"implementer\" ]; then PENDING=$(find .claude/tasks/ -name \"*.json\" -exec grep -l \"pending\" {} + 2>/dev/null | wc -l); if [ \"$PENDING\" -gt 0 ]; then echo \"$PENDING tasks still pending -- keep working\" >&2; exit 2; fi; fi; exit 0'"
          }
        ]
      }
    ]
  }
}

This prevents the implementer from going idle while pending tasks remain. The conditional on teammate_name lets other teammates idle normally.

TaskCreated

Enforce naming conventions or require acceptance criteria before tasks enter the queue:

#!/bin/bash
# .claude/hooks/validate-task.sh
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
TASK_DESC=$(echo "$INPUT" | jq -r '.task_description // empty')
 
# Require action verb prefix
if ! echo "$TASK_SUBJECT" | grep -qE '^(Add|Fix|Implement|Refactor|Update|Remove|Test|Review)'; then
  echo "Task subject must start with an action verb" >&2
  exit 2
fi
 
# Require description for non-trivial tasks
if [ -z "$TASK_DESC" ] && ! echo "$TASK_SUBJECT" | grep -qi "review\|test"; then
  echo "Non-review tasks require a description" >&2
  exit 2
fi
 
exit 0

Exit code 2 prevents task creation and sends the error message back to the model as feedback. The model adjusts and retries.

TaskCompleted

Validate work before allowing tasks to close. This is the most impactful team hook — it creates hard quality gates:

#!/bin/bash
# .claude/hooks/verify-completion.sh
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
 
# Implementation tasks must pass tests
if echo "$TASK_SUBJECT" | grep -qiE '(implement|add|fix|refactor)'; then
  if ! npm test 2>/dev/null; then
    echo "Tests must pass before marking implementation tasks complete" >&2
    exit 2
  fi
fi
 
# Writing tasks must pass lint
if echo "$TASK_SUBJECT" | grep -qiE '(implement|add|fix|refactor|write)'; then
  if ! npm run lint 2>/dev/null; then
    echo "Linting must pass before marking this task complete" >&2
    exit 2
  fi
fi
 
exit 0

All Team Hook Events

EventFires WhenExit 2 Behavior
TeammateIdleTeammate about to go idleKeeps teammate working
TaskCreatedTask being createdPrevents creation, feedback to model
TaskCompletedTask being marked completePrevents completion, feedback to model
SubagentStartSubagent begins executionN/A
SubagentStopSubagent completesN/A
WorktreeCreateWorktree being createdFails creation
WorktreeRemoveWorktree being removedCannot block (logged only)

Teams + Skills: Packaged Workflows

Skills turn team architectures into reusable commands. The skill content becomes instructions for the lead.

# .claude/skills/review-team/SKILL.md
---
name: review-team
description: Spin up a full review team for a PR
disable-model-invocation: true
allowed-tools: Bash(gh *)
---
 
## PR Context
- PR diff: !`gh pr diff`
- Changed files: !`gh pr diff --name-only`
 
## Instructions
 
Create an agent team to review this PR with three reviewers:
 
1. **Security reviewer**: Focus on auth, input validation, injection,
   secrets exposure. Use the security-reviewer agent type.
 
2. **Performance reviewer**: Focus on N+1 queries, unnecessary
   allocations, missing indexes, expensive operations in hot paths.
 
3. **Correctness reviewer**: Focus on logic errors, edge cases,
   error handling, race conditions, and whether tests cover the changes.
 
Have each reviewer submit their findings as a structured report.
After all three complete, synthesize a unified review with:
- Critical issues (must fix before merge)
- Suggestions (should fix, not blocking)
- Nits (style/preference)
 
Post the unified review as a PR comment using `gh pr comment`.

Invoke with /review-team. The ! backtick syntax executes shell commands at skill load time, injecting the PR diff and file list into the skill context before the lead starts.

disable-model-invocation: true means the skill content is the complete instruction set. No additional model interpretation layer.

A more targeted skill that spawns a vertical-slice implementation team:

# .claude/skills/vertical-slice/SKILL.md
---
name: vertical-slice
description: Implement a feature as a vertical slice with parallel agents
disable-model-invocation: false
allowed-tools: Bash(git *) Bash(npm *)
---
 
## Context
- Current branch: !`git branch --show-current`
- Recent commits: !`git log --oneline -5`
 
## Instructions
 
Implement $ARGUMENTS as a vertical slice using an agent team:
 
1. **API agent** (Sonnet, worktree isolation):
   - Implement the API route and service layer
   - Write integration tests for the endpoint
   - Domain: src/api/, src/services/, __tests__/api/
 
2. **UI agent** (Sonnet, worktree isolation):
   - Implement the React component and page
   - Wire up data fetching to the new API
   - Domain: src/components/, src/pages/, __tests__/ui/
 
3. **Schema agent** (Sonnet):
   - Create the database migration
   - Update the Prisma schema and generate types
   - Domain: prisma/, src/models/
 
Schema agent completes first. API and UI agents work in parallel after.
Each agent runs tests in its domain before marking tasks complete.

Teams + MCP: External Data Sources

MCP servers provide external data to teammate workflows. There is a key distinction in how MCP servers load:

  • Subagents: can scope MCP servers via the mcpServers field in their agent definition
  • Agent team teammates: load MCP servers from project and user settings only
# .claude/agents/db-analyst.md
---
name: db-analyst
description: Analyzes database performance and query patterns
tools: Read, Grep, Bash
mcpServers:
  - postgres-mcp:
      type: stdio
      command: npx
      args: ["-y", "@postgres-mcp/server"]
      env:
        DATABASE_URL: "${DATABASE_URL}"
  - github
---
 
You are a database performance analyst. Use the PostgreSQL MCP tools
to analyze query plans, identify slow queries, and recommend index
optimizations. Cross-reference with the application code to understand
query origins.

When this agent runs as a subagent, the mcpServers field applies. When used as a teammate in an agent team, it does not — configure MCP servers in .mcp.json instead.

This asymmetry matters for team design. If a teammate needs a specific MCP server, that server must be available project-wide.

Teams + Memory: Cross-Session Learning

Subagent persistent memory enables teammates to improve across sessions. A code reviewer that remembers patterns from previous reviews catches issues faster.

# .claude/agents/code-reviewer.md
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Grep, Glob, Bash
memory: project
model: sonnet
---
 
You are a code reviewer. As you review code:
 
1. Check your agent memory for patterns and conventions you've seen
   in this codebase before starting the review.
2. Apply known conventions to your review feedback.
3. After completing the review, update your agent memory with:
   - New patterns or conventions you discovered
   - Common issues you found (to check for proactively next time)
   - Architectural decisions that should be preserved
 
Memory location: .claude/agent-memory/code-reviewer/

Memory Scopes

ScopeLocationWhen to use
user~/.claude/agent-memory/<agent>/Knowledge applicable across all projects
project.claude/agent-memory/<agent>/Project-specific, shareable via git
local.claude/agent-memory-local/<agent>/Project-specific, not committed to git

When memory is enabled, the subagent's system prompt automatically includes the first 200 lines (or 25KB) of MEMORY.md from the memory directory. The Read, Write, and Edit tools are auto-enabled so the subagent can maintain its memory files.

Project-scoped memory committed to git means the entire team benefits from accumulated knowledge — a reviewer's memory becomes shared team knowledge.

Teams + Worktrees: Filesystem Isolation

Worktrees are the filesystem-level isolation mechanism for parallel agents. Without them, two teammates editing the same file cause silent overwrites.

# Start Claude in a named worktree
claude --worktree feature-auth
 
# Auto-generate a worktree name
claude --worktree

Worktrees are created at <repo>/.claude/worktrees/<name> and branch from origin/HEAD.

For subagents, add isolation: worktree to the frontmatter:

---
name: parallel-implementer
description: Implements features in isolated worktrees
isolation: worktree
---

Cleanup Behavior

ConditionBehavior
No changes madeWorktree and branch removed automatically
Changes existClaude prompts to keep or remove
Orphaned by crashAuto-removed at startup after cleanupPeriodDays

Copying Gitignored Files

Worktrees don't include gitignored files by default. Use .worktreeinclude to copy necessary files:

# .worktreeinclude
.env
.env.local
config/secrets.json

Conflict Detection

The open-source tool "Clash" detects conflicts between worktrees before they happen. It runs git merge-tree (three-way merge simulation) between all worktree pairs without touching working directories. Run it before merging parallel work back together.

Teams + CLAUDE.md: Team Conventions

CLAUDE.md is loaded by every teammate automatically. Use it to set team-wide coordination rules:

# CLAUDE.md
 
## Agent Team Conventions
 
When working as part of an agent team:
- Always check the shared task list before starting new work
- Claim tasks before beginning implementation
- Send a message to the lead when you complete a task with a summary
- If you discover work not in the task list, message the lead
  to create a new task rather than doing it ad hoc
- Never modify files owned by another teammate's task
 
## File Ownership
 
When tasks are assigned, respect these boundaries:
- Frontend: src/components/, src/pages/, src/styles/
- Backend: src/api/, src/services/, src/middleware/
- Database: src/models/, src/migrations/, prisma/
- Tests: __tests__/, src/**/*.test.ts

File ownership rules in CLAUDE.md are the simplest way to prevent file conflicts without worktree isolation. They work because every teammate loads the same instructions. Combine with TaskCompleted hooks that verify no out-of-scope files were modified for hard enforcement:

#!/bin/bash
# .claude/hooks/enforce-file-ownership.sh
# TaskCompleted hook: verify teammate only modified files in their domain
INPUT=$(cat)
TEAMMATE=$(echo "$INPUT" | jq -r '.teammate_name // empty')
 
# Map teammate names to allowed directories
case "$TEAMMATE" in
  frontend-*)
    ALLOWED="src/components/|src/pages/|src/styles/"
    ;;
  backend-*)
    ALLOWED="src/api/|src/services/|src/middleware/"
    ;;
  db-*)
    ALLOWED="src/models/|src/migrations/|prisma/"
    ;;
  *)
    exit 0  # No ownership rules for unnamed teammates
    ;;
esac
 
# Check which files were modified (staged + unstaged)
MODIFIED=$(git diff --name-only HEAD 2>/dev/null)
VIOLATIONS=$(echo "$MODIFIED" | grep -vE "^($ALLOWED)" | grep -v '^$')
 
if [ -n "$VIOLATIONS" ]; then
  echo "File ownership violation for $TEAMMATE. Modified files outside allowed scope:" >&2
  echo "$VIOLATIONS" >&2
  exit 2
fi
 
exit 0

Wire it into settings:

{
  "hooks": {
    "TaskCompleted": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/enforce-file-ownership.sh"
          }
        ]
      }
    ]
  }
}