Build a Team of AI Agents
(and a Breakout game) in VS Code
A from-scratch tutorial for someone who has written a little code, has never run an AI coding agent, and wants to end up with a small crew of Claude agents building a web game together while they watch. Every stage has a goal, the exact prompts to type, and the background you need to understand what just happened.
- Who this is for and how to read it
- Prerequisites: machine, accounts, software, skills
- The ideas: what an “agent” actually is
- The three kinds of agent (and the org chart)
- Stage 0 — Set up and verify
- Stage 1 — Solo: one session builds Brick Break
- Stage 2 — Subagents: helpers with their own memory
- Stage 3 — Your first agent team (review only)
- Stage 4 — A team that builds: power-ups
- Stage 5 — Two projects, project leads, and leads
- Running it day to day (and keeping the bill sane)
- Field notes from the first real run
- Troubleshooting
- Glossary
- Sources
Who this is for and how to read it
You're the target reader if you can open a terminal without panicking, have written a few hundred lines of JavaScript or Python at some point, and have a vague idea what Git is. You do not need to have used Claude Code, any AI coding tool, or multiple agents before. If you're more experienced, skim the “ideas” sections and jump to the prompts.
The tutorial is built around one project: Brick Break, a browser-based Breakout clone (paddle, ball, bricks, power-ups) written in plain HTML, CSS and JavaScript with no frameworks. It's chosen on purpose: you can see it working in seconds, it's fun to play-test, and it splits naturally into pieces that different agents can own without stepping on each other.
Each stage follows the same pattern so you always know where you are:
Goal — the one thing you'll have at the end of the stage.
What you'll learn — the concept the stage is really about. The game is the excuse; this is the point.
Background — the “why” a newcomer wouldn't know yet.
Check yourself — a quick test that the stage actually worked before moving on.
Budget roughly an afternoon for Stages 0–2, a second afternoon for Stages 3–4, and a third for Stage 5. Don't rush to Stage 5; the habits from Stages 3 and 4 are what make Stage 5 not fall over.
Prerequisites: machine, accounts, software, skills
Everything here is checked once. Get it all green before Stage 0 and the rest of the tutorial has no surprises.
1. The machine
| Item | Minimum | Recommended | Why it matters |
|---|---|---|---|
| Mac model | Any Apple Silicon Mac (M1, 2020 or later), or an Intel Mac from 2018+ | M2 or newer | Claude Code itself is light; VS Code windows and a dev server are the real load. Apple Silicon stays cool and quiet while running for hours. |
| Memory (RAM) | 8 GB | 16 GB or more | Stages 0–4 run fine on 8 GB. Stage 5 opens 3–5 VS Code windows, each with its own Claude session and a browser tab; 16 GB keeps that from swapping. |
| Free disk | 15 GB | 30 GB | VS Code, Node, Git, and Claude Code are a few GB. Claude also keeps session transcripts and team files under ~/.claude/, which grow over weeks. |
| macOS | macOS 12 Monterey | macOS 14 Sonoma or 15 Sequoia | Current VS Code and Node require a recent macOS. Update first if you're behind. |
| Internet | Any stable broadband | Wired or strong Wi-Fi | Every agent is talking to Anthropic's servers constantly. A flaky connection shows up as agents “stalling.” |
| Not a Mac? | Linux works identically. Windows works for every stage: native Windows needs Claude Code v2.1.234+ for the Stage 5 messaging layer; on older versions use WSL 2 for Stage 5. The one thing that never works inside VS Code's built-in terminal on any OS is “split-pane” teammate display, which this tutorial doesn't use. | ||
2. Accounts
| Account | Free? | Used for | Setup notes |
|---|---|---|---|
| Claude account with a Pro or Max plan | Paid | Signing in to Claude Code. This is what powers every agent. | Sign up at claude.ai. Pro is enough for Stages 0–3. Max is strongly recommended for Stages 4–5, because every teammate is a separate Claude instance and your usage scales with how many are running. No API key is needed; Claude Code signs in with the subscription. |
| GitHub | Free | Hosting your repository, keeping history safe, and (later) pull requests. | github.com → Sign up. Turn on two-factor authentication when it asks. Pick a username you'd put on a résumé. |
| Apple ID | Free | macOS updates and Xcode Command Line Tools. | You already have this if you use the Mac. Not needed for anything else here. |
| Anthropic Console (API key) | Pay-as-you-go | Not required. | Only relevant if you later want to run Claude Code on an API key instead of a subscription. Skip it. |
3. Software to install (in this order)
- Xcode Command Line Tools (gives you
git) Open Terminal (⌘ Space, type “Terminal”) and runxcode-select --install. Accept the dialog. Takes 5–10 minutes. Verify withgit --version. - Homebrew (optional, but makes everything else easier)
A package manager for macOS. Install from brew.sh by pasting their one-line command into Terminal. Verify with
brew --version. - Node.js 20 LTS or newer (gives you
node,npm,npx) Eitherbrew install nodeor download the LTS installer from nodejs.org. Verify withnode --version(want v20+). The game's tests and dev server run on Node, and Claude Code's npm install path needs it too. - Visual Studio Code 1.94 or newer
Download from code.visualstudio.com, drag to Applications. Open it once, then press ⌘ Shift P, type “shell command”, and run Install 'code' command in PATH so you can type
code .in a terminal. - Claude Code CLI (the standalone command-line tool)
curl -fsSL https://claude.ai/install.sh | bash # macOS / Linux / WSL # or, if you prefer npm: npm install -g @anthropic-ai/claude-code claude --version # want 2.1.224 or later
Then runclaudeonce and follow the sign-in link to connect your Claude subscription. - Claude Code extension for VS Code In VS Code: ⌘ Shift X → search “Claude Code” → install the one published by Anthropic (there are imitators). Click the ✱ Claude Code item in the bottom status bar and sign in. The extension has its own private copy of Claude Code for the chat panel; the CLI you installed in step 5 is what runs in the terminal. You want both.
- GitHub CLI (optional but handy)
brew install ghthengh auth login. Lets you create a GitHub repo from the terminal instead of the website. - A modern browser Safari or Chrome. Chrome's DevTools (⌥ ⌘ I) are easier to read when the game throws an error.
Background: why two copies of Claude Code? The VS Code extension bundles its own Claude Code to run the graphical chat panel. It does not put a claude command on your PATH. The multi-agent features in this tutorial are easiest to watch from the terminal version (it has an “agent panel” that shows who's doing what), so you install that separately. They share sign-in, settings and history.
4. Skills to have (10-minute refreshers)
| Skill | You need to be able to… | If you can't yet |
|---|---|---|
| Terminal basics | cd into a folder, ls to list it, mkdir a new one, run a command and read its output, press Ctrl C to stop something. | Any “Terminal for beginners” video; 15 minutes is plenty. |
| Git basics | Understand that a repo is a folder with history, a commit is a saved snapshot, a branch is a parallel line of snapshots, and merge combines branches. You don't need to type Git commands; Claude will. You need to recognize what it's doing. | GitHub's own “Hello World” guide, or the first two chapters of the free Pro Git book. |
| JavaScript reading | Read a function, recognize an object, understand import/export. You will be reviewing code Claude writes far more than writing it. | MDN's “JavaScript first steps.” Don't stop to master it; you'll learn by reading agent output. |
| Patience with experimental software | Accept that agent teams are labeled experimental, that the docs change weekly, and that the fix for a weird state is often “ask again more explicitly.” | Read the Troubleshooting section now so the failure modes aren't scary later. |
Final pre-flight checklist
git --version,node --version(v20+),code --version(1.94+),claude --version(2.1.224+) all print a version.- Running
claudein Terminal opens a session and shows you're signed in (no API key prompt). - VS Code shows the ✱ Claude Code item in the status bar and you're signed in there too.
- You can log in to github.com.
- You have 2–3 hours and nothing else urgent. Agents run for a while; the first time you should be watching.
The ideas: what an “agent” actually is
Before three kinds of agent, one kind. These six words come up constantly and are all you need.
- Model
- The AI itself: Claude. It reads text and produces text. Different sizes exist (Haiku is small and cheap, Sonnet is mid, Opus and above are the strongest). You'll pick sizes for different jobs later.
- Context window
- The model's short-term memory: everything it can currently “see.” Your messages, its replies, file contents it read, command output. It is finite. When it fills up, old material gets summarized or dropped. Most multi-agent tricks exist to protect this scarce memory.
- Session
- One running Claude Code conversation, with one context window. When you type
claudein a terminal, you start a session. Closing it ends the session (though history is saved and can be resumed). - Tool
- Something the model can do besides talk: read a file, edit a file, run a shell command, search the web, send a message to another agent. Claude Code is essentially Claude plus a toolbox.
- Agent
- A model, a context window, and a toolbox, working toward a goal with some autonomy: it decides which tool to use next, looks at the result, and keeps going until done. A single Claude Code session is already an agent. “Multi-agent” just means several of these at once.
- Permission
- Before Claude Code runs a command or edits a file it hasn't been pre-approved for, it asks you. This is the safety rail. With many agents, permission prompts pile up, so you pre-approve the boring ones and keep prompts for the dangerous ones.
Background: why not one giant, smart session? Two reasons. First, the whiteboard. A single session investigating 40 files to find a bug fills its context with all 40 files, and then has less room to fix the bug. Second, parallelism. If the frontend and the backend of a feature don't depend on each other, two agents finish in half the time. Everything in this tutorial is a way of buying either a clean whiteboard or parallel hands.
The three kinds of agent (and the org chart)
Claude Code has three separate mechanisms that people casually call “agents.” They're built for different jobs, they talk to different things, and they cost different amounts. The whole tutorial is learning them one at a time and then stacking them.
SendMessage tool; what differs is who can reach whom.Kind 1 — Subagent: a helper with its own whiteboard
A subagent is a second Claude that your session spins up for one focused job. It gets its own fresh context window, does the work, and hands back a summary. The parent never sees the 40 files the subagent read; it only sees “here are the three places the galleries table is used.” That's the point.
Subagents are defined as small Markdown files in your repo (.claude/agents/name.md) with a name, a description of when to use them, which tools they may use, and which model to run. Claude reads the description to decide when to delegate. You'll write three in Stage 2.
Talks to: only its parent. Costs: least, because only the summary lands in the parent's context. Use for: investigation, review, any bounded task where only the result matters.
Kind 2 — Agent team: teammates with a shared task board
When you enable the experimental agent-teams feature, your session becomes a lead that can spawn teammates. Each teammate is a full, independent Claude Code session with its own context, tools, and permission prompts. Unlike subagents, teammates don't just report up: they share a task list, claim tasks, and message each other directly. You can also open any teammate's transcript and talk to it yourself.
Talks to: the lead and each other. Costs: a lot more: each teammate burns tokens like a separate session. Use for: parallel work that needs coordination (a feature split across API, UI and tests) or debate (three reviewers challenging each other).
Two rules that shape everything later: teammates cannot spawn their own teammates, and each session has exactly one team. So you can't build “lead → project lead → workers” as one giant nested team. Instead, each project lead is its own session with its own team, and the top-level lead reaches them with Kind 3.
Kind 3 — Separate sessions that message each other
If you open two terminals and run claude in each, you have two independent sessions. Since v2.1.224 they can discover each other (ListAgents) and send plain-text notes (SendMessage) with nothing to enable. A message is just text: no history, no files. It arrives labeled as “from another Claude session, not from you,” and it cannot approve permissions or change settings on the receiving end.
Talks to: any session you're running. Costs: a message counts like a prompt you typed. Use for: gluing projects together: the “two leads” and “lead → project lead” layers in Stage 5.
The org chart you're building toward
| Layer | What it is mechanically | How many | Talks to | You appear in Stage |
|---|---|---|---|---|
| You | The human. Approves permissions, merges, releases, and sets direction. | 1 | Mostly leads, sometimes a project lead, rarely a worker | 0 |
| Lead | A plain session with no team. Keeps a status board, pings the other lead, escalates to you. | 2 | The other lead and every project lead, via cross-session messages | 5 |
| Project lead (“PM”) | A session in its own git worktree with agent teams on. Plans, spawns a team, merges when QA signs off. | 1 per project | Its team, and the leads | 5 |
| Worker (“IC”) | A teammate. Owns specific files, works tasks, reports by message. | 3–5 per project to start | Its lead and its teammates | 3, 4 |
| Subagent | A helper any of the above can spin up for a bounded lookup. | As needed | Its parent only | 2 |
Stages 1–4 all happen inside one session. Stage 5 is the first time you open several.
0Set up and verify
Goal: the CLI and the extension both work inside VS Code, agent teams are switched on, and you have one settings file you'll copy into every project.
What you'll learn: where Claude Code keeps its settings, the difference between user settings (you, everywhere) and project settings (this repo), and how permissions are pre-approved.
- Connect the terminal session to VS Code.
Open VS Code, open any folder, press Ctrl ` to open the integrated terminal, type
claude. Inside the session run/ideif it didn't connect automatically. You'll know it worked when Claude's file edits open in VS Code's diff viewer. Run/terminal-setuponce so Shift Enter adds a new line instead of sending. - Turn on agent teams in your user settings.
Create or edit
~/.claude/settings.json(the~is your home folder; in VS Code, ⌘ O and press ⌘ Shift . to show hidden folders). Paste:{ "$schema": "https://json.schemastore.org/claude-code-settings.json", "env": { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" }, "teammateMode": "in-process" }The$schemaline gives you autocomplete in VS Code.in-processmeans teammates run inside your one terminal with a little panel, which is the only mode that works in VS Code's terminal. - Make a reusable project settings file.
Save this somewhere handy (e.g.
~/claude-templates/settings.json). You'll copy it into every project's.claude/folder. It pre-approves the commands a Node project runs constantly and denies the destructive ones.{ "permissions": { "allow": [ "Read", "Edit", "Write", "Glob", "Grep", "Bash(npm test:*)", "Bash(npm run:*)", "Bash(node:*)", "Bash(npx:*)", "Bash(git status:*)", "Bash(git diff:*)", "Bash(git add:*)", "Bash(git commit:*)", "Bash(git log:*)", "Bash(git checkout:*)", "Bash(git branch:*)", "Bash(git worktree:*)" ], "deny": [ "Bash(git push --force:*)", "Bash(rm -rf:*)", "Read(.env)", "Read(.env.*)", "Read(**/.env)", "Read(**/.env.*)" ] } } - Verify.
In the terminal session:
/statusshould show a “Peer address” row (that means cross-session messaging is available)./list-agentsshould run without complaining, even if it lists nothing. In the chat panel (the Claude icon in the sidebar), type/and confirm a permission-mode switcher appears at the bottom of the prompt box.
Background: the three places settings live. ~/.claude/settings.json is you, and applies to every project and both the extension and the CLI. <repo>/.claude/settings.json is this project and is safe to commit so teammates (and future you) get it. <repo>/CLAUDE.md isn't a settings file at all; it's plain instructions that every session and every teammate reads on startup. It's the single most powerful lever for keeping a team consistent, and you'll write one in Stage 1.
A side effect to know about. With agent teams enabled, any time Claude decides to name a subagent, that subagent launches as a teammate instead. If you ever see a delegation hang “waiting for a result,” that's why: a teammate finished and only sent an “I'm idle” notice, not its output. The fix is to flip the env var to "0" in settings; it takes effect on save, no restart.
Check yourself: /status shows a Peer address, /list-agents is recognized, and you can open ~/.claude/settings.json in VS Code and see the env block.
1Solo: one session builds Brick Break
Goal: a fresh GitHub repo containing a playable Breakout game, a CLAUDE.md, a roadmap, and a passing test suite, built by one Claude session while you watch.
What you'll learn: how to brief an agent (conventions beat code), what plan mode is, and why the folder layout is designed for a team before the team exists.
The design, and why it's shaped this way
Brick Break is plain HTML + JavaScript drawing on a <canvas>. There is no build step, no framework, and the game logic that can be tested without a browser (physics, collision, level parsing, scoring) lives in pure modules with no DOM access. That split is what makes Stages 2–5 work: agents can own directories without colliding, and a test suite can run in under a second every time a teammate says “done.”
brick-break/ ├── CLAUDE.md ← conventions every agent reads ├── .claude/ │ ├── settings.json ← the permissions file from Stage 0 │ └── agents/ ← subagent roles (Stage 2) ├── docs/ │ ├── ROADMAP.md ← milestones (below) │ ├── STATUS.md ← leads write here (Stage 5) │ └── specs/ ← one spec per feature ├── public/ │ ├── index.html ← the page with the canvas │ └── style.css ├── src/ │ ├── engine/ ← loop.js (requestAnimationFrame), input.js, draw.js │ ├── physics/ ← vector.js, collision.js — pure, no DOM │ ├── entities/ ← paddle.js, ball.js, brick.js, powerup.js │ ├── levels/ ← levels.js (layouts), parse.js — pure │ ├── ui/ ← hud.js, screens.js (title, pause, game over) │ └── main.js ← wires it all together ├── tests/ │ ├── unit/ ← mirrors src/; node --test │ └── integration/ ← a headless “play a level” test ├── server.js ← tiny Express static server (npm start) └── package.json
Create the repo
- Make the folder and initialize Git.
mkdir -p ~/code/brick-break && cd ~/code/brick-break git init -b main code .
- Create the GitHub repo.
Either on github.com → New repository → name
brick-break, no README (the folder already exists), then follow its “push an existing repository” commands; or with the GitHub CLI:gh repo create brick-break --private --source=. --remote=origin. - Drop in the project settings.
mkdir -p .claude docs/specs && cp ~/claude-templates/settings.json .claude/settings.json - Start Claude in plan mode.
In the VS Code terminal:
claude, then press Shift Tab until the prompt shows plan mode. In plan mode Claude reads and proposes but doesn't edit; you approve the plan first. For a scaffold, this is exactly the rhythm you want.
When Claude shows its plan, read it. Look for: does it keep physics pure? Does it put the Express server in server.js? If so, approve it. Then paste the roadmap when asked:
Play it
When Claude reports done: npm install, npm start, open http://localhost:3000. Play a round. If the ball tunnels through bricks or the paddle feels wrong, tell Claude in plain words (“the ball sometimes passes through the corner of a brick”). This is the feedback loop you'll use at every level: play, describe, let it fix.
Then commit and push. Ask Claude: “Commit everything as ‘feat: milestone 1 core play’ and push to origin main.” You'll get a permission prompt for git push because it's not in the allowlist; that's on purpose. Approve it.
Do milestone 2 the same way
Merge it yourself when you're happy: “Merge feat/m2-score-lives into main and push.”
Background: what CLAUDE.md is doing for you. Every future session, subagent and teammate reads it before doing anything. Lines like “never edit outside your assigned files” and “run npm test before completing a task” cost you thirty seconds to write and save you hours of untangling overlapping edits later. When a teammate misbehaves, the first fix is almost always “add a sentence to CLAUDE.md.”
Check yourself: the game plays in your browser; npm test passes; git log shows two milestones; CLAUDE.md and docs/ROADMAP.md exist; the repo is on GitHub.
2Subagents: helpers with their own memory
Goal: three reusable subagent roles defined as files, and one real task where you watch Claude delegate to them and keep its own context clean.
What you'll learn: subagent definition files, tool allowlists, choosing a model per role, and why “summary back” is the whole value.
Anatomy of a subagent file
A subagent is a Markdown file with a YAML header. The header is configuration; the body is the agent's standing instructions (its “system prompt”). Project-level files go in .claude/agents/; personal ones in ~/.claude/agents/. The description is what the parent Claude reads when deciding whether to delegate, so write it like a job ad.
Create these three files. (You can ask Claude to create them by pasting this section, which is a fine first delegation.)
# .claude/agents/explorer.md — read-only, cheap, fast
---
name: explorer
description: Read-only codebase investigation. Use when you need to find where something lives, how a function is used, or what a module exports, without changing anything.
tools: Read, Grep, Glob
model: haiku
---
You are a codebase investigator. Answer with file paths, line numbers, and a short summary.
Do not propose changes. Do not read .env files.
# .claude/agents/implementer.md — writes code, runs tests
---
name: implementer
description: Implements a clearly scoped feature or fix in a specific set of files, with tests. Use when the files to change are already known.
tools: Read, Edit, Write, Grep, Glob, Bash, SendMessage
model: sonnet
---
You implement exactly the scope you were given, in exactly the files you were given.
Before finishing: run `npm test`. If tests fail, fix them or report precisely why you couldn't.
Never edit files outside your assigned list. If you need a change elsewhere, say so instead of making it.
# .claude/agents/reviewer.md — read-only critic
---
name: reviewer
description: Reviews a diff or a set of files for correctness, bugs, and test coverage. Use after code is written and before it is merged.
tools: Read, Grep, Glob, Bash(git diff:*), Bash(git log:*), SendMessage
model: sonnet
---
You are a senior reviewer. Run `git diff` to see what changed. Report findings as
Critical / Warning / Suggestion, each with file:line and a one-sentence fix. Be specific and brief.
Background: the three header fields that matter. tools is an allowlist; the explorer literally cannot edit a file, which is why it's safe to let it roam. model picks the brain size: Haiku for search (fast, cheap), Sonnet for writing code. If you omit model, the subagent inherits the parent's model, which is often more expensive than the job needs. The body is appended to the subagent's instructions, so it's the place for rules like “never touch .env.”
Watch a delegation
What to notice while it runs: the parent session's transcript stays short. Each subagent shows up briefly in the agent panel below the prompt, does its work in its own context, and what comes back is a few lines. Open the explorer's transcript (select it with ↑/↓, press Enter) and you'll see it read a dozen files that never touched the parent's context.
Background: why subagents exist. The main session's context is the scarce resource. Every file the main session reads stays on its whiteboard for the rest of the conversation. A subagent reads those files on its whiteboard, which is thrown away when it's done. Think of it as renting a second desk for an hour rather than cluttering your own.
Model choice is where the bill is decided. Run your main session on the strongest model you have; give workers the cheapest model that can do the job. You can also set a default for anything that doesn't name a model by adding "CLAUDE_CODE_SUBAGENT_MODEL": "sonnet" to the env block in your settings. With 5–10 workers per project later, this one habit is the difference between a reasonable bill and an alarming one.
Restart before delegating. Role files are read when a session starts. If your session predates the files, restart it (/exit, then claude) or the delegation will fall back to built-in agents. Verify by asking Claude “which subagent types are available?”
Check yourself: three files exist under .claude/agents/; you saw all three subagents appear and finish; the speed-up works in the browser; npm test passes; the reviewer's report had at least one concrete file:line finding. Commit as feat: ball speed-up.
3Your first agent team (review only)
Goal: spawn three teammates who investigate the game in parallel and talk to each other, without writing any code. You'll see the agent panel, the shared task list and direct messaging with zero risk of file conflicts.
What you'll learn: what a teammate is (a whole session), how to address one by name, how results travel (by message, never automatically), and how to shut a team down.
The docs recommend starting with a review team for exactly this reason: you get the coordination experience without the file-conflict experience.
- Start a terminal session in the repo.
claudein the VS Code terminal, normal (not plan) mode. The graphical chat panel also supports teams, but the terminal's agent panel gives you the clearest picture while you're learning. - Ask for a team, explicitly, with names.
Claude sometimes spawns subagents when you wanted teammates. Say “agent team” and “teammates,” and name them so you can address them later.
Prompt — review teamCreate an agent team to review the current state of this repo. Spawn three teammates named feel, bugs, and perf. Use Sonnet for each. - feel: play-test by reading the code as a game designer. Is paddle control responsive? Do ball angles off the paddle reward skill? Is level 1 too hard or too easy? Propose concrete tuning numbers. - bugs: look for logic errors: tunneling through bricks at high speed, edge cases at walls and corners, lives or score updating wrong, anything that could throw at runtime. - perf: look for per-frame allocations, redundant draws, O(n²) collision checks, and anything that won't hold 60fps with 200 bricks and 3 balls. Have them message each other when one finds something relevant to another's area (for example bugs telling perf about a collision loop). Then each reports findings to you with severity. Wait for all three before you synthesize a prioritized list for me.
- Watch the agent panel. Teammates appear below the prompt box. ↑/↓ selects one, Enter opens its transcript so you can read and message it, Esc interrupts its current turn, x stops it, Ctrl T toggles the shared task list. Idle rows hide after 30 seconds once the whole panel is idle; the teammate is still there.
- Message a teammate directly.
Select
bugs, press Enter, and type: “Also check whether the ball can get stuck bouncing horizontally forever.” Plain text goes to that teammate; slash commands still run in the lead's session. Press Esc to return to the lead. - Read the synthesis, then shut down. “Ask all teammates to shut down.” Team directories clean up automatically when the session ends. Save the prioritized list: “Write the prioritized findings to docs/specs/m4-polish.md.” You'll use it in Stage 4's second half.
Background: what just happened under the hood.
- Each teammate was a full Claude Code session. It loaded
CLAUDE.mdand your settings, but not the lead's conversation history. Everything it knew about the job came from the spawn prompt, which is why the prompt spelled out each role. - Messages were written to per-agent inbox files under
~/.claude/teams/<session-xxxxxxxx>/inboxes/and delivered automatically. Nobody polls. - When a teammate finished, the lead got an “idle” notification without the output. Results only travel by message or by task-list updates. That's why the prompt says “report findings to you.”
- Teammates inherited the lead's permission mode. Anything they needed approval for showed up in your lead session for you to approve.
Name your teammates. Names are how you and other agents address them, and a name keeps working even after a teammate finishes, because sending to it resumes it from its transcript. Unnamed teammates get names Claude invents, which you'll never remember.
Check yourself: you saw three named rows in the panel; at least one teammate messaged another (look for it in a transcript); you got a single prioritized list; docs/specs/m4-polish.md exists; the team shut down cleanly.
4A team that builds: power-ups
Goal: ship milestone 3 (power-ups) with a four-teammate team, using the three habits that make multi-day autonomous work survivable: strict file ownership, plan approval for the risky part, and hooks that refuse bad work.
What you'll learn: the shared task list with dependencies, plan approval, quality-gate hooks, and the fact that you stay in charge of merges.
Habit 1 — File ownership, written down
Two teammates editing one file produce overwrites, full stop. The fix is not cleverness: it's an explicit ownership map in the spawn prompt and in the task list. The folder layout from Stage 1 makes this easy: physics, entities, UI and tests are separate directories.
Habit 2 — Plan approval for the piece others depend on
The teammate whose work everyone else builds on (here: the power-up data model and physics) should plan first. It stays in read-only plan mode until the lead approves. The lead approves autonomously, so give it criteria: “only approve plans that list the exact files and include tests.”
Habit 3 — Hooks that refuse bad completions
A hook is a shell command Claude Code runs at a specific moment. Three hook events exist specifically for teams. If the command exits with code 2, the agent receives the printed text as feedback and keeps working instead of stopping.
| Hook | Fires when | Use it to |
|---|---|---|
| TaskCompleted | a teammate marks a task complete | run the test suite; refuse completion if it fails |
| TeammateIdle | a teammate is about to go idle | catch uncommitted work or an unreported result and send it back |
| TaskCreated | the lead creates a task | enforce that every task names its owner and its file list |
Add this hooks block to .claude/settings.json alongside permissions:
{
"permissions": { "...": "unchanged from Stage 0" },
"hooks": {
"TaskCompleted": [
{ "hooks": [ { "type": "command",
"command": "npm test --silent >/tmp/bb-test.log 2>&1 || { echo 'Tests failed. Fix them before completing this task:'; tail -30 /tmp/bb-test.log; exit 2; }" } ] }
],
"TeammateIdle": [
{ "hooks": [ { "type": "command",
"command": "if [ -n \"$(git status --porcelain)\" ]; then echo 'You have uncommitted changes. Commit to your branch and message the lead with a summary before going idle.'; exit 2; fi" } ] }
]
}
}
The spec teammates will read
Teammates only know the spawn prompt plus files they read, so the spec must be concrete. Write it (or have Claude draft it and then edit) at docs/specs/powerups.md:
# docs/specs/powerups.md
## Goal
Some bricks drop a capsule when destroyed. Catching it with the paddle applies an effect for a limited time.
## Types (id · effect · duration)
- multi · split each ball into three · until balls are lost
- wide · paddle width x1.5 · 12 s
- slow · ball speed x0.6 · 10 s
- laser · space fires a bolt that kills one brick · 8 s
## Data (src/entities/powerup.js)
PowerUp = { type, x, y, vy } falls at 120 px/s; removed when below the paddle.
Drop chance: 15% per destroyed brick, chosen uniformly from the four types.
Active effects live on the game state as { type, expiresAt }.
## Physics (src/physics/powerups.js — pure)
applyEffect(state, type, now) and expireEffects(state, now) return new state.
Must be pure: no DOM, no timers, no randomness (caller passes rng and now).
## UI (src/ui/hud.js, src/engine/draw.js)
Draw falling capsules with a letter (M W S L). HUD shows active effects and remaining seconds.
## Tests
Unit: drop selection with a seeded rng; apply/expire for each type; laser hit removes exactly one brick.
Integration: a headless run destroys a brick, catches a capsule, effect expires.
The build prompt
It's long on purpose. Start a fresh session (claude) on main.
While it runs
- Press Ctrl T and watch tasks move pending → in progress → completed. Dependent tasks unblock on their own.
- If the lead starts coding itself, tell it: “Wait for your teammates to complete their tasks before proceeding.”
- If a task looks stuck, check whether the work is actually done (task status can lag), then nudge the owner by name.
- When the TaskCompleted hook fires and fails, you'll see the teammate receive “Tests failed…” and go back to work. That's the hook doing its job.
- When it's done, you merge the four branches (or ask the lead to, one at a time, running tests between each). Keep the human on merges and releases. Then play it: catch a capsule, fire the laser.
Background: sizing rules from the docs. Start with 3–5 teammates; three focused ones usually beat five scattered ones. 5–6 tasks per teammate keeps everyone busy and lets the lead reassign if someone stalls. Scale to 8–10 only when the work really splits that wide.
Second half: the polish milestone, review → build handoff
M4 uses both patterns in sequence. First a review team (like Stage 3) refines docs/specs/m4-polish.md into an ordered task list with file owners; then a build team of two implementers plus qa executes it. Run this in one session:
Check yourself: power-ups work in the browser; npm test passes on main after merging; you saw at least one plan-approval exchange between physics and the lead in the transcript; you saw the TaskCompleted hook reject at least once (if it never did, that's fine too, but check the hook is actually wired by temporarily breaking a test).
5Two projects, project leads, and leads
Goal: run two projects at once (the game and a new leaderboard service), each with its own project-lead session and team, coordinated by two lead sessions through cross-session messaging. This is the full org chart from the “three kinds” section.
What you'll learn: git worktrees, naming sessions, /list-agents and SendMessage between windows, standing briefs, an accountability loop between leads, and what a restart actually looks like.
Everything so far happened inside one session. Now you'll start several yourself, arranged in layers. Here's the layout for two projects; add one more project-lead window per extra project.
VS Code window 1 ─ lead-a claude --name lead-a (repo root, no team; coordinates) VS Code window 2 ─ lead-b claude --name lead-b (repo root, no team; mirrors lead-a) VS Code window 3 ─ pm-game claude --worktree m4-game --name pm-game (its own checkout; runs a team) VS Code window 4 ─ pm-board claude --worktree leaderboard --name pm-board (its own checkout; runs a team)
Background: what a git worktree is. Normally a repo has one working folder. A worktree is a second folder checked out from the same repo on a different branch, so two teams can edit at the same time without ever touching the same files on disk. claude --worktree <name> creates one under your repo and starts the session inside it. When a project is done you merge its branch and delete the worktree.
Step by step
- Write the second project's spec first.
In your main session, ask Claude: “Draft docs/specs/leaderboard.md: a tiny Express + SQLite service in a new top-level folder leaderboard/ with POST /scores {name, score} and GET /scores?limit=10, input validation, node --test tests, and a 20-line client helper in src/ui/leaderboard.js that the game calls on game over. Keep it independent from the game's code except that one helper.” Commit it to
main. - Open one VS Code window per session.
File → New Window, open the repo (for leads) or the worktree folder (for project leads, after step 3 creates it), open the integrated terminal, start
claudewith the name shown above. Separate windows make it obvious which agent you're typing at; you'll be switching all day. Use the Activity Bar session list's groups to keep “leads,” “PMs,” and “scratch” apart. - Create the project-lead sessions with worktrees.
In window 3:
claude --worktree m4-game --name pm-game. In window 4:claude --worktree leaderboard --name pm-board. Name every session; names are the addresses messages are sent to./renamechanges one later. - Confirm they can see each other.
In any session:
/list-agents. You should see the other local sessions with their state and working directory. If the command isn't recognized, checkclaude --version. - Give each project lead a standing brief.
This is the project's charter. It goes in the PM session's first prompt and, for anything durable, into that worktree's
CLAUDE.md.Prompt — to pm-game (mirror for pm-board with its spec)You are the project lead for the Brick Break game in this worktree. Your job is to run an agent team that delivers docs/specs/m4-final.md, then anything lead-a assigns next, one milestone per team run. You never implement; you plan, spawn teammates with explicit file ownership, require plan approval for anything touching src/physics, keep 5–6 tasks per teammate, and merge completed branches into this worktree's branch after qa signs off. Reporting: when a milestone completes, or you are blocked for more than one task cycle, message lead-a with a 5-line status (milestone, done, blocked, next, risk). If lead-a does not reply within one cycle, message lead-b instead. Do not message pm-board directly; route cross-project questions through the leads. Start now. - Give the leads their accountability loop.
Leads hold no team; they coordinate.
Prompt — to lead-a (mirror it for lead-b, swapping names)You are lead-a. Your peers are lead-b and the project leads pm-game and pm-board. Your responsibilities: 1. Keep a running status board in docs/STATUS.md (one line per project) from the status messages the PMs send you. 2. Every time you receive a PM status, decide: approve the next milestone, ask a question, or escalate to me. Escalate only for scope changes, spend concerns, or anything that would change the public API between the game and the leaderboard. 3. Accountability with lead-b: after each status update, message lead-b a one-line ping. If you receive no ping from lead-b across two PM updates, or lead-b reports an error, tell me immediately and include the last thing you heard from lead-b, so I can restart it. 4. Never approve your own permission prompts via another agent; anything that needs consent comes to me. Confirm you can see all three peers with ListAgents, then wait for status.
- Run it for a session.
Your interaction pattern should start to look like this: most of your prompts go to a lead (“what's the state of things?”, “approve pm-board's next milestone”), a third go to a project lead when you care about the details of one project, and occasionally you open a worker's transcript because something went sideways. Since v2.1.232 you can also type
@pm-gamein a prompt to target a session by name.
About “restart the other if it fails”
A clear-eyed version of what you can and can't do today.
Works out of the box
- Leads detect each other's silence or errors via the ping protocol and tell you.
- If a teammate dies, its lead can spawn a replacement with the same name and brief.
- You restart a session with
claude --resume(extension and CLI share history), and/list-agentsshows it's back. - A lead can ask to be notified when another local session next goes idle (v2.1.236+), which is better than polling.
You'd have to build
- A lead can't “click Resume” in another window. To automate, give it a narrowly allowlisted script that opens a new terminal running
claude --resume <id> --name lead-b. Treat as a power tool. - Message loops are throttled on purpose: repeated messages are rate-limited and queues cap at 50, so a timer-based heartbeat won't work. Tie pings to events.
- Messages carry text only, never history. Anything a restarted lead needs lives in
docs/STATUS.md.
Safety boundaries you should want. A message from another agent arrives flagged as “from another Claude session, not from you.” It can't approve a permission prompt, can't change settings or CLAUDE.md, and a slash command inside it is just text. A teammate that was denied something can't ask another teammate to do it. Don't route around this with --dangerously-skip-permissions: with ten sessions running, the permission layer is what keeps one confused agent from becoming ten.
Check yourself: four named sessions visible in /list-agents; docs/STATUS.md has a line per project written by a lead; you saw a PM status arrive in lead-a's window and a ping arrive in lead-b's; the leaderboard service runs and the game posts a score to it.
Running it day to day (and keeping the bill sane)
A realistic rhythm
Morning: read docs/STATUS.md, ask lead-a for overnight exceptions, approve next milestones.
Midday: drop into one PM for the project you care about today; review its merges; adjust specs.
Afternoon: handle escalations, start new milestones, shut down finished teams.
Anytime: something derailed; open that worker's transcript, redirect or replace it.
Cost controls that matter
- Each teammate is a full Claude instance; cost scales roughly linearly with active teammates.
- Run
/usagein the chat panel; it attributes usage to subagents and flags subagent-heavy behavior. - Haiku for exploration, Sonnet for implementation, your strongest model for leads and PMs only.
- Shut teams down when a milestone ends. Idle teammates are cheap; forgotten ones aren't.
Checklist before letting a team run unattended
- Ownership map is in the task list and in the spawn prompt.
- TaskCompleted hook runs tests; TeammateIdle hook demands a commit and a report.
- Plan approval is on for the shared-contract piece (physics, data layer, API shape).
- Permissions allowlist covers routine commands; deny list covers the destructive ones.
- Every agent has a name you chose.
- The PM's reporting protocol names a lead and a fallback lead.
- Merges and releases stay with you.
Field notes from the first real run
This guide was walked end-to-end on a MacBook Pro against Claude Code v2.1.240 before being published. Everything worked; these are the trip-wires that actually fired, so you can step over them.
Subagent role files load at session start, not on save. The first delegation after creating .claude/agents/ failed with “Agent type 'explorer' not found” and silently fell back to the built-in Explore agent, because the session predated the files. Restart the session (/exit, then claude again) after creating or editing roles. The /agents wizard has been removed in current builds — verify your roles loaded by asking Claude “which subagent types are available?” or by typing @exp and checking the typeahead.
Give implementer and reviewer the SendMessage tool. The tools: line is an allowlist, and the original versions of these role files left SendMessage off. The build team routed around it with shared scratchpad files — it worked, but direct messaging is better and Stage 5 depends on it. The role files in this revision include it.
Watch for a stale editor tab while Claude edits settings. If a file is open in VS Code with unsaved changes (white dot on the tab instead of an ×), VS Code will not refresh it when Claude writes the file on disk — you'll be looking at your stale copy while the real file is different. This bit us twice on .claude/settings.json: once when a pasted hooks block was never actually saved, once when Claude's edit didn't appear until the file was reopened. Rule: before asking Claude to edit a file, save or close your tab for it, and after, trust cat over the editor.
Things that worked exactly as designed, worth watching for: the plan-approval gate on the shared-contract teammate ran as described (the lead reviewed and approved the physics plan before engine and ui unblocked); the QA teammate rejected an untestable design and the owning teammate added a pure primitive in response — cross-owner correction with no human involvement; and a spec gap surfaced as a decision rather than a bug (“bricks killed by laser don't drop capsules — deliberate or oversight?”). Specs don't need to be complete; they need to be concrete enough that gaps become questions.
Small mechanics: when Claude offers numbered options, arrow keys + Enter, the number key, or Tab all select — you don't retype the option. And git diff --stat (the file-by-file +/- summary Claude shows before committing) is your fastest ownership check: did it change the files you'd expect, and only those?
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Asked for a team, got subagents | Claude judged the task didn't need a team | Ask again with “agent team” and “teammates” explicitly; say how many and name them |
| Teammate rows vanished | Idle rows hide after 30 s once the whole panel is idle | They're still running. Message the teammate by name and the row returns |
| Lead started implementing itself | Default lead behavior | “Wait for your teammates to complete their tasks before proceeding” |
| Dependent task never unblocks | Teammate forgot to mark its task complete | Check the work; update the task or tell the lead to nudge the owner |
| Too many permission prompts | Teammates inherit the lead's mode; each prompt bubbles up | Pre-approve routine commands in project settings |
| Delegation hangs waiting for a subagent result | With teams on, a named subagent launched as a teammate and only sent an idle notice | Set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS to "0" for that project; takes effect on save |
After /resume, lead messages teammates that don't exist | In-process teammates aren't restored on resume | Tell the lead to spawn new teammates with the same names and briefs |
/list-agents not recognized | Below v2.1.224 (or v2.1.234 on native Windows) | Update the CLI; on older Windows, use WSL 2 for Stage 5 |
/list-agents works but a message never arrives | A deny rule on SendMessage/ListAgents, or the receiver's crossSessionInbound is holding or refusing | Check both sessions' settings; held messages expire after about five minutes by default |
| “Failed to write to teammate inbox” | Disk full or inbox directory not writable | Free space or fix permissions under ~/.claude/teams/; the send was not delivered |
| “Agent type 'explorer' not found” | The session started before the role files existed | Restart the session; roles load at session start |
| Claude edited a file but the open tab doesn't show it | The tab has unsaved changes, so VS Code won't refresh it from disk | Close and reopen the tab; watch for the white dot before letting Claude edit an open file |
| Game won't load at localhost:3000 | Server not running, or another app has port 3000 | npm start in the repo folder; or ask Claude to change the port in server.js |
| Ball tunnels through bricks after the speed-up | Collision checks once per frame; fast ball skips a brick | Ask for swept/sub-stepped collision in src/physics/collision.js; this is a classic and a good first “bugs” teammate find |
Glossary
- Agent panel
- The list under the prompt box in a terminal session showing subagents and teammates. Arrows select, Enter opens, Esc interrupts, x stops.
- Branch
- A parallel line of commits in Git. Each teammate commits to its own branch; you merge them.
- CLAUDE.md
- A plain-text file at the repo root that every session and teammate reads on startup. Your conventions go here.
- Context window
- A model's working memory for one session. Finite; protect it.
- Cross-session messaging
- Independent sessions on your machine discovering each other with ListAgents and passing text with SendMessage.
- Hook
- A shell command Claude Code runs at a defined moment (task completed, teammate idle). Exit code 2 sends the output back as feedback and keeps the agent working.
- Lead
- In a team: the session that spawned the teammates. In the Stage 5 stack: a plain session with no team that coordinates project leads.
- Permission mode
- How Claude Code asks before acting. Plan mode is read-only; default asks per action; auto mode uses a classifier. Cycle with Shift Tab.
- Plan approval
- A teammate stays read-only until the lead approves its written plan. Use for the piece everyone depends on.
- Project lead / PM
- A session in its own worktree that runs one project's team and reports to the leads.
- Session
- One running Claude Code conversation. Has a name (set with --name or /rename) that other sessions message.
- Subagent
- A helper with its own context that returns a summary to its parent. Defined in .claude/agents/*.md.
- Task list
- The shared board a team works from. Tasks have pending/in-progress/completed states and dependencies. Ctrl T toggles it.
- Teammate
- A full Claude Code session spawned by a lead as part of an agent team.
- Token
- The unit models read and write text in (roughly three-quarters of a word). Cost and context are measured in tokens.
- Worktree
- A second checkout of the same Git repo in its own folder on its own branch, so two teams can work at once without touching the same files.
Sources
Everything mechanical here was checked against these pages on August 22, 2026. Agent teams are experimental and the docs note version-specific changes almost weekly, so when something on screen disagrees with this page, trust the screen and re-read the docs page.
- Orchestrate teams of Claude Code sessions — code.claude.com/docs/en/agent-teams (enable flag, display modes, plan approval, hooks, architecture, limitations, troubleshooting)
- Message your other Claude Code sessions — code.claude.com/docs/en/cross-session-messaging (ListAgents/SendMessage, version and platform support, inbound controls, throttling, @-mentions, idle notices)
- Create custom subagents — code.claude.com/docs/en/sub-agents (frontmatter fields, scopes, model selection)
- Use Claude Code in VS Code — code.claude.com/docs/en/vs-code (extension install, bundled vs standalone CLI, windows, session groups, worktrees)
- Claude Code docs index — code.claude.com/docs/llms.txt