Multi-Agent Workflows¶
Overview¶
Multiple Claude (or other AI) agents can work in the same repository simultaneously without conflict — if the right isolation, coordination, and communication patterns are in place. This document describes the architecture used in this project.
When to use multi-agent approaches:
- Independent tasks with clearly non-overlapping file scopes
- Long-running research or validation that should run in parallel with active development
- Specialized workers (e.g., one agent for Terraform, one for Ansible, one for docs)
- Compute-bound tasks where sequential execution is unnecessarily slow
The Two Agent Models¶
Model 1 — Orchestrator + Subagents (Task tool)¶
Status: Production-ready. Used in this project today.
One orchestrator agent spawns specialized workers via the Task tool. Communication
is strictly hierarchical — subagents report only to the orchestrator; they cannot
talk to each other directly.
Orchestrator
├─ Task(Ansible worker) → result ─┐
├─ Task(Terraform worker) → result ─┤→ Orchestrator synthesizes
└─ Task(Docs worker) → result ─┘
Key constraints:
- Subagents run with an isolated context window (they do not see the main conversation)
- No direct peer-to-peer communication between subagents
- To pass data from subagent A to subagent B, the orchestrator receives A's result, then includes it in B's prompt
- Subagents can be run foreground (blocking, default) or background (concurrent)
- Background subagents pre-approve all tool permissions upfront; any tool call not pre-approved is auto-denied (no interactive prompts)
Model 2 — Agent Teams¶
Status: Experimental (Claude Code CLI only, not in Agent SDK).
Each "teammate" runs as an independent session. They share a task list and a mailbox system — teammates can message each other directly, not just the lead.
Agent Teams are the right model when agents need to negotiate with each other. Watch this feature — when it stabilizes, it replaces custom file-based coordination for complex workflows.
Isolation: Worktrees¶
Worktrees are the primary isolation mechanism for parallel agent work.
A git worktree gives each agent its own working directory and branch while sharing the repository's full history and remotes. Multiple agents can have different files checked out simultaneously with no checkout conflicts.
| Mechanism | Filesystem isolation | Git isolation | Complexity |
|---|---|---|---|
isolation: "worktree" (Task tool) |
✅ Automatic | ✅ Own branch | Zero — automatic |
/start-issue (interactive sessions) |
✅ Per session | ✅ Own branch | Low — EnterWorktree handles setup |
| Branches only (shared directory) | ❌ Same dir | ✅ Own branch | Medium — collapses on concurrent writes |
| Separate repo clones | ✅ Total | ✅ Total | High |
Automatic Worktrees (Subagents)¶
Add isolation: "worktree" to any Task tool call for a code-writing subagent:
Claude Code creates a worktree at .claude/worktrees/<auto-name> with a dedicated
branch. On completion:
- No changes made → worktree is automatically cleaned up
- Changes committed → worktree path and branch are returned; user prompted to keep or remove
Issue-Driven Worktrees (Interactive Sessions)¶
For a human-coordinated parallel Claude Code window, always start from an issue:
This runs EnterWorktree under the hood, which:
- Creates a worktree at
.claude/worktrees/<branch>with branchworktree-<type>/<slug> - Switches the session's CWD into the worktree
- Moves the issue to "In Progress" on the project board
When work is complete, run /ready (creates the PR) then /restart (tears down the worktree).
The branch is merged through GitHub, not via a local --no-ff merge.
Communication Mechanisms¶
Within a Single Orchestrator Session¶
The orchestrator is the message bus. Pass data between subagents via the orchestrator:
| Channel | Direction | Use case |
|---|---|---|
| Task prompt / result | Orchestrator ↔ subagent | Primary — all structured output |
| Files in repo | Any agent → any agent | Large results, structured data |
/tmp/agent-*.json temp files |
Subagent → next Task prompt | Pass intermediate results between sequential subagents |
Between Independent Sessions¶
| Channel | Direction | Latency | Notes |
|---|---|---|---|
| Git commits on branches | Sequential | Pull-based | Code handoffs between sessions |
| GitHub issues / comments | Any → any | Async | Work claiming, status, verification |
| GitHub Project board | Any → any | Async | Visual: who owns what |
| Shared state files | Any → any | File-based | Atomic mv-based writes for coordination |
| MCP-connected database | Any → any | Query-based | Persistent structured state (e.g., postgres-dumbo) |
No native real-time bus
There is no native real-time message bus between independent Claude Code sessions. The most practical options are a shared file with atomic writes, or a lightweight database accessible via MCP.
Coordination Protocols¶
GitHub Issues as Work-Claiming¶
Each agent works on a specific issue. The issue serves as:
- Work claim — prevents two agents from picking up the same task
- Status signal — board column shows where the work is
- Communication thread — comments contain verification steps and handoff notes
Workflow:
Issue created (backlog)
→ /start-issue <number> ← agent claims work, creates branch, moves to In Progress
→ commits on feature branch
→ /ready ← agent creates PR, moves to Review, posts verification comment
→ user reviews + merges PR
→ issue closed (user action)
See GitHub Projects for board structure.
Scope Boundary Rule¶
The best conflict prevention is design: give each agent a clearly non-overlapping file scope. Agents working on different top-level directories are always safe.
| Agent A scope | Agent B scope | Safe? |
|---|---|---|
cloud/ansible/roles/ |
cloud/terraform/ |
✅ Yes |
cloud/ansible/roles/ |
homeassistant/ |
✅ Yes |
cloud/ansible/roles/ |
docs/operations/ |
✅ Yes |
cloud/ansible/scripts/run-bogart.sh |
cloud/ansible/scripts/run-pluto.sh |
✅ Yes |
cloud/ansible/scripts/lib/run-script-common.sh |
cloud/ansible/scripts/lib/run-script-common.sh |
❌ No |
Protected Shared Files¶
Certain files must never be modified by worktree subagents (they affect all sessions):
CLAUDE.md— project instructions (all sessions read this)AGENTS.md— cross-agent project context (all AI agents read this)CLAUDE.md.proposed— transitional file (destined to replace CLAUDE.md post-merge).claude/settings.json— hooks and MCP config.mcp.json— MCP server configurationmemory/MEMORY.md— orchestrator-only cross-session state
Enforcement: Claude Code PreToolUse hooks block write/edit attempts to these files
from worktrees. See scripts/hooks/protect-shared-files.sh.
Claude Code Hooks for Coordination¶
Hook events useful for multi-agent coordination:
| Hook | Fires when | Coordination use |
|---|---|---|
SubagentStop |
Subagent finishes | Write results to shared log, notify orchestrator |
Stop |
Orchestrator finishes | Validate all expected results arrived (exit 2 to block) |
PreToolUse (Bash) |
Before any shell command | Enforce branch naming, check work isn't claimed |
WorktreeCreate |
Worktree being created | Custom VCS setup, register agent scope |
WorktreeRemove |
Worktree being removed | Custom cleanup, unregister scope |
Hook types: command hooks (shell scripts), prompt hooks (yes/no via model), agent hooks (spawn a subagent for complex verification, 60s timeout).
Exit code semantics: 0 = allow, 2 = block/deny.
Practical Patterns for This Repo¶
Pattern A: Orchestrator-Spawned Parallelism¶
One Claude session coordinates multiple workers. Use when you have several independent tasks in the same session.
Orchestrator session:
Task(isolation: "worktree", "Update all Ansible roles for X")
Task(isolation: "worktree", "Update all Terraform modules for X")
Task(isolation: "worktree", "Update docs for X")
← receive all results, synthesize, commit merge
Rules:
- Each subagent gets
isolation: "worktree"if it writes files - Define non-overlapping scopes in each subagent's prompt
- Orchestrator reviews and merges results; never auto-merges without review
Pattern B: Independent Parallel Sessions (Human-Coordinated)¶
Multiple Claude Code windows, each on their own worktree/branch. User coordinates.
# Window 1: working on Ansible role changes
scripts/wt-new.sh feat/ansible-zerotier-hardening
# Window 2: working on Terraform changes
scripts/wt-new.sh feat/terraform-vpc-cleanup
# Both sessions work independently; merge via PRs when done
Rules:
- Use
/start-issue <number>at session start (claims work on board) - Use
/readywhen done (creates PR, moves to Review) - Merge PRs sequentially if they touch shared files
Pattern C: Agent-to-Agent via Files¶
For passing structured data between subagents through the orchestrator:
# Subagent A writes result
echo '{"key": "value"}' > /tmp/agent-result-a.json
# Orchestrator reads and passes to Subagent B
# (include file contents in next Task prompt)
For persistent cross-session coordination, write to a shared file in the repo or query postgres-dumbo via MCP.
Upcoming: GitHub Flow Skills¶
Two Claude Code skills are planned to automate the issue lifecycle:
/start-issue <number>¶
Invoke before writing any code on an issue:
- Fetches issue title + labels via GitHub API
- Derives a branch name (e.g.,
feat/61-op-inject-migration) - Creates and checks out the branch
- Moves issue to "In Progress" on the project board
- Optionally posts a "Starting work" comment
/ready¶
Invoke after pushing commits and validating:
- Detects current branch + linked issue number
- Creates a GitHub PR (title from issue, body with summary + test plan)
- Moves issue to "Review" on the project board
- Posts a verification comment on the issue with confirmation steps
Related Documentation¶
- GitHub Projects — board structure and issue lifecycle
- Git Hooks — existing enforcement hooks
- Pre-Commit Hooks — commit-time validation
scripts/hooks/protect-shared-files.sh— shared file protection.claude/settings.json— Claude Code hooks configuration
Last updated: 2026-02-28 Status: Reference — patterns in use; skills planned