llms.txt@09-Agents-Patterns · git:20261001.bf1f66b · 2026-10-01 · sha256 525957bbe3a61488

llms.txt@09-Agents-Patterns git:20261001.bf1f66bF

Immutable. This exact content never changes and is served at /api/v1/blob/525957bbe3a61488.

# Agent Patterns

> Every page below, concatenated. Each section gives the page title, its upstream source and its path in this repository.

---

## Orchestrate teams of Claude Code sessions - Claude Code Docs

Source: https://code.claude.com/docs/en/agent-teams
Path: 09-Agents-Patterns/agent-teams.md

## On this page

- [When to use agent teams](#when-to-use-agent-teams)
  - [Compare with subagents](#compare-with-subagents)
- [Enable agent teams](#enable-agent-teams)
- [Start your first agent team](#start-your-first-agent-team)
- [Control your agent team](#control-your-agent-team)
  - [Choose a display mode](#choose-a-display-mode)
  - [Specify teammates and models](#specify-teammates-and-models)
  - [Have teammates plan before implementing](#have-teammates-plan-before-implementing)
  - [Talk to teammates directly](#talk-to-teammates-directly)
  - [Assign and claim tasks](#assign-and-claim-tasks)
  - [Shut down teammates](#shut-down-teammates)
  - [Enforce quality gates with hooks](#enforce-quality-gates-with-hooks)
- [How agent teams work](#how-agent-teams-work)
  - [How Claude starts agent teams](#how-claude-starts-agent-teams)
  - [Architecture](#architecture)
  - [Use subagent definitions for teammates](#use-subagent-definitions-for-teammates)
  - [Permissions](#permissions)
  - [Messages between agents](#messages-between-agents)
  - [Context and communication](#context-and-communication)
  - [Token usage](#token-usage)
- [Use case examples](#use-case-examples)
  - [Run a parallel code review](#run-a-parallel-code-review)
  - [Investigate with competing hypotheses](#investigate-with-competing-hypotheses)
- [Best practices](#best-practices)
  - [Give teammates enough context](#give-teammates-enough-context)
  - [Choose an appropriate team size](#choose-an-appropriate-team-size)
  - [Size tasks appropriately](#size-tasks-appropriately)
  - [Wait for teammates to finish](#wait-for-teammates-to-finish)
  - [Start with research and review](#start-with-research-and-review)
  - [Avoid file conflicts](#avoid-file-conflicts)
  - [Monitor and steer](#monitor-and-steer)
- [Troubleshooting](#troubleshooting)
  - [Teammates not appearing](#teammates-not-appearing)
  - [Claude spawns teammates instead of subagents](#claude-spawns-teammates-instead-of-subagents)
  - [Too many permission prompts](#too-many-permission-prompts)
  - [Agents stopping early](#agents-stopping-early)
  - [Orphaned tmux sessions](#orphaned-tmux-sessions)
- [Limitations](#limitations)
- [Next steps](#next-steps)

Agents and parallel work

# Orchestrate teams of Claude Code sessions

Copy pageCopy page

Coordinate multiple Claude Code instances working together as a team, with shared tasks, inter-agent messaging, and centralized management.

Copy pageCopy page

Agent teams are experimental and disabled by default. Enable them by setting `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` in your [settings.json](../02-Claude-Code-CLI/settings.md) or environment. Without that variable, no team is set up at session start, no team directories are written, and Claude does not spawn or propose teammates. Agent teams have [known limitations](#limitations) around session resumption, task coordination, and shutdown behavior.

Agent teams let you coordinate multiple Claude Code instances working together. One session acts as the team lead, coordinating work, assigning tasks, and synthesizing results. Teammates work independently, each in its own context window, and communicate directly with each other. You can also talk to any teammate directly without going through the lead. Before you set up a team, check whether a lighter option does the job. [Subagents](sub-agents.md) work within a single session, and with [cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md) Claude can pass findings between the sessions you run yourself.


[​](#when-to-use-agent-teams)

When to use agent teams

Agent teams are most effective for tasks where parallel exploration adds real value. See [use case examples](#use-case-examples) for full scenarios. The strongest use cases are:

- **Research and review**: multiple teammates can investigate different aspects of a problem simultaneously, then share and challenge each other’s findings
- **New modules or features**: teammates can each own a separate piece without stepping on each other
- **Debugging with competing hypotheses**: teammates test different theories in parallel and converge on the answer faster
- **Cross-layer coordination**: changes that span frontend, backend, and tests, each owned by a different teammate

Agent teams add coordination overhead and use significantly more tokens than a single session. They work best when teammates can operate independently. For sequential tasks, same-file edits, or work with many dependencies, a single session or [subagents](sub-agents.md) are more effective.


[​](#compare-with-subagents)

Compare with subagents

Both agent teams and [subagents](sub-agents.md) let you parallelize work, but they operate differently. For separate sessions that pass messages to each other without a team, see [cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md).

|                   | Subagents                                                                                                                                                | Agent teams                                                                                                                                        |
|:------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|
| **Context**       | Own context window; results return to the caller                                                                                                         | Own context window; fully independent                                                                                                              |
| **Communication** | Return a result to the caller. Subagents that Claude named when it spawned them can also [message each other](sub-agents.md#what-loads-at-startup) | Teammates message each other directly                                                                                                              |
| **Coordination**  | Main agent manages all work                                                                                                                              | Self-coordination through messages, plus a shared task list for [agents that have the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability) |
| **Best for**      | Focused tasks where only the result matters                                                                                                              | Complex work requiring discussion and collaboration                                                                                                |
| **Token cost**    | Lower: results summarized back to main context                                                                                                           | Higher: each teammate is a separate Claude instance                                                                                                |

Use subagents when you need quick, focused workers that report back. Use agent teams when teammates need to share findings, challenge each other, and coordinate on their own.


[​](#enable-agent-teams)

Enable agent teams

Agent teams are disabled by default. Enable them by setting the `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` environment variable to `1`, either in your shell environment or through [settings.json](../02-Claude-Code-CLI/settings.md):

settings.json

```python
{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  }
}
```

Enabling agent teams also changes ordinary delegation. Claude may [name a subagent](sub-agents.md#subagent-names) on its own, and while agent teams are enabled, a subagent that Claude names launches as a teammate, so teams can form even when you didn’t ask for one. For more, see [How Claude starts agent teams](#how-claude-starts-agent-teams); to turn the behavior off, see [Claude spawns teammates instead of subagents](#claude-spawns-teammates-instead-of-subagents). Spawning teammates also requires an interactive session. In [non-interactive mode](../02-Claude-Code-CLI/headless.md) with the `-p` flag, including Agent SDK sessions, Claude doesn’t spawn teammates, and a subagent that Claude names runs as an ordinary [subagent](sub-agents.md) even with agent teams enabled.


[​](#start-your-first-agent-team)

Start your first agent team

After enabling agent teams, describe the task and the teammates you want in natural language. Claude spawns them and coordinates work based on your prompt. This example works well because the three roles are independent and can explore the problem without waiting on each other:

```python
I'm designing a CLI tool that helps developers track TODO comments across
their codebase. Spawn three teammates to explore this from different angles:
one on UX, one on technical architecture, one playing devil's advocate.
```

From there, Claude populates a [shared task list](../02-Claude-Code-CLI/interactive-mode.md#task-list) in a [session that has the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability), spawns teammates for each perspective, has them explore the problem, and synthesizes findings when finished. Claude may sometimes use [subagents](sub-agents.md) instead of creating a team. Subagents appear in the same agent panel as teammates, so the panel alone doesn’t confirm a team formed. If Claude spawned subagents instead, ask again and explicitly request an agent team. The lead’s terminal lists teammates in the agent panel below the prompt input. From the panel:

- **Up and down arrows**: select a teammate
- **Enter**: open the selected teammate’s transcript and message it directly
- **Escape**: clear the selection. While you’re viewing a teammate’s transcript, Escape interrupts that teammate’s current turn

As of v2.1.199, an idle teammate’s row stays in the panel while any teammate or subagent is still working, so you can select it to review its transcript or send it more work. Once every agent in the panel is idle, idle rows hide after 30 seconds and reappear on the teammate’s next turn; the teammate stays running and addressable while hidden. In v2.1.181 through v2.1.198, an idle row hid 30 seconds after its own turn ended, even while other teammates were still working; idle rows are not hidden on versions before v2.1.181. When more than three teammates are idle at once, the rows beyond the first three collapse into a single row that counts the collapsed teammates, such as `2 idle agents` when five are idle. Select it and press Enter to expand the collapsed rows, or press Esc to collapse them again. Working teammates, failed teammates, and the teammate you’re viewing always keep their own rows. If you want each teammate in its own split pane, see [Choose a display mode](#choose-a-display-mode).


[​](#control-your-agent-team)

Control your agent team

Tell the lead what you want in natural language. It handles team coordination, task assignment, and delegation based on your instructions.


[​](#choose-a-display-mode)

Choose a display mode

Agent teams support two display modes:

- **In-process**: all teammates run inside your main terminal. Use the up and down arrow keys in the agent panel to select a teammate, then press Enter to view it and type to message it directly. Works in any terminal, no extra setup required.
- **Split panes**: each teammate gets its own pane. You can see everyone’s output at once and click into a pane to interact directly. Requires tmux, or iTerm2.

`tmux` has known limitations on certain operating systems and traditionally works best on macOS. Using `tmux -CC` in iTerm2 is the suggested entrypoint into `tmux`.

The default is `"in-process"`. Set `"auto"` to enable split panes when you’re already running inside a tmux session, or when your terminal is iTerm2 with the `it2` CLI installed, falling back to in-process otherwise. The `"tmux"` setting enables split-pane mode and auto-detects whether to use tmux or iTerm2 based on your terminal. Set `"iterm2"` to use iTerm2 native split panes explicitly. This mode requires the [`it2` CLI](https://github.com/mkusaka/it2) and shows an error with the install command if `it2` is missing. The setup prompt that offers to install `it2` or switch to tmux appears under `"auto"` or `"tmux"` when your terminal is iTerm2 and tmux is available as a fallback. To override the default, set [`teammateMode`](../02-Claude-Code-CLI/settings-reference.md#teammatemode) in `~/.claude/settings.json`:

```python
{
  "teammateMode": "auto"
}
```

To set the mode for a single session, pass it as a flag:

```python
claude --teammate-mode auto
```

The `--teammate-mode` flag is experimental and doesn’t appear in `claude --help`. Split-pane mode requires either [tmux](https://github.com/tmux/tmux/wiki) or iTerm2 with the [`it2` CLI](https://github.com/mkusaka/it2). To install manually:

- **tmux**: install through your system’s package manager. See the [tmux wiki](https://github.com/tmux/tmux/wiki/Installing) for platform-specific instructions.
- **iTerm2**: install the [`it2` CLI](https://github.com/mkusaka/it2), then enable the Python API in **iTerm2 → Settings → General → Magic → Enable Python API**.


[​](#specify-teammates-and-models)

Specify teammates and models

Claude decides the number of teammates to spawn based on your task, or you can specify exactly what you want:

```python
Spawn 4 teammates to refactor these modules in parallel. Use Sonnet for
each teammate.
```

Claude Code picks each teammate’s model from the first of these that applies:

1.  The model your spawn prompt names for that teammate.
2.  For a teammate spawned from a [subagent definition](#use-subagent-definitions-for-teammates), the definition’s `model`, where `inherit` selects the lead’s model.
3.  [`CLAUDE_CODE_SUBAGENT_MODEL`](../02-Claude-Code-CLI/model-config.md#environment-variables), when it’s set to anything other than `inherit`.
4.  The lead’s current model.

If you set [`CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1`](sub-agents.md#run-every-subagent-on-one-model), the first two sources don’t apply. Claude Code picks every teammate’s model from `CLAUDE_CODE_SUBAGENT_MODEL` when it’s set to anything other than `inherit`, and from the lead’s current model otherwise. Requires Claude Code v2.1.257 or later. Before v2.1.251, `CLAUDE_CODE_SUBAGENT_MODEL` came first in this order.

`teammateDefaultModel` was removed in v2.1.234; Claude Code ignores a leftover value. Name the model in your prompt instead.

Claude Code checks the model it selects for a teammate against your organization’s [`availableModels`](../02-Claude-Code-CLI/model-config.md#restrict-model-selection) allowlist. When the allowlist blocks a value, Claude Code substitutes another model:

- **Family alias such as `opus`**: On the Anthropic API and Claude Platform on AWS, Claude Code runs the teammate on the newest version of that family the allowlist permits. On providers with provider-specific model IDs, where the [substitution doesn’t operate](../02-Claude-Code-CLI/model-config.md#restrict-model-selection), a blocked alias falls back like any other blocked value per the next bullet
- **Any other blocked value, including a family alias on providers where the substitution doesn’t operate, or one whose family has no permitted version**: Claude Code runs the teammate on the lead’s model instead. If you set `CLAUDE_CODE_SUBAGENT_MODEL`, Claude Code tries that model first, under these same rules

Teammates inherit the lead’s [effort level](../02-Claude-Code-CLI/model-config.md#adjust-effort-level). In split-pane mode this applies from v2.1.186; earlier versions did not pass the lead’s session effort to split-pane teammates.


[​](#have-teammates-plan-before-implementing)

Have teammates plan before implementing

For complex or risky tasks, you can have teammates plan before implementing. A teammate that Claude spawns while the lead is in [plan mode](../02-Claude-Code-CLI/permission-modes.md#analyze-before-you-edit-with-plan-mode) works in read-only plan mode until its plan is ready. Switch the lead into plan mode first, then ask for the teammate:

```python
Spawn an architect teammate to refactor the authentication module.
```

When a teammate finishes planning, it sends a plan approval request to the lead. Claude Code approves the plan in the lead’s session as soon as the request arrives, without the lead reviewing it. The teammate’s edits and commands still go through the permission prompts described in [Permissions](#permissions). Once approved, the teammate exits plan mode and begins implementation.


[​](#talk-to-teammates-directly)

Talk to teammates directly

Each teammate is a full, independent Claude Code session. You can message any teammate directly to give additional instructions, ask follow-up questions, or redirect their approach.

- **In-process mode**: use the up and down arrow keys in the agent panel to select a teammate, then press Enter to view its session and type to send it a message. Press `x` on a selected teammate to stop it. Press Ctrl+T to toggle the task list.
- **Split-pane mode**: click into a teammate’s pane to interact with their session directly. Each teammate has a full view of their own terminal.

While you’re viewing an in-process teammate, plain text and [skills](../08-Plugins-Skills/skills.md) go to that teammate, but built-in commands still run in the lead’s session. A teammate’s model and fast mode are fixed when it spawns, so `/model` and `/fast` only change the lead’s settings. As of v2.1.199, typing either command while viewing a teammate shows a notice that the change applies to the lead; earlier versions applied it to the lead with no indication. `/effort` still applies to the viewed teammate’s later turns, because teammates follow the lead’s [effort level](../02-Claude-Code-CLI/model-config.md#adjust-effort-level).


[​](#assign-and-claim-tasks)

Assign and claim tasks

The shared task list coordinates work across the team. The lead creates tasks and teammates work through them. Tasks have three states: pending, in progress, and completed. Tasks can also depend on other tasks: a pending task with unresolved dependencies cannot be claimed until those dependencies are completed. Agents [without the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability) coordinate through messages instead of the shared task list. The lead can assign tasks explicitly, or teammates can self-claim:

- **Lead assigns**: tell the lead which task to give to which teammate
- **Self-claim**: after finishing a task, a teammate picks up the next unassigned, unblocked task on its own

Task claiming uses file locking to prevent race conditions when multiple teammates try to claim the same task simultaneously.


[​](#shut-down-teammates)

Shut down teammates

To gracefully end a teammate’s session, refer to it by name. For example, with a teammate named researcher:

```python
Ask the researcher teammate to shut down
```

The lead sends a shutdown request. The teammate can approve, exiting gracefully, or reject with an explanation. The team’s shared directories are cleaned up automatically when the session ends, so there’s no separate cleanup step. See [Architecture](#architecture) for which directories are removed and which persist for resumed sessions.


[​](#enforce-quality-gates-with-hooks)

Enforce quality gates with hooks

Use [hooks](../07-Hooks/hooks.md) to enforce rules when teammates finish work or tasks are created or completed:

- [`TeammateIdle`](../07-Hooks/hooks.md#teammateidle): runs when a teammate is about to go idle. Exit with code 2 to send feedback and keep the teammate working.
- [`TaskCreated`](../07-Hooks/hooks.md#taskcreated): runs when a task is being created. Exit with code 2 to prevent creation and send feedback.
- [`TaskCompleted`](../07-Hooks/hooks.md#taskcompleted): runs when a task is being marked complete. Exit with code 2 to prevent completion and send feedback.


[​](#how-agent-teams-work)

How agent teams work

This section covers the architecture and mechanics behind agent teams. If you want to start using them, see [Control your agent team](#control-your-agent-team) above.


[​](#how-claude-starts-agent-teams)

How Claude starts agent teams

To start a team, ask Claude for teammates. Claude launches a teammate when it calls the [Agent tool](../02-Claude-Code-CLI/tools-reference.md) with a [`name`](sub-agents.md#subagent-names) while agent teams are enabled, unless the call is a [fork](sub-agents.md#fork-the-current-conversation) or passes `isolation` on the call itself. Claude Code doesn’t ask you to confirm the launch. Claude also names ordinary subagents on its own so it can message them later. Those calls follow the same rule, so teams can form even when you didn’t ask for one. If you want subagents instead, [turn agent teams off](#claude-spawns-teammates-instead-of-subagents).


[​](#architecture)

Architecture

An agent team consists of:

| Component     | Role                                                                    |
|:--------------|:------------------------------------------------------------------------|
| **Team lead** | The main Claude Code session that spawns teammates and coordinates work |
| **Teammates** | Separate Claude Code instances that each work on assigned tasks         |
| **Task list** | Shared list of work items that teammates claim and complete             |
| **Mailbox**   | Messaging system for communication between agents                       |

Each agent’s mailbox is a JSON file at `~/.claude/teams/{team-name}/inboxes/{agent-name}.json`. Claude Code validates every entry when it reads a mailbox file. Entries that don’t match the message format are reported as errors and removed from the file; the valid messages are still delivered. Before v2.1.207, a single malformed mailbox entry caused a repeated error every second and blocked delivery for that mailbox until you deleted the file manually. Claude Code reports a message as sent only when the write to the recipient’s mailbox file succeeds, whether the message is plain text or a structured protocol message such as a plan approval or shutdown request. When the write fails, for example because the disk is full or the mailbox directory isn’t writable, the sending agent receives an error and nothing is sent. See [Failed to write to a teammate’s inbox](../02-Claude-Code-CLI/errors.md#failed-to-write-to-a-teammate-inbox) for the error messages and recovery steps. Claude Code manages task dependencies automatically: when a teammate completes a task that other tasks depend on, it unblocks the dependent tasks without any action from you. Teams and tasks are stored locally under a session-derived name. The name is `session-` followed by the first eight characters of the session ID:

- **Team config**: `~/.claude/teams/{team-name}/config.json`
- **Task list**: `~/.claude/tasks/{team-name}/`

Claude Code generates both of these automatically at session startup and updates them as teammates join, go idle, or leave. The team config directory is removed when the session ends. The task list directory persists locally and is never uploaded, so resumed sessions keep their tasks. Retention is governed by the same [`cleanupPeriodDays`](../02-Claude-Code-CLI/settings-reference.md#cleanupperioddays) you already control for session transcripts, following the [retention sweep rules](../02-Claude-Code-CLI/claude-directory.md#cleaned-up-automatically). The team config holds runtime state such as session IDs and tmux pane IDs, so don’t edit it by hand or pre-author it: your changes are overwritten on the next state update. To define reusable teammate roles, use [subagent definitions](#use-subagent-definitions-for-teammates) instead. The team config contains a `members` array with each member’s name and agent ID. The lead’s entry always carries the agent type `team-lead`. A teammate’s entry carries whatever agent type the lead named when spawning it, whether a [built-in type](sub-agents.md#built-in-subagents) or a [subagent definition](#use-subagent-definitions-for-teammates), and omits the field when the lead named none. Teammates can read this file to discover other team members. There is no project-level equivalent of the team config. A file like `.claude/teams/teams.json` in your project directory is not recognized as configuration; Claude treats it as an ordinary file.


[​](#use-subagent-definitions-for-teammates)

Use subagent definitions for teammates

When spawning a teammate in either display mode, you can reference a [subagent](sub-agents.md) type from the project, user, or managed [subagent scope](sub-agents.md#choose-the-subagent-scope). This lets you define a role once, such as a security-reviewer or test-runner, and reuse it both as a delegated subagent and as an agent team teammate. To use a subagent definition, name it when you ask Claude to spawn the teammate:

```python
Spawn a teammate using the security-reviewer agent type to audit the auth module.
```

Claude Code reads the subagent definition you named and applies these parts of it to the teammate. Where a part depends on the teammate’s [display mode](#choose-a-display-mode), the entry says so:

- **`tools`**: Claude Code limits the teammate to the tools in the definition’s `tools` list. For an in-process teammate, Claude Code adds `SendMessage` to that list, and in a [session that has the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability) it adds `TaskCreate`, `TaskGet`, `TaskList`, and `TaskUpdate` too.
- **`model`**: Claude Code uses the definition’s `model` in either display mode when your spawn prompt doesn’t name one. See [how Claude Code picks a teammate’s model](#specify-teammates-and-models).
- **Body**: for an in-process teammate, Claude Code appends the definition’s body to its default system prompt as additional instructions. For a split-pane teammate, Claude Code uses the body in place of its default system prompt.
- **`skills`**: Claude Code doesn’t apply the definition’s `skills` to a teammate in either display mode. The teammate loads skills from your project and user settings.
- **`mcpServers`**: for a split-pane teammate, Claude Code applies the definition’s `mcpServers` under the [rules for that field](sub-agents.md#scope-mcp-servers-to-a-subagent), which cover a session started with `--agent` as well. An in-process teammate ignores the field and loads MCP servers from your project and user settings.

When Claude messages an in-process teammate that is no longer running, Claude Code brings it back in the same session, restores any conversation saved for it, and gives it the message as its next prompt. After you resume a session, teammates aren’t brought back this way, per [the resume limitation](#limitations). For a teammate it brings back, Claude Code re-applies a definition that came from a project’s `.claude/agents/` directory or an `--add-dir` directory only if you’ve [trusted the folder the agent file is in](../02-Claude-Code-CLI/permissions.md#what-runs-before-you-trust-a-folder). Trusting a parent folder doesn’t count. Until then, the teammate comes back with none of the definition’s tools or instructions, keeping only the tools Claude Code adds to every in-process teammate. See [the teammate’s agent definition was not restored](../02-Claude-Code-CLI/errors.md#teammate-agent-definition-not-restored) for the notice text.


[​](#permissions)

Permissions

Teammates start with the lead’s permission mode, except [`dontAsk` mode](../02-Claude-Code-CLI/permission-modes.md#allow-only-pre-approved-tools-with-dontask-mode), which they don’t inherit. If the lead runs with an elevated permission mode, all teammates inherit it. After spawning, you can change an individual teammate’s permission mode, but you can’t set per-teammate permission modes at spawn time. Teammate permission prompts appear in the lead session, so approve them there yourself. [Plan approval](#have-teammates-plan-before-implementing) is the designed exception: the lead session grants teammate plan approvals without a separate prompt to you.


[​](#messages-between-agents)

Messages between agents

When one agent sends another a message over `SendMessage`, Claude Code tells the receiving agent the message came from another Claude session, not from you. A teammate can’t approve a permission prompt or supply consent on your behalf, and a teammate that was denied an action can’t relay it to another teammate to bypass the check. The same rules apply to a message that arrives from [one of your other Claude Code sessions](../02-Claude-Code-CLI/cross-session-messaging.md#how-a-session-treats-an-incoming-message), outside the team entirely. In [auto mode](../02-Claude-Code-CLI/permission-modes.md#eliminate-prompts-with-auto-mode), the classifier applies two checks to messages between agents:

- It treats an approval claim relayed from another agent as untrusted input rather than confirmation from you.
- It reviews each message before Claude Code delivers it, whether a plain message or a structured protocol message such as a shutdown request or plan approval response. A message it blocks never reaches the recipient.


[​](#context-and-communication)

Context and communication

Each teammate has its own context window. When spawned, a teammate loads the same project context as a regular session: CLAUDE.md, MCP servers, and skills. If you start the lead with [`--setting-sources`](../02-Claude-Code-CLI/cli-reference.md#cli-flags), teammates load from the same restricted list of sources. Before v2.1.281, [split-pane](#choose-a-display-mode) teammates loaded every settings source. A teammate also receives the spawn prompt from the lead. The lead’s conversation history does not carry over. **How teammates share information:**

- **Automatic message delivery**: when teammates send messages, they’re delivered automatically to recipients. The lead doesn’t need to poll for updates.
- **Idle notifications**: when a teammate finishes and stops, it automatically notifies the lead and includes its final answer in the notification. A teammate whose turn ends on an API error notifies the lead that it failed and includes the error text.
- **Shared task list**: [agents that have the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability) can see task status and claim available work.
- **Teammate messaging**: send a message to one specific teammate by name. To reach everyone, send one message per recipient.

The lead assigns every teammate a name when it spawns them, and any teammate can message any other by that name. To get predictable names you can reference in later prompts, tell the lead what to call each teammate in your spawn instruction.


[​](#token-usage)

Token usage

Agent teams use significantly more tokens than a single session. Each teammate has its own context window, and token usage scales with the number of active teammates. For research, review, and new feature work, the extra tokens are usually worthwhile. For routine tasks, a single session is more cost-effective. See [agent team token costs](../17-Billing-Plans/costs.md#agent-team-token-costs) for usage guidance. An in-process teammate’s requests fall outside the main conversation’s [cache TTL bucket](../02-Claude-Code-CLI/prompt-caching.md#which-ttl-each-request-gets), so its cache holds for five minutes by default, including on a Claude subscription. To keep it for an hour, set [`subagentPromptCacheTtl`](../02-Claude-Code-CLI/settings-reference.md#subagentpromptcachettl) to `1h`. The API bills 1-hour cache writes at a higher rate.


[​](#use-case-examples)

Use case examples

These examples show how agent teams handle tasks where parallel exploration adds value.


[​](#run-a-parallel-code-review)

Run a parallel code review

A single reviewer tends to gravitate toward one type of issue at a time. Splitting review criteria into independent domains means security, performance, and test coverage all get thorough attention simultaneously. The prompt assigns each teammate a distinct lens so they don’t overlap:

```python
Spawn three teammates to review PR #142:
- One focused on security implications
- One checking performance impact
- One validating test coverage
Have them each review and report findings.
```

Each reviewer works from the same PR but applies a different filter. The lead synthesizes findings across all three after they finish.


[​](#investigate-with-competing-hypotheses)

Investigate with competing hypotheses

When the root cause is unclear, a single agent tends to find one plausible explanation and stop looking. The prompt fights this by making teammates explicitly adversarial: each one’s job is not only to investigate its own theory but to challenge the others’.

```python
Users report the app exits after one message instead of staying connected.
Spawn 5 agent teammates to investigate different hypotheses. Have them talk to
each other to try to disprove each other's theories, like a scientific
debate. Update the findings doc with whatever consensus emerges.
```

The debate structure is the key mechanism here. Sequential investigation suffers from anchoring: once one theory is explored, subsequent investigation is biased toward it. With multiple independent investigators actively trying to disprove each other, the theory that survives is much more likely to be the actual root cause.


[​](#best-practices)

Best practices


[​](#give-teammates-enough-context)

Give teammates enough context

Teammates load project context automatically, including CLAUDE.md, MCP servers, and skills, but they don’t inherit the lead’s conversation history. See [Context and communication](#context-and-communication) for details. Include task-specific details in the spawn prompt:

```python
Spawn a security reviewer teammate with the prompt: "Review the authentication module
at src/auth/ for security vulnerabilities. Focus on token handling, session
management, and input validation. The app uses JWT tokens stored in
httpOnly cookies. Report any issues with severity ratings."
```


[​](#choose-an-appropriate-team-size)

Choose an appropriate team size

There’s no hard limit on the number of teammates, but practical constraints apply:

- **Token costs scale linearly**: each teammate has its own context window and consumes tokens independently. See [agent team token costs](../17-Billing-Plans/costs.md#agent-team-token-costs) for details.
- **Coordination overhead increases**: more teammates means more communication, task coordination, and potential for conflicts
- **Diminishing returns**: beyond a certain point, additional teammates don’t speed up work proportionally

Start with 3-5 teammates for most workflows. This balances parallel work with manageable coordination. If you have 15 independent tasks, 3 teammates is a good starting point. Scale up only when the work benefits from having teammates work simultaneously. Three focused teammates often outperform five scattered ones.


[​](#size-tasks-appropriately)

Size tasks appropriately

- **Too small**: coordination overhead exceeds the benefit
- **Too large**: teammates work too long without check-ins, increasing risk of wasted effort
- **Just right**: self-contained units that produce a clear deliverable, such as a function, a test file, or a review

The lead breaks work into tasks and assigns them to teammates automatically. If it isn’t creating enough tasks, ask it to split the work into smaller pieces. Having 5-6 tasks per teammate keeps everyone productive and lets the lead reassign work if someone gets stuck.


[​](#wait-for-teammates-to-finish)

Wait for teammates to finish

Sometimes the lead starts implementing tasks itself instead of waiting for teammates. If you notice this:

```python
Wait for your teammates to complete their tasks before proceeding
```


[​](#start-with-research-and-review)

Start with research and review

If you’re new to agent teams, start with tasks that have clear boundaries and don’t require writing code: reviewing a PR, researching a library, or investigating a bug. These tasks show the value of parallel exploration without the coordination challenges that come with parallel implementation.


[​](#avoid-file-conflicts)

Avoid file conflicts

Two teammates editing the same file leads to overwrites. Break the work so each teammate owns a different set of files.


[​](#monitor-and-steer)

Monitor and steer

Check in on teammates’ progress, redirect approaches that aren’t working, and synthesize findings as they come in. Letting a team run unattended for too long increases the risk of wasted effort.


[​](#troubleshooting)

Troubleshooting


[​](#teammates-not-appearing)

Teammates not appearing

If teammates aren’t appearing after you ask Claude to spawn them:

- In in-process mode, teammates appear in the agent panel below the prompt input. Use the up and down arrow keys to select one, then press Enter to view it.
- A teammate row that disappeared after sitting idle has been hidden, not stopped. Idle rows hide 30 seconds after the whole panel goes idle and reappear on the teammate’s next turn. When more than three teammates are idle, their surplus rows collapse into a single `N idle agents` row that Enter expands. Send the teammate a message by name to bring a hidden row back.
- Check that the task you gave Claude was complex enough to warrant a team. Claude decides whether to spawn teammates based on the task.
- If you explicitly requested split panes, ensure tmux is installed and available in your PATH:

  ``` shiki
  which tmux
  ```
- For iTerm2, verify the `it2` CLI is installed and the Python API is enabled in iTerm2 preferences.


[​](#claude-spawns-teammates-instead-of-subagents)

Claude spawns teammates instead of subagents

While agent teams are enabled, a subagent that Claude names in the lead’s session launches as a teammate. Claude [can name subagents on its own](#how-claude-starts-agent-teams), so this can happen during delegation you never framed as team work. To make named subagents launch as subagents again, turn agent teams off by setting `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` to `0`:

settings.json

```python
{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "0"
  }
}
```

You don’t need to start a new session: Claude Code reapplies settings-file `env` values to the running session when you save, and rereads the variable each time Claude spawns a subagent, so the next subagent Claude names launches as a subagent. Setting the variable to `0` in your user `settings.json` overrides a shell export. Other settings sources can still enable agent teams:

- **Higher-precedence settings files**: project settings, local settings, and a `--settings` payload apply after user settings, so an `env` entry that sets the variable to `1` in any of them wins. See [Settings precedence](../02-Claude-Code-CLI/settings.md#settings-precedence).
- **Managed settings**: [managed settings](../13-Enterprise-Admin/server-managed-settings.md) apply after every other source. If your organization enables agent teams there, ask your administrator to change the managed value.

After the change, Claude may still name subagents, and the name keeps working as a [`SendMessage` address](sub-agents.md#resume-subagents). Claude receives each subagent’s result when it completes.


[​](#too-many-permission-prompts)

Too many permission prompts

Teammate permission requests bubble up to the lead, which can create friction. Pre-approve common operations in your [permission settings](../02-Claude-Code-CLI/permissions.md) before spawning teammates to reduce interruptions.


[​](#agents-stopping-early)

Agents stopping early

Teammates may stop after encountering errors instead of recovering. Check their output by selecting the teammate in the agent panel and pressing Enter in in-process mode, or by clicking the pane in split mode, then either:

- Give them additional instructions directly
- Spawn a replacement teammate to continue the work

A message from the lead or another teammate wakes an in-process teammate that is waiting to retry a failed API request, so it retries immediately instead of waiting for the full retry delay. The lead can stop early too, deciding the team is finished before all tasks are actually complete. If that happens, tell it to keep going.


[​](#orphaned-tmux-sessions)

Orphaned tmux sessions

If a tmux session persists after the Claude Code session ends, it may not have been fully cleaned up. List sessions and end the one created by the team:

```python
tmux ls
tmux kill-session -t <session-name>
```


[​](#limitations)

Limitations

Agent teams are experimental. Current limitations to be aware of:

- **No session resumption with in-process teammates**: `/resume` and `/rewind` do not restore in-process teammates. After resuming a session, the lead may attempt to message teammates that no longer exist. If this happens, tell the lead to spawn new teammates.
- **Task status can lag**: teammates sometimes fail to mark tasks as completed, which blocks dependent tasks. If a task appears stuck, check whether the work is actually done and update the task status manually or tell the lead to nudge the teammate.
- **Shutdown can be slow**: teammates finish their current request or tool call before shutting down, which can take time.
- **One team per session**: a session has exactly one team, scoped to that session. You can’t create additional named teams or share a team across sessions.
- **No nested teams**: teammates cannot spawn their own teammates. Only the lead can manage the team.
- **No background subagents from in-process teammates**: an in-process teammate’s own subagents run in the foreground, because a teammate’s background work can’t outlive the lead’s process. Claude Code returns an error when a teammate spawns a subagent whose definition sets `background: true`. A teammate’s `run_in_background: true` request also fails, either with an error or by running silently in the foreground, as described in [how Claude Code picks foreground or background](sub-agents.md#run-subagents-in-foreground-or-background). Subagents launched from the main conversation follow the [background default](sub-agents.md#run-subagents-in-foreground-or-background).
- **Lead is fixed**: the main session is the lead for its lifetime. You can’t promote a teammate to lead or transfer leadership.
- **Permissions set at spawn**: teammates start with the permission mode described under [Permissions](#permissions). You can change an individual teammate’s permission mode after spawning, but you can’t set per-teammate permission modes at spawn time.
- **Split panes require tmux or iTerm2**: the default in-process mode works in any terminal. Split-pane mode isn’t supported in VS Code’s integrated terminal, Windows Terminal, or Ghostty.


[​](#next-steps)

Next steps

Explore related approaches for parallel work and delegation:

- **Lightweight delegation**: [subagents](sub-agents.md) spawn helper agents for research or verification within your session, better for tasks that don’t need inter-agent coordination
- **Messaging between your own sessions**: [cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md) lets Claude pass findings between the sessions you run yourself
- **Manual parallel sessions**: [Git worktrees](../02-Claude-Code-CLI/worktrees.md) let you run multiple Claude Code sessions yourself without automated team coordination

---

## Manage multiple agents with agent view - Claude Code Docs

Source: https://code.claude.com/docs/en/agent-view
Path: 09-Agents-Patterns/agent-view.md

## On this page

- [Quick start](#quick-start)
  - [Open agent view by default](#open-agent-view-by-default)
- [Monitor sessions with agent view](#monitor-sessions-with-agent-view)
  - [Read session state](#read-session-state)
  - [Row summaries](#row-summaries)
  - [Pull request status](#pull-request-status)
  - [Peek and reply](#peek-and-reply)
  - [Attach to a session](#attach-to-a-session)
  - [Switch sessions without leaving the terminal](#switch-sessions-without-leaving-the-terminal)
  - [Organize the list](#organize-the-list)
  - [Filter sessions](#filter-sessions)
  - [Keyboard shortcuts](#keyboard-shortcuts)
- [Dispatch new agents](#dispatch-new-agents)
  - [From agent view](#from-agent-view)
  - [Dispatch to a specific directory](#dispatch-to-a-specific-directory)
  - [From inside a session](#from-inside-a-session)
  - [Send the session to the background](#send-the-session-to-the-background)
  - [Copy the session with /fork](#copy-the-session-with-%2Ffork)
  - [What carries over when you background](#what-carries-over-when-you-background)
  - [From your shell](#from-your-shell)
  - [Run a shell command](#run-a-shell-command)
  - [How file edits are isolated](#how-file-edits-are-isolated)
  - [What deleting a session removes](#what-deleting-a-session-removes)
  - [Set the model](#set-the-model)
  - [Permission mode, model, and effort](#permission-mode-model-and-effort)
  - [Settings and provider](#settings-and-provider)
  - [LLM gateway](#llm-gateway)
  - [Permission mode](#permission-mode)
  - [Dispatch defaults](#dispatch-defaults)
  - [What persists across restarts](#what-persists-across-restarts)
  - [Settings, plugins, and MCP servers](#settings-plugins-and-mcp-servers)
- [Manage sessions from the shell](#manage-sessions-from-the-shell)
  - [List sessions as JSON](#list-sessions-as-json)
  - [Read session state from a script](#read-session-state-from-a-script)
- [How background sessions are hosted](#how-background-sessions-are-hosted)
  - [The supervisor process](#the-supervisor-process)
  - [Where state is stored](#where-state-is-stored)
  - [Turn off agent view](#turn-off-agent-view)
- [Troubleshooting](#troubleshooting)
  - [claude agents lists subagents instead of opening agent view](#claude-agents-lists-subagents-instead-of-opening-agent-view)
  - [Agent view opens with no sessions](#agent-view-opens-with-no-sessions)
  - [Backgrounding shows a Background this session? dialog](#backgrounding-shows-a-background-this-session-dialog)
  - [Prompt rejected as too short](#prompt-rejected-as-too-short)
  - [Sessions show as failed or stopped after shutdown](#sessions-show-as-failed-after-shutdown)
  - [Opening a session says the conversation is already open](#opening-a-session-says-the-conversation-is-already-open)
  - [Opening a session says it has no saved transcript](#opening-a-session-says-it-has-no-saved-transcript)
  - [The terminal host died or the session stopped responding](#the-terminal-host-died-or-the-session-stopped-responding)
  - [Terminal host died](#terminal-host-died)
  - [Session isn’t responding](#session-isn%E2%80%99t-responding)
  - [A session fails before starting with a possibly low memory note](#a-session-fails-before-starting-with-a-possibly-low-memory-note)
  - [Agent view says the background service did not respond](#agent-view-says-the-background-service-did-not-respond)
  - [Dispatch fails with Could not resolve authentication method](#dispatch-fails-with-could-not-resolve-authentication-method)
  - [Background sessions can’t read Desktop, Documents, or Downloads on macOS](#background-sessions-can%E2%80%99t-read-desktop-documents-or-downloads-on-macos)
  - [Background sessions can’t reach local-network hosts on macOS](#background-sessions-can%E2%80%99t-reach-local-network-hosts-on-macos)
  - [A session is slow to respond after attaching](#a-session-is-slow-to-respond-after-attaching)
  - [.claude/worktrees/ is filling up](#claude%2Fworktrees%2F-is-filling-up)
- [Limitations](#limitations)
- [Related resources](#related-resources)
- [Version history](#version-history)

Agents and parallel work

# Manage multiple agents with agent view

Copy pageCopy page

Dispatch and manage many Claude Code sessions from one screen. Agent view shows what every session is doing and which ones need your input.

Copy pageCopy page

Agent view, opened with `claude agents`, is one screen for all your background sessions: what’s running, what needs your input, and what’s done. Dispatch new sessions, watch their state at a glance instead of scrolling through transcripts, and step in only when one needs you. Each background session is a full Claude Code conversation that keeps running without a terminal attached, so you can open it, reply, and leave whenever you want.

Use agent view when you have several independent tasks Claude can work on without you watching every step. Dispatch a bug fix, a pull request review, and a flaky-test investigation as three rows, keep working in another window, and check back when a row shows it needs you or has a result. When you want to work more directly in any agent’s session, attach to the row to enter the full conversation. To compare agent view with subagents, agent teams, and worktrees, see [Run agents in parallel](agents.md). Agent view runs sessions on your machine and you dispatch each one; to have Claude start and track parallel sessions in the cloud from one conversation instead, see [Projects](../02-Claude-Code-CLI/claude-projects.md).

Agent view is in research preview. The interface and keyboard shortcuts may change as the feature evolves.


[​](#quick-start)

Quick start

This walkthrough covers the core agent view loop: dispatch a task, watch its row update as Claude works, peek to check on it and reply, and attach for the full conversation. The session you dispatch keeps running after you close agent view, so you can leave and come back to it.

1

Open agent view

From your shell, run:

```python
claude agents
```

If you haven’t yet accepted the [workspace trust dialog](../02-Claude-Code-CLI/permissions.md#project-allow-rules-and-workspace-trust) for the directory, Claude Code shows it before agent view opens, the same dialog `claude` shows. Accept to save trust for the workspace and continue. If you decline, Claude Code exits without opening agent view.Agent view opens with an input at the bottom and a table that fills in as sessions start. Press `Esc` to return to your shell; if you opened agent view by backgrounding a session with `←`, `Esc` returns to that conversation instead. Your sessions keep running while you’re away and reappear the next time you open agent view.

2

Dispatch a session

Type a prompt describing a task and press `Enter`. A new background session starts on that task and appears as a row showing whether it’s working, waiting on you, or done. The new session uses the model shown in the agent view header. [Which permission mode it starts in](#permission-mode-model-and-effort) depends on how you opened agent view.Every prompt you enter here starts its own new session. Typing another prompt and pressing `Enter` launches a second session alongside the first rather than sending a follow-up to it. You can run several in parallel this way.Each session uses your subscription quota independently, so see [Limitations](#limitations) before dispatching many at once.

3

Peek and reply

Select a row with the arrow keys and press `Space` to open the peek panel. It shows the session’s most recent output, or the question it’s waiting on, rather than the full transcript. Type a reply and press `Enter` to send it without leaving agent view.

4

Attach and detach

Press `Enter` or `→` on a row to attach when you want the full conversation. The session takes over the terminal as a full interactive Claude Code session. Press `←` on an empty prompt to detach and return to the table.

5

Bring an existing session in

This step needs a running session. If you followed the earlier steps you don’t have one open in this terminal, so open a regular `claude` session in another terminal and send it a message first.To move a session you already have open into agent view, run `/bg` inside it, or press `←` on an empty prompt to background it and open agent view in one step. In a fresh session with no messages yet, `/bg` asks you to send a message first, while `←` works right away. The session keeps running and appears as a row alongside the ones you dispatched.

Inside a regular `claude` session, the prompt footer’s `←` hint counts the background agents that are waiting on you, such as `← 2 agents`, and returns to `← for agents` when none need input. Counts above 99 show as `99+`. The count refreshes about every ten seconds while the terminal is focused and immediately when focus returns. It briefly changes color when it moves and when an agent completes, and when a background session finishes while none need your input it briefly shows the number completed, such as `← 2 done`. Both flashes are off when the [`prefersReducedMotion` setting](../02-Claude-Code-CLI/settings-reference.md#prefersreducedmotion) is on, and the hint is hidden in [screen reader mode](../02-Claude-Code-CLI/accessibility.md).


[​](#open-agent-view-by-default)

Open agent view by default

To have `claude` with no arguments open agent view instead of a new conversation, turn on a `/config` setting.

1

Turn on the setting

In a regular `claude` session, run `/config` and turn on **Open agents view by default**. To skip the menu, set the [`defaultToAgentsView`](../02-Claude-Code-CLI/settings-reference.md#defaulttoagentsview) key directly:

```python
/config defaultToAgentsView=true
```

2

Start Claude Code

Exit the session, then run `claude` with no arguments:

```python
claude
```

Agent view opens in place of a new conversation.

To start a regular session while the setting is on, pass a prompt: `claude "fix the login test"`. To turn the setting off, run `/config defaultToAgentsView=false` in a regular session or in one you attach to from agent view.


[​](#monitor-sessions-with-agent-view)

Monitor sessions with agent view

Run `claude agents` to open agent view. It takes over the full terminal and lists every session grouped by state, with pinned sessions and the ones that need you at the top. Each row shows the session’s name, current activity, and its age, counted from when the session was created; a finished session’s age freezes at how long the run took. The name is tinted with the color set by [`/color`](../02-Claude-Code-CLI/commands.md) in that session, including when you [background a session](#from-inside-a-session) with `←` or `/background`. By default the list shows every background session you’ve started, across all your projects. A session working in one repository and another in a different worktree both appear here, regardless of which directory you opened agent view from. To narrow the list to one project, pass `--cwd`:

```python
claude agents --cwd ~/projects/my-app
```

This shows only sessions started under that directory. It still lists a session that has [moved into a worktree](#how-file-edits-are-isolated) under `~/projects/my-app/.claude/worktrees/`. Interactive sessions you have open in other terminals don’t appear until you [background them](#from-inside-a-session). [Subagents](sub-agents.md) and [teammates](agent-teams.md) a session spawns aren’t listed as separate rows.

```python
Pinned
  ✽ clawd walk cycle          Drawing the walk-cycle sprite frames          3m

Ready for review
  ∙ jump physics              Opened PR with collision fix                 #2048  2h

Needs input
  ✻ power-up design           double jump or wall climb?                    1m

Working
  ✽ collision detection       Adding swept-AABB checks to CollisionSystem   2m
  ✢ playtest level 3          run 12 · all checkpoints cleared           in 4m

Completed
  ✻ title screen              result: menu, options, and credits done       9m
  ∙ sound effects             result: 14 SFX exported to assets/audio       4h
  … 6 more
```


[​](#read-session-state)

Read session state

Each row starts with an icon whose color and animation show the session’s state:

| State       | Icon shows as | What it means                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
|:------------|:--------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Working     | Animated      | Claude is actively running tools or generating a response                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Needs input | Yellow        | Claude is waiting on something only you can provide: an answer to a question, a permission decision, or another prompt only you can answer, such as a [sandbox](../02-Claude-Code-CLI/sandboxing.md) prompt to allow a network host or an MCP server’s [request for input](../06-MCP-Tools/General/mcp.md#respond-to-mcp-elicitation-requests). A command that needs an attached terminal, such as `/install-github-app` or the `/mcp` settings list, [holds an unattended session here too](#attach-to-a-session) |
| Idle        | Dimmed        | The session has nothing to do and is ready for your next prompt                                                                                                                                                                                                                                                                                                                                                                                                                  |
| Completed   | Green         | The task finished successfully                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| Failed      | Red           | The task ended with an error                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| Stopped     | Grey          | You stopped the session with `Ctrl+X` or `claude stop`, [its process was ended from outside Claude Code](#the-supervisor-process), or [it ended while the background service was off](#sessions-show-as-failed-after-shutdown)                                                                                                                                                                                                                                                   |

Separately, the icon’s shape shows whether the underlying process is running:

| Shape               | What it means                                                                                                               |
|:--------------------|:----------------------------------------------------------------------------------------------------------------------------|
| `✻` or animated `✽` | The session process is alive and replies immediately                                                                        |
| `∙`                 | The process has exited. You can still peek at the row, and when you reply or attach, Claude restarts from where it left off |
| `✢`                 | A [`/loop`](../02-Claude-Code-CLI/scheduled-tasks.md) session sleeping between iterations. The row shows its run count and a countdown      |

The `#N` or `!N` label that can appear at the right edge of a row is a link to the session’s [pull request or merge request](#pull-request-status), not part of the state icon. The terminal tab title shows the awaiting-input count while agent view is open: `2 awaiting input · claude agents` when sessions need input, or `claude agents` when none do. To read session state from a script or another program, use [`claude agents --json`](#read-session-state-from-a-script) rather than the files under `~/.claude/jobs/`. While agent view is open, Claude Code also sends a notification through your configured [terminal notification channel](../02-Claude-Code-CLI/terminal-config.md#get-a-terminal-bell-or-notification) when a local background session starts needing your input, finishes, or fails. Sessions that run on a schedule, such as [`/loop`](../02-Claude-Code-CLI/scheduled-tasks.md) sessions, notify only when they need your input. Notifications use the same [`preferredNotifChannel` setting](../02-Claude-Code-CLI/settings-reference.md#preferrednotifchannel) as the rest of Claude Code and fire the [`Notification` hook](../07-Hooks/hooks.md#notification) with the `agent_needs_input` or `agent_completed` type. Background sessions don’t need any terminal open to keep working. A separate [supervisor process](#the-supervisor-process) runs them, so you can close agent view, close your shell, or start a new interactive session and your dispatched work keeps going. Session state persists on disk through auto-updates and supervisor restarts. Sessions are also preserved when your machine sleeps. Their processes resume on wake and the supervisor reconnects to them instead of treating the time gap as idle. Shutting down still stops running sessions; see [Sessions show as failed or stopped after shutdown](#sessions-show-as-failed-after-shutdown) for how to recover them. A session that was mid-response when the machine slept can come back unresponsive. When you open a session that has stopped responding, the supervisor restarts its process and the session continues the interrupted response from where it left off.


[​](#row-summaries)

Row summaries

The one-line summary in each row is generated by a [Haiku-class model](../02-Claude-Code-CLI/model-config.md) so the row can tell you what the session is doing, what it needs, or what it produced without opening the transcript. While a session is actively working, the row text updates at most once every 15 seconds from the session’s own recent output without sending a model request, and the model writes a fresh summary when each turn ends. A working row shows what the session says it’s doing, and a blocked row shows the question it’s asking. During a long turn, the model also rewrites the summary every few minutes so a busy row doesn’t keep showing an outdated one. The summary text fills the row’s remaining width; open the [peek panel](#peek-and-reply) to read a sentence the terminal edge clips. When the list is [grouped by directory](#organize-the-list), the summary opens with the session’s state as a colored word, such as `Needs input · double jump or wall climb?`. In the default state grouping, the group header already names the state, so the row shows only the summary. The end-of-turn summary and each mid-turn rewrite are one short Haiku-class request through your normal provider, billed and handled under the same [data usage terms](../13-Enterprise-Admin/data-usage.md) as the session itself. The 15-second updates between model rewrites reuse the session’s own output and don’t send a request. On a third-party provider or gateway with no Haiku-class model configured, the request uses the session’s main model instead; set [`ANTHROPIC_DEFAULT_HAIKU_MODEL`](../02-Claude-Code-CLI/model-config.md#environment-variables) to choose one.


[​](#pull-request-status)

Pull request status

When a session [opens a pull request](#how-file-edits-are-isolated), Claude Code adds a label at the right edge of the row, linked to the pull request:

- Claude Code writes the label as `#1234` for a pull request and as `!1234` for a GitLab merge request.
- Claude Code emits the link even when it can’t detect hyperlink support, for example over SSH or tmux. Set [`FORCE_HYPERLINK=0`](../02-Claude-Code-CLI/env-vars.md) to render the label as plain text.
- After you send a follow-up to the session, Claude Code keeps the label while the row returns to live progress.

A session that works on an existing pull request is linked to it the same way. Claude Code finds the pull request differently depending on the command Claude runs:

- When Claude edits, comments on, closes, or marks a pull request ready with `gh`, Claude Code links the pull request that the command’s own output names. A `gh` command whose captured output names no pull request doesn’t create a link; `gh pr merge` is the common case, because it prints its result only to an interactive terminal.
- When Claude checks a pull request out with `gh pr checkout` or pushes to a branch, Claude Code looks the branch up with `gh pr view` and links its open pull request.
- The pull request doesn’t need to exist yet when Claude pushes: Claude Code retries the branch lookup after up to five later `git`, `gh`, `glab`, or `curl` commands run in the same directory, so a pull request created after the push, including one Claude creates through the GitHub REST API, links when a retry finds it.

When a session is linked to more than one pull request, the label shows a count instead, such as `3 PRs`, colored by the open pull request that most needs attention. Open the [peek panel](#peek-and-reply) to see them all. The pull request number is colored by its status:

| Color  | Pull request status                           |
|:-------|:----------------------------------------------|
| Yellow | Waiting on checks or review, or checks failed |
| Green  | Checks passed and no review is blocking       |
| Purple | Merged                                        |
| Grey   | Draft or closed                               |

For a task that ends in a pull request, check this label for the result: review and merge the pull request when its number turns green.


[​](#peek-and-reply)

Peek and reply

Press `Space` on a selected row to open the peek panel. It opens with the sentence the row truncates at the terminal edge, and which sentence that is depends on the session’s state:

- A session that’s waiting on you: the exact question it’s asking, above the reply input
- A finished session: its result
- A working session: its full status sentence

Any pull requests linked to the session are listed next. For a session that’s waiting on you, a line such as `waiting 3m` below them shows how long it has been waiting, and it’s the only time shown in the panel. The age at the right edge of the row is a different number: it counts from when the session started. Most of the time the peek panel is enough and you don’t need to open the full transcript. Type a reply in the peek panel and press `Enter` to send it to that session. When the session asks a question with predefined choices, the peek panel shows them as a numbered list and you can press a number key to pick one. A permission prompt shows as text describing what the session wants to run, without numbered options. Type a reply to answer it, or attach to answer with the standard prompt. For other blocked sessions, press `Tab` to fill the input with a suggested reply you can edit before sending. Prefix a reply with `!` to send a Bash command instead. When a [`PermissionRequest`](../07-Hooks/hooks.md#permissionrequest) or [`PreToolUse`](../07-Hooks/hooks.md#pretooluse) hook returns output Claude Code can’t validate for the call the session is asking about, the row shows the hook event and `hook output invalid:` with the validation error before the pending request’s text. For a hook that fails another way, the row says the hook failed. The session still waits on the same request. A reply that can’t be delivered, because the background service is unreachable or the send fails, is saved and sent to the session as its next prompt when its process starts again, and the error message says the reply was saved. A reply prefixed with `!` isn’t saved, because the saved text would reach the session as a plain prompt rather than run as a Bash command. With [voice dictation](../02-Claude-Code-CLI/voice-dictation.md) enabled, hold or tap your push-to-talk key while the reply input is focused to dictate a reply instead of typing it. The same works in the dispatch input at the bottom of agent view. Use `↑` and `↓` to peek at adjacent sessions without closing the panel, or `→` to attach.


[​](#attach-to-a-session)

Attach to a session

Press `Enter` or `→` on a selected row to attach. Agent view is replaced by the full interactive session. When you attach, Claude posts a short recap of what happened while you were away. While attached, the session behaves like any other Claude Code session: [commands](../02-Claude-Code-CLI/commands.md), keyboard shortcuts, and features all work, with the exceptions below. While you’re attached, `/install-github-app` and the [`/mcp`](../06-MCP-Tools/General/mcp.md) settings list work normally, since a human at the terminal can complete their dialogs. When nobody is attached, these commands can’t open their dialogs, so the session appears under `Needs input` in agent view with a row such as `open this session to manage MCP servers`, and the transcript reply says the same. Attach and run the command again to continue; the needs-input row clears when you attach. `/mcp reconnect <server>`, `/mcp enable`, and `/mcp disable` work without attaching either way. Attached sessions always render in [fullscreen mode](../02-Claude-Code-CLI/fullscreen.md), regardless of your `tui` setting, because a background session has no terminal scrollback to append to. Scroll with `PgUp`, `PgDn`, or the mouse wheel, and press `Ctrl+O` for transcript mode. Your terminal’s native scroll and tmux copy mode show only the current viewport, the same as when you run any fullscreen application. Press `←` on an empty prompt, or run `/exit`, to detach and return to agent view, whether you opened the session from agent view or with `claude attach <id>` from your shell. `←` also detaches while the [`/btw` overlay](../02-Claude-Code-CLI/interactive-mode.md#side-questions-with-%2Fbtw) is open. Requires Claude Code v2.1.257 or later. A side question that’s still answering keeps running while you’re away. The next time you attach, the overlay reopens with it, or with its answer. On Windows, if you press `←` within about half a second of attaching, Claude Code shows `Ambiguous ←, press again to detach`, because in that window the terminal can redeliver a press from before you attached. Press `←` again to detach. `Ctrl+Z` also detaches but goes back to where you started instead: agent view if you attached from there, or your shell if you ran `claude attach`. Use `Ctrl+Z` when a dialog has focus and isn’t responding to `←`. `Ctrl+C` keeps its standard interrupt behavior while attached: it cancels a running response or `!` shell command rather than detaching. Pressing `Ctrl+C` twice on an empty prompt detaches, the same as in any session. Detaching never stops a background session: `←`, `Ctrl+Z`, `/exit`, and double `Ctrl+C` or double `Ctrl+D` all leave it running. To end a session from inside it, run `/stop`.


[​](#switch-sessions-without-leaving-the-terminal)

Switch sessions without leaving the terminal

In a session running in the foreground, one you started in the terminal rather than attached to from agent view, pressing `←` on an empty prompt backgrounds it and opens agent view with that row selected, so you can switch sessions without leaving the terminal. The same single press detaches an attached session. If you press `←` right after you delete the last of the prompt’s text or move through prompt history, Claude Code asks you to confirm: the first press shows `Press ← again to open agents`, or `Press ← again to go back to agents` in an attached session, and the second press switches. When `←` backgrounds a foreground session, agent view shows `Your conversation moved to the background` above the list, with that session’s row already selected. From there:

- Press `Enter` to reopen the conversation.
- Press `Esc` to undo the switch and return to the conversation. If `Esc` shows `Still starting — try again in a moment`, the background session isn’t ready yet, so press `Esc` again in a moment.
- Press `Ctrl+C` twice to exit to your shell.

When Claude Code can’t reopen the conversation, it exits and prints a `claude --resume` command that resumes it. [Claude’s task list](../02-Claude-Code-CLI/interactive-mode.md#task-list) moves to the background session with the conversation, so the checklist is intact when you return to that row. The row you pressed `←` from also keeps a bold, undimmed name after you move the selection with the arrow keys or the mouse, so you can tell which session you came from. If a tool is running when you press `←`, Claude Code waits up to about ten seconds for it to finish before backgrounding, and Claude continues the response in the background session. Press `←` again to background immediately instead of waiting. When in-flight work can’t carry over to the background session, Claude Code shows the `Background this session?` dialog first, the same as with [`/background`](#from-inside-a-session). The ten-second limit doesn’t apply while the [foreground subagents](sub-agents.md#run-subagents-in-foreground-or-background) Claude started in the conversation are still running. Claude Code keeps waiting so their work carries over, and shows a `Still backgrounding after the current tool` notice while it waits. Press `←` again to background without waiting, which restarts those subagents from the beginning. Claude Code doesn’t wait for the subagents a [dynamic workflow](../02-Claude-Code-CLI/workflows.md) is running. When a workflow has subagents running, Claude Code shows the `Background this session?` dialog instead. Claude Code doesn’t background the session while you have unsent text in the prompt input, because the text stays in your terminal’s input box and wouldn’t move to the background session. If you type into the input while Claude Code waits to background the session, it cancels the switch with `Backgrounding cancelled — you have unsent text in the input. Send it or clear it, then press ← again.` Pressing `←` creates the session’s row even when the conversation has no messages yet, so `→` still returns to it. You can turn this shortcut off for foreground sessions with the [`leftArrowOpensAgents`](../02-Claude-Code-CLI/settings-reference.md#leftarrowopensagents) setting in `/config`.


[​](#organize-the-list)

Organize the list

Agent view groups sessions so the ones that need input are at the top, with `Ready for review` and `Needs input` above `Working` and `Completed`. These group names don’t map one-to-one to the [states](#read-session-state) above: a session moves to `Ready for review` when it has an open pull request, and `Completed` collects finished, failed, and stopped sessions together. Press `Ctrl+S` to group by directory instead. Your choice persists across runs. Within a group:

- Press `Ctrl+T` to pin a session to the top and [keep its process running](#the-supervisor-process) while idle
- Press `Shift+↑` or `Shift+↓` to reorder sessions
- Press `Ctrl+R` to rename a session
- Press `Enter` on a group header to collapse it

To remove a session from the list, press `Ctrl+X` to stop it and `Ctrl+X` again within two seconds to delete it. Pressing `Ctrl+X` on a group header deletes every session in that group after confirmation. The second press deletes the session even when the stop attempt fails, for example because the [background service isn’t responding](#agent-view-says-the-background-service-did-not-respond): the confirmation stays active for another two seconds, and the delete ends the session’s process itself. Press `Esc` to dismiss the confirmation without deleting. Except in the kept cases covered in [What deleting a session removes](#what-deleting-a-session-removes), deleting removes the session from the list, and a worktree Claude created for it is removed, kept, or left in place depending on how you delete and what the worktree holds. The conversation transcript always stays on your local machine, available through `claude --resume`. To bring a session back on Claude Code v2.1.212 or later, type `/resume` in the dispatch input. A picker opens with past sessions of the repository you opened agent view from, newest first, including sessions you deleted from the list; sessions that already have a row aren’t listed. `↑`/`↓` move the selection, `Enter` resumes the selected session as a background session so it rejoins the list as a row, and `Esc` closes the picker. The picker opens only for a bare `/resume`. A targeted, scoped, or restricted resume can’t be served by the picker, so agent view shows the `attach to a session to run it` hint instead when:

- `/resume` names an id or a search term
- the view is scoped with `--cwd`
- the view was started with [`--safe-mode`](../02-Claude-Code-CLI/cli-reference.md#cli-flags)
- the view was opened with a flag such as `--permission-mode` or `--settings`

Completed sessions that don’t fit on screen fold into a `… N more` row. Failures and sessions with an open pull request always stay visible. The `Completed` group fills the vertical space left after the live groups, and on a short terminal the header compacts to a single summary line so sessions that are working or need input stay visible.


[​](#filter-sessions)

Filter sessions

Type in the dispatch input to filter instead of dispatching:

| Filter                                     | Shows                                                                                                    |
|:-------------------------------------------|:---------------------------------------------------------------------------------------------------------|
| `a:<name>`                                 | Sessions running the named agent                                                                         |
| `s:<state>`                                | Sessions in the given state, such as `s:working`. Also accepts `s:blocked` for everything waiting on you |
| `#<number>` or a pull or merge request URL | The session working on that pull request or merge request                                                |
| Any other URL                              | The session whose first prompt contained that URL                                                        |


[​](#keyboard-shortcuts)

Keyboard shortcuts

Press `?` in agent view to see every shortcut in context. The table below summarizes them.

| Shortcut              | Action                                                                                                                                                                                                                                                                                                                                                               |
|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `↑` / `↓`             | Move between rows                                                                                                                                                                                                                                                                                                                                                    |
| `Enter`               | Attach to the selected session, or dispatch if there’s text in the input                                                                                                                                                                                                                                                                                             |
| `Space`               | Open or close the peek panel for the selected session                                                                                                                                                                                                                                                                                                                |
| `Shift+Enter`         | Insert a newline in the dispatch input, [as in the main prompt](../02-Claude-Code-CLI/terminal-config.md#enter-multiline-prompts)                                                                                                                                                                                                                                                    |
| `Ctrl+Enter`          | Dispatch and attach immediately, in terminals where the `?` overlay lists `ctrl+enter to start and open`                                                                                                                                                                                                                                                             |
| `→`                   | Attach to the selected session                                                                                                                                                                                                                                                                                                                                       |
| `Alt+1`..`Alt+9`      | Attach to session 1–9 in the focused session’s directory                                                                                                                                                                                                                                                                                                             |
| `Tab`                 | On an empty input, browse all subagents. Otherwise apply the highlighted suggestion                                                                                                                                                                                                                                                                                  |
| `Ctrl+S`              | Switch grouping between state and directory                                                                                                                                                                                                                                                                                                                          |
| `Ctrl+T`              | Pin or unpin the selected session                                                                                                                                                                                                                                                                                                                                    |
| `Ctrl+R`              | Rename the selected session                                                                                                                                                                                                                                                                                                                                          |
| `Ctrl+G`              | Open the dispatch prompt in your `$VISUAL` or `$EDITOR`                                                                                                                                                                                                                                                                                                              |
| `Ctrl+J`              | Insert a newline in the dispatch input                                                                                                                                                                                                                                                                                                                               |
| `Ctrl+X`              | Stop the session; press again within two seconds to delete it                                                                                                                                                                                                                                                                                                        |
| `Shift+↑` / `Shift+↓` | Reorder the selected session                                                                                                                                                                                                                                                                                                                                         |
| `Esc`                 | Close the peek panel, clear the input, or exit. When you opened agent view by backgrounding your session with `←`, the final `Esc` returns to that conversation instead of exiting. With [vim editor mode](../02-Claude-Code-CLI/interactive-mode.md#vim-editor-mode) on, pressing `Esc` in the input switches from INSERT to NORMAL mode and keeps your text, as in the main prompt |
| `Ctrl+C`              | Clear the input; press twice to exit                                                                                                                                                                                                                                                                                                                                 |
| `?`                   | Show all shortcuts                                                                                                                                                                                                                                                                                                                                                   |

`Ctrl+S`, `Ctrl+T`, and `Ctrl+G` follow your [`keybindings.json`](../02-Claude-Code-CLI/keybindings.md). Rebind or unbind `Ctrl+S` and `Ctrl+T` with the `agents:switchView` and `agents:togglePin` actions in the [`Agents` context](../02-Claude-Code-CLI/keybindings.md#agents-actions), and `Ctrl+G` through the `Chat` context’s `chat:externalEditor` binding. The other shortcuts in the table can’t be rebound.


[​](#dispatch-new-agents)

Dispatch new agents

You can dispatch new background sessions from agent view, send or copy an existing interactive session to the background, or start one directly from the shell.


[​](#from-agent-view)

From agent view

Type a prompt in the input at the bottom of agent view and press `Enter` to start a new background session. The session is named automatically from the prompt; rename it later with `Ctrl+R`. The automatic name is a short label written by a [Haiku-class model](../02-Claude-Code-CLI/model-config.md). A name the session gets later also appears on its row, including the [generated title](../02-Claude-Code-CLI/sessions.md#name-your-sessions) the session gets when you [accept a plan](../02-Claude-Code-CLI/permission-modes.md#review-and-approve-a-plan) in that session. Paste an image into the prompt to include a screenshot or diagram with the task. Pasted text longer than 800 characters or more than three lines collapses to a `[Pasted text #N]` placeholder so the input stays on one line; the full text is sent when you dispatch. To review or edit the collapsed text before dispatching, paste the same text again and the placeholder expands back into the input. Prefix or mention parts of the prompt to control how the session starts:

| Input                                      | Effect                                                                                                                                                              |
|:-------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `<agent-name> <prompt>`                    | If the first word matches a custom [subagent](sub-agents.md) name, that subagent runs as the session’s main agent with the configuration from its frontmatter |
| `@<agent-name>`                            | Mention a custom subagent anywhere in the prompt to run it as the main agent                                                                                        |
| `@<repo>`                                  | Mention a repository to run the session there. See [Dispatch to a specific directory](#dispatch-to-a-specific-directory) for which repositories are listed          |
| `/<command>`                               | Suggest [skills](../08-Plugins-Skills/skills.md) and [commands](../02-Claude-Code-CLI/commands.md) to dispatch as the prompt                                                                       |
| `! <command>`                              | Run a shell command as a background job instead of starting a Claude session. The job appears as a row you can attach to, watch, and detach from                    |
| `#<number>` or a pull or merge request URL | If a session is already working on that pull request or merge request, Claude Code selects its row instead of dispatching a new session                             |

A small set of commands run in agent view itself instead of dispatching:

- `/exit` and `/quit` close agent view
- `/logout` signs you out
- `/model` sets the [dispatch model](#set-the-model)
- `/login` opens the sign-in dialog so you can sign in again without attaching to a session
- A bare `/resume`, or its `/continue` alias, opens a picker of the repository’s past sessions to [bring one back](#organize-the-list) as a background session. Requires Claude Code v2.1.212 or later

Skills, your own commands, and prompt-expanding built-ins such as `/init` are sent to a new background session as their first prompt. Other built-in commands show an `attach to a session to run it` hint instead. Everything you typed stays in the input next to the hint so you can edit it. Packaging a recurring task as a [skill](../08-Plugins-Skills/skills.md) lets you start the same workflow from agent view repeatedly without retyping the prompt. When the same `@name` matches both a subagent and a sibling repository, the subagent takes precedence. The bare first-word match also applies, so a prompt that happens to begin with one of your subagent names dispatches that subagent rather than treating the word as plain text. Use the `@` form when you want to be explicit, or start the prompt with a different word to avoid the match.


[​](#dispatch-to-a-specific-directory)

Dispatch to a specific directory

A new session runs in the directory you opened agent view from. To target a different directory, use any of these:

- Open `claude agents` in that directory.
- Open `claude agents` in a parent directory and mention a child repository with `@<repo>` in the prompt. Typing `@` lists these targets:
  - Git repositories one level below the launch directory
  - The registered [git worktrees](../02-Claude-Code-CLI/worktrees.md) of the repository you launched from that live inside its directory tree, such as the ones Claude creates under `.claude/worktrees/`, labeled with their checked-out branch. Worktrees added outside the repository, such as with `git worktree add ../feature`, aren’t listed
  - Any directory that already has a session in the list

  A directory whose name contains a space isn’t listed.
- From the shell, `cd` into the directory and run `claude --bg "<prompt>"`.

When agent view is grouped by directory, dispatching sends the prompt to the selected row’s directory, so you can select a group and dispatch into it without retyping the path.


[​](#from-inside-a-session)

From inside a session

Two commands move work from the session you’re in to the background: `/background` sends the current conversation there and frees your terminal, and `/fork` sends a copy while you keep working where you are.


[​](#send-the-session-to-the-background)

Send the session to the background

Run `/background` or its alias `/bg` to move the current conversation into a background session. Pass a prompt such as `/bg run the test suite and fix any failures` to give one more instruction first. If Claude is responding when you run `/bg`, the response continues in the background session. Exiting a session that still has background work running, such as subagents, background shell commands, workflows, or [monitors](../02-Claude-Code-CLI/tools-reference.md#monitor-tool), shows a `Background work is running` dialog instead of quitting immediately. Choose `Move to background and exit` to background the session the same way `/background` does and return to your shell. The option isn’t shown when agent view is [turned off](#turn-off-agent-view). If a background session on the list already has the conversation’s name, Claude Code numbers the new row’s name, such as `my-session (2)`, and leaves the existing row’s name alone. To rename the new row, select it in agent view and press `Ctrl+R`.


[​](#copy-the-session-with-/fork)

Copy the session with /fork

Run `/fork` to copy the current conversation into a new background session while the original keeps running. The copy starts with everything in the conversation up to that point; see the bullets below for where the copy runs. It also carries over the model, permission mode, effort level, and any directories or “don’t ask again” permission grants you added during the session. The copy appears as its own row in agent view. After the fork, the two conversations are independent: nothing the copy does enters the original conversation on its own, though in sessions where [cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md) is enabled, either session’s Claude can explicitly message the other. Copying the session requires Claude Code v2.1.212 or later; on v2.1.161 through v2.1.211, `/fork` starts a [forked subagent](sub-agents.md#fork-the-current-conversation) instead, which is now `/subtask`. When [agent view is turned off](#turn-off-agent-view), `/fork` keeps the forked-subagent behavior and `/subtask` isn’t available. Pass a prompt such as `/fork open a draft pull request with the work so far` and the copy starts working on it immediately. Without a prompt the copy waits for its first instruction: select its row in `claude agents` and press `Space` to send one, or run `claude attach <id>`. The selected row shows `space to send it a prompt` while it waits. The `/fork` confirmation is one line showing the copy’s state, such as `session running`, the name of its agent-view row, and its session ID for `claude attach`. Click the name to switch into the copy: this session moves to the background, the same as pressing `←`, and agent view opens the copy’s session. Except when the copy [edits in place](#how-file-edits-are-isolated), Claude Code instructs it to create a worktree of its own before making code changes. Outside a git repository, only a copy moved out of a hook-created worktree gets the instruction; with no [`WorktreeCreate` hook](../07-Hooks/hooks.md#worktreecreate), the copy edits in place. A copy moved out of your worktree is also told never to edit, run commands in, or enter that worktree, whatever the isolation setting. Where the copy starts depends on where the current session is running:

- Like any dispatched session, the copy [moves into its own worktree before editing files](#how-file-edits-are-isolated). In that case the confirmation doesn’t mention where the copy runs.
- When your session moved into its linked [worktree](../02-Claude-Code-CLI/worktrees.md) after it started, the copy starts back where the session was before the move and, unless it [edits in place](#how-file-edits-are-isolated), makes its code changes in a worktree of its own there. When your worktree is checked out on a branch, that instruction also tells a copy whose task builds on your work to base its new branch on yours, since your branch stays checked out in your worktree. The confirmation ends with `runs in the origin tree`.
- When you launched the session inside a linked worktree of a repository that has a main working tree, the copy starts in that main working tree, with the same worktree-of-its-own rule but no branch instruction. The confirmation ends with `runs in the origin tree` here too.
- A session launched inside a worktree of a bare-repository layout has no main working tree to return to, so the copy stays where it is, and the confirmation ends with `edits this checkout`. The same note appears when worktree isolation is [turned off](#how-file-edits-are-isolated) in a session that isn’t inside a linked worktree, because the copy then edits the files you have open.

Sessions started with launch flags the copy wouldn’t inherit, such as a replaced system prompt or a `--tools` allowlist, can’t be forked; Claude Code says so instead of making a partial copy. A session dispatched from agent view forks normally: the copy is launched with the same [agent definition](sub-agents.md) and appended instructions as the session it came from.


[​](#what-carries-over-when-you-background)

What carries over when you background

Backgrounding starts a fresh process that resumes from the saved conversation, and in-flight work moves to it: running background shell commands, backgrounded subagents, dynamic workflows, scheduled tasks you created with [`/loop`](../02-Claude-Code-CLI/scheduled-tasks.md), and Claude’s [automatic replies to artifact comments](../02-Claude-Code-CLI/artifacts.md#let-claude-reply-to-comments-on-its-own) all carry over and keep running there. A subagent moves together with everything it started, so it carries over only when all of that work can move too. To stop in-flight work instead of carrying it over, set the [`CLAUDE_DISABLE_ADOPT=1`](../02-Claude-Code-CLI/env-vars.md#variables) environment variable; Claude Code then asks you to confirm before backgrounding. When a [dynamic workflow](../02-Claude-Code-CLI/workflows.md) still has subagents running, Claude Code asks before backgrounding with the `Background this session?` dialog, which says how many subagents would restart. Choose `Stay` to let them finish first. If you confirm, Claude Code replays the run in the background session: subagents that were still running start over from the beginning, so the tokens they used so far are spent again. See [Resume after a pause](../02-Claude-Code-CLI/workflows.md#resume-after-a-pause) for which completed subagents return their saved results and which run again. Claude Code stops work that can’t carry over, such as a running [monitor](../02-Claude-Code-CLI/tools-reference.md#monitor-tool), and stops a backgrounded subagent that owns a monitor along with it. When any such work is running, Claude Code shows the `Background this session?` dialog so you can confirm before it stops the work. Once in the background, the session can start new subagents, monitors, and background commands, and those keep running across later detach and reattach. Configuration flags from the original launch carry through to the backgrounded session, so its MCP servers, settings, and fallback model remain in effect:

- `--mcp-config` and `--strict-mcp-config`
- `--settings`
- `--setting-sources`
- `--add-dir`
- `--plugin-dir`
- `--fallback-model`
- `--allow-dangerously-skip-permissions`

Directories you added during the session with [`/add-dir`](../02-Claude-Code-CLI/permissions.md#additional-directories-grant-file-access-not-configuration) also carry through. Carrying `--allow-dangerously-skip-permissions` keeps `bypassPermissions` reachable in the backgrounded session, but it doesn’t grant anything new: the mode still requires the one-time interactive acceptance described in [Permission mode, model, and effort](#permission-mode-model-and-effort).


[​](#from-your-shell)

From your shell

Pass `--bg` or its long form `--background` to start a session that goes straight to the background:

```python
claude --bg "investigate the flaky SettingsChangeDetector test"
```

The prompt is the positional argument, not a `-p` value. Claude Code rejects `--bg` combined with `-p` or `--print` before any session is created, because `--print` never starts the interactive session that `claude agents` attaches to. If you run `claude --bg` from a terminal in a directory you haven’t [trusted](../02-Claude-Code-CLI/permissions.md#project-allow-rules-and-workspace-trust), the workspace trust dialog appears first and the session starts once you accept. If you decline, Claude Code exits without starting a session. Where no dialog can appear, such as in a script, the command exits with a [`Workspace not trusted`](../02-Claude-Code-CLI/errors.md#workspace-not-trusted-when-dispatching-a-background-session) error instead. To run a specific [subagent](sub-agents.md) you have defined, such as a `code-reviewer`, as the session’s main agent, combine `--bg` with `--agent`:

```python
claude --agent code-reviewer --bg "address review comments on PR 1234"
```

If the name doesn’t match any of your subagents, the launch fails: Claude Code prints a `no agent named` warning and still reports the session as backgrounded, but the session exits immediately with an `--agent '<name>' not found` error. When the backgrounded session later resumes or restarts, Claude Code restores the agent and its tool restrictions; for its system prompt, see [System prompt flags in resumed conversations](../02-Claude-Code-CLI/cli-reference.md#system-prompt-flags-in-resumed-conversations). It searches the session’s own directory for the agent first, provided you’ve [trusted that workspace](../02-Claude-Code-CLI/permissions.md#project-allow-rules-and-workspace-trust), so a project-scoped agent still loads when the session is resumed from another directory. If the agent no longer exists, the session continues with the default tools and its transcript opens with a [warning naming the agent](../02-Claude-Code-CLI/errors.md#session-agent-no-longer-available). To continue an existing conversation in the background, pass its full session ID with `--resume`:

```python
claude --resume 1f0e2c9a-6d0b-4c11-9f39-2a77c1d4e8b5 --bg "pick up where you left off and finish the migration"
```

On Claude Code v2.1.257 or later, Claude Code either continues that session under the same ID, or starts a copy under a new ID and prints a `note:` line explaining why it couldn’t continue in place. When the session continues in place, `claude agents` shows one row for it. When you combine `--bg` with `--continue`, a bare `--resume`, or `--resume` with a name or file path, Claude Code always starts such a copy. Add `--fork-session` to start a copy on purpose, without the note. Pass `--name` to set the session’s display name in agent view instead of the auto-generated one:

```python
claude --bg --name "flaky-test-fix" "investigate the flaky SettingsChangeDetector test"
```

After backgrounding, Claude prints the session’s short ID and the commands for managing it. When the service that hosts background sessions isn’t already running, `--bg` may first print `Starting background service…` above this output. When you pass `--name`, the name appears after the short ID:

```python
backgrounded · 7c5dcf5d · flaky-test-fix
  claude agents             list sessions
  claude attach 7c5dcf5d    open in this terminal
  claude logs 7c5dcf5d      show recent output
  claude stop 7c5dcf5d      stop this session
```


[​](#run-a-shell-command)

Run a shell command

To run a shell command as a background job instead of a Claude session, pass `--exec`. The following example runs `pytest -x` as a background job:

```python
claude --bg --exec 'pytest -x'
```

From agent view, dispatch the same kind of job by typing `!` as the first character of the dispatch input: the `!` shows as a prefix, everything after it is the command, and `Enter` starts the job. The command runs as a PTY-backed job and appears as a row in agent view, with the most recent line of output as its status. A shell job runs the command in place of Claude, so no model is invoked and the output isn’t sent to any session. To see the output, attach to the row, press `Space` to peek without attaching, or run `claude logs <id>` from your shell. The captured output stays in memory and isn’t written to disk. The row and its output clean up automatically about five minutes after the command exits, so read it before then if you need the result.


[​](#how-file-edits-are-isolated)

How file edits are isolated

Every background session, whether started from agent view, `/bg`, or `claude --bg`, starts in your working directory. Before editing files, Claude moves the session into an isolated [git worktree](../02-Claude-Code-CLI/worktrees.md) under `.claude/worktrees/`, so parallel sessions can read the same checkout but each writes to its own. Once the session is in its worktree, Claude Code [enforces worktree isolation](../02-Claude-Code-CLI/worktrees.md#how-claude-code-enforces-isolation) for the session and for any subagents it spawns. Claude skips the worktree when:

- The session is already inside a linked git worktree, whether Claude created it under `.claude/worktrees/` or you created it with `git worktree add` somewhere else
- The file that Claude is editing is inside a linked git worktree, such as one that the session or its subagent created with `git worktree add`
- The working directory isn’t a git repository and no [`WorktreeCreate` hook](../07-Hooks/hooks.md#worktreecreate) is configured
- The write is outside the working directory

To turn off worktree isolation for a repository where git worktrees are impractical, set [`worktree.bgIsolation`](../02-Claude-Code-CLI/settings-reference.md#worktree-bgisolation) to `"none"`. Background sessions then edit your working copy directly without moving into a worktree first. Add the setting to the project’s `.claude/settings.json`:

```python
{
  "worktree": {
    "bgIsolation": "none"
  }
}
```

Outside a git repository, sessions write to the working directory directly and aren’t isolated from each other, so avoid dispatching parallel sessions that edit the same files. If you use a different version control system, configure a [`WorktreeCreate` hook](../02-Claude-Code-CLI/worktrees.md#non-git-version-control) and Claude isolates edits the same way it does for git. When the hook fails in a directory that isn’t a git repository, Claude skips isolation for that directory and edits the working directory in place. Inside a git repository, Claude Code blocks writes to the shared checkout until Claude moves the session into a worktree. To find a session’s worktree path, peek the session or attach and check its working directory. A [subagent](sub-agents.md) the background session spawns inherits the session’s working directory, so its file edits land in the session’s worktree rather than your working copy. To give a subagent its own separate worktree instead, set [`isolation: worktree`](sub-agents.md#supported-frontmatter-fields) in its frontmatter or pass `isolation: "worktree"` when spawning it. When a background session has made code changes in a worktree Claude entered, Claude Code instructs Claude to preserve the work before finishing, so it survives if you delete the session and its worktree:

- **Commit and push**: Claude commits without asking, and pushes the branch when the repository has a remote.
- **Draft pull request**: Claude opens one when the task calls for it, and the [`#N` label](#pull-request-status) appears on the row.
- **Never**: pushing to `main` or `master`, force-pushing, and merging.
- **Your git instructions take precedence**: if the task, `CLAUDE.md`, or [memory](../02-Claude-Code-CLI/memory.md) says you handle committing or pushing yourself, Claude leaves git to you.

A session editing a checkout it didn’t isolate itself still asks before committing or switching branches. This applies when isolation is set to `"none"`, when the worktree move failed, or when the session started inside a worktree that already existed. Whatever the task, Claude ends the job with a report saying what it did and where the work is: a path, a branch, a pull request, or the answer itself.


[​](#what-deleting-a-session-removes)

What deleting a session removes

Delete a session with `Ctrl+X` twice in [agent view](#organize-the-list) or with [`claude rm`](#manage-sessions-from-the-shell). Except in the kept cases below, the session leaves the list. Its transcript stays on your machine through `claude --resume`, and the removal survives supervisor restarts. What happens to a worktree Claude created for the session:

- Agent view removes it, including uncommitted changes, so commit what you want to keep first.
- `claude rm` keeps it, along with the session row, when it has uncommitted changes.
- Neither agent view nor `claude rm` removes a worktree that another running session is using or has locked, and deleting again doesn’t change that. Claude Code keeps the worktree and the session, and names the kept directory and the reason; in agent view, the session’s row shows `not deleted`. Close the other session, then delete again.
- When you delete a session whose worktree has commits that Claude Code can’t confirm are saved elsewhere, Claude Code keeps the worktree and the session, and the message names the worktree’s branch and how many commits are unpushed. The message also offers the two ways forward: push the commits, or delete again to discard them. Commits on a remote don’t block the delete. Neither do commits on the local copy of your `origin` remote’s default branch, as long as that branch is checked out in your main checkout, the repository directory itself rather than a worktree. After that refusal, you choose:
  - To keep the commits, push them, or merge them into that default branch, then delete the session again.
  - To discard them, delete the session again without pushing: press `Ctrl+X` twice on its row in agent view, or run the `claude rm <id> --discard-unpushed` command the refusal printed. This removes the session and the worktree along with its branch, discarding the unpushed commits and any uncommitted changes.

  When you delete again, Claude Code discards only what the refusal showed: if the worktree has gained a commit since, Claude Code keeps it again and shows the updated state. When another finished session’s records also name the worktree, it stays when you delete again; push the commits, then delete again.
- A worktree git no longer recognizes, for example after `git worktree prune`, doesn’t block the delete. Claude Code deletes the session and leaves the directory on disk.
- When git or your [`WorktreeRemove` hook](../07-Hooks/hooks.md#worktreeremove) fails to remove the worktree, Claude Code keeps the worktree and the session, and the message names the cause. For a hook, the message says how it ended, such as `exited 1`, and quotes the start of its stderr. The message also tells you which of these to do next:
  - Delete the session again to remove the directory anyway, by pressing `Ctrl+X` twice on its row in agent view or running the `claude rm <id> --force-remove-worktree <worktree-id>` command that the `claude rm` refusal printed. The worktree’s branch stays in the repository. Claude Code offers this only when it can confirm all of the following:
    - The directory is one of the repository’s linked worktrees under `.claude/worktrees/`
    - Neither the worktree nor a checked-out submodule has uncommitted changes to tracked files
    - No other session’s record names it

    When Claude Code can’t verify a submodule checkout’s state, such as one replaced by a separate git repository, it doesn’t offer this either.
  - Fix what stands in the way, such as committing or stashing the uncommitted changes, moving a separate git repository out of the worktree, closing whatever is using the directory, or fixing the hook, then delete the session again.
  - Remove the directory yourself, then delete the session again.

A worktree you created yourself and started the session inside is left in place either way. A session whose worktree directory belongs to no git repository, because the repository was deleted or a [`WorktreeCreate` hook](../07-Hooks/hooks.md#worktreecreate) created the directory elsewhere, can still be deleted. While files remain in the directory:

- Agent view asks for the same `Ctrl+X` double-press before discarding them. For a hook-created directory it runs your [`WorktreeRemove` hook](../07-Hooks/hooks.md#worktreeremove) instead, and without one it refuses the delete and keeps the session.
- `claude rm` keeps the session and worktree, and names the reason.

Either path keeps a directory that another finished session’s records name.


[​](#set-the-model)

Set the model

The model name shown in the agent view header is the dispatch default. New sessions you start from the input use this model, which comes from the [`model` setting](../02-Claude-Code-CLI/settings-reference.md#model) in your user settings. Set it by selecting a model in the [`/model` picker](../02-Claude-Code-CLI/model-config.md), or edit the setting directly. To override the dispatch default for the whole agent view session, pass `--model` when opening agent view. See [Permission mode, model, and effort](#permission-mode-model-and-effort). To change the dispatch default from inside agent view, type `/model` followed by a model name in the dispatch input and press `Enter`. The header updates to show that model with a `(session)` marker, and sessions you dispatch afterward use it. Type `/model default` to clear the override and return to the dispatch default. This override lasts for the rest of the current `claude agents` run and doesn’t write to your settings file. The following example dispatches one session on Opus and the next on Sonnet:

```python
/model opus
refactor auth
/model sonnet
run the test suite
```

Each background session can run on a different model. To override it for one session:

- From the shell, pass `--model` with `claude --bg`.
- Attach to a running session and run `/model` to switch: a pick from the picker, or a typed `/model <name>`, saves as your default for new sessions unless you press `s` in the picker for a session-only switch. A session-only switch persists if the session is respawned.
- Dispatch a [subagent](sub-agents.md) whose frontmatter sets a `model` field.


[​](#permission-mode-model-and-effort)

Permission mode, model, and effort

A background session takes its settings, provider, permission mode, model, and effort from where and how you dispatched it. The subsections below cover each source, and what persists when the supervisor restarts the session.


[​](#settings-and-provider)

Settings and provider

A background session reads its [settings](../02-Claude-Code-CLI/settings.md) from the directory it runs in, the same as if you had started `claude` there with the [configuration flags it carried over](#what-carries-over-when-you-background). This includes [`env` values](../02-Claude-Code-CLI/settings-reference.md#env) in project settings, so an `ANTHROPIC_MODEL` or provider variable set there applies to every background session in that directory. A background session also runs with the `PATH` of the shell you dispatched it from, so the commands it runs find the same tools your terminal does. It keeps that shell’s cloud provider selection too, such as `CLAUDE_CODE_USE_BEDROCK` or `CLAUDE_CODE_USE_VERTEX`, along with its `ANTHROPIC_DEFAULT_*_MODEL` aliases and any [`CLAUDE_CODE_EXTRA_BODY`](../02-Claude-Code-CLI/env-vars.md) override you exported there.


[​](#llm-gateway)

LLM gateway

If you route Claude Code through an [LLM gateway](../13-Enterprise-Admin/llm-gateway.md), put the gateway variables in a settings file’s `env` block rather than exporting them in your shell, and background sessions read them with the rest of their settings. [Set in a settings file](../13-Enterprise-Admin/llm-gateway-connect.md#set-in-a-settings-file) shows the block and which settings file to use for the credential. If you export a gateway `ANTHROPIC_BASE_URL` only in your shell instead, it reaches a background session, together with the `ANTHROPIC_CUSTOM_HEADERS` and credential you exported with it, only when the [supervisor](#the-supervisor-process) was itself started from a shell that exported the same gateway, and only in these cases:

- You background your own session with `←` or `/background`
- You dispatch a session into the directory you’re in
- You wake a stopped session in the directory you’re in by attaching or replying to it

Claude Code forwards a gateway in front of a cloud provider. If the shell you dispatch from selects the provider and exports its gateway endpoint with its auth-bypass flag, Claude Code forwards the endpoint-and-flag pair to the session under the conditions that apply to `ANTHROPIC_BASE_URL`, together with `ANTHROPIC_CUSTOM_HEADERS`. For example, export `CLAUDE_CODE_USE_VERTEX=1` with `ANTHROPIC_VERTEX_BASE_URL` and `CLAUDE_CODE_SKIP_VERTEX_AUTH=1`, and Claude Code forwards that endpoint and flag. Claude Code applies a forwarded gateway to that session’s running process only and never writes it to disk.


[​](#permission-mode)

Permission mode

The [permission mode](../02-Claude-Code-CLI/permissions.md) depends on how you started the session:

- **Backgrounded with `/bg` or `←`**: Claude Code keeps the permission mode the session was in, so one you switched to `acceptEdits` or `auto` stays there after detaching
- **Dispatched from an agent view you opened with `←`**: the target’s own configuration comes first, and the permission mode of the session you came from applies when nothing else sets one
- **Dispatched from `claude agents` started in a shell, or with `claude --bg`**: the new session starts the way a new `claude` session in that directory would, unless you dispatched it from an agent view you opened with [dispatch defaults](#dispatch-defaults). [Which permission mode a session starts in](../02-Claude-Code-CLI/permission-modes.md#which-mode-a-session-starts-in) lists the order

For a session you dispatch from an agent view opened with `←`, Claude Code takes the permission mode from the first of these that applies:

1.  The target directory’s [`permissions.defaultMode`](../02-Claude-Code-CLI/settings-reference.md#permissions-defaultmode). Two source rules apply:
    - `auto` and `bypassPermissions` [take effect only from managed settings, a `--settings` file, or `~/.claude/settings.json`](../02-Claude-Code-CLI/settings-reference.md#permissions-defaultmode).
    - Claude Code refuses a `defaultMode` from the project’s `.claude/settings.json` or `.claude/settings.local.json` that selects a more permissive mode than the session you came from was in.
2.  The permission mode of the session you came from

When Claude Code refuses a source’s mode as too permissive, the next source in the list decides. For example, if you dispatch from a plan-mode session into a directory whose checked-in settings ask for `acceptEdits`, the new session starts in plan mode. If you move that `defaultMode` to `~/.claude/settings.json`, it applies regardless of the permission mode of the session you came from. Permissiveness runs plan, then Manual and `dontAsk`, then `acceptEdits` and auto, which each count as more permissive than the other, then `bypassPermissions`.


[​](#dispatch-defaults)

Dispatch defaults

To set defaults for every session you dispatch from agent view, pass any of `--permission-mode`, `--model`, `--effort`, or `--agent` when opening it:

```python
claude agents --permission-mode plan --model opus --effort high
```

`--effort` here accepts the same values as the [top-level `--effort` flag](../02-Claude-Code-CLI/cli-reference.md#cli-flags), including `ultracode`. `--agent` sets the [subagent](sub-agents.md) used when a dispatch prompt doesn’t name one, either with `@name` or as the first word. It defaults to the [`agent` setting](../02-Claude-Code-CLI/settings-reference.md#agent) if one is set, otherwise the built-in catch-all `claude` agent. Naming a subagent in the dispatch input overrides both. `claude agents` also accepts `--dangerously-skip-permissions` as shorthand for `--permission-mode bypassPermissions`, and `--allow-dangerously-skip-permissions` to make `bypassPermissions` available in each dispatched session’s `Shift+Tab` cycle without starting in that mode. Both match the [top-level CLI flags](../02-Claude-Code-CLI/cli-reference.md). Pass `--restricted` to start every session you dispatch from the view in [restricted mode](../02-Claude-Code-CLI/cli-reference.md#cli-flags), as if each were launched with the top-level `--restricted` flag. Requires Claude Code v2.1.248 or later. The active defaults appear in the footer below the dispatch input. Claude Code refuses `claude --bg --permission-mode bypassPermissions` until you’ve accepted the bypass disclaimer by running `claude --dangerously-skip-permissions` once interactively, since that mode lets a session you aren’t watching act without approval. Passing `--dangerously-skip-permissions` or `--permission-mode bypassPermissions` to `claude agents` shows the same disclaimer when you haven’t accepted it before, and accepting applies `bypassPermissions` to the sessions you launch from the view. Passing `--allow-dangerously-skip-permissions` shows the same disclaimer too, and accepting makes `bypassPermissions` available in the `Shift+Tab` cycle of those sessions without starting them in it.


[​](#what-persists-across-restarts)

What persists across restarts

The permission mode, model, and effort you chose for a background session, along with the [configuration flags it carries](#what-carries-over-when-you-background), all persist when the supervisor later [stops and restarts](#the-supervisor-process) its process. A session you launched with `claude --bg --dangerously-skip-permissions` or `claude --bg --permission-mode bypassPermissions` stays in `bypassPermissions` after that restart. A model or effort you changed mid-session with `/model` or `/effort` is kept too. If the session took its effort from your settings rather than from `--effort` or `/effort`, Claude Code reads your settings again each time it starts a process for the session. After you edit the saved effort in `settings.json`, the change reaches sessions you background with `←` or `/bg`, and their later restarts. The saved effort is the [`effortLevel`](../02-Claude-Code-CLI/settings-reference.md#effortlevel) key or a [`modelSettings`](../02-Claude-Code-CLI/settings-reference.md#modelsettings) entry. Claude Code also keeps a name you set with [`/rename`](../02-Claude-Code-CLI/commands.md) or `Ctrl+R` across that restart, so you can still run [`claude --resume <name>`](../02-Claude-Code-CLI/sessions.md#name-your-sessions) to reach the session. A prompt you stashed with [`Ctrl+S`](../02-Claude-Code-CLI/interactive-mode.md#general-controls) while attached is kept with the session too. Reopen the session after its process was stopped or restarted, and press `Ctrl+S` to restore the stashed text. Pasted content in the stash doesn’t survive the restart.


[​](#settings-plugins-and-mcp-servers)

Settings, plugins, and MCP servers

Agent view accepts the same configuration flags as `claude` for loading settings, plugins, MCP servers, and additional directories. Agent view applies `--settings`, `--setting-sources`, and `--plugin-dir` to itself and passes every configuration flag through to the sessions you dispatch from it, so a plugin or MCP server you load this way is available in those sessions.

| Flag                                                                                                  | Effect                                                                                                                                                                                                                                      |
|:------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`--settings <file-or-json>`](../02-Claude-Code-CLI/settings.md)                                                      | Override settings for agent view and dispatched sessions                                                                                                                                                                                    |
| [`--setting-sources <sources>`](../02-Claude-Code-CLI/cli-reference.md#cli-flags)                                     | Load only the named settings sources, in agent view and dispatched sessions                                                                                                                                                                 |
| [`--add-dir <path>`](../02-Claude-Code-CLI/permissions.md#additional-directories-grant-file-access-not-configuration) | Grant file access to an additional directory                                                                                                                                                                                                |
| [`--plugin-dir <path>`](../08-Plugins-Skills/plugins-create.md#load-a-directory-or-archive-for-one-session)          | Load a plugin from a local directory                                                                                                                                                                                                        |
| [`--mcp-config <file-or-json>`](../06-MCP-Tools/General/mcp.md)                                                         | Load MCP servers from a config file or JSON string                                                                                                                                                                                          |
| `--strict-mcp-config`                                                                                 | Use only the MCP servers from `--mcp-config`, ignoring other MCP configuration. See [Exclusive control with managed-mcp.json](../06-MCP-Tools/General/managed-mcp.md#exclusive-control-with-managed-mcp-json) for what the flag does under a managed MCP file |

Repeat `--add-dir`, `--plugin-dir`, or `--mcp-config` once per value. `claude agents` doesn’t support the space-separated form, such as `--add-dir a b c`. You can place `--settings`, `--setting-sources`, and `--plugin-dir` before or after `agents`. Keep `--add-dir` and `--mcp-config` after `agents`: if you place either before `agents`, [`claude agents --json`](#manage-sessions-from-the-shell) fails with an `unknown option` error. The following example opens agent view with a settings override and one extra directory:

```python
claude agents --settings ./ci-settings.json --add-dir ../shared-lib
```

`--settings` accepts a file path or an inline JSON string. A file path must point to an existing file; Claude Code exits with a `Settings file not found` error if it doesn’t.


[​](#manage-sessions-from-the-shell)

Manage sessions from the shell

Every background session has a short ID you can use from the shell. The ID is printed when you start a session with `claude --bg`, and each session’s ID is its directory name under `~/.claude/jobs/`. These commands are useful for scripting or when you don’t want to open agent view.

| Command                                                    | Purpose                                                                                                                                                                                                                                                                                                                                          |
|:-----------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `claude agents`                                            | Open agent view                                                                                                                                                                                                                                                                                                                                  |
| `claude agents --cwd <path>`                               | Open agent view scoped to sessions started under `<path>`                                                                                                                                                                                                                                                                                        |
| `claude agents --json`                                     | Print sessions as a JSON array and exit. See [List sessions as JSON](#list-sessions-as-json)                                                                                                                                                                                                                                                     |
| `claude attach <id>`                                       | Attach to a session in this terminal                                                                                                                                                                                                                                                                                                             |
| `claude logs <id>`                                         | Print the session’s recent output                                                                                                                                                                                                                                                                                                                |
| `claude stop <id>`                                         | Stop a session. Also accepts `claude kill`                                                                                                                                                                                                                                                                                                       |
| `claude respawn <id>`                                      | Restart a session, running or stopped, e.g. to pick up an updated Claude Code binary. The restarted session resumes its saved conversation; when none is on disk, it runs its original prompt again as a new conversation                                                                                                                        |
| `claude respawn --all`                                     | Restart every running session, e.g. to move all sessions onto an updated Claude Code binary at once                                                                                                                                                                                                                                              |
| `claude rm <id>`                                           | Remove a session from the list, along with a worktree Claude created for it when that’s safe to delete; see [What deleting a session removes](#what-deleting-a-session-removes). The conversation transcript stays on your local machine and remains available through `claude --resume`                                                         |
| `claude rm <id> --discard-unpushed <commit>@<worktree-id>` | Delete a session whose delete was refused over unpushed commits, discarding the worktree along with its branch and commits. Pass the exact value that refusal printed; see [What deleting a session removes](#what-deleting-a-session-removes). Requires v2.1.260 or later                                                                       |
| `claude rm <id> --force-remove-worktree <worktree-id>`     | Delete a session whose delete was refused because git or the `WorktreeRemove` hook couldn’t remove its worktree, deleting the worktree directory anyway and leaving its branch in the repository. Pass the exact value that refusal printed; see [What deleting a session removes](#what-deleting-a-session-removes). Requires v2.1.268 or later |
| `claude daemon status`                                     | Print the [supervisor’s](#the-supervisor-process) state, version, socket directory, and worker count                                                                                                                                                                                                                                             |
| `claude daemon stop --any`                                 | Stop the supervisor process and the background sessions it hosts. Pass `--keep-workers` to leave background sessions running so the next supervisor reconnects to them. The next `claude agents` or `claude --bg` starts a fresh supervisor                                                                                                      |


[​](#list-sessions-as-json)

List sessions as JSON

`claude agents --json` prints active sessions as a JSON array and exits: every live session, plus background sessions that are still working or blocked even when their process has exited. Add `--all` to also include completed background sessions, and `--cwd <path>` to limit the list to sessions started under that directory. Each entry describes one session:

| Field                      | Present                    | Description                                                                                                                                                                                                                                     |
|:---------------------------|:---------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `cwd`, `kind`, `startedAt` | Always                     | The working directory, `interactive` or `background`, and the start time in Unix milliseconds                                                                                                                                                   |
| `id`                       | Background sessions        | Short ID, usable with `claude attach`, `claude logs`, and `claude stop`                                                                                                                                                                         |
| `state`                    | Background sessions        | One of `working`, `blocked`, `done`, `failed`, or `stopped`. See [Read session state from a script](#read-session-state-from-a-script) for what each value means                                                                                |
| `pid`, `status`            | While the process is alive | Process ID and one of `busy`, `waiting`, or `idle`                                                                                                                                                                                              |
| `waitingFor`               | When `status` is `waiting` | What the session is blocked on: `permission prompt` for an approval, `input needed` for a question from Claude or an MCP server’s input request, `sandbox request`, `worker request`, or `dialog open`                                          |
| `sessionId`, `name`        | When set                   | `sessionId` is the full session UUID, usable with [`claude --resume`](../02-Claude-Code-CLI/sessions.md). An interactive session’s `name` is its [default display name](../02-Claude-Code-CLI/sessions.md#name-your-sessions) until you name the session or accept a plan in it |


[​](#read-session-state-from-a-script)

Read session state from a script

`claude agents --json` is the supported way to read session state from outside Claude Code, for example from a status bar, a scheduler, or another Claude session that supervises background work. Poll `claude agents --json --all`, which keeps listing sessions whose process has exited, and read each entry’s `state`, `status`, and `waitingFor`.

| `state`             | What it means                                                                                                                                                                                                                                                           |
|:--------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `working`           | A turn is running, or the session is between steps of work it drives on its own, such as a [`/loop`](../02-Claude-Code-CLI/scheduled-tasks.md) iteration or a wait on CI. `status` tells you whether its process is `busy` right now                                                    |
| `blocked`           | The session is waiting on you: a question it asked, a permission or sandbox decision, an error only you can clear such as an expired login, or its first prompt if you started it without one. When the wait is an open prompt in a live process, `waitingFor` names it |
| `done`              | The last turn finished what you asked for and the session is ready for your next prompt, whether or not its process is still alive                                                                                                                                      |
| `failed`, `stopped` | The task ended with an error, or the session was stopped                                                                                                                                                                                                                |

A session that finished its turn and is waiting for your next instruction reads `done`, not `blocked`. `blocked` always means the session needs something from you before it can continue. The files under `~/.claude/jobs/<id>/` are not a stable interface. Values that a session or another program writes to `state`, `detail`, `tempo`, or `needs` are replaced on the next update. If you want a session to report progress in its own words, have it write a file of its own, for example under `$CLAUDE_JOB_DIR/tmp`, instead of editing `state.json`.


[​](#how-background-sessions-are-hosted)

How background sessions are hosted

Claude Code treats every session listed in agent view as a background session, whether or not you’re currently attached to it. By contrast, a session started by running `claude` directly is tied to that terminal and ends when it closes, unless you [send it to the background](#from-inside-a-session). To check which kind of session you’re in, run [`/status`](../02-Claude-Code-CLI/commands.md). The `Session kind` row reads `background job · attached` or `background job · unattended` in a background session, depending on whether a terminal is attached, and `interactive` in any other session.


[​](#the-supervisor-process)

The supervisor process

The supervisor is a background service that runs your background sessions so they keep working after you close agent view or your terminal. Claude Code starts it the first time you background a session or open agent view, and you don’t need to manage it yourself. Each session is its own Claude Code process under the supervisor, and what happens to that process depends on the session’s state:

- **Working, paused on a permission prompt or other dialog, or attached**: the process keeps running. A running subagent, workflow, or monitor counts as working.
- **Finished or waiting for your next message, and unattached for about an hour**: the supervisor stops the process to free resources. A session that ended its turn by asking you a question counts as waiting for your next message. The conversation stays on disk, and the next time you attach or reply, the session resumes where it left off. Pin a session with `Ctrl+T` to keep its process running.
- **Exited unexpectedly while the supervisor is running**: the supervisor restarts the process. Ending a session you backgrounded yourself with `←` or `/background`, for example with `kill`, marks it stopped instead of restarting it. For sessions that ended with a shutdown, see [Sessions show as failed or stopped after shutdown](#sessions-show-as-failed-after-shutdown).
- **After an auto-update**: the supervisor restarts itself onto the new version and moves idle sessions over in the background. Sessions that are working, waiting on you, or attached aren’t interrupted.

When a session’s process stops or restarts, the background shell commands, dynamic workflows, and background subagents Claude started in it carry over to its next process; running monitors and shell commands a subagent started stop with the process. Deleting the session stops everything it carried over. To stop all of it with the process instead, set [`CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF`](../02-Claude-Code-CLI/env-vars.md#variables) to `1`. The supervisor and its sessions authenticate with the same stored credentials as your interactive sessions. For which settings and shell variables reach a session, including `PATH`, see [Settings and provider](#settings-and-provider). For gateway endpoints, see [LLM gateway](#llm-gateway).


[​](#where-state-is-stored)

Where state is stored

Session state is stored under your Claude Code config directory. If you set [`CLAUDE_CONFIG_DIR`](../02-Claude-Code-CLI/env-vars.md), the supervisor uses that directory instead of `~/.claude` and runs as a separate instance with its own sessions.

| Path                             | Contents                                                                                                                                       |
|:---------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------|
| `~/.claude/daemon.log`           | Supervisor log                                                                                                                                 |
| `~/.claude/daemon/roster.json`   | List of running background sessions, used to reconnect after a restart                                                                         |
| `~/.claude/jobs/<id>/state.json` | Per-session state shown in agent view. Read it through [`claude agents --json`](#read-session-state-from-a-script) instead of parsing the file |
| `~/.claude/jobs/<id>/tmp/`       | Per-session scratch directory. Claude’s `Write` and `Edit` calls here don’t prompt for permission. Removed when the session is deleted         |

Each background session has the `CLAUDE_JOB_DIR` environment variable set to its `~/.claude/jobs/<id>` directory, so shell commands the session runs can write temporary files to `$CLAUDE_JOB_DIR/tmp` without colliding with parallel sessions. To inspect this state without reading the files directly, run `claude daemon status`. It reports whether the supervisor is reachable, its process ID and version, the socket directory, and how many background sessions are live. The command also warns when the running supervisor is on a different version than the `claude` you invoked, which happens after an update the supervisor hasn’t restarted into yet. The warning shows both versions and tells you to run `claude daemon stop --any` to pick up the new version. When Claude Code is installed as an OS service, the suggested command is `claude daemon stop` without the flag. Sessions survive that version mismatch intact: an older Claude Code version that updates a session’s `state.json` preserves fields it doesn’t recognize and keeps the session listed. The session list in `roster.json` follows the same rule, so sessions started by the newer version stay reachable and keep accepting input after the supervisor restarts.


[​](#turn-off-agent-view)

Turn off agent view

To turn off background agents and agent view entirely, set the `disableAgentView` [setting](../02-Claude-Code-CLI/settings.md) to `true` or set the `CLAUDE_CODE_DISABLE_AGENT_VIEW` environment variable. Administrators can enforce this through [managed settings](../13-Enterprise-Admin/managed-settings.md).


[​](#troubleshooting)

Troubleshooting


[​](#claude-agents-lists-subagents-instead-of-opening-agent-view)

`claude agents` lists subagents instead of opening agent view

If `claude agents` prints a count followed by your configured subagents and then exits, agent view is unavailable in your environment. Run `claude update` to install the latest version. If agent view still doesn’t open after updating, check whether it has been [turned off](#turn-off-agent-view) by a setting or environment variable.


[​](#agent-view-opens-with-no-sessions)

Agent view opens with no sessions

Before you dispatch your first session, agent view shows the empty section headers with a description under each, plus a one-line explanation above the input, in place of the session list. Type a prompt in the input at the bottom and press `Enter` to dispatch your first session.


[​](#backgrounding-shows-a-background-this-session-dialog)

Backgrounding shows a `Background this session?` dialog

If you press `←` to background the current session and Claude Code shows a `Background this session?` dialog, the session has in-flight work that backgrounding would stop, restart, or leave running unattended, and Claude Code asks before it does any of those:

- **Work that can’t move**: the session has work that can’t move to the background session, such as a running [monitor](../02-Claude-Code-CLI/tools-reference.md#monitor-tool). The dialog names the work Claude Code would stop and, separately, counts the tasks that carry over.
- **A workflow with running subagents**: a [dynamic workflow](../02-Claude-Code-CLI/workflows.md) still has subagents running. The workflow itself carries over, but its running subagents restart from the beginning, and the dialog says how many.
- **Automatic artifact replies**: Claude is [replying to comments on an artifact on its own](../02-Claude-Code-CLI/artifacts.md#let-claude-reply-to-comments-on-its-own). Those replies continue in the background session, and the dialog says so.

Run `/tasks` to see everything that’s running, then confirm to background anyway or choose `Stay` to let the work finish first. See [What carries over when you background](#what-carries-over-when-you-background) for which kinds of work carry over and which Claude Code stops.


[​](#prompt-rejected-as-too-short)

Prompt rejected as too short

The dispatch input expects a task description, not a conversational opener. A prompt shorter than four characters is rejected with a `Too short` hint so a stray keystroke doesn’t start a session. Describe what you want the session to do, such as `investigate the flaky checkout test`.


[​](#sessions-show-as-failed-after-shutdown)

Sessions show as failed or stopped after shutdown

Shutting down or restarting your machine stops running background sessions. A session that was waiting on your input stays under `Needs input` when you come back. For any other running session, what agent view shows depends on how long ago it last made progress:

- Within 48 hours, the session shows as failed. Attach or reply to it and it restarts from where it left off.
- Past 48 hours, such as after the machine was off for days, the session shows as stopped with `ended while the background service was off`. Press `Enter` on the row and the footer shows `Press enter again to resume this session (it ended while the background service was off), or ctrl+x to delete it.` Press `Enter` on the same row again to resume its saved conversation. A reply, or `claude attach <id>`, resumes it without that footer prompt.

When [transcript cleanup](../02-Claude-Code-CLI/settings-reference.md#cleanupperioddays) has removed a stopped session’s saved conversation, Claude Code refuses to open the row: the message says there is nothing to resume. `claude rm <id>` deletes the row, except in the [kept cases](#what-deleting-a-session-removes) described above, and `claude respawn <id>` runs its original prompt again. See [This session’s saved conversation is no longer on disk](../02-Claude-Code-CLI/errors.md#this-sessions-saved-conversation-is-no-longer-on-disk). Sleep alone doesn’t stop sessions. Sessions are preserved across sleep and the supervisor reconnects to them on wake.


[​](#opening-a-session-says-the-conversation-is-already-open)

Opening a session says the conversation is already open

Two processes can’t write to the same transcript. When a stopped session’s saved conversation is already open in another live Claude Code process, Claude Code refuses to start the session’s own process. What you see depends on what holds the conversation:

- A terminal where you resumed the conversation, for example with `claude --resume` or `/resume`: the row shows `Open in a terminal` with a hint to continue it there, and opening the row shows `Can't open — this session is running in another terminal`. Continue in that terminal, or exit it and open the row again.
- Another non-interactive Claude Code process, for example a background session process for the same conversation that hasn’t exited yet: opening the row shows `This conversation is already open in another running Claude session`. Use that process, or wait for it to exit and open the row again.

Claude Code saves a reply you typed with the refused attempt and sends it the next time the session starts.


[​](#opening-a-session-says-it-has-no-saved-transcript)

Opening a session says it has no saved transcript

A stopped session that was [backgrounded from another conversation](#from-inside-a-session) and stopped before its first response finished has nothing to resume: until that first response finishes, the conversation still lives only in the session it was backgrounded from. `claude attach` refuses to open it with `This session has no saved transcript`. In agent view, opening that row shows `Press enter again to restart this session fresh` below the list. Press `Enter` on the same row again to restart the session with an empty conversation, or run `claude respawn <id>` from the shell. The original conversation is intact; resume it with `claude --resume` or keep working in it. See the [error reference](../02-Claude-Code-CLI/errors.md#this-session-has-no-saved-transcript) for details.


[​](#the-terminal-host-died-or-the-session-stopped-responding)

The terminal host died or the session stopped responding

The [supervisor](#the-supervisor-process) runs each background session’s terminal in its own host process. When that process dies or stops responding, Claude Code shows the reason and offers a restart; in both cases the conversation is saved and the restart resumes it. The [error reference](../02-Claude-Code-CLI/errors.md#terminal-host-process-died) quotes the full messages. Claude Code never restarts a row running a [shell command](#run-a-shell-command), from `Enter` or from `claude attach`, because that would run the command again; the row’s message and `claude attach` both say the command isn’t run again.


[​](#terminal-host-died)

Terminal host died

On Linux and WSL, the supervisor checks each host process every few seconds, whether or not you open the session, and marks the session failed when the process has exited but its connection to the supervisor never closed.

- In agent view, the row shows `terminal host process died — press Enter to restart`. Press `Enter` on it and Claude Code restarts the session on a fresh host process.
- From the shell, `claude attach <id>` restarts a session already marked failed. Otherwise it reports the cause and exits, telling you to run `claude attach <id>` again.


[​](#session-isn’t-responding)

Session isn’t responding

When the supervisor accepts an open but no output arrives for about ten seconds, Claude Code ends the attempt and offers a restart. A session that merely stalled, for example across machine sleep, doesn’t reach this offer: the supervisor [restarts it on open](#read-session-state) itself.

- In agent view, the footer shows `Press enter again to restart this session — it isn't responding (its conversation is saved and resumes).` Press `Enter` on the same row again and Claude Code stops the unresponsive process and restarts the session; it stops nothing without that second press.
- From the shell, `claude attach <id>` reports the cause and exits, telling you to run `claude stop <id>`, then `claude attach <id>`.


[​](#a-session-fails-before-starting-with-a-possibly-low-memory-note)

A session fails before starting with a `possibly low memory` note

When a background session’s process exits before it finishes starting and the host is low on memory, the row’s status names the exit and adds `possibly low memory — free some up and retry`. The note is a hypothesis, not a confirmed cause. Claude Code adds it only when the process exited silently, without writing an error and without being stopped by a signal, and the host reported low memory at that moment. When the process did write an error before exiting, the row shows that error instead. Free up memory on the machine, then attach or reply to the row and the supervisor starts a fresh process for the session. When memory stays low, the supervisor also [stops idle sessions](#the-supervisor-process) to free resources on its own, and stops idle pinned sessions too if stopping the others freed nothing.


[​](#agent-view-says-the-background-service-did-not-respond)

Agent view says the background service did not respond

If attaching, peeking, or `claude logs` reports that the background service did not respond, the supervisor process has likely stalled. Stop it and let the next `claude agents` start a fresh one. To keep your background sessions running through the restart, pass `--keep-workers`:

```python
claude daemon stop --any --keep-workers
```

The new supervisor reconnects to the running sessions. Without `--keep-workers`, the command ends the background sessions too. The `--any` flag confirms you want to stop a supervisor that started on demand rather than as an installed service, which is the default. A supervisor that starts but can’t accept connections exits and releases its lock on its own, so the next `claude agents` starts a fresh one without this manual stop. The steps above apply when a running supervisor stalls. If the command instead exits saying the recorded process couldn’t be verified as the supervisor, check the reported process ID: if it’s a supervisor you own, stop it yourself, then delete `~/.claude/daemon.lock` so the next `claude agents` starts fresh. On Windows, if the supervisor doesn’t respond to the stop request, the command prints its process ID. End that process with `taskkill /PID <pid>` to finish the recovery. Background sessions are still preserved when you passed `--keep-workers`.


[​](#dispatch-fails-with-could-not-resolve-authentication-method)

Dispatch fails with `Could not resolve authentication method`

If a background dispatch fails with `Could not resolve authentication method` while interactive sessions authenticate normally, the worker that received the dispatch didn’t pick up credentials. Background sessions get their credentials from the [supervisor](#the-supervisor-process), so this error means no stored credential was available to the supervisor process itself. Confirm you have run `/login` or configured an API key, then stop the supervisor:

```python
claude daemon stop --any --keep-workers
```

The next `claude agents` or `claude --bg` starts a fresh supervisor that reads your stored credentials. If you authenticate with an environment variable such as `ANTHROPIC_API_KEY` rather than `/login`, run that next command from a shell where the variable is set. See the [error reference](../02-Claude-Code-CLI/errors.md#could-not-resolve-authentication-method) for the full list of causes and fixes.


[​](#background-sessions-can’t-read-desktop-documents-or-downloads-on-macos)

Background sessions can’t read Desktop, Documents, or Downloads on macOS

On macOS, the background session host runs as its own process and requests access to protected folders separately from your terminal. If a background session reports `Operation not permitted` when reading `~/Desktop`, `~/Documents`, `~/Downloads`, or another protected location, grant access in System Settings under Privacy & Security \> Files and Folders, or enable Full Disk Access for the entry. With the native installer, the entry appears as Claude Code and the grant persists across updates. With other install methods such as Homebrew or npm, the entry shows the binary path and may need to be granted again after updating.


[​](#background-sessions-can’t-reach-local-network-hosts-on-macos)

Background sessions can’t reach local-network hosts on macOS

On macOS 15 and later, the system blocks a process from reaching devices on your local network until you grant Local Network permission, so a command targeting a LAN address can fail with `connect: no route to host` in a background session even though it works in a foreground terminal. The first command in a background session that connects to a local-network address triggers the macOS Local Network permission prompt for Claude Code. Grant it once and those commands reach LAN hosts the same way they do in a foreground terminal.


[​](#a-session-is-slow-to-respond-after-attaching)

A session is slow to respond after attaching

When a session that has finished or is waiting for your next message stays unattached for about an hour, the supervisor stops its process to free resources. Attaching starts a fresh process from where it left off and switches to the session immediately while the process restarts. Sessions that are working, paused on a permission prompt or other dialog, or [pinned](#organize-the-list) aren’t stopped this way, so pin a session with `Ctrl+T` to keep it responsive. While the process starts, Claude Code shows the tail of the session’s transcript formatted the way the live session renders it, with markdown, highlighted code blocks, and tool calls as dimmed rows, above a dimmed prompt area with a `Session is starting` note. The live session replaces it as soon as it’s ready.


[​](#claude/worktrees/-is-filling-up)

`.claude/worktrees/` is filling up

Deleting a session in agent view removes the worktree Claude created for it, but [some deletes keep the worktree or leave its directory on disk](#what-deleting-a-session-removes), so leftover directories can accumulate. Directories git no longer recognizes don’t appear in `git worktree list`, so remove those by hand. List leftover entries with `git worktree list` in the project directory and remove each with `git worktree remove <path>`. See [Clean up worktrees](../02-Claude-Code-CLI/worktrees.md#clean-up-worktrees).


[​](#limitations)

Limitations

Agent view is in research preview with the following limitations:

- **Rate limits apply**: background sessions consume your subscription usage the same as interactive sessions, so running ten agents in parallel uses quota roughly ten times as fast as running one.
- **Sessions are local**: background sessions run on your machine. They are preserved across sleep but stop if the machine shuts down.
- **Claude-created worktrees are deleted with the session in agent view**: commit changes before deleting a session that edited files in its own worktree. [Some deletes keep the worktree instead](#what-deleting-a-session-removes).


[​](#related-resources)

Related resources

For other ways to run Claude in parallel, and for passing findings between the sessions you run, see:

- [Run agents in parallel](agents.md): compare agent view with subagents, agent teams, and worktrees
- [Cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md): have your sessions pass findings to each other
- [Agent teams](agent-teams.md): coordinate multiple sessions that message each other
- [Use Claude Code in the cloud](../02-Claude-Code-CLI/claude-code-on-the-web.md): run sessions in a managed cloud environment instead of locally
- [Projects](../02-Claude-Code-CLI/claude-projects.md): have Claude coordinate parallel cloud sessions from one conversation and tell you which need you


[​](#version-history)

Version history

Agent view has evolved quickly during research preview. If you are on an older Claude Code version, some behavior on this page may differ; in particular, `claude agents` rejects flags it doesn’t yet support with an `unknown option` error. The table below lists when each flag and behavior was added.

[TABLE]

---

## Run agents in parallel - Claude Code Docs

Source: https://code.claude.com/docs/en/agents
Path: 09-Agents-Patterns/agents.md

## On this page

- [Choose an approach](#choose-an-approach)
- [Check on running work](#check-on-running-work)
- [Learn more](#learn-more)

Agents and parallel work

# Run agents in parallel

Copy pageCopy page

Compare the ways Claude Code can take on multiple tasks at once: subagents, agent view, agent teams, dynamic workflows, and projects.

Copy pageCopy page

Claude Code has five ways to work on several tasks at once: [subagents](sub-agents.md), [agent view](agent-view.md), [agent teams](agent-teams.md), [dynamic workflows](../02-Claude-Code-CLI/workflows.md), and [projects](../02-Claude-Code-CLI/claude-projects.md). They differ in how involved you stay, from steering each conversation yourself to letting Claude coordinate a group of workers, and in whether the work runs on your machine or in the cloud.

| Approach                                | What it gives you                                                                                                                                                                                                                                                                                  | Use it when                                                                                                                                                                                         |
|:----------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Subagents](sub-agents.md)        | Delegated workers inside one session that do a side task in their own context and return a summary                                                                                                                                                                                                 | A side task would flood your main conversation with search results, logs, or file contents you won’t reference again                                                                                |
| [Agent view](agent-view.md)       | One screen to dispatch and monitor sessions running in the background, opened with `claude agents`. Research preview                                                                                                                                                                               | You have several independent tasks and want to hand them off, check status at a glance, and step in only when one needs you                                                                         |
| [Agent teams](agent-teams.md)     | Multiple coordinated sessions with a shared task list and inter-agent messaging, managed by a lead. Experimental and disabled by default                                                                                                                                                           | You want Claude to split a project into pieces, assign them, and keep the workers in sync                                                                                                           |
| [Projects](../02-Claude-Code-CLI/claude-projects.md)    | One ongoing conversation at claude.ai/code or in the desktop app. Claude starts parallel sessions called threads, in the cloud or, when you ask, on your computer through Remote Control, gives each one the project’s instructions, and shows you which ones need you. Public beta on Pro and Max | The work spans many tasks over days or weeks, should keep running when your machine is off, and you’d rather describe it once than dispatch and track each session                                  |
| [Dynamic workflows](../02-Claude-Code-CLI/workflows.md) | A script that runs many subagents and cross-checks their results, for work too big to coordinate one turn at a time or that needs more than a single pass                                                                                                                                          | A job outgrows a handful of subagents, or you want findings verified against each other: a codebase-wide audit, a 500-file migration, cross-checked research, or a plan drafted from several angles |

In every approach the workers are Claude sessions. To involve a different tool, expose it to Claude as an [MCP server](../06-MCP-Tools/General/mcp.md). Three more tools support this work without being a way to run agents themselves:

- [Worktrees](../02-Claude-Code-CLI/worktrees.md) give each session a separate git checkout, so parallel sessions never edit the same files. Use them for sessions you run yourself. A session you dispatch from agent view [moves into a worktree of its own before it edits files](agent-view.md#how-file-edits-are-isolated), and subagents you spawn can each get one too.
- [Cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md) lets Claude list and message your other Claude Code sessions on this machine, on another machine, or [in the cloud](../02-Claude-Code-CLI/claude-code-on-the-web.md), so sessions you run yourself can pass findings and status between themselves.
- [`/batch`](../02-Claude-Code-CLI/commands.md) is a [skill](../08-Plugins-Skills/skills.md) that has Claude split one large change into 5 to 30 worktree-isolated subagents. It’s a packaged use of subagents and worktrees, not a separate coordination style.

A few other features run Claude without you driving each step, but they solve a different problem than splitting work across agents:

- A [background bash command](../02-Claude-Code-CLI/interactive-mode.md#background-bash-commands) runs one shell command without blocking the conversation. It doesn’t spawn an agent.
- A [forked subagent](sub-agents.md#fork-the-current-conversation) is a subagent that inherits your full conversation context instead of starting fresh. It’s a way to spawn a subagent, not a separate surface. Start one with `/subtask`. Claude also spawns one itself where [fork mode](sub-agents.md#turn-fork-mode-on-or-off) is on. To copy the whole session into a new [background session](agent-view.md#from-inside-a-session) that runs alongside it, use `/fork`. With [agent view turned off](agent-view.md#turn-off-agent-view), the forked-subagent command is `/fork` instead and `/subtask` isn’t available.
- A [routine](../02-Claude-Code-CLI/web-scheduled-tasks.md) runs a session on a schedule in the cloud, not in parallel on your machine.

Running several sessions or subagents at once multiplies token usage. See [Costs](../17-Billing-Plans/costs.md) for usage and rate-limit details.


[​](#choose-an-approach)

Choose an approach

The right approach depends on who coordinates the work, whether the workers need to communicate, and whether they edit the same files:

- **Who coordinates the work?**
  - Claude delegates and collects results inside one conversation: [subagents](sub-agents.md)
  - You hand off independent tasks and check back later: [agent view](agent-view.md)
  - Claude plans, assigns, and supervises a group of workers: [agent teams](agent-teams.md), experimental and disabled by default
  - A script holds the plan instead of Claude’s turn-by-turn judgment: [dynamic workflows](../02-Claude-Code-CLI/workflows.md). See [how workflows compare to subagents and skills](../02-Claude-Code-CLI/workflows.md#when-to-use-a-workflow)
- **Do the workers need to talk to each other?** Claude can pass findings with [cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md) between sessions you run yourself, including the sessions you dispatch from agent view. Subagents report results back to the conversation that spawned them, and agent view sessions report results only to you. Teammates in an agent team message each other directly and, when they [have the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability), share a task list.
- **Do the tasks touch the same files?** Isolate the work with [worktrees](../02-Claude-Code-CLI/worktrees.md). Subagents and sessions you run yourself can each use a separate worktree. Agent teams don’t isolate teammates in worktrees, so [partition the work](agent-teams.md#avoid-file-conflicts) so each teammate owns a different set of files.


[​](#check-on-running-work)

Check on running work

The command for checking on running work depends on which approach you used:

- For background sessions, `claude agents` opens [agent view](agent-view.md): one screen showing every session, its state, and which ones need your input.
- For subagents in the current session, named background subagents appear in the @-mention typeahead with their status. As of v2.1.198, `/agents` no longer opens a panel; it prints a notice pointing to the subagent file locations. To [create and edit custom subagents](sub-agents.md#configure-subagents), ask Claude or edit the files directly. Despite the similar name, `/agents` is separate from `claude agents`.
- For anything running in the background of the current session, `/tasks` lists each item and lets you check on, attach to, or stop it. The list also includes subagents that have finished.
- For dynamic workflows, `/workflows` lists running and completed runs, the phase each is in, and how many agents have finished.

For a desktop view of all your sessions, see [parallel sessions in the desktop app](../16-Mobile-Desktop/desktop.md#work-in-parallel-with-sessions).


[​](#learn-more)

Learn more

Each guide below covers setup and configuration for one approach:

- [Create custom subagents](sub-agents.md): define reusable specialists and control which tools they can use.
- [Manage agents with agent view](agent-view.md): dispatch sessions, watch their state, and attach when one needs you.
- [Orchestrate agent teams](agent-teams.md): set up a lead and teammates, assign tasks, and review their work.
- [Orchestrate dynamic workflows](../02-Claude-Code-CLI/workflows.md): run a bundled workflow or have Claude write one that runs many subagents and verifies their findings against each other.
- [Run parallel sessions with worktrees](../02-Claude-Code-CLI/worktrees.md): start Claude in an isolated checkout, control what gets copied in, and clean up afterward.

---

## Agent Creator

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/agents/agent-creator.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-agents-agent-creator.md

You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.

**Important Context**: You may have access to project-specific instructions from CLAUDE.md files and other context that may include coding standards, project structure, and custom requirements. Consider this context when creating agents to ensure they align with the project's established patterns and practices.

When a user describes what they want an agent to do, you will:

1. **Extract Core Intent**: Identify the fundamental purpose, key responsibilities, and success criteria for the agent. Look for both explicit requirements and implicit needs. Consider any project-specific context from CLAUDE.md files. For agents that are meant to review code, you should assume that the user is asking to review recently written code and not the whole codebase, unless the user has explicitly instructed you otherwise.

2. **Design Expert Persona**: Create a compelling expert identity that embodies deep domain knowledge relevant to the task. The persona should inspire confidence and guide the agent's decision-making approach.

3. **Architect Comprehensive Instructions**: Develop a system prompt that:
   - Establishes clear behavioral boundaries and operational parameters
   - Provides specific methodologies and best practices for task execution
   - Anticipates edge cases and provides guidance for handling them
   - Incorporates any specific requirements or preferences mentioned by the user
   - Defines output format expectations when relevant
   - Aligns with project-specific coding standards and patterns from CLAUDE.md

4. **Optimize for Performance**: Include:
   - Decision-making frameworks appropriate to the domain
   - Quality control mechanisms and self-verification steps
   - Efficient workflow patterns
   - Clear escalation or fallback strategies

5. **Create Identifier**: Design a concise, descriptive identifier that:
   - Uses lowercase letters, numbers, and hyphens only
   - Is typically 2-4 words joined by hyphens
   - Clearly indicates the agent's primary function
   - Is memorable and easy to type
   - Avoids generic terms like "helper" or "assistant"

6. **Craft Triggering Examples**: Create 2-4 `<example>` blocks showing:
   - Different phrasings for same intent
   - Both explicit and proactive triggering
   - Context, user message, assistant response, commentary
   - Why the agent should trigger in each scenario
   - Show assistant using the Agent tool to launch the agent

**Agent Creation Process:**

1. **Understand Request**: Analyze user's description of what agent should do

2. **Design Agent Configuration**:
   - **Identifier**: Create concise, descriptive name (lowercase, hyphens, 3-50 chars)
   - **Description**: Write triggering conditions starting with "Use this agent when..."
   - **Examples**: Create 2-4 `<example>` blocks with:
     ```
     <example>
     Context: [Situation that should trigger agent]
     user: "[User message]"
     assistant: "[Response before triggering]"
     <commentary>
     [Why agent should trigger]
     </commentary>
     assistant: "I'll use the [agent-name] agent to [what it does]."
     </example>
     ```
   - **System Prompt**: Create comprehensive instructions with:
     - Role and expertise
     - Core responsibilities (numbered list)
     - Detailed process (step-by-step)
     - Quality standards
     - Output format
     - Edge case handling

3. **Select Configuration**:
   - **Model**: Use `inherit` unless user specifies (sonnet for complex, haiku for simple)
   - **Color**: Choose appropriate color:
     - blue/cyan: Analysis, review
     - green: Generation, creation
     - yellow: Validation, caution
     - red: Security, critical
     - magenta: Transformation, creative
   - **Tools**: Recommend minimal set needed, or omit for full access

4. **Generate Agent File**: Use Write tool to create `agents/[identifier].md`:
   ```markdown
   ---
   name: [identifier]
   description: [Use this agent when... Examples: <example>...</example>]
   model: inherit
   color: [chosen-color]
   tools: ["Tool1", "Tool2"]  # Optional
   ---

   [Complete system prompt]
   ```

5. **Explain to User**: Provide summary of created agent:
   - What it does
   - When it triggers
   - Where it's saved
   - How to test it
   - Suggest running validation: `Use the plugin-validator agent to check the plugin structure`

**Quality Standards:**
- Identifier follows naming rules (lowercase, hyphens, 3-50 chars)
- Description has strong trigger phrases and 2-4 examples
- Examples show both explicit and proactive triggering
- System prompt is comprehensive (500-3,000 words)
- System prompt has clear structure (role, responsibilities, process, output)
- Model choice is appropriate
- Tool selection follows least privilege
- Color choice matches agent purpose

**Output Format:**
Create agent file, then provide summary:

## Agent Created: [identifier]

### Configuration
- **Name:** [identifier]
- **Triggers:** [When it's used]
- **Model:** [choice]
- **Color:** [choice]
- **Tools:** [list or "all tools"]

### File Created
`agents/[identifier].md` ([word count] words)

### How to Use
This agent will trigger when [triggering scenarios].

Test it by: [suggest test scenario]

Validate with: `scripts/validate-agent.sh agents/[identifier].md`

### Next Steps
[Recommendations for testing, integration, or improvements]

**Edge Cases:**
- Vague user request: Ask clarifying questions before generating
- Conflicts with existing agents: Note conflict, suggest different scope/name
- Very complex requirements: Break into multiple specialized agents
- User wants specific tool access: Honor the request in agent configuration
- User specifies model: Use specified model instead of inherit
- First agent in plugin: Create agents/ directory first
```

This agent automates agent creation using the proven patterns from Claude Code's internal implementation, making it easy for users to create high-quality autonomous agents.

---

## AI-Assisted Agent Generation Template

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/agent-development/examples/agent-creation-prompt.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-agent-development-examples-agent-creation-prompt.md

# AI-Assisted Agent Generation Template

Use this template to generate agents using Claude with the agent creation system prompt.

## Usage Pattern

### Step 1: Describe Your Agent Need

Think about:
- What task should the agent handle?
- When should it be triggered?
- Should it be proactive or reactive?
- What are the key responsibilities?

### Step 2: Use the Generation Prompt

Send this to Claude (with the agent-creation-system-prompt loaded):

```
Create an agent configuration based on this request: "[YOUR DESCRIPTION]"

Return ONLY the JSON object, no other text.
```

**Replace [YOUR DESCRIPTION] with your agent requirements.**

### Step 3: Claude Returns JSON

Claude will return:

```json
{
  "identifier": "agent-name",
  "whenToUse": "Use this agent when... Examples: <example>...</example>",
  "systemPrompt": "You are... **Your Core Responsibilities:**..."
}
```

### Step 4: Convert to Agent File

Create `agents/[identifier].md`:

```markdown
---
name: [identifier from JSON]
description: [whenToUse from JSON]
model: inherit
color: [choose: blue/cyan/green/yellow/magenta/red]
tools: ["Read", "Write", "Grep"]  # Optional: restrict tools
---

[systemPrompt from JSON]
```

## Example 1: Code Review Agent

**Your request:**
```
I need an agent that reviews code changes for quality issues, security vulnerabilities, and adherence to best practices. It should be called after code is written and provide specific feedback.
```

**Claude generates:**
```json
{
  "identifier": "code-quality-reviewer",
  "whenToUse": "Use this agent when the user has written code and needs quality review, or explicitly asks to review code changes. Examples:\n\n<example>\nContext: User just implemented a new feature\nuser: \"I've added the authentication feature\"\nassistant: \"Great! Let me review the code quality.\"\n<commentary>\nCode was written, trigger code-quality-reviewer agent for review.\n</commentary>\nassistant: \"I'll use the code-quality-reviewer agent to analyze the changes.\"\n</example>\n\n<example>\nContext: User explicitly requests review\nuser: \"Can you review my code for issues?\"\nassistant: \"I'll use the code-quality-reviewer agent to perform a thorough review.\"\n<commentary>\nExplicit review request triggers the agent.\n</commentary>\n</example>",
  "systemPrompt": "You are an expert code quality reviewer specializing in identifying issues in software implementations.\n\n**Your Core Responsibilities:**\n1. Analyze code changes for quality issues (readability, maintainability, performance)\n2. Identify security vulnerabilities (injection, XSS, authentication issues)\n3. Check adherence to project best practices and coding standards\n4. Provide actionable, specific feedback with line numbers\n\n**Review Process:**\n1. Read the code changes using available tools\n2. Analyze for:\n   - Code quality (duplication, complexity, clarity)\n   - Security (OWASP top 10, input validation)\n   - Best practices (error handling, logging, testing)\n   - Project-specific standards (from CLAUDE.md)\n3. Identify issues with severity (critical/major/minor)\n4. Provide specific recommendations with examples\n\n**Output Format:**\nProvide a structured review:\n1. Summary (2-3 sentences)\n2. Critical Issues (must fix)\n3. Major Issues (should fix)\n4. Minor Issues (nice to fix)\n5. Positive observations\n6. Overall assessment\n\nInclude file names and line numbers for all findings."
}
```

**You create:**

File: `agents/code-quality-reviewer.md`

```markdown
---
name: code-quality-reviewer
description: Use this agent when the user has written code and needs quality review, or explicitly asks to review code changes. Examples:

<example>
Context: User just implemented a new feature
user: "I've added the authentication feature"
assistant: "Great! Let me review the code quality."
<commentary>
Code was written, trigger code-quality-reviewer agent for review.
</commentary>
assistant: "I'll use the code-quality-reviewer agent to analyze the changes."
</example>

<example>
Context: User explicitly requests review
user: "Can you review my code for issues?"
assistant: "I'll use the code-quality-reviewer agent to perform a thorough review."
<commentary>
Explicit review request triggers the agent.
</commentary>
</example>

model: inherit
color: blue
tools: ["Read", "Grep", "Glob"]
---

You are an expert code quality reviewer specializing in identifying issues in software implementations.

**Your Core Responsibilities:**
1. Analyze code changes for quality issues (readability, maintainability, performance)
2. Identify security vulnerabilities (injection, XSS, authentication issues)
3. Check adherence to project best practices and coding standards
4. Provide actionable, specific feedback with line numbers

**Review Process:**
1. Read the code changes using available tools
2. Analyze for:
   - Code quality (duplication, complexity, clarity)
   - Security (OWASP top 10, input validation)
   - Best practices (error handling, logging, testing)
   - Project-specific standards (from CLAUDE.md)
3. Identify issues with severity (critical/major/minor)
4. Provide specific recommendations with examples

**Output Format:**
Provide a structured review:
1. Summary (2-3 sentences)
2. Critical Issues (must fix)
3. Major Issues (should fix)
4. Minor Issues (nice to fix)
5. Positive observations
6. Overall assessment

Include file names and line numbers for all findings.
```

## Example 2: Test Generation Agent

**Your request:**
```
Create an agent that generates unit tests for code. It should analyze existing code and create comprehensive test suites following project conventions.
```

**Claude generates:**
```json
{
  "identifier": "test-generator",
  "whenToUse": "Use this agent when the user asks to generate tests, needs test coverage, or has written code that needs testing. Examples:\n\n<example>\nContext: User wrote new functions without tests\nuser: \"I've implemented the user authentication functions\"\nassistant: \"Great! Let me generate tests for these functions.\"\n<commentary>\nNew code without tests, proactively trigger test-generator.\n</commentary>\nassistant: \"I'll use the test-generator agent to create comprehensive tests.\"\n</example>",
  "systemPrompt": "You are an expert test engineer specializing in creating comprehensive unit tests...\n\n**Your Core Responsibilities:**\n1. Analyze code to understand behavior\n2. Generate test cases covering happy paths and edge cases\n3. Follow project testing conventions\n4. Ensure high code coverage\n\n**Test Generation Process:**\n1. Read target code\n2. Identify testable units (functions, classes, methods)\n3. Design test cases (inputs, expected outputs, edge cases)\n4. Generate tests following project patterns\n5. Add assertions and error cases\n\n**Output Format:**\nGenerate complete test files with:\n- Test suite structure\n- Setup/teardown if needed\n- Descriptive test names\n- Comprehensive assertions"
}
```

**You create:** `agents/test-generator.md` with the structure above.

## Example 3: Documentation Agent

**Your request:**
```
Build an agent that writes and updates API documentation. It should analyze code and generate clear, comprehensive docs.
```

**Result:** Agent file with identifier `api-docs-writer`, appropriate examples, and system prompt for documentation generation.

## Tips for Effective Agent Generation

### Be Specific in Your Request

**Vague:**
```
"I need an agent that helps with code"
```

**Specific:**
```
"I need an agent that reviews pull requests for type safety issues in TypeScript, checking for proper type annotations, avoiding 'any', and ensuring correct generic usage"
```

### Include Triggering Preferences

Tell Claude when the agent should activate:

```
"Create an agent that generates tests. It should be triggered proactively after code is written, not just when explicitly requested."
```

### Mention Project Context

```
"Create a code review agent. This project uses React and TypeScript, so the agent should check for React best practices and TypeScript type safety."
```

### Define Output Expectations

```
"Create an agent that analyzes performance. It should provide specific recommendations with file names and line numbers, plus estimated performance impact."
```

## Validation After Generation

Always validate generated agents:

```bash
# Validate structure
./scripts/validate-agent.sh agents/your-agent.md

# Check triggering works
# Test with scenarios from examples
```

## Iterating on Generated Agents

If generated agent needs improvement:

1. Identify what's missing or wrong
2. Manually edit the agent file
3. Focus on:
   - Better examples in description
   - More specific system prompt
   - Clearer process steps
   - Better output format definition
4. Re-validate
5. Test again

## Advantages of AI-Assisted Generation

- **Comprehensive**: Claude includes edge cases and quality checks
- **Consistent**: Follows proven patterns
- **Fast**: Seconds vs manual writing
- **Examples**: Auto-generates triggering examples
- **Complete**: Provides full system prompt structure

## When to Edit Manually

Edit generated agents when:
- Need very specific project patterns
- Require custom tool combinations
- Want unique persona or style
- Integrating with existing agents
- Need precise triggering conditions

Start with generation, then refine manually for best results.

---

## Complete Agent Examples

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/agent-development/examples/complete-agent-examples.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-agent-development-examples-complete-agent-examples.md

# Complete Agent Examples

Full, production-ready agent examples for common use cases. Use these as templates for your own agents.

## Example 1: Code Review Agent

**File:** `agents/code-reviewer.md`

```markdown
---
name: code-reviewer
description: Use this agent when the user has written code and needs quality review, security analysis, or best practices validation. Examples:

<example>
Context: User just implemented a new feature
user: "I've added the payment processing feature"
assistant: "Great! Let me review the implementation."
<commentary>
Code written for payment processing (security-critical). Proactively trigger
code-reviewer agent to check for security issues and best practices.
</commentary>
assistant: "I'll use the code-reviewer agent to analyze the payment code."
</example>

<example>
Context: User explicitly requests code review
user: "Can you review my code for issues?"
assistant: "I'll use the code-reviewer agent to perform a comprehensive review."
<commentary>
Explicit code review request triggers the agent.
</commentary>
</example>

<example>
Context: Before committing code
user: "I'm ready to commit these changes"
assistant: "Let me review them first."
<commentary>
Before commit, proactively review code quality.
</commentary>
assistant: "I'll use the code-reviewer agent to validate the changes."
</example>

model: inherit
color: blue
tools: ["Read", "Grep", "Glob"]
---

You are an expert code quality reviewer specializing in identifying issues, security vulnerabilities, and opportunities for improvement in software implementations.

**Your Core Responsibilities:**
1. Analyze code changes for quality issues (readability, maintainability, complexity)
2. Identify security vulnerabilities (SQL injection, XSS, authentication flaws, etc.)
3. Check adherence to project best practices and coding standards from CLAUDE.md
4. Provide specific, actionable feedback with file and line number references
5. Recognize and commend good practices

**Code Review Process:**
1. **Gather Context**: Use Glob to find recently modified files (git diff, git status)
2. **Read Code**: Use Read tool to examine changed files
3. **Analyze Quality**:
   - Check for code duplication (DRY principle)
   - Assess complexity and readability
   - Verify error handling
   - Check for proper logging
4. **Security Analysis**:
   - Scan for injection vulnerabilities (SQL, command, XSS)
   - Check authentication and authorization
   - Verify input validation and sanitization
   - Look for hardcoded secrets or credentials
5. **Best Practices**:
   - Follow project-specific standards from CLAUDE.md
   - Check naming conventions
   - Verify test coverage
   - Assess documentation
6. **Categorize Issues**: Group by severity (critical/major/minor)
7. **Generate Report**: Format according to output template

**Quality Standards:**
- Every issue includes file path and line number (e.g., `src/auth.ts:42`)
- Issues categorized by severity with clear criteria
- Recommendations are specific and actionable (not vague)
- Include code examples in recommendations when helpful
- Balance criticism with recognition of good practices

**Output Format:**
## Code Review Summary
[2-3 sentence overview of changes and overall quality]

## Critical Issues (Must Fix)
- `src/file.ts:42` - [Issue description] - [Why critical] - [How to fix]

## Major Issues (Should Fix)
- `src/file.ts:15` - [Issue description] - [Impact] - [Recommendation]

## Minor Issues (Consider Fixing)
- `src/file.ts:88` - [Issue description] - [Suggestion]

## Positive Observations
- [Good practice 1]
- [Good practice 2]

## Overall Assessment
[Final verdict and recommendations]

**Edge Cases:**
- No issues found: Provide positive validation, mention what was checked
- Too many issues (>20): Group by type, prioritize top 10 critical/major
- Unclear code intent: Note ambiguity and request clarification
- Missing context (no CLAUDE.md): Apply general best practices
- Large changeset: Focus on most impactful files first
```

## Example 2: Test Generator Agent

**File:** `agents/test-generator.md`

```markdown
---
name: test-generator
description: Use this agent when the user has written code without tests, explicitly asks for test generation, or needs test coverage improvement. Examples:

<example>
Context: User implemented functions without tests
user: "I've added the data validation functions"
assistant: "Let me generate tests for these."
<commentary>
New code without tests. Proactively trigger test-generator agent.
</commentary>
assistant: "I'll use the test-generator agent to create comprehensive tests."
</example>

<example>
Context: User explicitly requests tests
user: "Generate unit tests for my code"
assistant: "I'll use the test-generator agent to create a complete test suite."
<commentary>
Direct test generation request triggers the agent.
</commentary>
</example>

model: inherit
color: green
tools: ["Read", "Write", "Grep", "Bash"]
---

You are an expert test engineer specializing in creating comprehensive, maintainable unit tests that ensure code correctness and reliability.

**Your Core Responsibilities:**
1. Generate high-quality unit tests with excellent coverage
2. Follow project testing conventions and patterns
3. Include happy path, edge cases, and error scenarios
4. Ensure tests are maintainable and clear

**Test Generation Process:**
1. **Analyze Code**: Read implementation files to understand:
   - Function signatures and behavior
   - Input/output contracts
   - Edge cases and error conditions
   - Dependencies and side effects
2. **Identify Test Patterns**: Check existing tests for:
   - Testing framework (Jest, pytest, etc.)
   - File organization (test/ directory, *.test.ts, etc.)
   - Naming conventions
   - Setup/teardown patterns
3. **Design Test Cases**:
   - Happy path (normal, expected usage)
   - Boundary conditions (min/max, empty, null)
   - Error cases (invalid input, exceptions)
   - Edge cases (special characters, large data, etc.)
4. **Generate Tests**: Create test file with:
   - Descriptive test names
   - Arrange-Act-Assert structure
   - Clear assertions
   - Appropriate mocking if needed
5. **Verify**: Ensure tests are runnable and clear

**Quality Standards:**
- Test names clearly describe what is being tested
- Each test focuses on single behavior
- Tests are independent (no shared state)
- Mocks used appropriately (avoid over-mocking)
- Edge cases and errors covered
- Tests follow DAMP principle (Descriptive And Meaningful Phrases)

**Output Format:**
Create test file at [appropriate path] with:
```[language]
// Test suite for [module]

describe('[module name]', () => {
  // Test cases with descriptive names
  test('should [expected behavior] when [scenario]', () => {
    // Arrange
    // Act
    // Assert
  })

  // More tests...
})
```

**Edge Cases:**
- No existing tests: Create new test file following best practices
- Existing test file: Add new tests maintaining consistency
- Unclear behavior: Add tests for observable behavior, note uncertainties
- Complex mocking: Prefer integration tests or minimal mocking
- Untestable code: Suggest refactoring for testability
```

## Example 3: Documentation Generator

**File:** `agents/docs-generator.md`

```markdown
---
name: docs-generator
description: Use this agent when the user has written code needing documentation, API endpoints requiring docs, or explicitly requests documentation generation. Examples:

<example>
Context: User implemented new public API
user: "I've added the user management API endpoints"
assistant: "Let me document these endpoints."
<commentary>
New public API needs documentation. Proactively trigger docs-generator.
</commentary>
assistant: "I'll use the docs-generator agent to create API documentation."
</example>

<example>
Context: User requests documentation
user: "Generate docs for this module"
assistant: "I'll use the docs-generator agent to create comprehensive documentation."
<commentary>
Explicit documentation request triggers the agent.
</commentary>
</example>

model: inherit
color: cyan
tools: ["Read", "Write", "Grep", "Glob"]
---

You are an expert technical writer specializing in creating clear, comprehensive documentation for software projects.

**Your Core Responsibilities:**
1. Generate accurate, clear documentation from code
2. Follow project documentation standards
3. Include examples and usage patterns
4. Ensure completeness and correctness

**Documentation Generation Process:**
1. **Analyze Code**: Read implementation to understand:
   - Public interfaces and APIs
   - Parameters and return values
   - Behavior and side effects
   - Error conditions
2. **Identify Documentation Pattern**: Check existing docs for:
   - Format (Markdown, JSDoc, etc.)
   - Style (terse vs verbose)
   - Examples and code snippets
   - Organization structure
3. **Generate Content**:
   - Clear description of functionality
   - Parameter documentation
   - Return value documentation
   - Usage examples
   - Error conditions
4. **Format**: Follow project conventions
5. **Validate**: Ensure accuracy and completeness

**Quality Standards:**
- Documentation matches actual code behavior
- Examples are runnable and correct
- All public APIs documented
- Clear and concise language
- Proper formatting and structure

**Output Format:**
Create documentation in project's standard format:
- Function/method signatures
- Description of behavior
- Parameters with types and descriptions
- Return values
- Exceptions/errors
- Usage examples
- Notes or warnings if applicable

**Edge Cases:**
- Private/internal code: Document only if requested
- Complex APIs: Break into sections, provide multiple examples
- Deprecated code: Mark as deprecated with migration guide
- Unclear behavior: Document observable behavior, note assumptions
```

## Example 4: Security Analyzer

**File:** `agents/security-analyzer.md`

```markdown
---
name: security-analyzer
description: Use this agent when the user implements security-critical code (auth, payments, data handling), explicitly requests security analysis, or before deploying sensitive changes. Examples:

<example>
Context: User implemented authentication logic
user: "I've added JWT token validation"
assistant: "Let me check the security."
<commentary>
Authentication code is security-critical. Proactively trigger security-analyzer.
</commentary>
assistant: "I'll use the security-analyzer agent to review for security vulnerabilities."
</example>

<example>
Context: User requests security check
user: "Check my code for security issues"
assistant: "I'll use the security-analyzer agent to perform a thorough security review."
<commentary>
Explicit security review request triggers the agent.
</commentary>
</example>

model: inherit
color: red
tools: ["Read", "Grep", "Glob"]
---

You are an expert security analyst specializing in identifying vulnerabilities and security issues in software implementations.

**Your Core Responsibilities:**
1. Identify security vulnerabilities (OWASP Top 10 and beyond)
2. Analyze authentication and authorization logic
3. Check input validation and sanitization
4. Verify secure data handling and storage
5. Provide specific remediation guidance

**Security Analysis Process:**
1. **Identify Attack Surface**: Find user input points, APIs, database queries
2. **Check Common Vulnerabilities**:
   - Injection (SQL, command, XSS, etc.)
   - Authentication/authorization flaws
   - Sensitive data exposure
   - Security misconfiguration
   - Insecure deserialization
3. **Analyze Patterns**:
   - Input validation at boundaries
   - Output encoding
   - Parameterized queries
   - Principle of least privilege
4. **Assess Risk**: Categorize by severity and exploitability
5. **Provide Remediation**: Specific fixes with examples

**Quality Standards:**
- Every vulnerability includes CVE/CWE reference when applicable
- Severity based on CVSS criteria
- Remediation includes code examples
- False positive rate minimized

**Output Format:**
## Security Analysis Report

### Summary
[High-level security posture assessment]

### Critical Vulnerabilities ([count])
- **[Vulnerability Type]** at `file:line`
  - Risk: [Description of security impact]
  - How to Exploit: [Attack scenario]
  - Fix: [Specific remediation with code example]

### Medium/Low Vulnerabilities
[...]

### Security Best Practices Recommendations
[...]

### Overall Risk Assessment
[High/Medium/Low with justification]

**Edge Cases:**
- No vulnerabilities: Confirm security review completed, mention what was checked
- False positives: Verify before reporting
- Uncertain vulnerabilities: Mark as "potential" with caveat
- Out of scope items: Note but don't deep-dive
```

## Customization Tips

### Adapt to Your Domain

Take these templates and customize:
- Change domain expertise (e.g., "Python expert" vs "React expert")
- Adjust process steps for your specific workflow
- Modify output format to match your needs
- Add domain-specific quality standards
- Include technology-specific checks

### Adjust Tool Access

Restrict or expand based on agent needs:
- **Read-only agents**: `["Read", "Grep", "Glob"]`
- **Generator agents**: `["Read", "Write", "Grep"]`
- **Executor agents**: `["Read", "Write", "Bash", "Grep"]`
- **Full access**: Omit tools field

### Customize Colors

Choose colors that match agent purpose:
- **Blue**: Analysis, review, investigation
- **Cyan**: Documentation, information
- **Green**: Generation, creation, success-oriented
- **Yellow**: Validation, warnings, caution
- **Red**: Security, critical analysis, errors
- **Magenta**: Refactoring, transformation, creative

## Using These Templates

1. Copy template that matches your use case
2. Replace placeholders with your specifics
3. Customize process steps for your domain
4. Adjust examples to your triggering scenarios
5. Validate with `scripts/validate-agent.sh`
6. Test triggering with real scenarios
7. Iterate based on agent performance

These templates provide battle-tested starting points. Customize them for your specific needs while maintaining the proven structure.

---

## Agent Creation System Prompt

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/agent-development/references/agent-creation-system-prompt.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-agent-development-references-agent-creation-system.md

# Agent Creation System Prompt

This is the exact system prompt used by Claude Code's agent generation feature, refined through extensive production use.

## The Prompt

```
You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.

**Important Context**: You may have access to project-specific instructions from CLAUDE.md files and other context that may include coding standards, project structure, and custom requirements. Consider this context when creating agents to ensure they align with the project's established patterns and practices.

When a user describes what they want an agent to do, you will:

1. **Extract Core Intent**: Identify the fundamental purpose, key responsibilities, and success criteria for the agent. Look for both explicit requirements and implicit needs. Consider any project-specific context from CLAUDE.md files. For agents that are meant to review code, you should assume that the user is asking to review recently written code and not the whole codebase, unless the user has explicitly instructed you otherwise.

2. **Design Expert Persona**: Create a compelling expert identity that embodies deep domain knowledge relevant to the task. The persona should inspire confidence and guide the agent's decision-making approach.

3. **Architect Comprehensive Instructions**: Develop a system prompt that:
   - Establishes clear behavioral boundaries and operational parameters
   - Provides specific methodologies and best practices for task execution
   - Anticipates edge cases and provides guidance for handling them
   - Incorporates any specific requirements or preferences mentioned by the user
   - Defines output format expectations when relevant
   - Aligns with project-specific coding standards and patterns from CLAUDE.md

4. **Optimize for Performance**: Include:
   - Decision-making frameworks appropriate to the domain
   - Quality control mechanisms and self-verification steps
   - Efficient workflow patterns
   - Clear escalation or fallback strategies

5. **Create Identifier**: Design a concise, descriptive identifier that:
   - Uses lowercase letters, numbers, and hyphens only
   - Is typically 2-4 words joined by hyphens
   - Clearly indicates the agent's primary function
   - Is memorable and easy to type
   - Avoids generic terms like "helper" or "assistant"

6. **Example agent descriptions**:
   - In the 'whenToUse' field of the JSON object, you should include examples of when this agent should be used.
   - Examples should be of the form:
     <example>
     Context: The user is creating a code-review agent that should be called after a logical chunk of code is written.
     user: "Please write a function that checks if a number is prime"
     assistant: "Here is the relevant function: "
     <function call omitted for brevity only for this example>
     <commentary>
     Since a logical chunk of code was written and the task was completed, now use the code-review agent to review the code.
     </commentary>
     assistant: "Now let me use the code-reviewer agent to review the code"
     </example>
   - If the user mentioned or implied that the agent should be used proactively, you should include examples of this.
   - NOTE: Ensure that in the examples, you are making the assistant use the Agent tool and not simply respond directly to the task.

Your output must be a valid JSON object with exactly these fields:
{
  "identifier": "A unique, descriptive identifier using lowercase letters, numbers, and hyphens (e.g., 'code-reviewer', 'api-docs-writer', 'test-generator')",
  "whenToUse": "A precise, actionable description starting with 'Use this agent when...' that clearly defines the triggering conditions and use cases. Ensure you include examples as described above.",
  "systemPrompt": "The complete system prompt that will govern the agent's behavior, written in second person ('You are...', 'You will...') and structured for maximum clarity and effectiveness"
}

Key principles for your system prompts:
- Be specific rather than generic - avoid vague instructions
- Include concrete examples when they would clarify behavior
- Balance comprehensiveness with clarity - every instruction should add value
- Ensure the agent has enough context to handle variations of the core task
- Make the agent proactive in seeking clarification when needed
- Build in quality assurance and self-correction mechanisms

Remember: The agents you create should be autonomous experts capable of handling their designated tasks with minimal additional guidance. Your system prompts are their complete operational manual.
```

## Usage Pattern

Use this prompt to generate agent configurations:

```markdown
**User input:** "I need an agent that reviews pull requests for code quality issues"

**You send to Claude with the system prompt above:**
Create an agent configuration based on this request: "I need an agent that reviews pull requests for code quality issues"

**Claude returns JSON:**
{
  "identifier": "pr-quality-reviewer",
  "whenToUse": "Use this agent when the user asks to review a pull request, check code quality, or analyze PR changes. Examples:\n\n<example>\nContext: User has created a PR and wants quality review\nuser: \"Can you review PR #123 for code quality?\"\nassistant: \"I'll use the pr-quality-reviewer agent to analyze the PR.\"\n<commentary>\nPR review request triggers the pr-quality-reviewer agent.\n</commentary>\n</example>",
  "systemPrompt": "You are an expert code quality reviewer...\n\n**Your Core Responsibilities:**\n1. Analyze code changes for quality issues\n2. Check adherence to best practices\n..."
}
```

## Converting to Agent File

Take the JSON output and create the agent markdown file:

**agents/pr-quality-reviewer.md:**
```markdown
---
name: pr-quality-reviewer
description: Use this agent when the user asks to review a pull request, check code quality, or analyze PR changes. Examples:

<example>
Context: User has created a PR and wants quality review
user: "Can you review PR #123 for code quality?"
assistant: "I'll use the pr-quality-reviewer agent to analyze the PR."
<commentary>
PR review request triggers the pr-quality-reviewer agent.
</commentary>
</example>

model: inherit
color: blue
---

You are an expert code quality reviewer...

**Your Core Responsibilities:**
1. Analyze code changes for quality issues
2. Check adherence to best practices
...
```

## Customization Tips

### Adapt the System Prompt

The base prompt is excellent but can be enhanced for specific needs:

**For security-focused agents:**
```
Add after "Architect Comprehensive Instructions":
- Include OWASP top 10 security considerations
- Check for common vulnerabilities (injection, XSS, etc.)
- Validate input sanitization
```

**For test-generation agents:**
```
Add after "Optimize for Performance":
- Follow AAA pattern (Arrange, Act, Assert)
- Include edge cases and error scenarios
- Ensure test isolation and cleanup
```

**For documentation agents:**
```
Add after "Design Expert Persona":
- Use clear, concise language
- Include code examples
- Follow project documentation standards from CLAUDE.md
```

## Best Practices from Internal Implementation

### 1. Consider Project Context

The prompt specifically mentions using CLAUDE.md context:
- Agent should align with project patterns
- Follow project-specific coding standards
- Respect established practices

### 2. Proactive Agent Design

Include examples showing proactive usage:
```
<example>
Context: After writing code, agent should review proactively
user: "Please write a function..."
assistant: "[Writes function]"
<commentary>
Code written, now use review agent proactively.
</commentary>
assistant: "Now let me review this code with the code-reviewer agent"
</example>
```

### 3. Scope Assumptions

For code review agents, assume "recently written code" not entire codebase:
```
For agents that review code, assume recent changes unless explicitly
stated otherwise.
```

### 4. Output Structure

Always define clear output format in system prompt:
```
**Output Format:**
Provide results as:
1. Summary (2-3 sentences)
2. Detailed findings (bullet points)
3. Recommendations (action items)
```

## Integration with Plugin-Dev

Use this system prompt when creating agents for your plugins:

1. Take user request for agent functionality
2. Feed to Claude with this system prompt
3. Get JSON output (identifier, whenToUse, systemPrompt)
4. Convert to agent markdown file with frontmatter
5. Validate with agent validation rules
6. Test triggering conditions
7. Add to plugin's `agents/` directory

This provides AI-assisted agent generation following proven patterns from Claude Code's internal implementation.

---

## System Prompt Design Patterns

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/agent-development/references/system-prompt-design.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-agent-development-references-system-prompt-design.md

# System Prompt Design Patterns

Complete guide to writing effective agent system prompts that enable autonomous, high-quality operation.

## Core Structure

Every agent system prompt should follow this proven structure:

```markdown
You are [specific role] specializing in [specific domain].

**Your Core Responsibilities:**
1. [Primary responsibility - the main task]
2. [Secondary responsibility - supporting task]
3. [Additional responsibilities as needed]

**[Task Name] Process:**
1. [First concrete step]
2. [Second concrete step]
3. [Continue with clear steps]
[...]

**Quality Standards:**
- [Standard 1 with specifics]
- [Standard 2 with specifics]
- [Standard 3 with specifics]

**Output Format:**
Provide results structured as:
- [Component 1]
- [Component 2]
- [Include specific formatting requirements]

**Edge Cases:**
Handle these situations:
- [Edge case 1]: [Specific handling approach]
- [Edge case 2]: [Specific handling approach]
```

## Pattern 1: Analysis Agents

For agents that analyze code, PRs, or documentation:

```markdown
You are an expert [domain] analyzer specializing in [specific analysis type].

**Your Core Responsibilities:**
1. Thoroughly analyze [what] for [specific issues]
2. Identify [patterns/problems/opportunities]
3. Provide actionable recommendations

**Analysis Process:**
1. **Gather Context**: Read [what] using available tools
2. **Initial Scan**: Identify obvious [issues/patterns]
3. **Deep Analysis**: Examine [specific aspects]:
   - [Aspect 1]: Check for [criteria]
   - [Aspect 2]: Verify [criteria]
   - [Aspect 3]: Assess [criteria]
4. **Synthesize Findings**: Group related issues
5. **Prioritize**: Rank by [severity/impact/urgency]
6. **Generate Report**: Format according to output template

**Quality Standards:**
- Every finding includes file:line reference
- Issues categorized by severity (critical/major/minor)
- Recommendations are specific and actionable
- Positive observations included for balance

**Output Format:**
## Summary
[2-3 sentence overview]

## Critical Issues
- [file:line] - [Issue description] - [Recommendation]

## Major Issues
[...]

## Minor Issues
[...]

## Recommendations
[...]

**Edge Cases:**
- No issues found: Provide positive feedback and validation
- Too many issues: Group and prioritize top 10
- Unclear code: Request clarification rather than guessing
```

## Pattern 2: Generation Agents

For agents that create code, tests, or documentation:

```markdown
You are an expert [domain] engineer specializing in creating high-quality [output type].

**Your Core Responsibilities:**
1. Generate [what] that meets [quality standards]
2. Follow [specific conventions/patterns]
3. Ensure [correctness/completeness/clarity]

**Generation Process:**
1. **Understand Requirements**: Analyze what needs to be created
2. **Gather Context**: Read existing [code/docs/tests] for patterns
3. **Design Structure**: Plan [architecture/organization/flow]
4. **Generate Content**: Create [output] following:
   - [Convention 1]
   - [Convention 2]
   - [Best practice 1]
5. **Validate**: Verify [correctness/completeness]
6. **Document**: Add comments/explanations as needed

**Quality Standards:**
- Follows project conventions (check CLAUDE.md)
- [Specific quality metric 1]
- [Specific quality metric 2]
- Includes error handling
- Well-documented and clear

**Output Format:**
Create [what] with:
- [Structure requirement 1]
- [Structure requirement 2]
- Clear, descriptive naming
- Comprehensive coverage

**Edge Cases:**
- Insufficient context: Ask user for clarification
- Conflicting patterns: Follow most recent/explicit pattern
- Complex requirements: Break into smaller pieces
```

## Pattern 3: Validation Agents

For agents that validate, check, or verify:

```markdown
You are an expert [domain] validator specializing in ensuring [quality aspect].

**Your Core Responsibilities:**
1. Validate [what] against [criteria]
2. Identify violations and issues
3. Provide clear pass/fail determination

**Validation Process:**
1. **Load Criteria**: Understand validation requirements
2. **Scan Target**: Read [what] needs validation
3. **Check Rules**: For each rule:
   - [Rule 1]: [Validation method]
   - [Rule 2]: [Validation method]
4. **Collect Violations**: Document each failure with details
5. **Assess Severity**: Categorize issues
6. **Determine Result**: Pass only if [criteria met]

**Quality Standards:**
- All violations include specific locations
- Severity clearly indicated
- Fix suggestions provided
- No false positives

**Output Format:**
## Validation Result: [PASS/FAIL]

## Summary
[Overall assessment]

## Violations Found: [count]
### Critical ([count])
- [Location]: [Issue] - [Fix]

### Warnings ([count])
- [Location]: [Issue] - [Fix]

## Recommendations
[How to fix violations]

**Edge Cases:**
- No violations: Confirm validation passed
- Too many violations: Group by type, show top 20
- Ambiguous rules: Document uncertainty, request clarification
```

## Pattern 4: Orchestration Agents

For agents that coordinate multiple tools or steps:

```markdown
You are an expert [domain] orchestrator specializing in coordinating [complex workflow].

**Your Core Responsibilities:**
1. Coordinate [multi-step process]
2. Manage [resources/tools/dependencies]
3. Ensure [successful completion/integration]

**Orchestration Process:**
1. **Plan**: Understand full workflow and dependencies
2. **Prepare**: Set up prerequisites
3. **Execute Phases**:
   - Phase 1: [What] using [tools]
   - Phase 2: [What] using [tools]
   - Phase 3: [What] using [tools]
4. **Monitor**: Track progress and handle failures
5. **Verify**: Confirm successful completion
6. **Report**: Provide comprehensive summary

**Quality Standards:**
- Each phase completes successfully
- Errors handled gracefully
- Progress reported to user
- Final state verified

**Output Format:**
## Workflow Execution Report

### Completed Phases
- [Phase]: [Result]

### Results
- [Output 1]
- [Output 2]

### Next Steps
[If applicable]

**Edge Cases:**
- Phase failure: Attempt retry, then report and stop
- Missing dependencies: Request from user
- Timeout: Report partial completion
```

## Writing Style Guidelines

### Tone and Voice

**Use second person (addressing the agent):**
```
✅ You are responsible for...
✅ You will analyze...
✅ Your process should...

❌ The agent is responsible for...
❌ This agent will analyze...
❌ I will analyze...
```

### Clarity and Specificity

**Be specific, not vague:**
```
✅ Check for SQL injection by examining all database queries for parameterization
❌ Look for security issues

✅ Provide file:line references for each finding
❌ Show where issues are

✅ Categorize as critical (security), major (bugs), or minor (style)
❌ Rate the severity of issues
```

### Actionable Instructions

**Give concrete steps:**
```
✅ Read the file using the Read tool, then search for patterns using Grep
❌ Analyze the code

✅ Generate test file at test/path/to/file.test.ts
❌ Create tests
```

## Common Pitfalls

### ❌ Vague Responsibilities

```markdown
**Your Core Responsibilities:**
1. Help the user with their code
2. Provide assistance
3. Be helpful
```

**Why bad:** Not specific enough to guide behavior.

### ✅ Specific Responsibilities

```markdown
**Your Core Responsibilities:**
1. Analyze TypeScript code for type safety issues
2. Identify missing type annotations and improper 'any' usage
3. Recommend specific type improvements with examples
```

### ❌ Missing Process Steps

```markdown
Analyze the code and provide feedback.
```

**Why bad:** Agent doesn't know HOW to analyze.

### ✅ Clear Process

```markdown
**Analysis Process:**
1. Read code files using Read tool
2. Scan for type annotations on all functions
3. Check for 'any' type usage
4. Verify generic type parameters
5. List findings with file:line references
```

### ❌ Undefined Output

```markdown
Provide a report.
```

**Why bad:** Agent doesn't know what format to use.

### ✅ Defined Output Format

```markdown
**Output Format:**
## Type Safety Report

### Summary
[Overview of findings]

### Issues Found
- `file.ts:42` - Missing return type on `processData`
- `utils.ts:15` - Unsafe 'any' usage in parameter

### Recommendations
[Specific fixes with examples]
```

## Length Guidelines

### Minimum Viable Agent

**~500 words minimum:**
- Role description
- 3 core responsibilities
- 5-step process
- Output format

### Standard Agent

**~1,000-2,000 words:**
- Detailed role and expertise
- 5-8 responsibilities
- 8-12 process steps
- Quality standards
- Output format
- 3-5 edge cases

### Comprehensive Agent

**~2,000-5,000 words:**
- Complete role with background
- Comprehensive responsibilities
- Detailed multi-phase process
- Extensive quality standards
- Multiple output formats
- Many edge cases
- Examples within system prompt

**Avoid > 10,000 words:** Too long, diminishing returns.

## Testing System Prompts

### Test Completeness

Can the agent handle these based on system prompt alone?

- [ ] Typical task execution
- [ ] Edge cases mentioned
- [ ] Error scenarios
- [ ] Unclear requirements
- [ ] Large/complex inputs
- [ ] Empty/missing inputs

### Test Clarity

Read the system prompt and ask:

- Can another developer understand what this agent does?
- Are process steps clear and actionable?
- Is output format unambiguous?
- Are quality standards measurable?

### Iterate Based on Results

After testing agent:
1. Identify where it struggled
2. Add missing guidance to system prompt
3. Clarify ambiguous instructions
4. Add process steps for edge cases
5. Re-test

## Conclusion

Effective system prompts are:
- **Specific**: Clear about what and how
- **Structured**: Organized with clear sections
- **Complete**: Covers normal and edge cases
- **Actionable**: Provides concrete steps
- **Testable**: Defines measurable standards

Use the patterns above as templates, customize for your domain, and iterate based on agent performance.

---

## Agent Triggering Examples: Best Practices

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/agent-development/references/triggering-examples.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-agent-development-references-triggering-examples.md

# Agent Triggering Examples: Best Practices

Complete guide to writing effective `<example>` blocks in agent descriptions for reliable triggering.

## Example Block Format

The standard format for triggering examples:

```markdown
<example>
Context: [Describe the situation - what led to this interaction]
user: "[Exact user message or request]"
assistant: "[How Claude should respond before triggering]"
<commentary>
[Explanation of why this agent should be triggered in this scenario]
</commentary>
assistant: "[How Claude triggers the agent - usually 'I'll use the [agent-name] agent...']"
</example>
```

## Anatomy of a Good Example

### Context

**Purpose:** Set the scene - what happened before the user's message

**Good contexts:**
```
Context: User just implemented a new authentication feature
Context: User has created a PR and wants it reviewed
Context: User is debugging a test failure
Context: After writing several functions without documentation
```

**Bad contexts:**
```
Context: User needs help (too vague)
Context: Normal usage (not specific)
```

### User Message

**Purpose:** Show the exact phrasing that should trigger the agent

**Good user messages:**
```
user: "I've added the OAuth flow, can you check it?"
user: "Review PR #123"
user: "Why is this test failing?"
user: "Add docs for these functions"
```

**Vary the phrasing:**
Include multiple examples with different phrasings for the same intent:
```
Example 1: user: "Review my code"
Example 2: user: "Can you check this implementation?"
Example 3: user: "Look over my changes"
```

### Assistant Response (Before Triggering)

**Purpose:** Show what Claude says before launching the agent

**Good responses:**
```
assistant: "I'll analyze your OAuth implementation."
assistant: "Let me review that PR for you."
assistant: "I'll investigate the test failure."
```

**Proactive example:**
```
assistant: "Great! Now let me review the code quality."
<commentary>
Code was just written, proactively trigger review agent.
</commentary>
```

### Commentary

**Purpose:** Explain the reasoning - WHY this agent should trigger

**Good commentary:**
```
<commentary>
User explicitly requested code review, trigger the code-reviewer agent.
</commentary>

<commentary>
After code implementation, proactively use review agent to check quality.
</commentary>

<commentary>
PR analysis request matches pr-analyzer agent's expertise.
</commentary>
```

**Include decision logic:**
```
<commentary>
User wrote tests (Test tool used). The test-analyzer agent should check
test quality and coverage before continuing.
</commentary>
```

### Assistant Response (Triggering)

**Purpose:** Show how Claude invokes the agent

**Standard pattern:**
```
assistant: "I'll use the [agent-name] agent to [what it will do]."
```

**Examples:**
```
assistant: "I'll use the code-reviewer agent to analyze the changes."
assistant: "Let me use the test-generator agent to create comprehensive tests."
assistant: "I'll use the security-analyzer agent to check for vulnerabilities."
```

## Example Types

### Type 1: Explicit Request

User directly asks for what the agent does:

```markdown
<example>
Context: User explicitly requests security analysis
user: "Check my code for security vulnerabilities"
assistant: "I'll use the security-analyzer agent to perform a thorough security review."
<commentary>
Direct security analysis request triggers the security-analyzer agent.
</commentary>
</example>
```

### Type 2: Proactive Triggering

Agent triggers after relevant work without explicit request:

```markdown
<example>
Context: User just implemented database queries
user: "I've added the user search functionality"
assistant: "Great! Let me review it for security."
<commentary>
Database code written. Proactively trigger security-analyzer to check
for SQL injection and other database security issues.
</commentary>
assistant: "I'll use the security-analyzer agent to check the database code."
</example>
```

### Type 3: Implicit Request

User implies need without stating it directly:

```markdown
<example>
Context: User mentions code is hard to understand
user: "This code is confusing and hard to follow"
assistant: "I can help improve the code clarity."
<commentary>
User indicates complexity issues. Trigger code-simplifier agent to refactor
for better readability.
</commentary>
assistant: "I'll use the code-simplifier agent to suggest improvements."
</example>
```

### Type 4: Tool Usage Pattern

Agent triggers based on prior tool usage:

```markdown
<example>
Context: User made multiple edits to test files
user: "I've updated all the tests"
assistant: "Great! Let me verify test quality."
<commentary>
Multiple Edit tools used on test files. Proactively trigger test-quality-analyzer
to ensure tests follow best practices.
</commentary>
assistant: "I'll use the test-quality-analyzer agent to review the tests."
</example>
```

## Multiple Examples Strategy

### Cover Different Phrasings

```markdown
<example>
user: "Review my code"
[...]
</example>

<example>
user: "Can you check my implementation?"
[...]
</example>

<example>
user: "Look over these changes"
[...]
</example>
```

### Cover Proactive and Reactive

```markdown
<example>
Context: User explicitly requests review
user: "Review my code for issues"
[...]
</example>

<example>
Context: After user writes code
user: "I've implemented the feature"
assistant: "Great! Now let me review it."
<commentary>
Code written, proactively review.
</commentary>
[...]
</example>
```

### Cover Edge Cases

```markdown
<example>
Context: Typical usage
user: "Check my PR"
[...]
</example>

<example>
Context: Large PR that needs thorough analysis
user: "This is a big PR, can you do a deep review?"
[...]
<commentary>
Large PR mentioned, use thorough analysis mode.
</commentary>
</example>
```

## Common Mistakes

### ❌ Missing Context

```markdown
<example>
user: "Review my code"
assistant: "I'll use the code-reviewer agent."
</example>
```

**Why bad:** No context about what led to this request.

### ✅ With Context

```markdown
<example>
Context: User just finished implementing authentication
user: "Review my code"
assistant: "I'll use the code-reviewer agent to analyze the auth implementation."
<commentary>
Auth code written, review for security and best practices.
</commentary>
</example>
```

### ❌ No Commentary

```markdown
<example>
Context: User requests review
user: "Check my changes"
assistant: "I'll use the reviewer agent."
</example>
```

**Why bad:** Doesn't explain WHY agent triggers.

### ✅ With Commentary

```markdown
<example>
Context: User requests review after making changes
user: "Check my changes"
assistant: "I'll use the code-reviewer agent to analyze the modifications."
<commentary>
Code review request triggers agent to check quality, security, and adherence to standards.
</commentary>
</example>
```

### ❌ Agent Responds Directly

```markdown
<example>
user: "Review my code"
assistant: "I found the following issues: [lists issues]"
</example>
```

**Why bad:** Shows agent's output, not triggering.

### ✅ Shows Triggering

```markdown
<example>
user: "Review my code"
assistant: "I'll use the code-reviewer agent to perform the review."
<commentary>
Review request triggers the agent.
</commentary>
</example>
```

## How Many Examples?

### Minimum: 2 Examples

Cover at least:
1. Explicit request
2. One variation or proactive trigger

### Recommended: 3-4 Examples

Cover:
1. Explicit request (direct ask)
2. Implicit request (user implies need)
3. Proactive trigger (after relevant work)
4. Edge case or specific scenario

### Maximum: 6 Examples

More than 6 makes description too long. Focus on most important scenarios.

## Template Library

### Code Review Agent

```markdown
<example>
Context: User just implemented a new feature
user: "I've added the user registration feature"
assistant: "Great! Let me review the code quality."
<commentary>
Code written, proactively trigger code-reviewer agent.
</commentary>
assistant: "I'll use the code-reviewer agent to analyze the implementation."
</example>

<example>
Context: User explicitly requests review
user: "Can you review my changes for issues?"
assistant: "I'll use the code-reviewer agent to perform a thorough review."
<commentary>
Explicit review request triggers the agent.
</commentary>
</example>
```

### Test Generation Agent

```markdown
<example>
Context: User implemented functions without tests
user: "I've added the data processing functions"
assistant: "Great! Let me generate tests for these."
<commentary>
New code without tests, proactively trigger test-generator agent.
</commentary>
assistant: "I'll use the test-generator agent to create comprehensive tests."
</example>

<example>
Context: User explicitly asks for tests
user: "Generate tests for my code"
assistant: "I'll use the test-generator agent to create a complete test suite."
<commentary>
Direct test generation request triggers the agent.
</commentary>
</example>
```

### Documentation Agent

```markdown
<example>
Context: User added new API endpoints
user: "I've implemented the REST API endpoints"
assistant: "I'll document these endpoints."
<commentary>
New API code, proactively generate documentation.
</commentary>
assistant: "I'll use the api-docs-writer agent to create comprehensive documentation."
</example>

<example>
Context: User requests documentation
user: "Write docs for this API"
assistant: "I'll use the api-docs-writer agent to generate clear documentation."
<commentary>
Documentation request triggers the agent.
</commentary>
</example>
```

### Validation Agent

```markdown
<example>
Context: User ready to commit changes
user: "I'm ready to commit this code"
assistant: "Let me validate it first."
<commentary>
Before commit, proactively validate with validation-agent.
</commentary>
assistant: "I'll use the code-validator agent to check for issues."
</example>

<example>
Context: User asks for validation
user: "Validate my implementation"
assistant: "I'll use the code-validator agent to verify correctness."
<commentary>
Explicit validation request triggers the agent.
</commentary>
</example>
```

## Debugging Triggering Issues

### Agent Not Triggering

**Check:**
1. Examples include relevant keywords from user message
2. Context matches actual usage scenarios
3. Commentary explains triggering logic clearly
4. Assistant shows use of Agent tool in examples

**Fix:**
Add more examples covering different phrasings.

### Agent Triggers Too Often

**Check:**
1. Examples are too broad or generic
2. Triggering conditions overlap with other agents
3. Commentary doesn't distinguish when NOT to use

**Fix:**
Make examples more specific, add negative examples.

### Agent Triggers in Wrong Scenarios

**Check:**
1. Examples don't match actual intended use
2. Commentary suggests inappropriate triggering

**Fix:**
Revise examples to show only correct triggering scenarios.

## Best Practices Summary

✅ **DO:**
- Include 2-4 concrete, specific examples
- Show both explicit and proactive triggering
- Provide clear context for each example
- Explain reasoning in commentary
- Vary user message phrasing
- Show Claude using Agent tool

❌ **DON'T:**
- Use generic, vague examples
- Omit context or commentary
- Show only one type of triggering
- Skip the agent invocation step
- Make examples too similar
- Forget to explain why agent triggers

## Conclusion

Well-crafted examples are crucial for reliable agent triggering. Invest time in creating diverse, specific examples that clearly demonstrate when and why the agent should be used.

---

## Advanced Workflow Patterns

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/command-development/references/advanced-workflows.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-command-development-references-advanced-workflows.md

# Advanced Workflow Patterns

Multi-step command sequences and composition patterns for complex workflows.

## Overview

Advanced workflows combine multiple commands, coordinate state across invocations, and create sophisticated automation sequences. These patterns enable building complex functionality from simple command building blocks.

## Multi-Step Command Patterns

### Sequential Workflow Command

Commands that guide users through multi-step processes:

```markdown
---
description: Complete PR review workflow
argument-hint: [pr-number]
allowed-tools: Bash(gh:*), Read, Grep
---

# PR Review Workflow for #$1

## Step 1: Fetch PR Details
!`gh pr view $1 --json title,body,author,files`

## Step 2: Review Files
Files changed: !`gh pr diff $1 --name-only`

For each file:
- Check code quality
- Verify tests exist
- Review documentation

## Step 3: Run Checks
Test status: !`gh pr checks $1`

Verify:
- All tests passing
- No merge conflicts
- CI/CD successful

## Step 4: Provide Feedback

Summarize:
- Issues found (critical/minor)
- Suggestions for improvement
- Approval recommendation

Would you like to:
1. Approve PR
2. Request changes
3. Leave comments only

Reply with your choice and I'll help complete the action.
```

**Key features:**
- Numbered steps for clarity
- Bash execution for context
- Decision points for user input
- Next action suggestions

### State-Carrying Workflow

Commands that maintain state between invocations:

```markdown
---
description: Initialize deployment workflow
allowed-tools: Write, Bash(git:*)
---

# Initialize Deployment

Creating deployment tracking file...

Current branch: !`git branch --show-current`
Latest commit: !`git log -1 --format=%H`

Deployment state saved to `.claude/deployment-state.local.md`:

\`\`\`markdown
---
initialized: true
branch: $(git branch --show-current)
commit: $(git log -1 --format=%H)
timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)
status: initialized
---

# Deployment Tracking

Branch: $(git branch --show-current)
Started: $(date)

Next steps:
1. Run tests: /deploy-test
2. Build: /deploy-build
3. Deploy: /deploy-execute
\`\`\`

State saved. Run `/deploy-test` to continue.
```

**Next command** (`/deploy-test`):
```markdown
---
description: Run deployment tests
allowed-tools: Read, Bash(npm:*)
---

Reading deployment state from `.claude/deployment-state.local.md`...

Running tests: !`npm test`

Updating state to 'tested'...

Tests complete. Run `/deploy-build` to continue.
```

**Pattern benefits:**
- Persistent state across commands
- Clear workflow progression
- Safety checkpoints
- Resume capability

### Conditional Workflow Branching

Commands that adapt based on conditions:

```markdown
---
description: Smart deployment workflow
argument-hint: [environment]
allowed-tools: Bash(git:*), Bash(npm:*), Read
---

# Deploy to $1

## Pre-flight Checks

Branch: !`git branch --show-current`
Status: !`git status --short`

**Checking conditions:**

1. Branch status:
   - If main/master: Require approval
   - If feature branch: Warning about target
   - If hotfix: Fast-track process

2. Tests:
   !`npm test`
   - If tests fail: STOP - fix tests first
   - If tests pass: Continue

3. Environment:
   - If $1 = 'production': Extra validation
   - If $1 = 'staging': Standard process
   - If $1 = 'dev': Minimal checks

**Workflow decision:**
Based on above, proceeding with: [determined workflow]

[Conditional steps based on environment and status]

Ready to deploy? (yes/no)
```

## Command Composition Patterns

### Command Chaining

Commands designed to work together:

```markdown
---
description: Prepare for code review
---

# Prepare Code Review

Running preparation sequence:

1. Format code: /format-code
2. Run linter: /lint-code
3. Run tests: /test-all
4. Generate coverage: /coverage-report
5. Create review summary: /review-summary

This is a meta-command. After completing each step above,
I'll compile results and prepare comprehensive review materials.

Starting sequence...
```

**Individual commands** are simple:
- `/format-code` - Just formats
- `/lint-code` - Just lints
- `/test-all` - Just tests

**Composition command** orchestrates them.

### Pipeline Pattern

Commands that process output from previous commands:

```markdown
---
description: Analyze test failures
---

# Analyze Test Failures

## Step 1: Get test results
(Run /test-all first if not done)

Reading test output...

## Step 2: Categorize failures
- Flaky tests (random failures)
- Consistent failures
- New failures vs existing

## Step 3: Prioritize
Rank by:
- Impact (critical path vs edge case)
- Frequency (always fails vs sometimes)
- Effort (quick fix vs major work)

## Step 4: Generate fix plan
For each failure:
- Root cause hypothesis
- Suggested fix approach
- Estimated effort

Would you like me to:
1. Fix highest priority failure
2. Generate detailed fix plans for all
3. Create GitHub issues for each
```

### Parallel Execution Pattern

Commands that coordinate multiple simultaneous operations:

```markdown
---
description: Run comprehensive validation
allowed-tools: Bash(*), Read
---

# Comprehensive Validation

Running validations in parallel...

Starting:
- Code quality checks
- Security scanning
- Dependency audit
- Performance profiling

This will take 2-3 minutes. I'll monitor all processes
and report when complete.

[Poll each process and report progress]

All validations complete. Summary:
- Quality: PASS (0 issues)
- Security: WARN (2 minor issues)
- Dependencies: PASS
- Performance: PASS (baseline met)

Details:
[Collated results from all checks]
```

## Workflow State Management

### Using .local.md Files

Store workflow state in plugin-specific files:

```markdown
.claude/plugin-name-workflow.local.md:

---
workflow: deployment
stage: testing
started: 2025-01-15T10:30:00Z
environment: staging
branch: feature/new-api
commit: abc123def
tests_passed: false
build_complete: false
---

# Deployment Workflow State

Current stage: Testing
Started: 2025-01-15 10:30 UTC

Completed steps:
- ✅ Validation
- ✅ Branch check
- ⏳ Testing (in progress)

Pending steps:
- Build
- Deploy
- Smoke tests
```

**Reading state in commands:**

```markdown
---
description: Continue deployment workflow
allowed-tools: Read, Write
---

Reading workflow state from .claude/plugin-name-workflow.local.md...

Current stage: @.claude/plugin-name-workflow.local.md

[Parse YAML frontmatter to determine next step]

Next action based on state: [determined action]
```

### Workflow Recovery

Handle interrupted workflows:

```markdown
---
description: Resume deployment workflow
allowed-tools: Read
---

# Resume Deployment

Checking for interrupted workflow...

State file: @.claude/plugin-name-workflow.local.md

**Workflow found:**
- Started: [timestamp]
- Environment: [env]
- Last completed: [step]

**Recovery options:**
1. Resume from last step
2. Restart from beginning
3. Abort and clean up

Which would you like? (1/2/3)
```

## Workflow Coordination Patterns

### Cross-Command Communication

Commands that signal each other:

```markdown
---
description: Mark feature complete
allowed-tools: Write
---

# Mark Feature Complete

Writing completion marker...

Creating: .claude/feature-complete.flag

This signals other commands that feature is ready for:
- Integration testing (/integration-test will auto-detect)
- Documentation generation (/docs-generate will include)
- Release notes (/release-notes will add)

Feature marked complete.
```

**Other commands check for flag:**

```markdown
---
description: Generate release notes
allowed-tools: Read, Bash(git:*)
---

Checking for completed features...

if [ -f .claude/feature-complete.flag ]; then
  Feature ready for release notes
fi

[Include in release notes]
```

### Workflow Locking

Prevent concurrent workflow execution:

```markdown
---
description: Start deployment
allowed-tools: Read, Write, Bash
---

# Start Deployment

Checking for active deployments...

if [ -f .claude/deployment.lock ]; then
  ERROR: Deployment already in progress
  Started: [timestamp from lock file]

  Cannot start concurrent deployment.
  Wait for completion or run /deployment-abort

  Exit.
fi

Creating deployment lock...

Deployment started. Lock created.
[Proceed with deployment]
```

**Lock cleanup:**

```markdown
---
description: Complete deployment
allowed-tools: Write, Bash
---

Deployment complete.

Removing deployment lock...
rm .claude/deployment.lock

Ready for next deployment.
```

## Advanced Argument Handling

### Optional Arguments with Defaults

```markdown
---
description: Deploy with optional version
argument-hint: [environment] [version]
---

Environment: ${1:-staging}
Version: ${2:-latest}

Deploying ${2:-latest} to ${1:-staging}...

Note: Using defaults for missing arguments:
- Environment defaults to 'staging'
- Version defaults to 'latest'
```

### Argument Validation

```markdown
---
description: Deploy to validated environment
argument-hint: [environment]
---

Environment: $1

Validating environment...

valid_envs="dev staging production"
if ! echo "$valid_envs" | grep -w "$1" > /dev/null; then
  ERROR: Invalid environment '$1'
  Valid options: dev, staging, production
  Exit.
fi

Environment validated. Proceeding...
```

### Argument Transformation

```markdown
---
description: Deploy with shorthand
argument-hint: [env-shorthand]
---

Input: $1

Expanding shorthand:
- d/dev → development
- s/stg → staging
- p/prod → production

case "$1" in
  d|dev) ENV="development";;
  s|stg) ENV="staging";;
  p|prod) ENV="production";;
  *) ENV="$1";;
esac

Deploying to: $ENV
```

## Error Handling in Workflows

### Graceful Failure

```markdown
---
description: Resilient deployment workflow
---

# Deployment Workflow

Running steps with error handling...

## Step 1: Tests
!`npm test`

if [ $? -ne 0 ]; then
  ERROR: Tests failed

  Options:
  1. Fix tests and retry
  2. Skip tests (NOT recommended)
  3. Abort deployment

  What would you like to do?

  [Wait for user input before continuing]
fi

## Step 2: Build
[Continue only if Step 1 succeeded]
```

### Rollback on Failure

```markdown
---
description: Deployment with rollback
---

# Deploy with Rollback

Saving current state for rollback...
Previous version: !`current-version.sh`

Deploying new version...

!`deploy.sh`

if [ $? -ne 0 ]; then
  DEPLOYMENT FAILED

  Initiating automatic rollback...
  !`rollback.sh`

  Rolled back to previous version.
  Check logs for failure details.
fi

Deployment complete.
```

### Checkpoint Recovery

```markdown
---
description: Workflow with checkpoints
---

# Multi-Stage Deployment

## Checkpoint 1: Validation
!`validate.sh`
echo "checkpoint:validation" >> .claude/deployment-checkpoints.log

## Checkpoint 2: Build
!`build.sh`
echo "checkpoint:build" >> .claude/deployment-checkpoints.log

## Checkpoint 3: Deploy
!`deploy.sh`
echo "checkpoint:deploy" >> .claude/deployment-checkpoints.log

If any step fails, resume with:
/deployment-resume [last-successful-checkpoint]
```

## Best Practices

### Workflow Design

1. **Clear progression**: Number steps, show current position
2. **Explicit state**: Don't rely on implicit state
3. **User control**: Provide decision points
4. **Error recovery**: Handle failures gracefully
5. **Progress indication**: Show what's done, what's pending

### Command Composition

1. **Single responsibility**: Each command does one thing well
2. **Composable design**: Commands work together easily
3. **Standard interfaces**: Consistent input/output formats
4. **Loose coupling**: Commands don't depend on each other's internals

### State Management

1. **Persistent state**: Use .local.md files
2. **Atomic updates**: Write complete state files atomically
3. **State validation**: Check state file format/completeness
4. **Cleanup**: Remove stale state files
5. **Documentation**: Document state file formats

### Error Handling

1. **Fail fast**: Detect errors early
2. **Clear messages**: Explain what went wrong
3. **Recovery options**: Provide clear next steps
4. **State preservation**: Keep state for recovery
5. **Rollback capability**: Support undoing changes

## Example: Complete Deployment Workflow

### Initialize Command

```markdown
---
description: Initialize deployment
argument-hint: [environment]
allowed-tools: Write, Bash(git:*)
---

# Initialize Deployment to $1

Creating workflow state...

\`\`\`yaml
---
workflow: deployment
environment: $1
branch: !`git branch --show-current`
commit: !`git rev-parse HEAD`
stage: initialized
timestamp: !`date -u +%Y-%m-%dT%H:%M:%SZ`
---
\`\`\`

Written to .claude/deployment-state.local.md

Next: Run /deployment-validate
```

### Validation Command

```markdown
---
description: Validate deployment
allowed-tools: Read, Bash
---

Reading state: @.claude/deployment-state.local.md

Running validation...
- Branch check: PASS
- Tests: PASS
- Build: PASS

Updating state to 'validated'...

Next: Run /deployment-execute
```

### Execution Command

```markdown
---
description: Execute deployment
allowed-tools: Read, Bash, Write
---

Reading state: @.claude/deployment-state.local.md

Executing deployment to [environment]...

!`deploy.sh [environment]`

Deployment complete.
Updating state to 'completed'...

Cleanup: /deployment-cleanup
```

### Cleanup Command

```markdown
---
description: Clean up deployment
allowed-tools: Bash
---

Removing deployment state...
rm .claude/deployment-state.local.md

Deployment workflow complete.
```

This complete workflow demonstrates state management, sequential execution, error handling, and clean separation of concerns across multiple commands.

---

## Command Documentation Patterns

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/command-development/references/documentation-patterns.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-command-development-references-documentation.md

# Command Documentation Patterns

Strategies for creating self-documenting, maintainable commands with excellent user experience.

## Overview

Well-documented commands are easier to use, maintain, and distribute. Documentation should be embedded in the command itself, making it immediately accessible to users and maintainers.

## Self-Documenting Command Structure

### Complete Command Template

```markdown
---
description: Clear, actionable description under 60 chars
argument-hint: [arg1] [arg2] [optional-arg]
allowed-tools: Read, Bash(git:*)
model: sonnet
---

<!--
COMMAND: command-name
VERSION: 1.0.0
AUTHOR: Team Name
LAST UPDATED: 2025-01-15

PURPOSE:
Detailed explanation of what this command does and why it exists.

USAGE:
  /command-name arg1 arg2

ARGUMENTS:
  arg1: Description of first argument (required)
  arg2: Description of second argument (optional, defaults to X)

EXAMPLES:
  /command-name feature-branch main
    → Compares feature-branch with main

  /command-name my-branch
    → Compares my-branch with current branch

REQUIREMENTS:
  - Git repository
  - Branch must exist
  - Permissions to read repository

RELATED COMMANDS:
  /other-command - Related functionality
  /another-command - Alternative approach

TROUBLESHOOTING:
  - If branch not found: Check branch name spelling
  - If permission denied: Check repository access

CHANGELOG:
  v1.0.0 (2025-01-15): Initial release
  v0.9.0 (2025-01-10): Beta version
-->

# Command Implementation

[Command prompt content here...]

[Explain what will happen...]

[Guide user through steps...]

[Provide clear output...]
```

### Documentation Comment Sections

**PURPOSE**: Why the command exists
- Problem it solves
- Use cases
- When to use vs when not to use

**USAGE**: Basic syntax
- Command invocation pattern
- Required vs optional arguments
- Default values

**ARGUMENTS**: Detailed argument documentation
- Each argument described
- Type information
- Valid values/ranges
- Defaults

**EXAMPLES**: Concrete usage examples
- Common use cases
- Edge cases
- Expected outputs

**REQUIREMENTS**: Prerequisites
- Dependencies
- Permissions
- Environmental setup

**RELATED COMMANDS**: Connections
- Similar commands
- Complementary commands
- Alternative approaches

**TROUBLESHOOTING**: Common issues
- Known problems
- Solutions
- Workarounds

**CHANGELOG**: Version history
- What changed when
- Breaking changes highlighted
- Migration guidance

## In-Line Documentation Patterns

### Commented Sections

```markdown
---
description: Complex multi-step command
---

<!-- SECTION 1: VALIDATION -->
<!-- This section checks prerequisites before proceeding -->

Checking prerequisites...
- Git repository: !`git rev-parse --git-dir 2>/dev/null`
- Branch exists: [validation logic]

<!-- SECTION 2: ANALYSIS -->
<!-- Analyzes the differences between branches -->

Analyzing differences between $1 and $2...
[Analysis logic...]

<!-- SECTION 3: RECOMMENDATIONS -->
<!-- Provides actionable recommendations -->

Based on analysis, recommend:
[Recommendations...]

<!-- END: Next steps for user -->
```

### Inline Explanations

```markdown
---
description: Deployment command with inline docs
---

# Deploy to $1

## Pre-flight Checks

<!-- We check branch status to prevent deploying from wrong branch -->
Current branch: !`git branch --show-current`

<!-- Production deploys must come from main/master -->
if [ "$1" = "production" ] && [ "$(git branch --show-current)" != "main" ]; then
  ⚠️  WARNING: Not on main branch for production deploy
  This is unusual. Confirm this is intentional.
fi

<!-- Test status ensures we don't deploy broken code -->
Running tests: !`npm test`

✓ All checks passed

## Deployment

<!-- Actual deployment happens here -->
<!-- Uses blue-green strategy for zero-downtime -->
Deploying to $1 environment...
[Deployment steps...]

<!-- Post-deployment verification -->
Verifying deployment health...
[Health checks...]

Deployment complete!

## Next Steps

<!-- Guide user on what to do after deployment -->
1. Monitor logs: /logs $1
2. Run smoke tests: /smoke-test $1
3. Notify team: /notify-deployment $1
```

### Decision Point Documentation

```markdown
---
description: Interactive deployment command
---

# Interactive Deployment

## Configuration Review

Target: $1
Current version: !`cat version.txt`
New version: $2

<!-- DECISION POINT: User confirms configuration -->
<!-- This pause allows user to verify everything is correct -->
<!-- We can't automatically proceed because deployment is risky -->

Review the above configuration.

**Continue with deployment?**
- Reply "yes" to proceed
- Reply "no" to cancel
- Reply "edit" to modify configuration

[Await user input before continuing...]

<!-- After user confirms, we proceed with deployment -->
<!-- All subsequent steps are automated -->

Proceeding with deployment...
```

## Help Text Patterns

### Built-in Help Command

Create a help subcommand for complex commands:

```markdown
---
description: Main command with help
argument-hint: [subcommand] [args]
---

# Command Processor

if [ "$1" = "help" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
  **Command Help**

  USAGE:
    /command [subcommand] [args]

  SUBCOMMANDS:
    init [name]       Initialize new configuration
    deploy [env]      Deploy to environment
    status            Show current status
    rollback          Rollback last deployment
    help              Show this help

  EXAMPLES:
    /command init my-project
    /command deploy staging
    /command status
    /command rollback

  For detailed help on a subcommand:
    /command [subcommand] --help

  Exit.
fi

[Regular command processing...]
```

### Contextual Help

Provide help based on context:

```markdown
---
description: Context-aware command
argument-hint: [operation] [target]
---

# Context-Aware Operation

if [ -z "$1" ]; then
  **No operation specified**

  Available operations:
  - analyze: Analyze target for issues
  - fix: Apply automatic fixes
  - report: Generate detailed report

  Usage: /command [operation] [target]

  Examples:
    /command analyze src/
    /command fix src/app.js
    /command report

  Run /command help for more details.

  Exit.
fi

[Command continues if operation provided...]
```

## Error Message Documentation

### Helpful Error Messages

```markdown
---
description: Command with good error messages
---

# Validation Command

if [ -z "$1" ]; then
  ❌ ERROR: Missing required argument

  The 'file-path' argument is required.

  USAGE:
    /validate [file-path]

  EXAMPLE:
    /validate src/app.js

  Try again with a file path.

  Exit.
fi

if [ ! -f "$1" ]; then
  ❌ ERROR: File not found: $1

  The specified file does not exist or is not accessible.

  COMMON CAUSES:
  1. Typo in file path
  2. File was deleted or moved
  3. Insufficient permissions

  SUGGESTIONS:
  - Check spelling: $1
  - Verify file exists: ls -la $(dirname "$1")
  - Check permissions: ls -l "$1"

  Exit.
fi

[Command continues if validation passes...]
```

### Error Recovery Guidance

```markdown
---
description: Command with recovery guidance
---

# Operation Command

Running operation...

!`risky-operation.sh`

if [ $? -ne 0 ]; then
  ❌ OPERATION FAILED

  The operation encountered an error and could not complete.

  WHAT HAPPENED:
  The risky-operation.sh script returned a non-zero exit code.

  WHAT THIS MEANS:
  - Changes may be partially applied
  - System may be in inconsistent state
  - Manual intervention may be needed

  RECOVERY STEPS:
  1. Check operation logs: cat /tmp/operation.log
  2. Verify system state: /check-state
  3. If needed, rollback: /rollback-operation
  4. Fix underlying issue
  5. Retry operation: /retry-operation

  NEED HELP?
  - Check troubleshooting guide: /help troubleshooting
  - Contact support with error code: ERR_OP_FAILED_001

  Exit.
fi
```

## Usage Example Documentation

### Embedded Examples

```markdown
---
description: Command with embedded examples
---

# Feature Command

This command performs feature analysis with multiple options.

## Basic Usage

\`\`\`
/feature analyze src/
\`\`\`

Analyzes all files in src/ directory for feature usage.

## Advanced Usage

\`\`\`
/feature analyze src/ --detailed
\`\`\`

Provides detailed analysis including:
- Feature breakdown by file
- Usage patterns
- Optimization suggestions

## Use Cases

**Use Case 1: Quick overview**
\`\`\`
/feature analyze .
\`\`\`
Get high-level feature summary of entire project.

**Use Case 2: Specific directory**
\`\`\`
/feature analyze src/components
\`\`\`
Focus analysis on components directory only.

**Use Case 3: Comparison**
\`\`\`
/feature analyze src/ --compare baseline.json
\`\`\`
Compare current features against baseline.

---

Now processing your request...

[Command implementation...]
```

### Example-Driven Documentation

```markdown
---
description: Example-heavy command
---

# Transformation Command

## What This Does

Transforms data from one format to another.

## Examples First

### Example 1: JSON to YAML
**Input:** `data.json`
\`\`\`json
{"name": "test", "value": 42}
\`\`\`

**Command:** `/transform data.json yaml`

**Output:** `data.yaml`
\`\`\`yaml
name: test
value: 42
\`\`\`

### Example 2: CSV to JSON
**Input:** `data.csv`
\`\`\`csv
name,value
test,42
\`\`\`

**Command:** `/transform data.csv json`

**Output:** `data.json`
\`\`\`json
[{"name": "test", "value": "42"}]
\`\`\`

### Example 3: With Options
**Command:** `/transform data.json yaml --pretty --sort-keys`

**Result:** Formatted YAML with sorted keys

---

## Your Transformation

File: $1
Format: $2

[Perform transformation...]
```

## Maintenance Documentation

### Version and Changelog

```markdown
<!--
VERSION: 2.1.0
LAST UPDATED: 2025-01-15
AUTHOR: DevOps Team

CHANGELOG:
  v2.1.0 (2025-01-15):
    - Added support for YAML configuration
    - Improved error messages
    - Fixed bug with special characters in arguments

  v2.0.0 (2025-01-01):
    - BREAKING: Changed argument order
    - BREAKING: Removed deprecated --old-flag
    - Added new validation checks
    - Migration guide: /migration-v2

  v1.5.0 (2024-12-15):
    - Added --verbose flag
    - Improved performance by 50%

  v1.0.0 (2024-12-01):
    - Initial stable release

MIGRATION NOTES:
  From v1.x to v2.0:
    Old: /command arg1 arg2 --old-flag
    New: /command arg2 arg1

  The --old-flag is removed. Use --new-flag instead.

DEPRECATION WARNINGS:
  - The --legacy-mode flag is deprecated as of v2.1.0
  - Will be removed in v3.0.0 (estimated 2025-06-01)
  - Use --modern-mode instead

KNOWN ISSUES:
  - #123: Slow performance with large files (workaround: use --stream flag)
  - #456: Special characters in Windows (fix planned for v2.2.0)
-->
```

### Maintenance Notes

```markdown
<!--
MAINTENANCE NOTES:

CODE STRUCTURE:
  - Lines 1-50: Argument parsing and validation
  - Lines 51-100: Main processing logic
  - Lines 101-150: Output formatting
  - Lines 151-200: Error handling

DEPENDENCIES:
  - Requires git 2.x or later
  - Uses jq for JSON processing
  - Needs bash 4.0+ for associative arrays

PERFORMANCE:
  - Fast path for small inputs (< 1MB)
  - Streams large files to avoid memory issues
  - Caches results in /tmp for 1 hour

SECURITY CONSIDERATIONS:
  - Validates all inputs to prevent injection
  - Uses allowed-tools to limit Bash access
  - No credentials in command file

TESTING:
  - Unit tests: tests/command-test.sh
  - Integration tests: tests/integration/
  - Manual test checklist: tests/manual-checklist.md

FUTURE IMPROVEMENTS:
  - TODO: Add support for TOML format
  - TODO: Implement parallel processing
  - TODO: Add progress bar for large files

RELATED FILES:
  - lib/parser.sh: Shared parsing logic
  - lib/formatter.sh: Output formatting
  - config/defaults.yml: Default configuration
-->
```

## README Documentation

Commands should have companion README files:

```markdown
# Command Name

Brief description of what the command does.

## Installation

This command is part of the [plugin-name] plugin.

Install with:
\`\`\`
/plugin install plugin-name
\`\`\`

## Usage

Basic usage:
\`\`\`
/command-name [arg1] [arg2]
\`\`\`

## Arguments

- `arg1`: Description (required)
- `arg2`: Description (optional, defaults to X)

## Examples

### Example 1: Basic Usage
\`\`\`
/command-name value1 value2
\`\`\`

Description of what happens.

### Example 2: Advanced Usage
\`\`\`
/command-name value1 --option
\`\`\`

Description of advanced feature.

## Configuration

Optional configuration file: `.claude/command-name.local.md`

\`\`\`markdown
---
default_arg: value
enable_feature: true
---
\`\`\`

## Requirements

- Git 2.x or later
- jq (for JSON processing)
- Node.js 14+ (optional, for advanced features)

## Troubleshooting

### Issue: Command not found

**Solution:** Ensure plugin is installed and enabled.

### Issue: Permission denied

**Solution:** Check file permissions and allowed-tools setting.

## Contributing

Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).

## License

MIT License - See [LICENSE](LICENSE).

## Support

- Issues: https://github.com/user/plugin/issues
- Docs: https://docs.example.com
- Email: support@example.com
```

## Best Practices

### Documentation Principles

1. **Write for your future self**: Assume you'll forget details
2. **Examples before explanations**: Show, then tell
3. **Progressive disclosure**: Basic info first, details available
4. **Keep it current**: Update docs when code changes
5. **Test your docs**: Verify examples actually work

### Documentation Locations

1. **In command file**: Core usage, examples, inline explanations
2. **README**: Installation, configuration, troubleshooting
3. **Separate docs**: Detailed guides, tutorials, API reference
4. **Comments**: Implementation details for maintainers

### Documentation Style

1. **Clear and concise**: No unnecessary words
2. **Active voice**: "Run the command" not "The command can be run"
3. **Consistent terminology**: Use same terms throughout
4. **Formatted well**: Use headings, lists, code blocks
5. **Accessible**: Assume reader is beginner

### Documentation Maintenance

1. **Version everything**: Track what changed when
2. **Deprecate gracefully**: Warn before removing features
3. **Migration guides**: Help users upgrade
4. **Archive old docs**: Keep old versions accessible
5. **Review regularly**: Ensure docs match reality

## Documentation Checklist

Before releasing a command:

- [ ] Description in frontmatter is clear
- [ ] argument-hint documents all arguments
- [ ] Usage examples in comments
- [ ] Common use cases shown
- [ ] Error messages are helpful
- [ ] Requirements documented
- [ ] Related commands listed
- [ ] Changelog maintained
- [ ] Version number updated
- [ ] README created/updated
- [ ] Examples actually work
- [ ] Troubleshooting section complete

With good documentation, commands become self-service, reducing support burden and improving user experience.

---

## Interactive Command Patterns

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/command-development/references/interactive-commands.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-command-development-references-interactive-commands.md

# Interactive Command Patterns

Comprehensive guide to creating commands that gather user feedback and make decisions through the AskUserQuestion tool.

## Overview

Some commands need user input that doesn't work well with simple arguments. For example:
- Choosing between multiple complex options with trade-offs
- Selecting multiple items from a list
- Making decisions that require explanation
- Gathering preferences or configuration interactively

For these cases, use the **AskUserQuestion tool** within command execution rather than relying on command arguments.

## When to Use AskUserQuestion

### Use AskUserQuestion When:

1. **Multiple choice decisions** with explanations needed
2. **Complex options** that require context to choose
3. **Multi-select scenarios** (choosing multiple items)
4. **Preference gathering** for configuration
5. **Interactive workflows** that adapt based on answers

### Use Command Arguments When:

1. **Simple values** (file paths, numbers, names)
2. **Known inputs** user already has
3. **Scriptable workflows** that should be automatable
4. **Fast invocations** where prompting would slow down

## AskUserQuestion Basics

### Tool Parameters

```typescript
{
  questions: [
    {
      question: "Which authentication method should we use?",
      header: "Auth method",  // Short label (max 12 chars)
      multiSelect: false,     // true for multiple selection
      options: [
        {
          label: "OAuth 2.0",
          description: "Industry standard, supports multiple providers"
        },
        {
          label: "JWT",
          description: "Stateless, good for APIs"
        },
        {
          label: "Session",
          description: "Traditional, server-side state"
        }
      ]
    }
  ]
}
```

**Key points:**
- Users can always choose "Other" to provide custom input (automatic)
- `multiSelect: true` allows selecting multiple options
- Options should be 2-4 choices (not more)
- Can ask 1-4 questions per tool call

## Command Pattern for User Interaction

### Basic Interactive Command

```markdown
---
description: Interactive setup command
allowed-tools: AskUserQuestion, Write
---

# Interactive Plugin Setup

This command will guide you through configuring the plugin with a series of questions.

## Step 1: Gather Configuration

Use the AskUserQuestion tool to ask:

**Question 1 - Deployment target:**
- header: "Deploy to"
- question: "Which deployment platform will you use?"
- options:
  - AWS (Amazon Web Services with ECS/EKS)
  - GCP (Google Cloud with GKE)
  - Azure (Microsoft Azure with AKS)
  - Local (Docker on local machine)

**Question 2 - Environment strategy:**
- header: "Environments"
- question: "How many environments do you need?"
- options:
  - Single (Just production)
  - Standard (Dev, Staging, Production)
  - Complete (Dev, QA, Staging, Production)

**Question 3 - Features to enable:**
- header: "Features"
- question: "Which features do you want to enable?"
- multiSelect: true
- options:
  - Auto-scaling (Automatic resource scaling)
  - Monitoring (Health checks and metrics)
  - CI/CD (Automated deployment pipeline)
  - Backups (Automated database backups)

## Step 2: Process Answers

Based on the answers received from AskUserQuestion:

1. Parse the deployment target choice
2. Set up environment-specific configuration
3. Enable selected features
4. Generate configuration files

## Step 3: Generate Configuration

Create `.claude/plugin-name.local.md` with:

\`\`\`yaml
---
deployment_target: [answer from Q1]
environments: [answer from Q2]
features:
  auto_scaling: [true if selected in Q3]
  monitoring: [true if selected in Q3]
  ci_cd: [true if selected in Q3]
  backups: [true if selected in Q3]
---

# Plugin Configuration

Generated: [timestamp]
Target: [deployment_target]
Environments: [environments]
\`\`\`

## Step 4: Confirm and Next Steps

Confirm configuration created and guide user on next steps.
```

### Multi-Stage Interactive Workflow

```markdown
---
description: Multi-stage interactive workflow
allowed-tools: AskUserQuestion, Read, Write, Bash
---

# Multi-Stage Deployment Setup

This command walks through deployment setup in stages, adapting based on your answers.

## Stage 1: Basic Configuration

Use AskUserQuestion to ask about deployment basics.

Based on answers, determine which additional questions to ask.

## Stage 2: Advanced Options (Conditional)

If user selected "Advanced" deployment in Stage 1:

Use AskUserQuestion to ask about:
- Load balancing strategy
- Caching configuration
- Security hardening options

If user selected "Simple" deployment:
- Skip advanced questions
- Use sensible defaults

## Stage 3: Confirmation

Show summary of all selections.

Use AskUserQuestion for final confirmation:
- header: "Confirm"
- question: "Does this configuration look correct?"
- options:
  - Yes (Proceed with setup)
  - No (Start over)
  - Modify (Let me adjust specific settings)

If "Modify", ask which specific setting to change.

## Stage 4: Execute Setup

Based on confirmed configuration, execute setup steps.
```

## Interactive Question Design

### Question Structure

**Good questions:**
```markdown
Question: "Which database should we use for this project?"
Header: "Database"
Options:
  - PostgreSQL (Relational, ACID compliant, best for complex queries)
  - MongoDB (Document store, flexible schema, best for rapid iteration)
  - Redis (In-memory, fast, best for caching and sessions)
```

**Poor questions:**
```markdown
Question: "Database?"  // Too vague
Header: "DB"  // Unclear abbreviation
Options:
  - Option 1  // Not descriptive
  - Option 2
```

### Option Design Best Practices

**Clear labels:**
- Use 1-5 words
- Specific and descriptive
- No jargon without context

**Helpful descriptions:**
- Explain what the option means
- Mention key benefits or trade-offs
- Help user make informed decision
- Keep to 1-2 sentences

**Appropriate number:**
- 2-4 options per question
- Don't overwhelm with too many choices
- Group related options
- "Other" automatically provided

### Multi-Select Questions

**When to use multiSelect:**

```markdown
Use AskUserQuestion for enabling features:

Question: "Which features do you want to enable?"
Header: "Features"
multiSelect: true  // Allow selecting multiple
Options:
  - Logging (Detailed operation logs)
  - Metrics (Performance monitoring)
  - Alerts (Error notifications)
  - Backups (Automatic backups)
```

User can select any combination: none, some, or all.

**When NOT to use multiSelect:**

```markdown
Question: "Which authentication method?"
multiSelect: false  // Only one auth method makes sense
```

Mutually exclusive choices should not use multiSelect.

## Command Patterns with AskUserQuestion

### Pattern 1: Simple Yes/No Decision

```markdown
---
description: Command with confirmation
allowed-tools: AskUserQuestion, Bash
---

# Destructive Operation

This operation will delete all cached data.

Use AskUserQuestion to confirm:

Question: "This will delete all cached data. Are you sure?"
Header: "Confirm"
Options:
  - Yes (Proceed with deletion)
  - No (Cancel operation)

If user selects "Yes":
  Execute deletion
  Report completion

If user selects "No":
  Cancel operation
  Exit without changes
```

### Pattern 2: Multiple Configuration Questions

```markdown
---
description: Multi-question configuration
allowed-tools: AskUserQuestion, Write
---

# Project Configuration Setup

Gather configuration through multiple questions.

Use AskUserQuestion with multiple questions in one call:

**Question 1:**
- question: "Which programming language?"
- header: "Language"
- options: Python, TypeScript, Go, Rust

**Question 2:**
- question: "Which test framework?"
- header: "Testing"
- options: Jest, PyTest, Go Test, Cargo Test
  (Adapt based on language from Q1)

**Question 3:**
- question: "Which CI/CD platform?"
- header: "CI/CD"
- options: GitHub Actions, GitLab CI, CircleCI

**Question 4:**
- question: "Which features do you need?"
- header: "Features"
- multiSelect: true
- options: Linting, Type checking, Code coverage, Security scanning

Process all answers together to generate cohesive configuration.
```

### Pattern 3: Conditional Question Flow

```markdown
---
description: Conditional interactive workflow
allowed-tools: AskUserQuestion, Read, Write
---

# Adaptive Configuration

## Question 1: Deployment Complexity

Use AskUserQuestion:

Question: "How complex is your deployment?"
Header: "Complexity"
Options:
  - Simple (Single server, straightforward)
  - Standard (Multiple servers, load balancing)
  - Complex (Microservices, orchestration)

## Conditional Questions Based on Answer

If answer is "Simple":
  - No additional questions
  - Use minimal configuration

If answer is "Standard":
  - Ask about load balancing strategy
  - Ask about scaling policy

If answer is "Complex":
  - Ask about orchestration platform (Kubernetes, Docker Swarm)
  - Ask about service mesh (Istio, Linkerd, None)
  - Ask about monitoring (Prometheus, Datadog, CloudWatch)
  - Ask about logging aggregation

## Process Conditional Answers

Generate configuration appropriate for selected complexity level.
```

### Pattern 4: Iterative Collection

```markdown
---
description: Collect multiple items iteratively
allowed-tools: AskUserQuestion, Write
---

# Collect Team Members

We'll collect team member information for the project.

## Question: How many team members?

Use AskUserQuestion:

Question: "How many team members should we set up?"
Header: "Team size"
Options:
  - 2 people
  - 3 people
  - 4 people
  - 6 people

## Iterate Through Team Members

For each team member (1 to N based on answer):

Use AskUserQuestion for member details:

Question: "What role for team member [number]?"
Header: "Role"
Options:
  - Frontend Developer
  - Backend Developer
  - DevOps Engineer
  - QA Engineer
  - Designer

Store each member's information.

## Generate Team Configuration

After collecting all N members, create team configuration file with all members and their roles.
```

### Pattern 5: Dependency Selection

```markdown
---
description: Select dependencies with multi-select
allowed-tools: AskUserQuestion
---

# Configure Project Dependencies

## Question: Required Libraries

Use AskUserQuestion with multiSelect:

Question: "Which libraries does your project need?"
Header: "Dependencies"
multiSelect: true
Options:
  - React (UI framework)
  - Express (Web server)
  - TypeORM (Database ORM)
  - Jest (Testing framework)
  - Axios (HTTP client)

User can select any combination.

## Process Selections

For each selected library:
- Add to package.json dependencies
- Generate sample configuration
- Create usage examples
- Update documentation
```

## Best Practices for Interactive Commands

### Question Design

1. **Clear and specific**: Question should be unambiguous
2. **Concise header**: Max 12 characters for clean display
3. **Helpful options**: Labels are clear, descriptions explain trade-offs
4. **Appropriate count**: 2-4 options per question, 1-4 questions per call
5. **Logical order**: Questions flow naturally

### Error Handling

```markdown
# Handle AskUserQuestion Responses

After calling AskUserQuestion, verify answers received:

If answers are empty or invalid:
  Something went wrong gathering responses.

  Please try again or provide configuration manually:
  [Show alternative approach]

  Exit.

If answers look correct:
  Process as expected
```

### Progressive Disclosure

```markdown
# Start Simple, Get Detailed as Needed

## Question 1: Setup Type

Use AskUserQuestion:

Question: "How would you like to set up?"
Header: "Setup type"
Options:
  - Quick (Use recommended defaults)
  - Custom (Configure all options)
  - Guided (Step-by-step with explanations)

If "Quick":
  Apply defaults, minimal questions

If "Custom":
  Ask all available configuration questions

If "Guided":
  Ask questions with extra explanation
  Provide recommendations along the way
```

### Multi-Select Guidelines

**Good multi-select use:**
```markdown
Question: "Which features do you want to enable?"
multiSelect: true
Options:
  - Logging
  - Metrics
  - Alerts
  - Backups

Reason: User might want any combination
```

**Bad multi-select use:**
```markdown
Question: "Which database engine?"
multiSelect: true  // ❌ Should be single-select

Reason: Can only use one database engine
```

## Advanced Patterns

### Validation Loop

```markdown
---
description: Interactive with validation
allowed-tools: AskUserQuestion, Bash
---

# Setup with Validation

## Gather Configuration

Use AskUserQuestion to collect settings.

## Validate Configuration

Check if configuration is valid:
- Required dependencies available?
- Settings compatible with each other?
- No conflicts detected?

If validation fails:
  Show validation errors

  Use AskUserQuestion to ask:

  Question: "Configuration has issues. What would you like to do?"
  Header: "Next step"
  Options:
    - Fix (Adjust settings to resolve issues)
    - Override (Proceed despite warnings)
    - Cancel (Abort setup)

  Based on answer, retry or proceed or exit.
```

### Build Configuration Incrementally

```markdown
---
description: Incremental configuration builder
allowed-tools: AskUserQuestion, Write, Read
---

# Incremental Setup

## Phase 1: Core Settings

Use AskUserQuestion for core settings.

Save to `.claude/config-partial.yml`

## Phase 2: Review Core Settings

Show user the core settings:

Based on these core settings, you need to configure:
- [Setting A] (because you chose [X])
- [Setting B] (because you chose [Y])

Ready to continue?

## Phase 3: Detailed Settings

Use AskUserQuestion for settings based on Phase 1 answers.

Merge with core settings.

## Phase 4: Final Review

Present complete configuration.

Use AskUserQuestion for confirmation:

Question: "Is this configuration correct?"
Options:
  - Yes (Save and apply)
  - No (Start over)
  - Modify (Edit specific settings)
```

### Dynamic Options Based on Context

```markdown
---
description: Context-aware questions
allowed-tools: AskUserQuestion, Bash, Read
---

# Context-Aware Setup

## Detect Current State

Check existing configuration:
- Current language: !`detect-language.sh`
- Existing frameworks: !`detect-frameworks.sh`
- Available tools: !`check-tools.sh`

## Ask Context-Appropriate Questions

Based on detected language, ask relevant questions.

If language is TypeScript:

  Use AskUserQuestion:

  Question: "Which TypeScript features should we enable?"
  Options:
    - Strict Mode (Maximum type safety)
    - Decorators (Experimental decorator support)
    - Path Mapping (Module path aliases)

If language is Python:

  Use AskUserQuestion:

  Question: "Which Python tools should we configure?"
  Options:
    - Type Hints (mypy for type checking)
    - Black (Code formatting)
    - Pylint (Linting and style)

Questions adapt to project context.
```

## Real-World Example: Multi-Agent Swarm Launch

**From multi-agent-swarm plugin:**

```markdown
---
description: Launch multi-agent swarm
allowed-tools: AskUserQuestion, Read, Write, Bash
---

# Launch Multi-Agent Swarm

## Interactive Mode (No Task List Provided)

If user didn't provide task list file, help create one interactively.

### Question 1: Agent Count

Use AskUserQuestion:

Question: "How many agents should we launch?"
Header: "Agent count"
Options:
  - 2 agents (Best for simple projects)
  - 3 agents (Good for medium projects)
  - 4 agents (Standard team size)
  - 6 agents (Large projects)
  - 8 agents (Complex multi-component projects)

### Question 2: Task Definition Approach

Use AskUserQuestion:

Question: "How would you like to define tasks?"
Header: "Task setup"
Options:
  - File (I have a task list file ready)
  - Guided (Help me create tasks interactively)
  - Custom (Other approach)

If "File":
  Ask for file path
  Validate file exists and has correct format

If "Guided":
  Enter iterative task creation mode (see below)

### Question 3: Coordination Mode

Use AskUserQuestion:

Question: "How should agents coordinate?"
Header: "Coordination"
Options:
  - Team Leader (One agent coordinates others)
  - Collaborative (Agents coordinate as peers)
  - Autonomous (Independent work, minimal coordination)

### Iterative Task Creation (If "Guided" Selected)

For each agent (1 to N from Question 1):

**Question A: Agent Name**
Question: "What should we call agent [number]?"
Header: "Agent name"
Options:
  - auth-agent
  - api-agent
  - ui-agent
  - db-agent
  (Provide relevant suggestions based on common patterns)

**Question B: Task Type**
Question: "What task for [agent-name]?"
Header: "Task type"
Options:
  - Authentication (User auth, JWT, OAuth)
  - API Endpoints (REST/GraphQL APIs)
  - UI Components (Frontend components)
  - Database (Schema, migrations, queries)
  - Testing (Test suites and coverage)
  - Documentation (Docs, README, guides)

**Question C: Dependencies**
Question: "What does [agent-name] depend on?"
Header: "Dependencies"
multiSelect: true
Options:
  - [List of previously defined agents]
  - No dependencies

**Question D: Base Branch**
Question: "Which base branch for PR?"
Header: "PR base"
Options:
  - main
  - staging
  - develop

Store all task information for each agent.

### Generate Task List File

After collecting all agent task details:

1. Ask for project name
2. Generate task list in proper format
3. Save to `.daisy/swarm/tasks.md`
4. Show user the file path
5. Proceed with launch using generated task list
```

## Best Practices

### Question Writing

1. **Be specific**: "Which database?" not "Choose option?"
2. **Explain trade-offs**: Describe pros/cons in option descriptions
3. **Provide context**: Question text should stand alone
4. **Guide decisions**: Help user make informed choice
5. **Keep concise**: Header max 12 chars, descriptions 1-2 sentences

### Option Design

1. **Meaningful labels**: Specific, clear names
2. **Informative descriptions**: Explain what each option does
3. **Show trade-offs**: Help user understand implications
4. **Consistent detail**: All options equally explained
5. **2-4 options**: Not too few, not too many

### Flow Design

1. **Logical order**: Questions flow naturally
2. **Build on previous**: Later questions use earlier answers
3. **Minimize questions**: Ask only what's needed
4. **Group related**: Ask related questions together
5. **Show progress**: Indicate where in flow

### User Experience

1. **Set expectations**: Tell user what to expect
2. **Explain why**: Help user understand purpose
3. **Provide defaults**: Suggest recommended options
4. **Allow escape**: Let user cancel or restart
5. **Confirm actions**: Summarize before executing

## Common Patterns

### Pattern: Feature Selection

```markdown
Use AskUserQuestion:

Question: "Which features do you need?"
Header: "Features"
multiSelect: true
Options:
  - Authentication
  - Authorization
  - Rate Limiting
  - Caching
```

### Pattern: Environment Configuration

```markdown
Use AskUserQuestion:

Question: "Which environment is this?"
Header: "Environment"
Options:
  - Development (Local development)
  - Staging (Pre-production testing)
  - Production (Live environment)
```

### Pattern: Priority Selection

```markdown
Use AskUserQuestion:

Question: "What's the priority for this task?"
Header: "Priority"
Options:
  - Critical (Must be done immediately)
  - High (Important, do soon)
  - Medium (Standard priority)
  - Low (Nice to have)
```

### Pattern: Scope Selection

```markdown
Use AskUserQuestion:

Question: "What scope should we analyze?"
Header: "Scope"
Options:
  - Current file (Just this file)
  - Current directory (All files in directory)
  - Entire project (Full codebase scan)
```

## Combining Arguments and Questions

### Use Both Appropriately

**Arguments for known values:**
```markdown
---
argument-hint: [project-name]
allowed-tools: AskUserQuestion, Write
---

Setup for project: $1

Now gather additional configuration...

Use AskUserQuestion for options that require explanation.
```

**Questions for complex choices:**
```markdown
Project name from argument: $1

Now use AskUserQuestion to choose:
- Architecture pattern
- Technology stack
- Deployment strategy

These require explanation, so questions work better than arguments.
```

## Troubleshooting

**Questions not appearing:**
- Verify AskUserQuestion in allowed-tools
- Check question format is correct
- Ensure options array has 2-4 items

**User can't make selection:**
- Check option labels are clear
- Verify descriptions are helpful
- Consider if too many options
- Ensure multiSelect setting is correct

**Flow feels confusing:**
- Reduce number of questions
- Group related questions
- Add explanation between stages
- Show progress through workflow

With AskUserQuestion, commands become interactive wizards that guide users through complex decisions while maintaining the clarity that simple arguments provide for straightforward inputs.

---

## Component Organization Patterns

Source: https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/plugin-structure/references/component-patterns.md
Path: 09-Agents-Patterns/claude-code-plugins-plugin-dev-skills-plugin-structure-references-component-patterns.md

# Component Organization Patterns

Advanced patterns for organizing plugin components effectively.

## Component Lifecycle

### Discovery Phase

When Claude Code starts:

1. **Scan enabled plugins**: Read `.claude-plugin/plugin.json` for each
2. **Discover components**: Look in default and custom paths
3. **Parse definitions**: Read YAML frontmatter and configurations
4. **Register components**: Make available to Claude Code
5. **Initialize**: Start MCP servers, register hooks

**Timing**: Component registration happens during Claude Code initialization, not continuously.

### Activation Phase

When components are used:

**Commands**: User types slash command → Claude Code looks up → Executes
**Agents**: Task arrives → Claude Code evaluates capabilities → Selects agent
**Skills**: Task context matches description → Claude Code loads skill
**Hooks**: Event occurs → Claude Code calls matching hooks
**MCP Servers**: Tool call matches server capability → Forwards to server

## Command Organization Patterns

### Flat Structure

Single directory with all commands:

```
commands/
├── build.md
├── test.md
├── deploy.md
├── review.md
└── docs.md
```

**When to use**:
- 5-15 commands total
- All commands at same abstraction level
- No clear categorization

**Advantages**:
- Simple, easy to navigate
- No configuration needed
- Fast discovery

### Categorized Structure

Multiple directories for different command types:

```
commands/              # Core commands
├── build.md
└── test.md

admin-commands/        # Administrative
├── configure.md
└── manage.md

workflow-commands/     # Workflow automation
├── review.md
└── deploy.md
```

**Manifest configuration**:
```json
{
  "commands": [
    "./commands",
    "./admin-commands",
    "./workflow-commands"
  ]
}
```

**When to use**:
- 15+ commands
- Clear functional categories
- Different permission levels

**Advantages**:
- Organized by purpose
- Easier to maintain
- Can restrict access by directory

### Hierarchical Structure

Nested organization for complex plugins:

```
commands/
├── ci/
│   ├── build.md
│   ├── test.md
│   └── lint.md
├── deployment/
│   ├── staging.md
│   └── production.md
└── management/
    ├── config.md
    └── status.md
```

**Note**: Claude Code doesn't support nested command discovery automatically. Use custom paths:

```json
{
  "commands": [
    "./commands/ci",
    "./commands/deployment",
    "./commands/management"
  ]
}
```

**When to use**:
- 20+ commands
- Multi-level categorization
- Complex workflows

**Advantages**:
- Maximum organization
- Clear boundaries
- Scalable structure

## Agent Organization Patterns

### Role-Based Organization

Organize agents by their primary role:

```
agents/
├── code-reviewer.md        # Reviews code
├── test-generator.md       # Generates tests
├── documentation-writer.md # Writes docs
└── refactorer.md          # Refactors code
```

**When to use**:
- Agents have distinct, non-overlapping roles
- Users invoke agents manually
- Clear agent responsibilities

### Capability-Based Organization

Organize by specific capabilities:

```
agents/
├── python-expert.md        # Python-specific
├── typescript-expert.md    # TypeScript-specific
├── api-specialist.md       # API design
└── database-specialist.md  # Database work
```

**When to use**:
- Technology-specific agents
- Domain expertise focus
- Automatic agent selection

### Workflow-Based Organization

Organize by workflow stage:

```
agents/
├── planning-agent.md      # Planning phase
├── implementation-agent.md # Coding phase
├── testing-agent.md       # Testing phase
└── deployment-agent.md    # Deployment phase
```

**When to use**:
- Sequential workflows
- Stage-specific expertise
- Pipeline automation

## Skill Organization Patterns

### Topic-Based Organization

Each skill covers a specific topic:

```
skills/
├── api-design/
│   └── SKILL.md
├── error-handling/
│   └── SKILL.md
├── testing-strategies/
│   └── SKILL.md
└── performance-optimization/
    └── SKILL.md
```

**When to use**:
- Knowledge-based skills
- Educational or reference content
- Broad applicability

### Tool-Based Organization

Skills for specific tools or technologies:

```
skills/
├── docker/
│   ├── SKILL.md
│   └── references/
│       └── dockerfile-best-practices.md
├── kubernetes/
│   ├── SKILL.md
│   └── examples/
│       └── deployment.yaml
└── terraform/
    ├── SKILL.md
    └── scripts/
        └── validate-config.sh
```

**When to use**:
- Tool-specific expertise
- Complex tool configurations
- Tool best practices

### Workflow-Based Organization

Skills for complete workflows:

```
skills/
├── code-review-workflow/
│   ├── SKILL.md
│   └── references/
│       ├── checklist.md
│       └── standards.md
├── deployment-workflow/
│   ├── SKILL.md
│   └── scripts/
│       ├── pre-deploy.sh
│       └── post-deploy.sh
└── testing-workflow/
    ├── SKILL.md
    └── examples/
        └── test-structure.md
```

**When to use**:
- Multi-step processes
- Company-specific workflows
- Process automation

### Skill with Rich Resources

Comprehensive skill with all resource types:

```
skills/
└── api-testing/
    ├── SKILL.md              # Core skill (1500 words)
    ├── references/
    │   ├── rest-api-guide.md
    │   ├── graphql-guide.md
    │   └── authentication.md
    ├── examples/
    │   ├── basic-test.js
    │   ├── authenticated-test.js
    │   └── integration-test.js
    ├── scripts/
    │   ├── run-tests.sh
    │   └── generate-report.py
    └── assets/
        └── test-template.json
```

**Resource usage**:
- **SKILL.md**: Overview and when to use resources
- **references/**: Detailed guides (loaded as needed)
- **examples/**: Copy-paste code samples
- **scripts/**: Executable test runners
- **assets/**: Templates and configurations

## Hook Organization Patterns

### Monolithic Configuration

Single hooks.json with all hooks:

```
hooks/
├── hooks.json     # All hook definitions
└── scripts/
    ├── validate-write.sh
    ├── validate-bash.sh
    └── load-context.sh
```

**hooks.json**:
```json
{
  "PreToolUse": [...],
  "PostToolUse": [...],
  "Stop": [...],
  "SessionStart": [...]
}
```

**When to use**:
- 5-10 hooks total
- Simple hook logic
- Centralized configuration

### Event-Based Organization

Separate files per event type:

```
hooks/
├── hooks.json              # Combines all
├── pre-tool-use.json      # PreToolUse hooks
├── post-tool-use.json     # PostToolUse hooks
├── stop.json              # Stop hooks
└── scripts/
    ├── validate/
    │   ├── write.sh
    │   └── bash.sh
    └── context/
        └── load.sh
```

**hooks.json** (combines):
```json
{
  "PreToolUse": ${file:./pre-tool-use.json},
  "PostToolUse": ${file:./post-tool-use.json},
  "Stop": ${file:./stop.json}
}
```

**Note**: Use build script to combine files, Claude Code doesn't support file references.

**When to use**:
- 10+ hooks
- Different teams managing different events
- Complex hook configurations

### Purpose-Based Organization

Group by functional purpose:

```
hooks/
├── hooks.json
└── scripts/
    ├── security/
    │   ├── validate-paths.sh
    │   ├── check-credentials.sh
    │   └── scan-malware.sh
    ├── quality/
    │   ├── lint-code.sh
    │   ├── check-tests.sh
    │   └── verify-docs.sh
    └── workflow/
        ├── notify-team.sh
        └── update-status.sh
```

**When to use**:
- Many hook scripts
- Clear functional boundaries
- Team specialization

## Script Organization Patterns

### Flat Scripts

All scripts in single directory:

```
scripts/
├── build.sh
├── test.py
├── deploy.sh
├── validate.js
└── report.py
```

**When to use**:
- 5-10 scripts
- All scripts related
- Simple plugin

### Categorized Scripts

Group by purpose:

```
scripts/
├── build/
│   ├── compile.sh
│   └── package.sh
├── test/
│   ├── run-unit.sh
│   └── run-integration.sh
├── deploy/
│   ├── staging.sh
│   └── production.sh
└── utils/
    ├── log.sh
    └── notify.sh
```

**When to use**:
- 10+ scripts
- Clear categories
- Reusable utilities

### Language-Based Organization

Group by programming language:

```
scripts/
├── bash/
│   ├── build.sh
│   └── deploy.sh
├── python/
│   ├── analyze.py
│   └── report.py
└── javascript/
    ├── bundle.js
    └── optimize.js
```

**When to use**:
- Multi-language scripts
- Different runtime requirements
- Language-specific dependencies

## Cross-Component Patterns

### Shared Resources

Components sharing common resources:

```
plugin/
├── commands/
│   ├── test.md        # Uses lib/test-utils.sh
│   └── deploy.md      # Uses lib/deploy-utils.sh
├── agents/
│   └── tester.md      # References lib/test-utils.sh
├── hooks/
│   └── scripts/
│       └── pre-test.sh # Sources lib/test-utils.sh
└── lib/
    ├── test-utils.sh
    └── deploy-utils.sh
```

**Usage in components**:
```bash
#!/bin/bash
source "${CLAUDE_PLUGIN_ROOT}/lib/test-utils.sh"
run_tests
```

**Benefits**:
- Code reuse
- Consistent behavior
- Easier maintenance

### Layered Architecture

Separate concerns into layers:

```
plugin/
├── commands/          # User interface layer
├── agents/            # Orchestration layer
├── skills/            # Knowledge layer
└── lib/
    ├── core/         # Core business logic
    ├── integrations/ # External services
    └── utils/        # Helper functions
```

**When to use**:
- Large plugins (100+ files)
- Multiple developers
- Clear separation of concerns

### Plugin Within Plugin

Nested plugin structure:

```
plugin/
├── .claude-plugin/
│   └── plugin.json
├── core/              # Core functionality
│   ├── commands/
│   └── agents/
└── extensions/        # Optional extensions
    ├── extension-a/
    │   ├── commands/
    │   └── agents/
    └── extension-b/
        ├── commands/
        └── agents/
```

**Manifest**:
```json
{
  "commands": [
    "./core/commands",
    "./extensions/extension-a/commands",
    "./extensions/extension-b/commands"
  ]
}
```

**When to use**:
- Modular functionality
- Optional features
- Plugin families

## Best Practices

### Naming

1. **Consistent naming**: Match file names to component purpose
2. **Descriptive names**: Indicate what component does
3. **Avoid abbreviations**: Use full words for clarity

### Organization

1. **Start simple**: Use flat structure, reorganize when needed
2. **Group related items**: Keep related components together
3. **Separate concerns**: Don't mix unrelated functionality

### Scalability

1. **Plan for growth**: Choose structure that scales
2. **Refactor early**: Reorganize before it becomes painful
3. **Document structure**: Explain organization in README

### Maintainability

1. **Consistent patterns**: Use same structure throughout
2. **Minimize nesting**: Keep directory depth manageable
3. **Use conventions**: Follow community standards

### Performance

1. **Avoid deep nesting**: Impacts discovery time
2. **Minimize custom paths**: Use defaults when possible
3. **Keep configurations small**: Large configs slow loading

---

## Building a One-Liner Research Agent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/00_The_one_liner_research_agent.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-claude-agent-sdk-00-the-one-liner-research-agent.md

# Building a One-Liner Research Agent

Research tasks consume hours of expert time: market analysts manually
gathering competitive intelligence, legal teams tracking regulatory
changes, engineers investigating bug reports across documentation. The
core challenge isn\'t finding information but knowing what to search for
next based on what you just discovered.

The Claude Agent SDK makes it possible to build agents that autonomously
explore external systems without a predefined workflow. Unlike
traditional workflow automations that follow fixed steps, research
agents adapt their strategy based on what they find\--following
promising leads, synthesizing conflicting sources, and knowing when they
have enough information to answer the question.

## By the end of this cookbook, you\'ll be able to:

- Build a research agent that autonomously searches and synthesizes
  information with a few lines of code

This foundation applies to any task where the information needed isn\'t
available upfront: competitive analysis, technical troubleshooting,
investment research, or literature reviews.

# Why Research Agents?

Research is an ideal agentic use case for two reasons:

1.  **Information isn\'t self-contained**. The input question alone
    doesn\'t contain the answer. The agent must interact with external
    systems (search engines, databases, APIs) to gather what it needs.
2.  **The path emerges during exploration**. You can\'t predetermine the
    workflow. Whether an agent should search for company financials or
    regulatory filings depends on what it discovers about the business
    model. The optimal strategy reveals itself through investigation.

In its simplest form, a research agent searches the web and synthesizes
findings. Below, we\'ll build exactly that with the Claude Agent SDK\'s
built-in web search tool in just a few lines of code.

Note: You can also view the full list of [Claude Code\'s built-in
tools](https://docs.claude.com/en/docs/claude-code/settings#tools-available-to-claude)
:::

::: {#301fb086 .cell .markdown}
# Prerequisites

Before following this guide, ensure you have:

**Required Knowledge**

- Python fundamentals - comfortable with async/await, functions, and
  basic data structures
- Basic understanding of agentic patterns - we recommend reading
  [Building effective
  agents](https://www.anthropic.com/engineering/building-effective-agents)
  first if you\'re new to agents

**Required Tools**

- Python 3.11 or higher
- Anthropic API key [(get one here)](https://console.anthropic.com)

**Recommended:**

- Familiarity with the Claude Agent SDK concepts
- Understanding of tool use patterns in LLMs

## Setup

First, install the required dependencies:
:::

::: {#ab9830f9 .cell .code}
``` python
%%capture
%pip install -U claude-agent-sdk python-dotenv
```
:::

::: {#d88272cf .cell .markdown}
Note: Ensure your .env file contains:

``` bash
ANTHROPIC_API_KEY=your_key_here
```

Load your environment variables and configure the client:
:::

::: {#c41abcdf .cell .code execution_count="2"}
``` python
from dotenv import load_dotenv

load_dotenv()

MODEL = "claude-opus-4-5"
```
:::

::: {#041415b8 .cell .markdown}
## Building Your First Research Agent

Let\'s start with the simplest possible implementation: a research agent
that can search the web and synthesize findings. With the Claude Agent
SDK, this takes just a few lines of code.

The key is the query() function, which creates a stateless agent
interaction. We\'ll provide Claude with a single tool, WebSearch, and
let it autonomously decide when and how to use it based on our research
question.
:::

:::: {#b00890fb .cell .code execution_count="3"}
``` python
from utils.agent_visualizer import (
    display_agent_response,
    print_activity,
)

from claude_agent_sdk import ClaudeAgentOptions, query

messages = []
async for msg in query(
    prompt="Research the latest trends in AI agents and give me a brief summary and relevant citiations links.",
    options=ClaudeAgentOptions(model=MODEL, allowed_tools=["WebSearch"]),
):
    print_activity(msg)
    messages.append(msg)
```

::: {.output .stream .stdout}
    🤖 Using: WebSearch()
    🤖 Using: WebSearch()
    🤖 Using: WebSearch()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
:::
::::

:::: {#e4556936 .cell .code execution_count="4"}
``` python
display_agent_response(messages)
```

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><h2>Latest Trends in AI Agents (2025) - Summary</h2>
<h3>🚀 Market Growth &amp; Adoption</h3>
<p>The AI agent market is experiencing explosive growth, nearly doubling from <strong>$3.7 billion (2023) to $7.38 billion (2025)</strong>, with projections reaching <strong>$103.6 billion by 2032</strong>. According to PwC's 2025 survey, <strong>79% of organizations</strong> have adopted AI agents, with <strong>88% of executives</strong> piloting or scaling autonomous agent systems.</p>
<h3>🔑 Key Trends</h3>
<p><strong>1. Rise of Multi-Agent Systems</strong><br />
Instead of single AI systems trying to do everything, 2025 has introduced the "orchestra approach" where multiple specialized agents collaborate—one gathers research, another drafts reports, and a third reviews. Frameworks like <strong>CrewAI, AutoGen, and LangGraph</strong> are enabling this coordination across enterprise departments.</p>
<p><strong>2. From Assistants to Autonomous Decision-Makers</strong><br />
AI agents are evolving from knowledge assistants to <strong>self-directed workers</strong> that can take initiative, make decisions, and complete multi-step tasks without constant human input. By 2029, <strong>80% of customer service issues</strong> are expected to be resolved entirely by autonomous agents.</p>
<p><strong>3. Model Context Protocol (MCP)</strong><br />
Anthropic's open standard provides a "USB-C for AI"—standardizing how language models connect with external systems, enabling structured multi-step workflows and access to real-time information.</p>
<p><strong>4. Two-Speed Enterprise Landscape</strong><br />
A divide is emerging: companies with existing automation are racing ahead with agentic AI, while others watch from the sidelines. Among highly automated enterprises, <strong>50%</strong> have either adopted or are preparing to adopt autonomous agents.</p>
<h3>⚠️ Key Challenges</h3>
<ul>
<li><strong>Integration with legacy systems</strong> (cited by ~60% of AI leaders)</li>
<li><strong>Trust issues</strong> for high-stakes tasks like financial transactions</li>
<li><strong>Enterprise readiness</strong>—organizations need to expose APIs and prepare infrastructure</li>
<li><strong>Reliability concerns</strong>—agents can misinterpret instructions or fail on edge cases</li>
</ul>
<h3>💼 Impact</h3>
<ul>
<li><strong>66%</strong> of adopters report measurable productivity gains</li>
<li>Early movers are cutting operational costs by up to <strong>40%</strong></li>
<li><strong>75% of executives</strong> believe AI agents will reshape the workplace more than the internet did</li>
<li><strong>87%</strong> agree AI agents augment roles rather than replace them</li>
</ul>
<hr />
<h2>Sources:</h2>
<ul>
<li><a href="https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai">The State of AI in 2025 - McKinsey</a></li>
<li><a href="https://www.ibm.com/think/insights/ai-agents-2025-expectations-vs-reality">AI Agents in 2025: Expectations vs. Reality - IBM</a></li>
<li><a href="https://www.pwc.com/us/en/tech-effect/ai-analytics/ai-agent-survey.html">PwC's AI Agent Survey</a></li>
<li><a href="https://www.mckinsey.com/capabilities/quantumblack/our-insights/seizing-the-agentic-ai-advantage">Seizing the Agentic AI Advantage - McKinsey</a></li>
<li><a href="https://www.gartner.com/en/newsroom/press-releases/2025-08-05-gartner-hype-cycle-identifies-top-ai-innovations-in-2025">Gartner Hype Cycle Identifies Top AI Innovations in 2025</a></li>
<li><a href="https://www.deloitte.com/us/en/services/consulting/blogs/ai-adoption-challenges-ai-trends.html">AI Trends 2025: Adoption Barriers - Deloitte</a></li>
<li><a href="https://aws.amazon.com/blogs/aws-insights/the-rise-of-autonomous-agents-what-enterprise-leaders-need-to-know-about-the-next-wave-of-ai/">The Rise of Autonomous Agents - AWS</a></li>
<li><a href="https://terralogic.com/multi-agent-ai-systems-why-they-matter-2025/">Multi-Agent AI Systems in 2025 - Terralogic</a></li>
<li><a href="https://www.index.dev/blog/ai-agents-statistics">50+ Key AI Agent Statistics - Index.dev</a></li>
<li><a href="https://www.salesforce.com/news/stories/future-of-ai-agents-2025/">Future of AI Agents 2025 - Salesforce</a></li>
<li><a href="https://superagi.com/top-5-agentic-ai-trends-in-2025-from-multi-agent-collaboration-to-self-healing-systems/">Top 5 Agentic AI Trends - SuperAGI</a></li>
</ul></div>
:::
::::

::: {#b965c2ee .cell .markdown}
## What\'s happening here:

- `query()` creates a single-turn agent interaction (no conversation
  memory)
- `allowed_tools=["WebSearch"]` gives Claude permission to search the
  web without asking for approval
- The agent autonomously decides when to search, what queries to run,
  and how to synthesize results

**Visualization utilities from `utils.agent_visualizer`:**

- `print_activity()` - Shows the agent\'s actions in real-time (tool
  calls, thinking)
- `display_agent_response()` - Renders the final response as a styled
  HTML card
- `visualize_conversation()` - Creates a timeline view of the full
  conversation

That\'s it! A functional research agent in just a few lines of code. The
agent will search for relevant information, follow up on promising
leads, and provide a synthesized summary with citations.
:::

::: {#6b888772 .cell .markdown}
The query() function creates a stateless agent interaction. Each call is
independent---no conversation memory, no context from previous queries.
This makes it perfect for one-off research tasks where you need a quick
answer without maintaining state.

**How tool permissions work:**

The `allowed_tools=["WebSearch"]` parameter gives Claude permission to
search without asking for approval. This is critical for autonomous
operation:

- `Allowed tools` - Claude can use these freely (in this case,
  WebSearch)
- `Other tools` - Available but require approval before use
- `Read-only tools` - Tools like Read are always allowed by default
- `Disallowed tools` - Add tools to disallowed_tools to remove them
  entirely from Claude\'s context

**When to use stateless queries:**

- One-off research questions where context doesn\'t matter
- Parallel processing of independent research tasks
- Scenarios where you want fresh context for each query

**When not to use stateless queries:**

- Multi-turn investigations that build on previous findings
- Iterative refinement of research based on initial results
- Complex analysis requiring sustained context

Let\'s inspect what the agent actually did using the
visualize_conversation helper:
:::

:::: {#1d7c6d90 .cell .code execution_count="5"}
``` python
from utils.agent_visualizer import visualize_conversation

visualize_conversation(messages)
```

::: {.output .display_data}

    
<style>
.conversation-timeline {
    font-family: ui-sans-serif, system-ui;
    max-width: 900px;
    margin: 1em 0;
}
.timeline-header {
    background: linear-gradient(135deg, #3b82f6, #9333ea);
    color: white;
    padding: 12px 16px;
    border-radius: 12px 12px 0 0;
    font-weight: 700;
    font-size: 14px;
}
.timeline-body {
    border: 1px solid #e5e7eb;
    border-top: none;
    border-radius: 0 0 12px 12px;
    padding: 12px;
    background: #fafafa;
}
.msg-block {
    margin: 8px 0;
    padding: 10px 12px;
    border-radius: 8px;
    background: white;
    border-left: 3px solid #e5e7eb;
}
.msg-block.system { border-left-color: #6b7280; }
.msg-block.assistant { border-left-color: #3b82f6; }
.msg-block.tool { border-left-color: #10b981; background: #f0fdf4; }
.msg-block.subagent { border-left-color: #9333ea; background: #faf5ff; }
.msg-block.result { border-left-color: #f59e0b; background: #fffbeb; }
.msg-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: #6b7280;
    margin-bottom: 4px;
}
.msg-content {
    font-size: 13px;
    color: #111;
}
.msg-content pre {
    background: #f3f4f6;
    padding: 8px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 12px;
}
.tool-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.tool-badge {
    background: #e0f2fe;
    color: #0369a1;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-family: monospace;
}
.stats-bar {
    display: flex;
    gap: 16px;
    padding: 10px 12px;
    background: #f9fafb;
    border-radius: 8px;
    font-size: 12px;
    color: #374151;
    margin-top: 8px;
}
.stat-item { display: flex; gap: 4px; }
.stat-label { color: #6b7280; }
</style>

    <div class="conversation-timeline">
        <div class="timeline-header">🤖 Agent Conversation Timeline • claude-opus-4-5</div>
        <div class="timeline-body">
            <div class="msg-block system"><div class="msg-label">⚙️ System</div><div class="msg-content">Initialized (4e8497a9...)</div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">WebSearch: &quot;AI agents trends 2025 latest d...&quot;</span><span class="tool-badge">WebSearch: &quot;autonomous AI agents enterpris...&quot;</span><span class="tool-badge">WebSearch: &quot;multi-agent AI systems trends ...&quot;</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><h2>Latest Trends in AI Agents (2025) - Summary</h2>
<h3>🚀 Market Growth &amp; Adoption</h3>
<p>The AI agent market is experiencing explosive growth, nearly doubling from <strong>$3.7 billion (2023) to $7.38 billion (2025)</strong>, with projections reaching <strong>$103.6 billion by 2032</strong>. According to PwC's 2025 survey, <strong>79% of organizations</strong> have adopted AI agents, with <strong>88% of executives</strong> piloting or scaling autonomous agent systems.</p>
<h3>🔑 Key Trends</h3>
<p><strong>1. Rise of Multi-Agent Systems</strong><br />
Instead of single AI systems trying to do everything, 2025 has introduced the "orchestra approach" where multiple specialized agents collaborate—one gathers research, another drafts reports, and a third reviews. Frameworks like <strong>CrewAI, AutoGen, and LangGraph</strong> are enabling this coordination across enterprise departments.</p>
<p><strong>2. From Assistants to Autonomous Decision-Makers</strong><br />
AI agents are evolving from knowledge assistants to <strong>self-directed workers</strong> that can take initiative, make decisions, and complete multi-step tasks without constant human input. By 2029, <strong>80% of customer service issues</strong> are expected to be resolved entirely by autonomous agents.</p>
<p><strong>3. Model Context Protocol (MCP)</strong><br />
Anthropic's open standard provides a "USB-C for AI"—standardizing how language models connect with external systems, enabling structured multi-step workflows and access to real-time information.</p>
<p><strong>4. Two-Speed Enterprise Landscape</strong><br />
A divide is emerging: companies with existing automation are racing ahead with agentic AI, while others watch from the sidelines. Among highly automated enterprises, <strong>50%</strong> have either adopted or are preparing to adopt autonomous agents.</p>
<h3>⚠️ Key Challenges</h3>
<ul>
<li><strong>Integration with legacy systems</strong> (cited by ~60% of AI leaders)</li>
<li><strong>Trust issues</strong> for high-stakes tasks like financial transactions</li>
<li><strong>Enterprise readiness</strong>—organizations need to expose APIs and prepare infrastructure</li>
<li><strong>Reliability concerns</strong>—agents can misinterpret instructions or fail on edge cases</li>
</ul>
<h3>💼 Impact</h3>
<ul>
<li><strong>66%</strong> of adopters report measurable productivity gains</li>
<li>Early movers are cutting operational costs by up to <strong>40%</strong></li>
<li><strong>75% of executives</strong> believe AI agents will reshape the workplace more than the internet did</li>
<li><strong>87%</strong> agree AI agents augment roles rather than replace them</li>
</ul>
<hr />
<h2>Sources:</h2>
<ul>
<li><a href="https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai">The State of AI in 2025 - McKinsey</a></li>
<li><a href="https://www.ibm.com/think/insights/ai-agents-2025-expectations-vs-reality">AI Agents in 2025: Expectations vs. Reality - IBM</a></li>
<li><a href="https://www.pwc.com/us/en/tech-effect/ai-analytics/ai-agent-survey.html">PwC's AI Agent Survey</a></li>
<li><a href="https://www.mckinsey.com/capabilities/quantumblack/our-insights/seizing-the-agentic-ai-advantage">Seizing the Agentic AI Advantage - McKinsey</a></li>
<li><a href="https://www.gartner.com/en/newsroom/press-releases/2025-08-05-gartner-hype-cycle-identifies-top-ai-innovations-in-2025">Gartner Hype Cycle Identifies Top AI Innovations in 2025</a></li>
<li><a href="https://www.deloitte.com/us/en/services/consulting/blogs/ai-adoption-challenges-ai-trends.html">AI Trends 2025: Adoption Barriers - Deloitte</a></li>
<li><a href="https://aws.amazon.com/blogs/aws-insights/the-rise-of-autonomous-agents-what-enterprise-leaders-need-to-know-about-the-next-wave-of-ai/">The Rise of Autonomous Agents - AWS</a></li>
<li><a href="https://terralogic.com/multi-agent-ai-systems-why-they-matter-2025/">Multi-Agent AI Systems in 2025 - Terralogic</a></li>
<li><a href="https://www.index.dev/blog/ai-agents-statistics">50+ Key AI Agent Statistics - Index.dev</a></li>
<li><a href="https://www.salesforce.com/news/stories/future-of-ai-agents-2025/">Future of AI Agents 2025 - Salesforce</a></li>
<li><a href="https://superagi.com/top-5-agentic-ai-trends-in-2025-from-multi-agent-collaboration-to-self-healing-systems/">Top 5 Agentic AI Trends - SuperAGI</a></li>
</ul></div></div><div class="msg-block result"><div class="msg-label">✅ Complete</div><div class="stats-bar"><span class="stat-item"><span class="stat-label">Turns:</span> 4</span> <span class="stat-item"><span class="stat-label">Tokens:</span> 4,145</span> <span class="stat-item"><span class="stat-label">Cost:</span> $0.51</span> <span class="stat-item"><span class="stat-label">Duration:</span> 51.1s</span></div></div>
        </div>
    </div>
    
:::
::::

::: {#22426729 .cell .markdown}
## From Prototype to Production: Three Key Improvements

Our one-line research agent works, but it\'s limited. Single queries
without memory can\'t handle iterative research (\"find X, then analyze
Y based on what you found\"). Let\'s explore three ways we can further
improve our implementation.

**1. Conversation Memory with ClaudeSDKClient**: Stateless queries
can\'t build on previous findings. If you ask \"What are the top AI
startups?\" then \"How are they funded?\", the second query has no
context about which startups you mean. We can use `ClaudeSDKClient` to
maintain conversation history across multiple queries.

**2. System Prompts for Specialized Behavior**: Research domains often
have specific requirements. Financial analysis needs different rigor
than tech news summaries. Use the system prompt to encode your research
standards, preferred sources, citation format, or output structure. See
our [agent prompting
guide](https://github.com/anthropics/anthropic-cookbook/tree/main/patterns/agents/prompts)
for research-specific examples.

**3. Multimodal Research with the Read Tool**: Real research isn\'t just
text. Market reports have charts, technical docs have diagrams,
competitive analysis requires screenshot comparison. Enable the `Read`
tool so Claude can analyze images, PDFs, and other visual content.

Let\'s implement these three changes for our research agent.
:::

:::: {#fa4c4d8f .cell .code execution_count="6"}
``` python
from claude_agent_sdk import ClaudeSDKClient

# System prompt with citation requirements for research quality
RESEARCH_SYSTEM_PROMPT = """You are a research agent specialized in AI.

When providing research findings:
- Always include source URLs as citations
- Format citations as markdown links: [Source Title](URL)
- Group sources in a "Sources:" section at the end of your response"""

messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="research_agent",
        system_prompt=RESEARCH_SYSTEM_PROMPT,
        allowed_tools=["WebSearch", "Read"],
        max_buffer_size=10 * 1024 * 1024,  # Increase to 10MB for image handling
    )
) as research_agent:
    # First query: Analyze the chart image
    await research_agent.query("Analyze the chart in research_agent/projects_claude.png")
    async for msg in research_agent.receive_response():
        print_activity(msg)
        messages.append(msg)

    # Second query: Use web search to validate/contextualize the chart findings
    await research_agent.query(
        "Based on the chart analysis, search for recent news or data that validates or provides context for these findings. Include source URLs."
    )
    async for msg in research_agent.receive_response():
        print_activity(msg)
        messages.append(msg)
```

::: {.output .stream .stdout}
    🤖 Using: Read()
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Glob()
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Read()
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: WebSearch()
    🤖 Using: WebSearch()
    🤖 Using: WebSearch()
    🤖 Using: WebSearch()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
:::
::::

::: {#i4blqsetg8 .cell .markdown}
### 🔧 Handling Large Responses and Buffer Limits {#wrench-handling-large-responses-and-buffer-limits}

When working with images or large data, you may encounter buffer
overflow errors:

    Fatal error in message reader: Failed to decode JSON: JSON message exceeded maximum buffer size of 1048576 bytes

**Why this happens:**

- The default `max_buffer_size` is 1MB (1,048,576 bytes)
- Images are base64-encoded in messages, significantly increasing size
- The chart image (\~200KB on disk) becomes \~270KB+ when
  base64-encoded, plus message overhead

**Solution:** Set `max_buffer_size` in `ClaudeAgentOptions` to a higher
value (e.g., 10MB) when working with images or large tool outputs.

**Best practices:**

- Set buffer size based on your use case: 10MB for typical multimodal
  work, higher for large document processing
- Consider if you really need to pass full images - sometimes
  descriptions or smaller thumbnails suffice
- Monitor for buffer errors and adjust accordingly
- Include citation requirements in your system prompt to ensure
  verifiable research outputs
:::

::: {#6eb4ed21 .cell .markdown}
## What\'s happening here: {#whats-happening-here}

This example combines all three improvements: conversation memory,
citation-aware system prompt, and multimodal analysis.

**Key components:**

  -----------------------------------------------------------------------
  Component                               Purpose
  --------------------------------------- -------------------------------
  `ClaudeSDKClient`                       Maintains conversation state
                                          across multiple queries

  `RESEARCH_SYSTEM_PROMPT`                Enforces citation formatting
                                          and source URLs

  `allowed_tools=["WebSearch", "Read"]`   Enables web search and
                                          image/document analysis

  `max_buffer_size=10MB`                  Handles base64-encoded images
                                          without overflow
  -----------------------------------------------------------------------

**Execution flow:**

1.  **First query** - Analyzes the chart image using the `Read` tool
2.  **First response loop** - Collects all messages until the agent
    completes
3.  **Second query** - Searches the web to validate/contextualize the
    chart findings
4.  **Context inheritance** - The second query remembers the chart
    analysis from the first

**Why `ClaudeSDKClient` vs `query()`:**

The `async with ClaudeSDKClient()` context manager maintains
conversation state. Each `receive_response()` call builds on previous
context. This differs from `query()` which creates independent,
stateless sessions.
:::

:::: {#7971eae4-3ff1-48d8-99ef-fecca7332163 .cell .code execution_count="7"}
``` python
visualize_conversation(messages)
```

::: {.output .display_data}

    
<style>
.conversation-timeline {
    font-family: ui-sans-serif, system-ui;
    max-width: 900px;
    margin: 1em 0;
}
.timeline-header {
    background: linear-gradient(135deg, #3b82f6, #9333ea);
    color: white;
    padding: 12px 16px;
    border-radius: 12px 12px 0 0;
    font-weight: 700;
    font-size: 14px;
}
.timeline-body {
    border: 1px solid #e5e7eb;
    border-top: none;
    border-radius: 0 0 12px 12px;
    padding: 12px;
    background: #fafafa;
}
.msg-block {
    margin: 8px 0;
    padding: 10px 12px;
    border-radius: 8px;
    background: white;
    border-left: 3px solid #e5e7eb;
}
.msg-block.system { border-left-color: #6b7280; }
.msg-block.assistant { border-left-color: #3b82f6; }
.msg-block.tool { border-left-color: #10b981; background: #f0fdf4; }
.msg-block.subagent { border-left-color: #9333ea; background: #faf5ff; }
.msg-block.result { border-left-color: #f59e0b; background: #fffbeb; }
.msg-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: #6b7280;
    margin-bottom: 4px;
}
.msg-content {
    font-size: 13px;
    color: #111;
}
.msg-content pre {
    background: #f3f4f6;
    padding: 8px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 12px;
}
.tool-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.tool-badge {
    background: #e0f2fe;
    color: #0369a1;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-family: monospace;
}
.stats-bar {
    display: flex;
    gap: 16px;
    padding: 10px 12px;
    background: #f9fafb;
    border-radius: 8px;
    font-size: 12px;
    color: #374151;
    margin-top: 8px;
}
.stat-item { display: flex; gap: 4px; }
.stat-label { color: #6b7280; }
</style>

    <div class="conversation-timeline">
        <div class="timeline-header">🤖 Agent Conversation Timeline • claude-opus-4-5</div>
        <div class="timeline-body">
            <div class="msg-block system"><div class="msg-label">⚙️ System</div><div class="msg-content">Initialized (9d494ab0...)</div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Read: projects_claude.png</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>Let me search for the file in different locations:</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Glob</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>Found it. Let me read the image:</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Read: projects_claude.png</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><h2>Analysis of the Chart: Types of Projects in Claude.ai and Claude Code</h2>
<p>This is a <strong>dumbbell chart</strong> (also called a connected dot plot) that compares the prevalence of different project types between two Anthropic products: <strong>Claude.ai</strong> (blue dots) and <strong>Claude Code</strong> (orange dots).</p>
<h3>Key Findings</h3>
<h4>1. <strong>Personal Projects Lead Both Platforms</strong></h4>
<ul>
<li><strong>Claude Code</strong>: 36.0%</li>
<li><strong>Claude.ai</strong>: 30.2%</li>
<li>This is the most common use case for both platforms, with Claude Code having a slight edge (~6% higher).</li>
</ul>
<h4>2. <strong>Startup Work Shows the Largest Gap</strong></h4>
<ul>
<li><strong>Claude Code</strong>: 32.9%</li>
<li><strong>Claude.ai</strong>: 13.1%</li>
<li>This represents the <strong>biggest difference</strong> between the two platforms (~20% gap), indicating Claude Code is heavily favored for startup development work.</li>
</ul>
<h4>3. <strong>Enterprise Work is Relatively Balanced</strong></h4>
<ul>
<li><strong>Claude.ai</strong>: 25.9%</li>
<li><strong>Claude Code</strong>: 23.8%</li>
<li>Both platforms see similar usage for enterprise work, with Claude.ai slightly ahead (~2% difference).</li>
</ul>
<h4>4. <strong>Learning &amp; Academic Use Favors Claude.ai</strong></h4>
<ul>
<li><strong>Tutorial or Learning</strong>: Claude.ai (12.2%) vs Claude Code (0.7%)</li>
<li><strong>Academic Research</strong>: Claude.ai (11.9%) vs Claude Code (2.2%)</li>
<li><strong>Coursework</strong>: Claude.ai (4.9%) vs Claude Code (0.4%)</li>
<li>These categories show Claude.ai is significantly more popular for educational purposes, likely due to its conversational interface being more accessible for learning.</li>
</ul>
<h4>5. <strong>Open Source Projects are Low for Both</strong></h4>
<ul>
<li><strong>Claude Code</strong>: 4.0%</li>
<li><strong>Claude.ai</strong>: 1.8%</li>
<li>Neither platform sees heavy use for open source contributions, though Claude Code is used slightly more.</li>
</ul>
<h3>Insights &amp; Interpretation</h3>
<table>
<thead>
<tr>
<th>Pattern</th>
<th>Implication</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Claude Code dominates Startup Work</strong></td>
<td>Developers building products at startups prefer the code-focused interface for rapid development</td>
</tr>
<tr>
<td><strong>Claude.ai leads in educational contexts</strong></td>
<td>The conversational nature of Claude.ai makes it more approachable for learning, research, and coursework</td>
</tr>
<tr>
<td><strong>Personal Projects are universal</strong></td>
<td>Both platforms serve individual developers working on side projects equally well</td>
</tr>
<tr>
<td><strong>Enterprise usage is balanced</strong></td>
<td>Both products have found their place in professional enterprise environments</td>
</tr>
</tbody>
</table>
<h3>Summary</h3>
<p>The chart reveals clear <strong>product differentiation</strong>: <br />
- <strong>Claude Code</strong> is preferred for <strong>active software development</strong> (startups, personal coding projects, open source)<br />
- <strong>Claude.ai</strong> excels in <strong>knowledge work and learning</strong> (tutorials, academic research, coursework)</p>
<p>This aligns with the nature of each product—Claude Code is a development tool while Claude.ai is a general-purpose AI assistant with a broader conversational interface.</p></div></div><div class="msg-block result"><div class="msg-label">✅ Complete</div><div class="stats-bar"><span class="stat-item"><span class="stat-label">Turns:</span> 4</span> <span class="stat-item"><span class="stat-label">Tokens:</span> 887</span> <span class="stat-item"><span class="stat-label">Cost:</span> $0.07</span> <span class="stat-item"><span class="stat-label">Duration:</span> 27.6s</span></div></div><div class="msg-block system"><div class="msg-label">⚙️ System</div><div class="msg-content">Initialized (9d494ab0...)</div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">WebSearch: &quot;Claude Code developer adoption...&quot;</span><span class="tool-badge">WebSearch: &quot;Claude AI education academic r...&quot;</span><span class="tool-badge">WebSearch: &quot;Anthropic Claude Code vs Claud...&quot;</span><span class="tool-badge">WebSearch: &quot;AI coding assistants startup d...&quot;</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><h2>Validation &amp; Context for Chart Findings</h2>
<p>Based on my research, here's how recent news and data validate or provide context for the chart analysis:</p>
<hr />
<h3>1. ✅ <strong>Startup Dominance in Claude Code - VALIDATED</strong></h3>
<p>The chart showed Claude Code usage for Startup Work at <strong>32.9%</strong> vs only <strong>13.1%</strong> for Claude.ai—the largest gap in the data. Recent news strongly confirms this:</p>
<blockquote>
<p><strong>"Startups are the main early adopters of Claude Code, suggesting that smaller, agile businesses are leveraging this AI tool to gain a technological advantage."</strong> - <a href="https://blockchain.news/flashnews/startups-lead-claude-code-adoption-key-trends-for-crypto-project-development-in-2025">Blockchain News</a></p>
</blockquote>
<p><strong>YC Startups as Case Studies:</strong><br />
- <strong>HumanLayer (F24)</strong> - Built their entire platform with Claude Code<br />
- <strong>Ambral (W25)</strong> - Scaling AI-powered account management with sub-agent workflows<br />
- <strong>Vulcan Technologies (S25)</strong> - Using Claude Code for regulatory complexity</p>
<p>As noted by <a href="https://www.claude.com/blog/building-companies-with-claude-code">Anthropic's blog</a>: <em>"Founders can now ship products directly from the terminal, compressing development cycles from weeks to hours."</em></p>
<hr />
<h3>2. ✅ <strong>Educational Use Favors Claude.ai - VALIDATED</strong></h3>
<p>The chart showed Claude.ai leading significantly in:<br />
- Tutorial or Learning: <strong>12.2%</strong> (vs 0.7% for Claude Code)<br />
- Academic Research: <strong>11.9%</strong> (vs 2.2%)<br />
- Coursework: <strong>4.9%</strong> (vs 0.4%)</p>
<p>This aligns perfectly with Anthropic's dedicated education initiatives:</p>
<blockquote>
<p><strong>Anthropic launched "Claude for Education"</strong> with features like <strong>"Learning Mode"</strong> that uses Socratic questioning rather than giving direct answers. - <a href="https://venturebeat.com/ai/anthropic-flips-the-script-on-ai-in-education-claude-learning-mode-makes-students-do-the-thinking/">VentureBeat</a></p>
</blockquote>
<p><strong>Key Statistics from Anthropic's Education Report:</strong><br />
- <strong>39.3%</strong> of student conversations involve creating and improving educational content<br />
- <strong>33.5%</strong> involve getting technical explanations for academic assignments<br />
- <strong>57%</strong> of higher ed instructor chats involved developing curricula<br />
- <strong>13%</strong> were conducting academic research</p>
<p>Early adopters include <strong>Northeastern University</strong> (50,000+ students across 13 campuses), <strong>London School of Economics</strong>, and <strong>Champlain College</strong>. - <a href="https://www.anthropic.com/news/anthropic-education-report-how-educators-use-claude">Anthropic Education Report</a></p>
<hr />
<h3>3. ✅ <strong>Coding/Development Dominance - VALIDATED</strong></h3>
<p>The chart showed Personal Projects and Startup Work (both development-heavy) as top uses for Claude Code (<strong>36%</strong> and <strong>32.9%</strong>).</p>
<p>Anthropic's own research confirms:</p>
<blockquote>
<p><strong>"About 44% of API traffic involved coding, compared with 36% on Claude.ai."</strong> - <a href="https://www.anthropic.com/research/anthropic-economic-index-september-2025-report">Anthropic Economic Index</a></p>
<p><strong>"Software development remains Claude's most common use case, making up more than a third of activity globally."</strong> - <a href="https://www.eweek.com/news/anthropic-economic-index-claude-ai-usage/">eWeek</a></p>
</blockquote>
<hr />
<h3>4. ✅ <strong>Product Differentiation (Claude Code vs Claude.ai) - VALIDATED</strong></h3>
<p>The chart's overall pattern showing Claude Code for development and Claude.ai for knowledge work is confirmed by Fortune:</p>
<blockquote>
<p><strong>"ChatGPT is emerging increasingly as a personal or exploratory tool... while Claude is a more work-focused productivity tool, used heavily for coding, research, and business automation."</strong> - <a href="https://fortune.com/2025/09/15/openai-chatgpt-claude-anthropic-work-personal-use-new-data/">Fortune</a></p>
</blockquote>
<p><strong>Automation patterns differ by platform:</strong><br />
- <strong>77% of API tasks</strong> are automated (full task delegation)<br />
- <strong>~50% of Claude.ai tasks</strong> are automated (more collaborative)</p>
<hr />
<h3>5. 📊 <strong>Broader AI Coding Assistant Context</strong></h3>
<p>The chart's findings fit into the larger industry trend:</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>2025 Data</th>
</tr>
</thead>
<tbody>
<tr>
<td>AI-generated/assisted code</td>
<td><strong>41%</strong> of all code globally</td>
</tr>
<tr>
<td>Developers using AI coding assistants</td>
<td><strong>82%</strong> daily or weekly</td>
</tr>
<tr>
<td>Market size projection</td>
<td><strong>$30.1 billion by 2032</strong></td>
</tr>
<tr>
<td>Google's AI-assisted code</td>
<td><strong>25%</strong></td>
</tr>
</tbody>
</table>
<p>Source: <a href="https://www.secondtalent.com/resources/ai-coding-assistant-statistics/">AI Coding Assistant Statistics</a></p>
<hr />
<h3>6. ⚠️ <strong>Enterprise Work Balance - PARTIALLY EXPLAINED</strong></h3>
<p>The chart showed Enterprise Work relatively balanced (Claude.ai: 25.9%, Claude Code: 23.8%). This makes sense given:</p>
<ul>
<li><strong>70-75% of Anthropic's revenue</strong> comes from enterprise API consumption</li>
<li>Enterprises use both products depending on use case</li>
<li>Security features like <strong>FedRAMP High certification</strong> drive enterprise adoption of both platforms</li>
</ul>
<hr />
<h2>Summary</h2>
<p>The chart's findings are <strong>strongly validated</strong> by recent data:</p>
<table>
<thead>
<tr>
<th>Chart Finding</th>
<th>Validation Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Startups prefer Claude Code (32.9% vs 13.1%)</td>
<td>✅ Confirmed by Anthropic &amp; YC case studies</td>
</tr>
<tr>
<td>Education favors Claude.ai (12.2% vs 0.7%)</td>
<td>✅ Confirmed by Anthropic Education Report</td>
</tr>
<tr>
<td>Personal projects lead both platforms</td>
<td>✅ Confirmed by usage statistics</td>
</tr>
<tr>
<td>Claude Code = development tool</td>
<td>✅ Confirmed (44% API traffic is coding)</td>
</tr>
<tr>
<td>Claude.ai = knowledge/learning tool</td>
<td>✅ Confirmed by education initiatives</td>
</tr>
</tbody>
</table>
<hr />
<h2>Sources</h2>
<ul>
<li><a href="https://www.claude.com/blog/building-companies-with-claude-code">How Three YC Startups Built Their Companies with Claude Code</a></li>
<li><a href="https://www.anthropic.com/startups">Anthropic Startups Program</a></li>
<li><a href="https://blockchain.news/flashnews/startups-lead-claude-code-adoption-key-trends-for-crypto-project-development-in-2025">Startups Lead Claude Code Adoption - Blockchain News</a></li>
<li><a href="https://www.anthropic.com/news/anthropic-education-report-how-educators-use-claude">Anthropic Education Report: How Educators Use Claude</a></li>
<li><a href="https://www.anthropic.com/news/anthropic-education-report-how-university-students-use-claude">How University Students Use Claude</a></li>
<li><a href="https://www.anthropic.com/news/introducing-claude-for-education">Introducing Claude for Education</a></li>
<li><a href="https://www.eweek.com/news/anthropic-economic-index-claude-ai-usage/">Anthropic's AI Usage Study: Coding Still Dominates - eWeek</a></li>
<li><a href="https://www.anthropic.com/research/anthropic-economic-index-september-2025-report">Anthropic Economic Index September 2025 Report</a></li>
<li><a href="https://fortune.com/2025/09/15/openai-chatgpt-claude-anthropic-work-personal-use-new-data/">New Studies Show What People Really Use ChatGPT and Claude For - Fortune</a></li>
<li><a href="https://backlinko.com/claude-users">Claude Statistics 2025 - Backlinko</a></li>
<li><a href="https://www.secondtalent.com/resources/ai-coding-assistant-statistics/">AI Coding Assistant Statistics &amp; Trends 2025</a></li>
<li><a href="https://venturebeat.com/ai/anthropic-flips-the-script-on-ai-in-education-claude-learning-mode-makes-students-do-the-thinking/">Anthropic Flips the Script on AI in Education - VentureBeat</a></li>
<li><a href="https://keywordseverywhere.com/blog/anthropic-claude-stats/">55 Latest Anthropic Claude Stats - Keywords Everywhere</a></li>
</ul></div></div><div class="msg-block result"><div class="msg-label">✅ Complete</div><div class="stats-bar"><span class="stat-item"><span class="stat-label">Turns:</span> 5</span> <span class="stat-item"><span class="stat-label">Tokens:</span> 2,152</span> <span class="stat-item"><span class="stat-label">Cost:</span> $0.76</span> <span class="stat-item"><span class="stat-label">Duration:</span> 73.0s</span></div></div>
        </div>
    </div>
    
:::
::::

::: {#38256581 .cell .markdown}
## Building for Production

Jupyter notebooks are great for learning, but production systems need
reusable modules. We\'ve packaged the research agent into
`research_agent/agent.py` with a clean interface:

### Core functions:

- `print_activity()` - Shows what the agent is doing in real-time
  (imported from shared utilities)
- `get_activity_text()` - Extract activity text for custom handlers,
  such as logging or monitoring
- `send_query()` - Main entry point for research queries with built-in
  activity display

### Built-in best practices:

The module includes the `RESEARCH_SYSTEM_PROMPT` which ensures:

- Source URLs are always included as citations
- Citations are formatted as markdown links for clean rendering
- A \"Sources:\" section groups all references

### Display control:

The `send_query()` function has a `display_result` parameter (default:
`True`):

- `display_result=True` - Renders a styled HTML card in Jupyter
  notebooks
- `display_result=False` - Returns only the text result for programmatic
  use

This agent can now be used in any Python script!
:::

::: {#e220b5c7-463b-4171-b687-b1ec974958de .cell .markdown}
For independent questions where conversation context doesn\'t matter.

The module automatically handles:

- Activity display during execution
- Context reset for new conversations
- Styled HTML rendering of the final response
:::

::::: {#3c2ca449-7a36-4b67-af47-fdb68fb3e36b .cell .code execution_count="8"}
``` python
from research_agent.agent import send_query

# The module handles activity display, context reset, and result visualization internally
result = await send_query("What is the Claude Code SDK? Only do one websearch and be concise")
```

::: {.output .stream .stdout}
    🤖 Using: WebSearch()
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><h2>Claude Code SDK</h2>
<p>The <strong>Claude Code SDK</strong> (now renamed to <strong>Claude Agent SDK</strong>) is a toolkit from Anthropic that allows developers to build AI agents using the same infrastructure that powers Claude Code.</p>
<p><strong>Key capabilities:</strong><br />
- <strong>Context management</strong> - Automatic compaction to prevent running out of context<br />
- <strong>Rich tool ecosystem</strong> - File operations, code execution, web search, MCP extensibility<br />
- <strong>Fine-grained permissions</strong> - Control over agent capabilities<br />
- <strong>Production features</strong> - Error handling, session management, monitoring</p>
<p><strong>Available in:</strong><br />
- TypeScript (<code>@anthropic-ai/claude-code</code>)<br />
- Python (<code>pip install claude-code-sdk</code>)<br />
- Command line</p>
<p>It enables building agents for coding automation, customer support, personal assistants, and more—all using the same core systems that power Claude Code.</p>
<hr />
<p><strong>Sources:</strong><br />
- <a href="https://docs.anthropic.com/en/docs/claude-code/sdk">Agent SDK overview - Claude Docs</a><br />
- <a href="https://www.anthropic.com/engineering/building-agents-with-the-claude-agent-sdk">Building agents with the Claude Agent SDK</a><br />
- <a href="https://www.infoq.com/news/2025/06/claude-code-sdk/">Anthropic Releases Claude Code SDK - InfoQ</a></p></div>
:::
:::::

::: {#466155ec-9f54-49d4-83cb-00032b077147 .cell .markdown}
Now we test out a multi-turn conversation that reuses the same
conversation.

Multi-turn conversations work seamlessly---just pass
`continue_conversation=True`:
:::

::::: {#38ba1eda .cell .code execution_count="9"}
``` python
result1 = await send_query("What is Anthropic? Only do one websearch and be concise")
```

::: {.output .stream .stdout}
    🤖 Using: WebSearch()
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><p><strong>Anthropic</strong> is an American AI safety company founded in 2021 by former OpenAI executives, including siblings Dario and Daniela Amodei. The company builds Claude, a family of large language models, with a focus on creating reliable, interpretable, and safe AI systems. Anthropic is valued at approximately $183 billion and has received major investments from Amazon, Google, Microsoft, and NVIDIA. Its Claude Code product recently reached $1 billion in run-rate revenue.</p>
<p>Sources:<br />
- <a href="https://en.wikipedia.org/wiki/Anthropic">Anthropic - Wikipedia</a><br />
- <a href="https://www.anthropic.com/">Anthropic Homepage</a><br />
- <a href="https://www.voiceflow.com/blog/anthropic-ai">What's Anthropic AI? - Voiceflow</a></p></div>
:::
:::::

::::: {#36931a9e .cell .code execution_count="10"}
``` python
# Continue the conversation to dig deeper by setting continue_conversation=True
result2 = await send_query(
    "What are some of their products?",
    continue_conversation=True,
)
```

::: {.output .stream .stdout}
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><p>Based on my previous search results, here are Anthropic's main products:</p>
<ol>
<li>
<p><strong>Claude</strong> - Their flagship AI assistant and family of large language models, which incorporates "Constitutional AI" for safety. Named after mathematician Claude Shannon.</p>
</li>
<li>
<p><strong>Claude Code</strong> - A developer tool that recently reached $1 billion in run-rate revenue just six months after public launch.</p>
</li>
<li>
<p><strong>Bun</strong> - A JavaScript runtime that Anthropic recently acquired to accelerate Claude Code's capabilities.</p>
</li>
</ol>
<p>Anthropic offers Claude through their website, API access for developers, and enterprise solutions.</p>
<p>Sources:<br />
- <a href="https://www.anthropic.com/">Anthropic Homepage</a><br />
- <a href="https://www.anthropic.com/news/anthropic-acquires-bun-as-claude-code-reaches-usd1b-milestone">Anthropic acquires Bun as Claude Code reaches $1B milestone</a></p></div>
:::
:::::

::: {#5344587c .cell .markdown}
## Conclusion

### What You Built

In this cookbook, you built three progressively sophisticated research
agents:

- Stateless research agent - One-line queries for independent research
  tasks
- Stateful agent with memory - Multi-turn investigations that build on
  previous findings
- Production module - Reusable research functions for integration into
  applications

### Key Takeaways

**When to use stateless queries (query()):**

- Independent research questions
- Parallel processing of unrelated tasks
- Scenarios requiring fresh context each time

**When to use stateful agents (ClaudeSDKClient):**

- Multi-turn investigations building on previous findings
- Iterative refinement of research
- Complex analysis requiring sustained context

Research agents excel when information isn\'t self-contained and the
optimal workflow emerges during exploration---competitive analysis,
technical troubleshooting, literature reviews, and investigative
journalism all fit this pattern.

### Next Steps

This foundation in autonomous research prepares you for enterprise-grade
multi-agent systems. In the next notebook, you\'ll learn to:

Orchestrate specialized subagents under a coordinating agent Implement
governance through hooks and custom commands Adapt output styles for
different stakeholders (executives vs. technical teams)

Next:
[01_The_chief_of_staff_agent.ipynb](https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb) -
From single agents to multi-agent orchestration.
:::

---

## Define the model to use throughout this notebook

Source: https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-claude-agent-sdk-01-the-chief-of-staff-agent.md

from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient

load_dotenv()

# Define the model to use throughout this notebook
# Using Opus 4.5 for its superior planning and reasoning capabilities
MODEL = "claude-opus-4-5"
print(f"📋 Notebook configured to use: {MODEL}")
```

::: {.output .stream .stdout}
    📋 Notebook configured to use: claude-opus-4-5
:::
::::

::: {.cell .markdown}
# 01 - The Chief of Staff Agent {#01---the-chief-of-staff-agent}

#### Introduction

In notebook 00, we built a simple research agent. In this notebook,
we\'ll incrementally introduce key Claude Code SDK features for building
comprehensive agents. For each introduced feature, we\'ll explain:

- **What**: what the feature is
- **Why**: what the feature can do and why you would want to use it
- **How**: a minimal implementation showing how to use it

If you are familiar with Claude Code, you\'ll notice how the SDK brings
feature parity and enables you to leverage all of Claude Code\'s
capabilities in a programmatic headless manner.

#### Scenario

Throughout this notebook, we\'ll build an **AI Chief of Staff** for a
50-person startup that just raised \$10M Series A. The CEO needs
data-driven insights to balance aggressive growth with financial
sustainability.

Our final Chief of Staff agent will:

- **Coordinate specialized subagents** for different domains
- **Aggregate insights** from multiple sources
- **Provide executive summaries** with actionable recommendations
:::

::: {.cell .markdown}
## Basic Features
:::

::: {.cell .markdown}
### Feature 0: Memory with [CLAUDE.md](https://www.anthropic.com/engineering/claude-code-best-practices) {#feature-0-memory-with-claudemd}

**What**: `CLAUDE.md` files serve as persistent memory and instructions
for your agent. When present in the project directory, Claude Code
automatically reads and incorporates this context when you initialize
your agent.

**Why**: Instead of repeatedly providing project context, team
preferences, or standards in each interaction, you can define them once
in `CLAUDE.md`. This ensures consistent behavior and reduces token usage
by avoiding redundant explanations.

**How**:

- Have a `CLAUDE.md` file in the working directory - in our example:
  `chief_of_staff_agent/CLAUDE.md`
- Set the `cwd` argument of your ClaudeSDKClient to point to directory
  of your CLAUDE.md file
- Use explicit prompts to guide the agent when you want it to prefer
  high-level context over detailed data files

**Important Behavior Note**: When both CLAUDE.md and detailed data files
(like CSVs) are available, the agent may prefer to read the more
granular data sources to provide precise answers. This is expected
behavior - agents naturally seek authoritative data. To ensure the agent
uses high-level CLAUDE.md context, use explicit prompt instructions (see
example below). This teaches an important lesson: CLAUDE.md provides
*context and guidance*, not hard constraints on data sources.
:::

::::: {.cell .code execution_count="2"}
``` python
messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="chief_of_staff_agent",  # Points to subdirectory with our CLAUDE.md
        setting_sources=["project"],
    )
) as agent:
    await agent.query("What's our current runway?")
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)

# Display the response with HTML rendering
display_agent_response(messages)
# With this prompt, the agent should use CLAUDE.md values: ~$500K burn, 20 months runway
```

::: {.output .stream .stdout}
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><p>Based on the company information, <strong>TechStart Inc's current runway is 20 months</strong> (until September 2025).</p>
<p>Here are the key financial details:<br />
- <strong>Cash in Bank</strong>: $10M<br />
- <strong>Monthly Burn Rate</strong>: ~$500,000<br />
- <strong>Runway</strong>: 20 months</p>
<p>This gives you a solid runway to execute on Q2 2024 priorities, including hiring 10 engineers, launching the AI code review feature, European expansion, and beginning Series B conversations (targeting $30M).</p></div>
:::
:::::

::: {.cell .markdown}
#### Understanding Agent Data Source Preferences

**What Just Happened:** By adding to our prompt, we guided the agent to
rely on the CLAUDE.md context rather than seeking more granular data
from CSV files.

**Key Insights:**

1.  **CLAUDE.md as Context, Not Constraint**: When you set `cwd`, the
    CLAUDE.md file is loaded as background context. However, agents will
    naturally seek the most authoritative data sources available. If
    detailed CSV files exist, the agent may prefer them for precision.

2.  **Prompt Engineering Matters**: The phrasing \"high-level financial
    numbers from context\" signals to the agent that you want the
    simplified executive summary from CLAUDE.md (\$500K burn, 20 months
    runway) rather than the precise month-by-month data from
    financial_data/burn_rate.csv (\$525K gross, \$235K net burn).

3.  **Architectural Design Choice**: This behavior is actually desirable
    in production systems - you want agents to find the best data
    source. CLAUDE.md should contain:

    - High-level context and strategy
    - Company information and standards
    - Pointers to where detailed data lives
    - Guidelines on when to use high-level vs. detailed numbers

4.  **Real-World Pattern**: Think of CLAUDE.md as an \"onboarding
    document\" that orients the agent, while detailed files are \"source
    systems\" the agent can query when precision matters.
:::

::: {.cell .markdown}
### Feature 1: The Bash tool for Python Script Execution

**What**: The Bash tool allows your agent to (among other things) run
Python scripts directly, enabling access to procedural knowledge,
complex computations, data analysis and other integrations that go
beyond the agent\'s native capabilities.

**Why**: Our Chief of Staff might need to process data files, run
financial models or generate visualizations based on this data. These
are all good scenarios for using the Bash tool.

**How**: Have your Python scripts set-up in a place where your agent can
reach them and add some context on what they are and how they can be
called. If the scripts are meant for your chief of staff agent, add this
context to its CLAUDE.md file and if they are meant for one your
subagents, add said context to their MD files (more details on this
later). For this tutorial, we added five toy examples to
`chief_of_staff_agent/scripts`:

1.  `hiring_impact.py`: Calculates how new engineering hires affect burn
    rate, runway, and cash position. Essential for the
    `financial-analyst` subagent to model hiring scenarios against the
    \$500K monthly burn and 20-month runway.
2.  `talent_scorer.py`: Scores candidates on technical skills,
    experience, culture fit, and salary expectations using weighted
    criteria. Core tool for the `recruiter` subagent to rank engineering
    candidates against TechStart\'s \$180-220K senior engineer
    benchmarks.
3.  `simple_calculation.py`: Performs quick financial calculations for
    runway, burn rate, and quarterly metrics. Utility script for chief
    of staff to get instant metrics without complex modeling.
4.  `financial_forecast.py`: Models ARR growth scenarios
    (base/optimistic/pessimistic) given the current \$2.4M ARR growing
    at 15% MoM.Critical for `financial-analyst` to project Series B
    readiness and validate the \$30M fundraising target.
5.  `decision_matrix.py`: Creates weighted decision matrices for
    strategic choices like the SmartDev acquisition or office expansion.
    Helps chief of staff systematically evaluate complex decisions with
    multiple stakeholders and criteria.
:::

::::: {.cell .code execution_count="3"}
``` python
messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        allowed_tools=["Bash", "Read"],
        cwd="chief_of_staff_agent",  # Points to subdirectory where our agent is defined
    )
) as agent:
    await agent.query(
        "Use your simple calculation script with a total runway of 2904829 and a monthly burn of 121938."
    )
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)

# Display the response with HTML rendering
display_agent_response(messages)
```

::: {.output .stream .stdout}
    🤖 Using: Glob()
    🤖 Using: Glob()
    🤖 Using: Glob()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Read()
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Bash()
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><p>Here are the financial metrics calculated using the simple calculation script:</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Total Runway</strong></td>
<td>$2,904,829.00</td>
</tr>
<tr>
<td><strong>Monthly Burn</strong></td>
<td>$121,938.00</td>
</tr>
<tr>
<td><strong>Runway Months</strong></td>
<td>~23.82 months</td>
</tr>
<tr>
<td><strong>Quarterly Burn</strong></td>
<td>$365,814.00</td>
</tr>
<tr>
<td><strong>Daily Burn Rate</strong></td>
<td>$4,064.60</td>
</tr>
</tbody>
</table>
<p>Based on these calculations, with a total runway of $2,904,829 and a monthly burn rate of $121,938, you have approximately <strong>23.8 months</strong> (just under 2 years) of runway remaining.</p></div>
:::
:::::

::: {.cell .markdown}
### Feature 2: Output Styles

**What**: Output styles allow you to use different output styles for
different audiences. Each style is defined in a markdown file.

**Why**: Your agent might be used by people of different levels of
expertise or they might have different priorities. Your output style can
help differentiate between these segments without having to create a
separate agent.

**How**:

- Configure a markdown file per style in
  `chief_of_staff_agent/.claude/output-styles/`. For example, check out
  the Executive Ouput style in `.claude/output-styles/executive.md`.
  Output styles are defined with a simple frontmatter including two
  fields: name and description. Note: Make sure the name in the
  frontmatter matches exactly the file\'s name (case sensitive)

> **IMPORTANT**: Output styles modify the system prompt that Claude Code
> has underneath, leaving out the parts focused on software engineering
> and giving you more control for your specific use case beyond software
> engineering work.

> **SDK CONFIGURATION NOTE**: Similar to slash commands (covered in
> Feature 4), output styles are stored on the filesystem in
> `.claude/output-styles/`. For the SDK to load these files, you
> **must** include `setting_sources=["project"]` in your
> `ClaudeAgentOptions`. The `settings` parameter tells the SDK *which*
> style to use, but `setting_sources` is required to actually *load* the
> style definitions. This requirement was identified while debugging
> later sections and applies to all filesystem-based settings.
:::

:::: {.cell .code execution_count="4"}
``` python
messages_executive = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="chief_of_staff_agent",
        settings='{"outputStyle": "executive"}',
        # IMPORTANT: setting_sources must include "project" to load output styles from .claude/output-styles/
        # Without this, the SDK does NOT load filesystem settings (output styles, slash commands, etc.)
        setting_sources=["project"],
    )
) as agent:
    await agent.query("Tell me in two sentences about your writing output style.")
    async for msg in agent.receive_response():
        print_activity(msg)
        messages_executive.append(msg)

messages_technical = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="chief_of_staff_agent",
        settings='{"outputStyle": "technical"}',
        setting_sources=["project"],
    )
) as agent:
    await agent.query("Tell me in two sentences about your writing output style.")
    async for msg in agent.receive_response():
        print_activity(msg)
        messages_technical.append(msg)
```

::: {.output .stream .stdout}
    🤖 Thinking...
    🤖 Thinking...
:::
::::

:::: {.cell .code execution_count="5"}
``` python
# Display executive style response
display_agent_response(messages_executive)
```

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><p>My writing style is direct, concise, and professional—I avoid unnecessary filler and get straight to actionable insights. I adapt my tone based on context: more formal for strategic recommendations and board-level communications, more conversational for quick operational questions.</p></div>
:::
::::

:::: {.cell .code execution_count="6"}
``` python
# Technical output style - detailed, implementation-focused
display_agent_response(messages_technical, title="Technical Style")
```

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Technical Style</div><p>My writing style is direct, clear, and professional—I provide concise answers without unnecessary filler while ensuring the information is complete and actionable. I adapt my tone to the context, being more formal for business analysis and more conversational for general questions, and I use formatting (like bullet points, headers, or code blocks) when it helps organize complex information.</p></div>
:::
::::

::: {.cell .markdown}
### Feature 3: Plan Mode - Strategic Planning Without Execution

**What**: Plan mode instructs the agent to create a detailed execution
plan without performing any actions. The agent analyzes requirements,
proposes solutions, and outlines steps, but doesn\'t modify files,
execute commands, or make changes.

**Why**: Complex tasks benefit from upfront planning to reduce errors,
enable review and improve coordination. After the planning phase, the
agent will have a red thread to follow throughout its execution.

**How**: Just set `permission_mode="plan"`

**Plan Persistence**: Since plans are valuable artifacts for review and
decision-making, we\'ll demonstrate how to capture and save them to
persistent markdown files. This enables stakeholders to review plans
before approving execution.

> Note: this feature shines in Claude Code but still needs to be fully
> adapted for headless applications with the SDK. Namely, the agent will
> try calling its `ExitPlanMode()` tool, which is only relevant in the
> interactive mode. In this case, you can send up a follow-up query with
> `continue_conversation=True` for the agent to execute its plan in
> context.
:::

:::: {.cell .code execution_count="7"}
``` python
# =============================================================================
# Plan Mode Helper Functions
# =============================================================================
# These utilities handle the various ways an agent might output its plan.
# Since agents can output plans via direct text, Write tool, or Claude's
# internal plan directory, we need robust extraction from multiple sources.

import glob as glob_module
import os
import re
from datetime import datetime
from pathlib import Path
from typing import Any


def extract_plan_from_xml(text: str | None, min_length: int = 200) -> str | None:
    """
    Extract content between <plan> tags from text.

    Args:
        text: The text to search for plan content
        min_length: Minimum character count for valid plan (prevents empty matches)

    Returns:
        Extracted plan content, or None if not found/too short
    """
    if not text:
        return None
    match = re.search(r"<plan>(.*?)</plan>", text, re.DOTALL)
    if match:
        extracted = match.group(1).strip()
        if len(extracted) > min_length:
            return extracted
    return None


def extract_plan_from_messages(
    plan_content: list[str], min_fallback_length: int = 500
) -> tuple[str | None, str | None]:
    """
    Try to extract plan from captured message stream content.

    Args:
        plan_content: List of text blocks captured during streaming
        min_fallback_length: Minimum length for fallback (no XML tags)

    Returns:
        Tuple of (plan_text, source_description)
    """
    combined_text = "\n\n".join(plan_content)

    # First try: XML tags
    plan = extract_plan_from_xml(combined_text)
    if plan:
        return plan, "message stream"

    # Fallback: Use raw content if substantial
    if len(combined_text.strip()) > min_fallback_length:
        return combined_text.strip(), "full message content (fallback)"

    return None, None


def extract_plan_from_write_tool(
    write_contents: list[str], min_fallback_length: int = 500
) -> tuple[str | None, str | None]:
    """
    Try to extract plan from captured Write tool calls.

    Args:
        write_contents: List of content strings from Write tool calls
        min_fallback_length: Minimum length for fallback (no XML tags)

    Returns:
        Tuple of (plan_text, source_description)
    """
    for content in write_contents:
        # Try XML extraction first
        plan = extract_plan_from_xml(content)
        if plan:
            return plan, "Write tool capture"

        # Fallback: substantial content without tags
        if content and len(content.strip()) > min_fallback_length:
            return content.strip(), "Write tool capture (no XML tags)"

    return None, None


def extract_plan_from_claude_dir(
    max_age_seconds: int = 300, min_fallback_length: int = 500
) -> tuple[str | None, str | None]:
    """
    Check Claude's internal plan directory for recently created plans.

    Args:
        max_age_seconds: Maximum age of plan file to consider (default: 5 minutes)
        min_fallback_length: Minimum length for fallback (no XML tags)

    Returns:
        Tuple of (plan_text, source_description)
    """
    claude_plans_dir = os.path.expanduser("~/.claude/plans")

    if not os.path.exists(claude_plans_dir):
        return None, None

    # Find most recent plan file
    plan_files = sorted(
        glob_module.glob(os.path.join(claude_plans_dir, "*.md")),
        key=os.path.getmtime,
        reverse=True,
    )

    if not plan_files:
        return None, None

    most_recent = plan_files[0]
    file_age = datetime.now().timestamp() - os.path.getmtime(most_recent)

    if file_age > max_age_seconds:
        return None, None

    with open(most_recent) as f:
        content = f.read()

    filename = os.path.basename(most_recent)

    # Try XML extraction first
    plan = extract_plan_from_xml(content)
    if plan:
        return plan, f"Claude plan file ({filename})"

    # Fallback: substantial content without tags
    if len(content.strip()) > min_fallback_length:
        return content.strip(), f"Claude plan file ({filename}, no XML tags)"

    return None, None


def save_plan_to_file(
    plan_content: str,
    plan_source: str,
    model_name: str,
    prompt_summary: str,
    output_dir: str = "chief_of_staff_agent/plans",
    title: str = "Agent Plan: Engineering Restructure for AI Focus",
) -> Path:
    """
    Save extracted plan to a timestamped markdown file.

    Args:
        plan_content: The plan text to save
        plan_source: Description of where plan was extracted from
        model_name: The model used to generate the plan
        prompt_summary: Brief description of the original prompt
        output_dir: Directory to save plan files
        title: Title for the plan document

    Returns:
        Path to the saved plan file
    """
    plans_dir = Path(output_dir)
    plans_dir.mkdir(exist_ok=True)

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    plan_file = plans_dir / f"plan_{timestamp}.md"

    with open(plan_file, "w") as f:
        f.write(f"# {title}\n\n")
        f.write(f"**Created:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
        f.write(f"**Prompt:** {prompt_summary}\n")
        f.write(f"**Model:** {model_name}\n")
        f.write(f"**Plan Source:** {plan_source}\n\n")
        f.write("---\n\n")
        f.write(plan_content)
        f.write("\n\n---\n\n")
        f.write("*This plan was generated in plan mode and has not been executed.*\n")

    return plan_file


def capture_message_content(
    msg: Any,
    plan_content: list[str],
    write_tool_content: list[str],
    write_tool_paths: list[str],
) -> None:
    """
    Process a streaming message and capture relevant plan content.

    This function extracts content from three potential sources:
    1. Text blocks in message content
    2. Write tool call parameters
    3. Final result attribute

    Args:
        msg: The message object from the agent stream
        plan_content: List to append text content to
        write_tool_content: List to append Write tool content to
        write_tool_paths: List to append Write tool file paths to
    """
    # Source 1: Text blocks from message content
    if hasattr(msg, "content"):
        for block in msg.content:
            if hasattr(block, "text"):
                plan_content.append(block.text)

            # Source 2: Write tool calls
            if hasattr(block, "type") and block.type == "tool_use":
                if hasattr(block, "name") and block.name == "Write":
                    if hasattr(block, "input") and isinstance(block.input, dict):
                        if "content" in block.input:
                            write_tool_content.append(block.input["content"])
                        if "file_path" in block.input:
                            write_tool_paths.append(block.input["file_path"])

    # Source 3: Final result
    if hasattr(msg, "result") and msg.result:
        plan_content.append(msg.result)


print("✅ Plan Mode helper functions loaded")
```

::: {.output .stream .stdout}
    ✅ Plan Mode helper functions loaded
:::
::::

:::: {.cell .code execution_count="8"}
``` python
# =============================================================================
# Plan Mode Configuration
# =============================================================================

# Note: MODEL is defined in cell-0 as "claude-opus-4-5"
# Opus excels at complex planning tasks

# The prompt is carefully crafted to:
# 1. Provide explicit context (since Opus prefers explicit information)
# 2. Request XML-tagged output for reliable extraction
# 3. Prevent file-writing so we can capture the plan programmatically

PLAN_PROMPT = """Restructure our engineering team for AI focus.

**CONTEXT (from CLAUDE.md):**
You are the Chief of Staff for TechStart Inc, a 50-person B2B SaaS startup that raised $10M Series A.
- Current engineering team: 25 people (Backend: 12, Frontend: 8, DevOps: 5)
- Monthly burn rate: ~$500K, Runway: 20 months
- Senior Engineer compensation: $180K-$220K + equity

**CRITICAL OUTPUT INSTRUCTIONS:**

1. **DO NOT use the Write tool** - Output your plan directly in your response text
2. **DO NOT save to any files** - I will handle saving the plan myself
3. **Wrap your ENTIRE plan inside `<plan> </plan>` XML tags** in your response

**Required Format:**
<plan>
[Your complete restructuring plan here - include all sections, timelines, budgets, and recommendations]
</plan>

**IMPORTANT:**
- The plan content MUST appear directly in your response between the XML tags
- Do NOT use Write, Edit, or any file-saving tools
- You may research and analyze before outputting, but the final plan must be in your response text
- Include: team structure, hiring recommendations, timeline, budget impact, and success metrics
- Use the company context provided above - do NOT ask clarifying questions"""

print(f"📋 Plan Mode configured with model: {MODEL}")
print(f"📝 Prompt length: {len(PLAN_PROMPT):,} characters")
```

::: {.output .stream .stdout}
    📋 Plan Mode configured with model: claude-opus-4-5
    📝 Prompt length: 1,180 characters
:::
::::

:::: {.cell .code execution_count="9"}
``` python
# =============================================================================
# Execute Plan Mode Agent
# =============================================================================
# Run the agent with plan mode enabled. The agent will create a detailed plan
# but won't execute any actions. We capture content from multiple sources
# to handle different agent behaviors.

# Initialize capture lists
messages = []
plan_content = []  # Text from message stream
write_tool_content = []  # Content from Write tool calls
write_tool_paths = []  # Paths from Write tool calls

# Run the agent in plan mode
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        permission_mode="plan",
        cwd="chief_of_staff_agent",
    )
) as agent:
    await agent.query(PLAN_PROMPT)
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)

        # Capture content from this message
        capture_message_content(msg, plan_content, write_tool_content, write_tool_paths)

print(f"\n✅ Agent completed. Captured {len(plan_content)} content blocks.")
```

::: {.output .stream .stdout}
    🤖 Thinking...
    🤖 Using: ExitPlanMode()
    ✓ Tool completed
    🤖 Thinking...

    ✅ Agent completed. Captured 3 content blocks.
:::
::::

:::: {.cell .code execution_count="10"}
``` python
# =============================================================================
# Extract and Save the Plan
# =============================================================================
# Try multiple sources in priority order to find the plan content.
# This handles different agent behaviors robustly.

final_plan = None
plan_source = None

# Priority 1: Message stream (preferred - direct from agent response)
final_plan, plan_source = extract_plan_from_messages(plan_content)

# Priority 2: Write tool captures (if agent saved despite instructions)
if not final_plan and write_tool_content:
    final_plan, plan_source = extract_plan_from_write_tool(write_tool_content)

# Priority 3: Claude's internal plan directory (safety net)
if not final_plan:
    final_plan, plan_source = extract_plan_from_claude_dir()

# Report results
if final_plan:
    print(f"✅ Plan extracted from: {plan_source}")
    print(f"   Plan length: {len(final_plan):,} characters")

    # Save to file
    plan_file = save_plan_to_file(
        plan_content=final_plan,
        plan_source=plan_source,
        model_name=MODEL,
        prompt_summary="Restructure our engineering team for AI focus.",
    )
    print(f"\n📁 Plan saved to: {plan_file}")
else:
    error_msg = "Could not extract plan content from any source!\n"
    error_msg += "   Sources checked: message stream, Write tool, ~/.claude/plans/"
    if write_tool_paths:
        error_msg += f"\n   Write tool attempted to save to: {write_tool_paths}"
    print(f"❌ ERROR: {error_msg}")
    raise RuntimeError(f"Plan extraction failed: {error_msg}")
```

::: {.output .stream .stdout}
    ✅ Plan extracted from: message stream
       Plan length: 6,783 characters

    📁 Plan saved to: chief_of_staff_agent/plans/plan_20251204_152737.md
:::
::::

:::: {.cell .code execution_count="11"}
``` python
# Display the plan result with styled HTML
display_agent_response(messages, title="Engineering Restructure Plan")
```

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Engineering Restructure Plan</div><p>I've provided the complete engineering team restructuring plan directly in my response within the <code>&lt;plan&gt;</code> tags as requested. The plan includes:</p>
<ul>
<li><strong>Team structure changes</strong> - From 25 to 29 engineers with 2 new AI-focused teams</li>
<li><strong>Hiring roadmap</strong> - 6 new hires over 8 months, prioritized by criticality</li>
<li><strong>Internal transfers</strong> - 4 engineers upskilled from existing teams</li>
<li><strong>12-month timeline</strong> - Phased implementation with clear milestones</li>
<li><strong>Budget analysis</strong> - Monthly burn increases from ~$380K to ~$537K</li>
<li><strong>Success metrics</strong> - Concrete KPIs for 6 and 12-month checkpoints</li>
<li><strong>Risk mitigation</strong> - Key risks identified with mitigation strategies</li>
</ul>
<p>Ready to proceed when you've reviewed the plan!</p></div>
:::
::::

::: {.cell .markdown}
#### Executing the Saved Plan

As mentioned above, the agent will stop after creating its plan. The
saved plan file serves as a review artifact for stakeholders.

**To execute the plan after review:**

1.  Review the saved plan in `chief_of_staff_agent/plans/plan_*.md`
2.  If approved, send a new query with `continue_conversation=True` and
    remove `permission_mode="plan"` to execute

This workflow enables a \"plan → review → approve → execute\" cycle,
perfect for high-stakes decisions like organizational restructuring or
major infrastructure changes.
:::

::: {.cell .markdown}
#### How Plan Persistence Works

In the code above, we implemented a **robust multi-source plan capture
mechanism** that handles the various ways Plan Mode agents may output
their plans:

**The Challenge:** When using `permission_mode="plan"`, the agent may
output the plan in different ways:

1.  **Direct text output** in the message stream (ideal case)
2.  **Write tool** to save to `~/.claude/plans/` (Claude\'s internal
    plan system)
3.  **Write tool** to save to a custom path

Our capture mechanism handles all three scenarios with a
**priority-based fallback system**:

**Source Priority (in order):**

1.  **Message Stream** (Preferred)
    - Capture text blocks from `msg.content` during streaming
    - Extract content between `<plan></plan>` XML tags
    - This is the cleanest approach as content comes directly from the
      response
2.  **Write Tool Capture**
    - Monitor for Write tool calls in the message stream
    - Extract the `content` parameter being written
    - Useful when the agent decides to save despite prompt instructions
3.  **Claude\'s Internal Plan Directory**
    - Check `~/.claude/plans/` for recently created plan files (within 5
      minutes)
    - Read and extract content from the most recent file
    - Acts as a safety net when other methods fail
4.  **Full Content Fallback**
    - If no XML tags found but substantial content exists (\>500 chars),
      use it directly
    - Prevents empty plan files while preserving partial information

**Key Implementation Details:**

``` python
def extract_plan_from_text(text):
    """Extract content between <plan> tags, return None if not found or empty."""
    match = re.search(r'<plan>(.*?)</plan>', text, re.DOTALL)
    if match:
        extracted = match.group(1).strip()
        # Validate minimum content length (a real plan should be substantial)
        if len(extracted) > 200:
            return extracted
    return None
```

**Why Content Validation Matters:**

- Previous versions could produce empty plan files if extraction
  \"succeeded\" with no content
- We now require a minimum of 200 characters for XML-tagged content
- This prevents false positives where regex matches empty or trivial
  content

**Prompt Engineering for Direct Output:** The prompt explicitly
instructs the agent:

- **DO NOT use the Write tool** - prevents file-system detours
- **Output directly in response** - ensures content flows through
  message stream
- **Use XML tags** - enables clean extraction from potentially verbose
  responses

This approach gives you:

- **Reliability**: Plans are captured regardless of agent behavior
- **Transparency**: The saved file indicates which source was used
- **Audit Trail**: History of all plans with timestamps and source
  metadata
- **Debugging**: Clear error messages when extraction fails

Let\'s view the saved plan:
:::

::::: {.cell .code execution_count="15"}
``` python
# Display the saved plan with markdown rendering
from IPython.display import Markdown, display

# Show the plan with proper markdown formatting
display(Markdown(f"## 📋 Saved Plan Preview\n\n{final_plan}"))

print(f"\n📁 Full plan with metadata saved to: {plan_file}")
```

::: {.output .display_data}
## 📋 Saved Plan Preview

# TechStart Inc. Engineering Team Restructuring Plan for AI Focus

## Executive Summary
Restructure the 25-person engineering team to build AI/ML capabilities while maintaining core product development. This plan balances immediate hiring needs with internal upskilling and strategic reorganization over a 12-month period.

---

## Current State Assessment

| Team | Headcount | Current Focus |
|------|-----------|---------------|
| Backend | 12 | Core product, APIs, infrastructure |
| Frontend | 8 | Web/mobile interfaces |
| DevOps | 5 | CI/CD, cloud infrastructure |
| **Total** | **25** | |

**Key Constraints:**
- Monthly burn: ~$500K | Runway: 20 months
- Senior Engineer comp: $180K-$220K + equity
- Series A stage - need to show growth metrics

---

## Proposed Future State (Month 12)

### New Team Structure

| Team | Current | Future | Change |
|------|---------|--------|--------|
| Backend/Core | 12 | 8 | -4 |
| Frontend | 8 | 6 | -2 |
| DevOps/MLOps | 5 | 6 | +1 |
| **AI/ML Platform** | 0 | 5 | +5 |
| **AI Product** | 0 | 4 | +4 |
| **Total** | **25** | **29** | **+4** |

### New Teams Created

**1. AI/ML Platform Team (5 engineers)**
- Focus: Infrastructure, model training pipelines, ML tooling
- Composition: 2 new hires (ML Engineers) + 2 internal transfers (Backend) + 1 internal (DevOps)
- Lead: New hire - Senior ML Engineer ($200-220K)

**2. AI Product Team (4 engineers)**
- Focus: AI features, integrations, user-facing ML applications
- Composition: 2 new hires (ML/AI specialists) + 1 internal (Backend) + 1 internal (Frontend)
- Lead: Promoted internal senior engineer + AI upskilling

---

## Hiring Plan

### New Positions (6 total new hires)

| Role | Priority | Timeline | Comp Range | Notes |
|------|----------|----------|------------|-------|
| Senior ML Engineer (Lead) | P0 | Month 1-2 | $200-220K | Team lead, architecture |
| ML Engineer | P0 | Month 2-3 | $180-200K | Platform focus |
| ML Engineer | P1 | Month 3-4 | $180-200K | Product focus |
| AI/ML Engineer | P1 | Month 4-5 | $170-190K | Generalist |
| MLOps Engineer | P2 | Month 5-6 | $160-180K | DevOps + ML |
| Junior ML Engineer | P2 | Month 6-8 | $130-150K | Growth hire |

**Total New Hiring Cost:** ~$1.02-1.14M annually

### Internal Transfers & Upskilling (4 engineers)

| From Team | # Engineers | New Role | Training Investment |
|-----------|-------------|----------|---------------------|
| Backend | 3 | ML Platform/Product | $15K each (courses, certs) |
| Frontend | 1 | AI Product (UI/UX) | $10K (AI tools training) |

**Upskilling Budget:** ~$55K total

---

## Implementation Timeline

### Phase 1: Foundation (Months 1-3)
- [ ] Hire Senior ML Engineer (Team Lead) - **Critical first hire**
- [ ] Identify 4 internal transfer candidates based on interest/aptitude
- [ ] Begin ML upskilling program for transfer candidates
- [ ] Set up ML infrastructure foundations (MLOps engineer involvement)
- [ ] Define AI product roadmap with Product team

### Phase 2: Team Formation (Months 4-6)
- [ ] Complete core AI team hiring (4 of 6 hires)
- [ ] Officially launch AI/ML Platform team
- [ ] Internal transfers complete bootcamp/training
- [ ] First AI feature POC delivered
- [ ] MLOps practices integrated into DevOps workflow

### Phase 3: Scaling (Months 7-9)
- [ ] Complete remaining hires
- [ ] AI Product team fully operational
- [ ] First AI feature in production
- [ ] Cross-team collaboration patterns established
- [ ] Model monitoring and observability in place

### Phase 4: Optimization (Months 10-12)
- [ ] Team velocity optimization
- [ ] Evaluate team composition effectiveness
- [ ] Plan for next growth phase
- [ ] Document AI development best practices

---

## Budget Impact Analysis

### Monthly Cost Changes

| Category | Current | Month 6 | Month 12 |
|----------|---------|---------|----------|
| Engineering Salaries | ~$375K | ~$430K | ~$485K |
| Training/Upskilling | $0 | $9K | $2K |
| AI Tools/Infrastructure | ~$5K | ~$20K | ~$35K |
| Recruiting Costs | Variable | ~$40K | ~$15K |
| **Monthly Total** | **~$380K** | **~$499K** | **~$537K** |

### Annual Impact Summary
- **Year 1 Additional Investment:** ~$900K-1.1M
- **New Monthly Burn (Month 12):** ~$537K (+$37K from engineering growth)
- **Runway Impact:** Reduces to ~17 months (still healthy for Series A)

### ROI Considerations
- AI features typically command 20-40% pricing premium in B2B SaaS
- Competitive differentiation in market
- Potential for AI-driven operational efficiencies

---

## Risk Mitigation

| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Senior ML hire takes >3 months | Medium | High | Engage specialized recruiters early; consider contractor bridge |
| Internal transfers struggle with ML | Low | Medium | Rigorous selection process; extended training runway |
| AI projects don't deliver value | Medium | High | Start with high-impact, lower-complexity features |
| Team culture friction | Low | Medium | Integrate teams gradually; shared goals and rituals |
| Budget overrun | Medium | Medium | Phase hiring based on runway checks quarterly |

---

## Success Metrics

### 6-Month Milestones
- [ ] AI/ML Platform team fully staffed (5 engineers)
- [ ] First AI-powered feature in beta
- [ ] 4 internal engineers completed ML certification
- [ ] ML infrastructure supporting model training/deployment

### 12-Month Milestones
- [ ] 2+ AI features in production
- [ ] AI team velocity matches core team benchmarks
- [ ] Customer NPS improvement attributable to AI features
- [ ] 15%+ of product roadmap is AI-focused
- [ ] Retention of transferred engineers >90%

### KPIs to Track
- Time-to-hire for ML roles
- AI feature adoption rates
- Model performance metrics (latency, accuracy)
- Engineering velocity (story points/sprint) across teams
- Employee satisfaction scores (especially transfers)

---

## Immediate Next Steps (Week 1-2)

1. **Executive alignment** - Present plan to leadership for approval
2. **Recruiter engagement** - Brief recruiting on Senior ML Engineer search
3. **Internal survey** - Gauge interest in AI/ML roles among current engineers
4. **Budget approval** - Finance sign-off on increased burn rate
5. **Infrastructure assessment** - DevOps audit of ML infrastructure needs

---

## Organizational Chart (Future State)

```
VP Engineering
├── Backend/Core Team (8)
│   └── 2 squads × 4 engineers
├── Frontend Team (6)
│   └── 2 squads × 3 engineers
├── DevOps/MLOps Team (6)
│   └── 4 DevOps + 2 MLOps
├── AI/ML Platform Team (5) [NEW]
│   └── Lead + 4 engineers
└── AI Product Team (4) [NEW]
    └── Lead + 3 engineers
```

---

*Plan prepared for TechStart Inc. Series A stage (~$10M raised, 20-month runway)*
*Recommended review: Quarterly budget and hiring progress checkpoints*
:::

::: {.output .stream .stdout}

    📁 Full plan with metadata saved to: chief_of_staff_agent/plans/plan_20251204_152737.md
:::
:::::

::: {.cell .markdown}
## Advanced Features
:::

::: {.cell .markdown}
### Feature 4: Custom Slash Commands

> Note: slash commands are syntactic sugar for users, not new agent
> capabilities

**What**: Custom slash commands are predefined prompt templates that
users can trigger with shorthand syntax (e.g., `/budget-impact`). These
are **user-facing shortcuts**, not agent capabilities. Think of them as
keyboard shortcuts that expand into full, well-crafted prompts.

**Why**: Your Chief of Staff will handle recurring executive questions.
Instead of users typing complex prompts repeatedly, they can use already
vetted prompts. This improves consistency and standardization.

**How**:

- Define a markdown file in `.claude/commands/`. For example, we defined
  one in `.claude/commands/slash-command-test.md`. Notice how the
  command is defined: frontmatter with two fields (name, description)
  and the expanded prompt with an option to include arguments passed on
  in the query.
- You can add parameters to your prompt using `$ARGUMENTS` (for full
  argument string) or `$1`, `$2`, etc. (for positional arguments)
- The user uses the slash command in their prompt

> **CRITICAL SDK CONFIGURATION**: When using the SDK, you **must** set
> `setting_sources=["project"]` in your `ClaudeAgentOptions` for slash
> commands to work. By default, the SDK operates in isolation mode and
> does NOT load filesystem settings (slash commands, CLAUDE.md,
> subagents, hooks, etc.). This is different from using Claude Code
> interactively where these are loaded automatically.
:::

:::: {.cell .code execution_count="16"}
``` python
# User types: "/slash-command-test this is a test"
# -> behind the scenes EXPANDS to the prompt in .claude/commands/slash-command-test.md
# In this case the expanded prompt says to simply reverse the sentence word wise

messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="chief_of_staff_agent",
        # IMPORTANT: setting_sources must include "project" to load slash commands from .claude/commands/
        # Without this, the SDK does NOT load filesystem settings (slash commands, CLAUDE.md, etc.)
        setting_sources=["project"],
    )
) as agent:
    await agent.query("/slash-command-test this is a test")
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)
```

::: {.output .stream .stdout}
    🤖 Thinking...
:::
::::

:::: {.cell .code execution_count="17"}
``` python
display_agent_response(messages, title="Slash Command Result")
```

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Slash Command Result</div><p>The sentence "this is a test" reversed word-wise is:</p>
<p><strong>test a is this</strong></p></div>
:::
::::

::: {.cell .markdown}
### Feature 5: Hooks - Automated Deterministic Actions

**What**: Hooks are Python scripts that you can set to execute
automatically, among other events, before (pre) or after (post) specific
tool calls. Hooks run **deterministically**, making them perfect for
validation and audit trails.

**Why**: Imagine scenarios where you want to make sure that your agent
has some guardrails (e.g., prevent dangerous operations) or when you
want to have an audit trail. Hooks are ideal in combination with agents
to allow them enough freedom to achieve their task, while still making
sure that the agents behave in a safe way.

**How**:

- Define hook scripts in `.claude/hooks/` -\> *what* is the behaviour
  that should be executed when a hook is triggered
- Define hook configuration in `.claude/settings.local.json` -\> *when*
  should a hook be triggered
- In this case, our hooks are configured to watch specific tool calls
  (Bash, Write, Edit)
- When those tools are called, the hook script runs after the tool
  completes (PostToolUse)

> **SDK CONFIGURATION NOTE**: Hooks configured in
> `.claude/settings.local.json` require
> `setting_sources=["project", "local"]`. The SDK distinguishes between
> three setting sources:
>
> - `"project"` → `.claude/settings.json` (version-controlled,
>   team-shared)
> - `"local"` → `.claude/settings.local.json` (gitignored, local
>   settings like hooks)
> - `"user"` → `~/.claude/settings.json` (global user settings)
>
> Since our hooks are in `settings.local.json`, we must include
> `"local"` in `setting_sources`.

**Example: Report Tracking for Compliance**

A hook to log Write/Edit operations on financial reports for audit and
compliance purposes. The hook is defined in
`chief_of_staff_agent/.claude/hooks/report-tracker.py` and the logic
that enforces it is in
`chief_of_staff_agent/.claude/settings.local.json`:

``` json
"hooks": {
  "PostToolUse": [
    {
      "matcher": "Write",
      "hooks": [
        {
          "type": "command",
          "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/report-tracker.py"
        }
      ]
    },
    {
      "matcher": "Edit",
      "hooks": [
        {
          "type": "command",
          "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/report-tracker.py"
        }
      ]
    }
  ]
}
```
:::

::::: {.cell .code execution_count="18"}
``` python
messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        cwd="chief_of_staff_agent",
        allowed_tools=["Bash", "Write", "Edit", "MultiEdit"],
        # IMPORTANT: setting_sources must include BOTH "project" AND "local" to load hooks
        # - "project" loads .claude/settings.json (shared settings, CLAUDE.md, slash commands)
        # - "local" loads .claude/settings.local.json (where hooks are configured)
        setting_sources=["project", "local"],
    )
) as agent:
    await agent.query(
        "Create a quick Q2 financial forecast report with our current burn rate and runway projections. Save it to our /output_reports folder."
    )
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)

# The hook will track this in audit/report_history.json
display_agent_response(messages, title="Q2 Financial Forecast")
```

::: {.output .stream .stdout}
    🤖 Using: Bash()
    🤖 Using: Bash()
    🤖 Using: Bash()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Using: Read()
    🤖 Using: Read()
    🤖 Using: Read()
    🤖 Using: Bash()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Write()
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Q2 Financial Forecast</div><p>I've created a comprehensive Q2 Financial Forecast Report and saved it to the output_reports folder. Here's a summary of what's included:</p>
<h2>Report Summary</h2>
<p><strong>📊 Q2 2024 Financial Forecast Report Created</strong></p>
<p><strong>Location:</strong> <code>/output_reports/Q2_2024_Financial_Forecast_Report.md</code></p>
<h3>Key Highlights:</h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Cash in Bank</strong></td>
<td>$10M</td>
</tr>
<tr>
<td><strong>Current Runway</strong></td>
<td>20 months (until Sept 2025)</td>
</tr>
<tr>
<td><strong>Monthly Burn</strong></td>
<td>$500K gross / ~$260K net</td>
</tr>
<tr>
<td><strong>Q2 Total Net Burn</strong></td>
<td>$740K</td>
</tr>
<tr>
<td><strong>ARR</strong></td>
<td>$2.4M (15% MoM growth)</td>
</tr>
</tbody>
</table>
<h3>Positive Trends:</h3>
<ul>
<li>✅ Net burn <strong>decreasing</strong> 9.6% month-over-month (from $260K → $235K)</li>
<li>✅ Revenue growth (20.8%) <strong>outpacing</strong> burn increase (5%)</li>
<li>✅ Revenue per employee improving 14%</li>
</ul>
<h3>Planning Scenarios:</h3>
<ul>
<li><strong>Conservative</strong>: 38-month runway (if revenue holds flat)</li>
<li><strong>With 10 new engineers</strong>: ~15-month runway</li>
<li><strong>Base case with growth</strong>: Path to break-even by Q2 2025</li>
</ul>
<p>The report includes detailed monthly breakdowns, hiring cost impact analysis, revenue milestones, risk assessment, and strategic recommendations for Series B timing.</p></div>
:::
:::::

::: {.cell .markdown}
If you now navigate to
`./chief_of_staff_agent/audit/report_history.json`, you will find that
it has logged that the agent has created and/or made changes to your
report. The generated report itself you can find at
`./chief_of_staff_agent/output_reports/`.
:::

::: {.cell .markdown}
### Feature 6: Subagents via Task Tool

**What**: The Task tool enables your agent to delegate specialized work
to other subagents. These subagents each have their own instructions,
tools, and expertise.

**Why**: Adding subagents opens up a lot of possibilities:

1.  Specialization: each subagent is an expert in their domain
2.  Separate context: subagents have their own conversation history and
    tools
3.  Parallellization: multiple subagents can work simultaneously on
    different aspects.

**How**:

- Add `"Task"` to allowed_tools
- Use a system prompt to instruct your agent how to delegate tasks (you
  can also define this its CLAUDE.md more generally)
- Create a markdown file for each agent in `.claude/agents/`. For
  example, check the one for `.claude/agents/financial-analyst.md` and
  notice how a (sub)agent can be defined with such an easy and intuitive
  markdown file: frontmatter with three fields (name, description, and
  tools) and its system prompt. The description is useful for the main
  chief of staff agent to know when to invoke each subagent.

**Visualization Enhancements**: Our `print_activity()` and
`visualize_conversation()` utilities have been enhanced to clearly show
subagent operations:

- 🚀 indicates when a subagent is being delegated to (with the subagent
  name)
- 📎 indicates tools being used BY the subagent (indented for visual
  hierarchy)
- Visual separators clearly mark subagent delegation and completion
  boundaries
- Task descriptions and prompts are shown in the conversation timeline
:::

::::: {.cell .code execution_count="19"}
``` python
# Reset the subagent tracking context before starting a new query
# This ensures clean state for activity display
reset_activity_context()

messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model=MODEL,
        allowed_tools=["Task"],  # this enables our Chief agent to invoke subagents
        system_prompt="Delegate financial questions to the financial-analyst subagent. Do not try to answer these questions yourself.",
        cwd="chief_of_staff_agent",
        setting_sources=["project", "local"],
    )
) as agent:
    await agent.query("Should we hire 5 engineers? Analyze the financial impact.")
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)

display_agent_response(messages, title="Hiring Impact Analysis")
```

::: {.output .stream .stdout}
    🤖 Thinking...
    🚀 Delegating to subagent: financial-analyst
       └─ Task: Analyze 5 engineer hiring impact
       ✓ Tool completed
       📎 [financial-analyst] Using: Bash()
       📎 [financial-analyst] Using: Read()
       📎 [financial-analyst] Using: Read()
       ✓ Tool completed
       ✓ Tool completed
       ✓ Tool completed
       📎 [financial-analyst] Using: Read()
       📎 [financial-analyst] Using: Bash()
       ✓ Tool completed
       ✓ Tool completed
       📎 [financial-analyst] Using: Bash()
       ✓ Tool completed
       📎 [financial-analyst] Using: Bash()
       ✓ Tool completed
       📎 [financial-analyst] Using: Bash()
       ✓ Tool completed
       📎 [financial-analyst] Using: Bash()
       ✓ Tool completed
       ✓ Tool completed
       📎 [financial-analyst] Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Hiring Impact Analysis</div><h2>Financial Impact Analysis: Hiring 5 Engineers</h2>
<h3>Executive Summary</h3>
<p><strong>Recommendation: ✅ PROCEED WITH CAUTION</strong> - Use a staged hiring approach with 3 Senior + 2 Junior engineers</p>
<hr />
<h3>Financial Impact at a Glance</h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Current</th>
<th>After 5 Hires</th>
<th>Change</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Monthly Burn</strong></td>
<td>$500,000</td>
<td>$575,833</td>
<td>+15.2%</td>
</tr>
<tr>
<td><strong>Runway</strong></td>
<td>20 months</td>
<td>17.1 months</td>
<td>-2.9 months</td>
</tr>
<tr>
<td><strong>Headcount</strong></td>
<td>50</td>
<td>55</td>
<td>+10%</td>
</tr>
<tr>
<td><strong>Engineering %</strong></td>
<td>50%</td>
<td>54.5%</td>
<td>+4.5%</td>
</tr>
</tbody>
</table>
<p><strong>One-time costs:</strong> ~$165K (recruiting + onboarding)</p>
<hr />
<h3>Three Scenarios Analyzed</h3>
<table>
<thead>
<tr>
<th>Scenario</th>
<th>Mix</th>
<th>New Monthly Burn</th>
<th>New Runway</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A (Recommended)</strong></td>
<td>3 Senior + 2 Junior</td>
<td>$575,833</td>
<td>17.1 months</td>
</tr>
<tr>
<td>B</td>
<td>5 Senior</td>
<td>$591,665</td>
<td>16.6 months</td>
</tr>
<tr>
<td>C</td>
<td>2 Senior + 3 Junior</td>
<td>$567,917</td>
<td>17.3 months</td>
</tr>
</tbody>
</table>
<hr />
<h3>Why This Works ✅</h3>
<ol>
<li><strong>Strong Revenue Growth</strong> - 15% MoM ARR growth ($2.4M → projected $5.5M by Dec 2024) partially offsets increased burn</li>
<li><strong>Healthy Runway Post-Hire</strong> - 17+ months exceeds the minimum 12-month threshold</li>
<li><strong>Series B Alignment</strong> - Maintains sufficient runway to close Series B (target Q1 2026)</li>
<li><strong>Strategic Necessity</strong> - Product launch and European expansion require engineering capacity</li>
</ol>
<h3>Key Risks ⚠️</h3>
<ol>
<li><strong>Runway Compression</strong> - 2.9-month reduction leaves less buffer</li>
<li><strong>Series B Dependency</strong> - Must close by Q1 2026 (reduced negotiating flexibility)</li>
<li><strong>Revenue Assumptions</strong> - Projections depend on continued 15% MoM growth</li>
</ol>
<hr />
<h3>Recommended Implementation Plan</h3>
<p><strong>Phase 1 (Immediate):</strong> Hire 3 engineers (2 Senior + 1 Junior)<br />
<strong>Phase 2 (30-60 days later):</strong> Hire remaining 2 engineers (1 Senior + 1 Junior)</p>
<p><strong>Financial Guardrails:</strong><br />
- Maintain minimum 15-month runway at all times<br />
- Pause hiring if revenue growth drops below 12% MoM<br />
- Begin Series B conversations by August 2024</p>
<hr />
<h3>Bottom Line</h3>
<p>The hire is <strong>financially prudent</strong> given your strong growth trajectory and healthy runway buffer. However, it's critical to:<br />
1. Execute staged hiring to de-risk<br />
2. Maintain revenue momentum<br />
3. Stay on track with Series B timeline</p>
<p><strong>Confidence Level: 75%</strong> — Proceed, but with active monitoring and clear guardrails.</p></div>
:::
:::::

:::: {.cell .code execution_count="20"}
``` python
visualize_conversation(messages)
```

::: {.output .display_data}

    
<style>
.conversation-timeline {
    font-family: ui-sans-serif, system-ui;
    max-width: 900px;
    margin: 1em 0;
}
.timeline-header {
    background: linear-gradient(135deg, #3b82f6, #9333ea);
    color: white;
    padding: 12px 16px;
    border-radius: 12px 12px 0 0;
    font-weight: 700;
    font-size: 14px;
}
.timeline-body {
    border: 1px solid #e5e7eb;
    border-top: none;
    border-radius: 0 0 12px 12px;
    padding: 12px;
    background: #fafafa;
}
.msg-block {
    margin: 8px 0;
    padding: 10px 12px;
    border-radius: 8px;
    background: white;
    border-left: 3px solid #e5e7eb;
}
.msg-block.system { border-left-color: #6b7280; }
.msg-block.assistant { border-left-color: #3b82f6; }
.msg-block.tool { border-left-color: #10b981; background: #f0fdf4; }
.msg-block.subagent { border-left-color: #9333ea; background: #faf5ff; }
.msg-block.result { border-left-color: #f59e0b; background: #fffbeb; }
.msg-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: #6b7280;
    margin-bottom: 4px;
}
.msg-content {
    font-size: 13px;
    color: #111;
}
.msg-content pre {
    background: #f3f4f6;
    padding: 8px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 12px;
}
.tool-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.tool-badge {
    background: #e0f2fe;
    color: #0369a1;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-family: monospace;
}
.stats-bar {
    display: flex;
    gap: 16px;
    padding: 10px 12px;
    background: #f9fafb;
    border-radius: 8px;
    font-size: 12px;
    color: #374151;
    margin-top: 8px;
}
.stat-item { display: flex; gap: 4px; }
.stat-label { color: #6b7280; }
</style>

    <div class="conversation-timeline">
        <div class="timeline-header">🤖 Agent Conversation Timeline • claude-opus-4-5</div>
        <div class="timeline-body">
            <div class="msg-block system"><div class="msg-label">⚙️ System</div><div class="msg-content">Initialized (bf3bc346...)</div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>I'll delegate this financial analysis to the financial-analyst subagent who can properly analyze the impact of hiring 5 engineers.</p></div></div><div class="msg-block subagent"><div class="msg-label">🚀 Subagent: financial-analyst</div><div class="msg-content">Analyze 5 engineer hiring impact</div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Bash</span><span class="tool-badge">Read: burn_rate.csv</span><span class="tool-badge">Read: revenue_forecast.json</span><span class="tool-badge">Read: hiring_costs.csv</span><span class="tool-badge">Bash</span><span class="tool-badge">Bash</span><span class="tool-badge">Bash</span><span class="tool-badge">Bash</span><span class="tool-badge">Bash</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><h2>Financial Impact Analysis: Hiring 5 Engineers</h2>
<h3>Executive Summary</h3>
<p><strong>Recommendation: ✅ PROCEED WITH CAUTION</strong> - Use a staged hiring approach with 3 Senior + 2 Junior engineers</p>
<hr />
<h3>Financial Impact at a Glance</h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Current</th>
<th>After 5 Hires</th>
<th>Change</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Monthly Burn</strong></td>
<td>$500,000</td>
<td>$575,833</td>
<td>+15.2%</td>
</tr>
<tr>
<td><strong>Runway</strong></td>
<td>20 months</td>
<td>17.1 months</td>
<td>-2.9 months</td>
</tr>
<tr>
<td><strong>Headcount</strong></td>
<td>50</td>
<td>55</td>
<td>+10%</td>
</tr>
<tr>
<td><strong>Engineering %</strong></td>
<td>50%</td>
<td>54.5%</td>
<td>+4.5%</td>
</tr>
</tbody>
</table>
<p><strong>One-time costs:</strong> ~$165K (recruiting + onboarding)</p>
<hr />
<h3>Three Scenarios Analyzed</h3>
<table>
<thead>
<tr>
<th>Scenario</th>
<th>Mix</th>
<th>New Monthly Burn</th>
<th>New Runway</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A (Recommended)</strong></td>
<td>3 Senior + 2 Junior</td>
<td>$575,833</td>
<td>17.1 months</td>
</tr>
<tr>
<td>B</td>
<td>5 Senior</td>
<td>$591,665</td>
<td>16.6 months</td>
</tr>
<tr>
<td>C</td>
<td>2 Senior + 3 Junior</td>
<td>$567,917</td>
<td>17.3 months</td>
</tr>
</tbody>
</table>
<hr />
<h3>Why This Works ✅</h3>
<ol>
<li><strong>Strong Revenue Growth</strong> - 15% MoM ARR growth ($2.4M → projected $5.5M by Dec 2024) partially offsets increased burn</li>
<li><strong>Healthy Runway Post-Hire</strong> - 17+ months exceeds the minimum 12-month threshold</li>
<li><strong>Series B Alignment</strong> - Maintains sufficient runway to close Series B (target Q1 2026)</li>
<li><strong>Strategic Necessity</strong> - Product launch and European expansion require engineering capacity</li>
</ol>
<h3>Key Risks ⚠️</h3>
<ol>
<li><strong>Runway Compression</strong> - 2.9-month reduction leaves less buffer</li>
<li><strong>Series B Dependency</strong> - Must close by Q1 2026 (reduced negotiating flexibility)</li>
<li><strong>Revenue Assumptions</strong> - Projections depend on continued 15% MoM growth</li>
</ol>
<hr />
<h3>Recommended Implementation Plan</h3>
<p><strong>Phase 1 (Immediate):</strong> Hire 3 engineers (2 Senior + 1 Junior)<br />
<strong>Phase 2 (30-60 days later):</strong> Hire remaining 2 engineers (1 Senior + 1 Junior)</p>
<p><strong>Financial Guardrails:</strong><br />
- Maintain minimum 15-month runway at all times<br />
- Pause hiring if revenue growth drops below 12% MoM<br />
- Begin Series B conversations by August 2024</p>
<hr />
<h3>Bottom Line</h3>
<p>The hire is <strong>financially prudent</strong> given your strong growth trajectory and healthy runway buffer. However, it's critical to:<br />
1. Execute staged hiring to de-risk<br />
2. Maintain revenue momentum<br />
3. Stay on track with Series B timeline</p>
<p><strong>Confidence Level: 75%</strong> — Proceed, but with active monitoring and clear guardrails.</p></div></div><div class="msg-block result"><div class="msg-label">✅ Complete</div><div class="stats-bar"><span class="stat-item"><span class="stat-label">Turns:</span> 2</span> <span class="stat-item"><span class="stat-label">Tokens:</span> 1,173</span> <span class="stat-item"><span class="stat-label">Cost:</span> $0.28</span> <span class="stat-item"><span class="stat-label">Duration:</span> 164.9s</span></div></div>
        </div>
    </div>
    
:::
::::

::: {.cell .markdown}
Here, when our main agent decides to use a subagent, it will:

1.  Call the Task tool with parameters like:

``` json
  {
    "description": "Analyze hiring impact",
    "prompt": "Analyze the financial impact of hiring 5 engineers...",
    "subagent_type": "financial-analyst"
  }
```

1.  The Task tool executes the subagent in a separate context
2.  Return results to main Chief of Staff agent to continue processing
:::

::: {.cell .markdown}
## Putting It All Together
:::

::: {.cell .markdown}
Let\'s now put everything we\'ve seen together. We will ask our agent to
determine the financial impact of hiring 3 senior engineers and write
their insights to `output_reports/hiring_decision.md`. This demonstrates
all the features seen above:

- **Bash Tool**: Used to execute the `hiring_impact.py` script to
  determine the impact of hiring new engineers
- **Memory**: Reads `CLAUDE.md` in directory as context to understand
  the current budgets, runway, revenue and other relevant information
- **Output style**: Different output styles, defined in
  `chief_of_staff_agent/.claude/output-styles`
- **Custom Slash Commands**: Uses the shortcut `/budget-impact` that
  expands to full prompt defined in
  `chief_of_staff_agent/.claude/commands`
- **Subagents**: Our `/budget_impact` command guides the chief of staff
  agent to invoke the financial-analyst subagent defined in
  `chief_of_staff_agent/.claude/agents`
- **Hooks**: Hooks are defined in `chief_of_staff_agent/.claude/hooks`
  and configured in `chief_of_staff_agent/.claude/settings.local.json`
  - If one of our agents is updating the financial report, the hook
    should log this edit/write activity in the
    `chief_of_staff_agent/audit/report_history.json` logfile
  - If the financial analyst subagent will invoke the `hiring_impact.py`
    script, this will be logged in
    `chief_of_staff_agent/audit/tool_usage_log.json` logfile
- **Plan Mode**: If you want the chief of staff to come up with a plan
  for you to approve before taking any action, uncomment the commented
  line below

To have this ready to go, we have encapsulated the agent loop in a
python file, similar to what we did in the previous notebook. Check out
the agent.py file in the `chief_of_staff_agent` subdirectory.

All in all, our `send_query()` function takes in 4 parameters (prompt,
continue_conversation, permission_mode, and output_style), everything
else is set up in the agent file, namely: system prompt, max turns,
allowed tools, and the working directory.

To better visualize how this all comes together, check out these [flow
and architecture diagrams that Claude made for us
:)](./chief_of_staff_agent/flow_diagram.md)
:::

:::: {.cell .code execution_count="21"}
``` python
from chief_of_staff_agent.agent import send_query

reset_activity_context()

result, messages = await send_query(
    "/budget-impact hiring 3 senior engineers. Save your insights by updating the 'hiring_decision.md' file in /output_reports or creating a new file there",
    # permission_mode="plan", # Enable this to use planning mode
    output_style="executive",
)
```

::: {.output .stream .stdout}
    🤖 Thinking...
    🤖 Using: Glob()
    🤖 Using: Glob()
    ✓ Tool completed
    ✓ Tool completed
    🤖 Using: Read()
    🤖 Using: Read()
    🤖 Using: Read()
    🤖 Using: Read()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Task()
    ✓ Tool completed
    🤖 Using: Bash()
    🤖 Using: Read()
    🤖 Using: Read()
    🤖 Using: Read()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: Write()
    ✓ Tool completed
    🤖 Thinking...
:::
::::

:::: {.cell .code execution_count="22"}
``` python
visualize_conversation(messages)
```

::: {.output .display_data}

    
<style>
.conversation-timeline {
    font-family: ui-sans-serif, system-ui;
    max-width: 900px;
    margin: 1em 0;
}
.timeline-header {
    background: linear-gradient(135deg, #3b82f6, #9333ea);
    color: white;
    padding: 12px 16px;
    border-radius: 12px 12px 0 0;
    font-weight: 700;
    font-size: 14px;
}
.timeline-body {
    border: 1px solid #e5e7eb;
    border-top: none;
    border-radius: 0 0 12px 12px;
    padding: 12px;
    background: #fafafa;
}
.msg-block {
    margin: 8px 0;
    padding: 10px 12px;
    border-radius: 8px;
    background: white;
    border-left: 3px solid #e5e7eb;
}
.msg-block.system { border-left-color: #6b7280; }
.msg-block.assistant { border-left-color: #3b82f6; }
.msg-block.tool { border-left-color: #10b981; background: #f0fdf4; }
.msg-block.subagent { border-left-color: #9333ea; background: #faf5ff; }
.msg-block.result { border-left-color: #f59e0b; background: #fffbeb; }
.msg-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: #6b7280;
    margin-bottom: 4px;
}
.msg-content {
    font-size: 13px;
    color: #111;
}
.msg-content pre {
    background: #f3f4f6;
    padding: 8px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 12px;
}
.tool-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.tool-badge {
    background: #e0f2fe;
    color: #0369a1;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-family: monospace;
}
.stats-bar {
    display: flex;
    gap: 16px;
    padding: 10px 12px;
    background: #f9fafb;
    border-radius: 8px;
    font-size: 12px;
    color: #374151;
    margin-top: 8px;
}
.stat-item { display: flex; gap: 4px; }
.stat-label { color: #6b7280; }
</style>

    <div class="conversation-timeline">
        <div class="timeline-header">🤖 Agent Conversation Timeline • claude-opus-4-5</div>
        <div class="timeline-body">
            <div class="msg-block system"><div class="msg-label">⚙️ System</div><div class="msg-content">Initialized (cea37adf...)</div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>I'll analyze the budget impact of hiring 3 senior engineers. Let me first check the current financial data and existing reports, then delegate to the financial analyst for a comprehensive analysis.</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Glob</span><span class="tool-badge">Glob</span><span class="tool-badge">Read: hiring_costs.csv</span><span class="tool-badge">Read: burn_rate.csv</span><span class="tool-badge">Read: revenue_forecast.json</span><span class="tool-badge">Read: hiring_decision.md</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>I see there's already an existing analysis. Let me delegate to the financial analyst subagent to provide an updated, comprehensive analysis with the latest data and additional insights.</p></div></div><div class="msg-block subagent"><div class="msg-label">🚀 Subagent: financial-analyst</div><div class="msg-content">Analyze hiring 3 senior engineers budget impact</div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Bash</span><span class="tool-badge">Read: hiring_costs.csv</span><span class="tool-badge">Read: burn_rate.csv</span><span class="tool-badge">Read: revenue_forecast.json</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>Excellent! The financial analyst has provided a comprehensive analysis. Let me now update the hiring decision report with this enhanced analysis.</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">Write</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>I've completed the comprehensive budget impact analysis for hiring 3 senior engineers. Here's a summary of the key findings:</p>
<hr />
<h2>Budget Impact Analysis Summary</h2>
<h3>Recommendation: <strong>CONDITIONAL APPROVAL WITH STAGGERED APPROACH</strong></h3>
<h3>Key Financial Impact</h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Current</th>
<th>Post-Hiring</th>
<th>Change</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monthly Gross Burn</td>
<td>$525K</td>
<td>$590K</td>
<td>+$65K (+12.4%)</td>
</tr>
<tr>
<td>Monthly Net Burn</td>
<td>$235K</td>
<td>$300K</td>
<td>+$65K (+27.7%)</td>
</tr>
<tr>
<td>Cash Runway</td>
<td>42.6 months</td>
<td>32.9 months</td>
<td>-9.7 months</td>
</tr>
<tr>
<td><strong>Break-Even</strong></td>
<td>-</td>
<td><strong>November 2024</strong></td>
<td>5 months</td>
</tr>
</tbody>
</table>
<h3>Total Investment</h3>
<ul>
<li><strong>One-time costs:</strong> $129,000 (recruiting, onboarding, equipment)</li>
<li><strong>Annual recurring:</strong> $780,000 ($65K/month loaded)</li>
<li><strong>First year total:</strong> $909,000</li>
</ul>
<h3>Why Proceed?</h3>
<ol>
<li><strong>Break-even achievable in 5 months</strong> with current 15% MoM revenue growth</li>
<li><strong>Strong runway buffer</strong> - 32.9 months even without revenue growth</li>
<li><strong>Strategic timing</strong> aligns with Q2 product launch and market opportunity</li>
</ol>
<h3>Risk Mitigation Strategy</h3>
<ul>
<li><strong>Staggered hiring</strong> (1 engineer/month) reduces integration risk</li>
<li><strong>Milestone gates</strong> allow pause/abort if revenue growth slows</li>
<li><strong>Series B prep</strong> should begin immediately to strengthen position</li>
</ul>
<h3>Critical Success Factors</h3>
<ol>
<li>Maintain &gt;12% MoM revenue growth</li>
<li>Hire Engineering Manager concurrent with first engineer</li>
<li>Begin Series B conversations now</li>
<li>Complete stock refresh for key engineer retention</li>
</ol>
<p>The full analysis has been saved to <code>/output_reports/hiring_decision.md</code> with detailed sections on ROI analysis, 4 alternative options, 8 risk factors with mitigations, implementation timeline, and success metrics.</p></div></div><div class="msg-block result"><div class="msg-label">✅ Complete</div><div class="stats-bar"><span class="stat-item"><span class="stat-label">Turns:</span> 9</span> <span class="stat-item"><span class="stat-label">Tokens:</span> 5,871</span> <span class="stat-item"><span class="stat-label">Cost:</span> $0.48</span> <span class="stat-item"><span class="stat-label">Duration:</span> 279.1s</span></div></div>
        </div>
    </div>
    
:::
::::

::: {.cell .markdown}
## Conclusion

We\'ve demonstrated how the Claude Code SDK enables you to build
sophisticated multi-agent systems with enterprise-grade features.
Starting from basic script execution with the Bash tool, we
progressively introduced advanced capabilities including persistent
memory with CLAUDE.md, custom output styles for different audiences,
strategic planning mode, slash commands for user convenience, compliance
hooks for guardrailing, and subagent coordination for specialized tasks.

By combining these features, we created an AI Chief of Staff capable of
handling complex executive decision-making workflows. The system
delegates financial analysis to specialized subagents, maintains audit
trails through hooks, adapts communication styles for different
stakeholders, and provides actionable insights backed by data-driven
analysis.

This foundation in advanced agentic patterns and multi-agent
orchestration prepares you for building production-ready enterprise
systems. In the next notebook, we\'ll explore how to connect our agents
to external services through Model Context Protocol (MCP) servers,
dramatically expanding their capabilities beyond the built-in tools.

Next:
[02_The_observability_agent.ipynb](02_The_observability_agent.ipynb) -
Learn how to extend your agents with custom integrations and external
data sources through MCP.
:::

---

## 02 - The Observability Agent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/02_The_observability_agent.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-claude-agent-sdk-02-the-observability-agent.md

the-observability-agent}"
category: "09-Agents-Patterns"
tags: ["agents", "git", "mcp"]
---

::: {#7e7958dd .cell .code execution_count="1"}
``` python
import os
import shutil
import subprocess
from typing import Any

from dotenv import load_dotenv
from IPython.display import Markdown, display
from utils.agent_visualizer import (
    display_agent_response,
    print_activity,
    reset_activity_context,
    visualize_conversation,
)

from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient
```
:::

::: {#ea47572b .cell .markdown}
# 02 - The Observability Agent {#02---the-observability-agent}
:::

::: {#08cc95b6 .cell .markdown}
In the previous notebooks we have built a basic research agent and a
Chief of Staff multi-agent framework. While the agents we have built are
already powerful, they were still limited in what they could do: the web
search agent is limited to searching the internet and our Chief of Staff
agent was limited to interacting with its own filesystem.

This is a serious constraint: real-world agents often need to interact
with other systems like databases, APIs, file systems, and other
specialized services. [MCP (Model Context
Protocol)](../06-MCP-Tools/General/getting-started-intro.md)
is an open-source standard for AI-tool integrations that allows for an
easy connection between our agents and these external systems. In this
notebook, we will explore how to connect MCP servers to our agent.

**Need more details on MCP?** For comprehensive setup instructions,
configuration best practices, and troubleshooting tips, see the [Claude
Code MCP
documentation](https://docs.claude.com/en/docs/claude-code/mcp).
:::

::: {#95247d94 .cell .markdown}
## Introduction to the MCP Server

### 1. The Git MCP server {#1-the-git-mcp-server}

Let\'s first give our agent the ability to understand and work with Git
repositories. By adding the [Git MCP
server](https://github.com/modelcontextprotocol/servers/tree/main/src/git)
to our agent, it gains access to 13 Git-specific tools that let it
examine commit history, check file changes, create branches, and even
make commits. This transforms our agent from a passive observer into an
active participant in your development workflow. In this example, we\'ll
configure the agent to explore a repository\'s history using only Git
tools. This is pretty simple, but knowing this, it is not difficult to
imagine agents that can automatically create pull requests, analyze code
evolution patterns, or help manage complex Git workflows across multiple
repositories.
:::

::: {#21de60c4 .cell .code execution_count="2"}
``` python
# Get the git repository root (mcp_server_git requires a valid git repo path)
# os.getcwd() may return a subdirectory, so we find the actual repo root
git_executable = shutil.which("git")
if git_executable is None:
    raise RuntimeError("Git executable not found in PATH")

git_repo_root = subprocess.run(  # noqa: S603
    [git_executable, "rev-parse", "--show-toplevel"],
    capture_output=True,
    text=True,
    check=True,
).stdout.strip()

# Define our git MCP server (installed via uv sync from pyproject.toml)
git_mcp: dict[str, Any] = {
    "git": {
        "command": "uv",
        "args": ["run", "python", "-m", "mcp_server_git", "--repository", git_repo_root],
    }
}
```
:::

:::: {#23aa5a3d .cell .code execution_count="3"}
``` python
messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model="claude-opus-4-5",
        mcp_servers=git_mcp,
        allowed_tools=["mcp__git"],
        # disallowed_tools ensures the agent ONLY uses MCP tools, not Bash with git commands
        disallowed_tools=["Bash", "Task", "WebSearch", "WebFetch"],
        permission_mode="acceptEdits",
    )
) as agent:
    await agent.query(
        "Explore this repo's git history and provide a brief summary of recent activity."
    )
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)
```

::: {.output .stream .stdout}
    🤖 Using: mcp__git__git_log()
    🤖 Using: mcp__git__git_status()
    🤖 Using: mcp__git__git_branch()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: mcp__git__git_log()
    🤖 Using: mcp__git__git_status()
    🤖 Using: mcp__git__git_branch()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
:::
::::

:::: {#691e0812 .cell .code execution_count="4"}
``` python
display(Markdown(f"\nResult:\n{messages[-1].result}"))
```

::: {.output .display_data}

Result:
## Git Repository Summary

### Current Branch
You're on the **`upstream-contribution`** branch (up to date with origin), with `main` also available locally.

---

### Recent Commit Activity (Last ~5 Days)

| Date | Author | Summary |
|------|--------|---------|
| **Nov 27, 2025** | costiash | 3 commits enhancing the **Claude Agent SDK** - improved chief of staff agent, notebooks, observability agent, research agent, documentation, and utilities |
| **Nov 26, 2025** | Pedram Navid | Added GitHub issue templates, `/review-issue` command, `/add-registry` slash command, and new cookbook entries |
| **Nov 25, 2025** | Elie Schoppik | Renamed PTC notebook to `programmatic_tool_calling_ptc.ipynb` for clarity |
| **Nov 24, 2025** | henrykeetay | Added **tool search cookbook** |
| **Nov 24, 2025** | Alex Notov | Multiple merges consolidating cookbooks for Opus 4.5, dependency updates |
| **Nov 23, 2025** | Cal Rueb | Simplified crop tool notebook with Claude Agent SDK section |
| **Nov 23, 2025** | Pedram Navid | PR comment fixes and lint cleanup |

---

### Key Themes in Recent Development
1. **Claude Agent SDK enhancements** - Major work on agent implementations (research, chief of staff, observability agents)
2. **New cookbooks** - Tool search, crop tool, programmatic tool calling
3. **CI/CD improvements** - PR review workflows, issue templates, slash commands
4. **Documentation** - Added troubleshooting guides, codebase overviews

---

### Working Directory Status
There are **uncommitted changes** in your working directory:
- **22 modified files** (mostly in `claude_agent_sdk/`)
- **4 deleted files** (documentation files in `docs/`)
- **6 untracked files** (new reports, plans, VS Code config)

These changes appear to be further work on the Claude Agent SDK agents, notebooks, and utilities that haven't been staged or committed yet.
:::
::::

::: {#346a8754 .cell .markdown}
### 2. The GitHub MCP server {#2-the-github-mcp-server}
:::

::: {#1361ba84 .cell .markdown}
Now let\'s level up from local Git operations to full GitHub platform
integration. By switching to the [official GitHub MCP
server](https://github.com/github/github-mcp-server/tree/main), our
agent gains access to over 100 tools that interact with GitHub\'s entire
ecosystem -- from managing issues and pull requests to monitoring CI/CD
workflows and analyzing code security alerts. This server can work with
both public and private repositories, giving your agent the ability to
automate complex GitHub workflows that would typically require multiple
manual steps.
:::

::: {#7fdb4aa2 .cell .markdown}
#### Step 1: Set up your GitHub Token

You need a GitHub Personal Access Token. Get one
[here](https://github.com/settings/personal-access-tokens/new) and put
in the .env file as `GITHUB_TOKEN="<token>"`

> Note: When getting your token, select \"Fine-grained\" token with the
> default options (i.e., public repos, no account permissions), that\'ll
> be the easiest way to get this demo working.

Also, for this example you will have to have
[Docker](https://www.docker.com/products/docker-desktop/) running on
your machine. Docker is required because the GitHub MCP server runs in a
containerized environment for security and isolation.

**Docker Quick Setup:**

- Install Docker Desktop from
  [docker.com](https://www.docker.com/products/docker-desktop/)
- Ensure Docker is running (you\'ll see the Docker icon in your system
  tray)
- Verify with `docker --version` in your terminal
- **Troubleshooting:** If Docker won\'t start, check that virtualization
  is enabled in your BIOS. For detailed setup instructions, see the
  [Docker documentation](https://docs.docker.com/get-docker/)

#### Step 2: Define the mcp server and start the agent loop!
:::

::: {#c1e65281 .cell .code execution_count="5"}
``` python
# define our github mcp server
load_dotenv(override=True)
github_mcp: dict[str, Any] = {
    "github": {
        "command": "docker",
        "args": [
            "run",
            "-i",
            "--rm",
            "-e",
            "GITHUB_PERSONAL_ACCESS_TOKEN",
            "ghcr.io/github/github-mcp-server",
        ],
        "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": os.environ.get("GITHUB_TOKEN")},
    }
}
```
:::

:::: {#e4c524c1 .cell .code execution_count="6"}
``` python
# run our agent
messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model="claude-opus-4-5",
        mcp_servers=github_mcp,
        allowed_tools=["mcp__github"],
        # disallowed_tools ensures the agent ONLY uses MCP tools, not Bash with gh CLI
        disallowed_tools=["Bash", "Task", "WebSearch", "WebFetch"],
        permission_mode="acceptEdits",
    )
) as agent:
    await agent.query(
        "Search for the anthropics/claude-agent-sdk-python repository and give me a few key facts about it."
    )
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)
```

::: {.output .stream .stdout}
    🤖 Using: mcp__github__search_repositories()
    ✓ Tool completed
    🤖 Thinking...
:::
::::

:::: {#4e0ac04f .cell .code execution_count="7"}
``` python
display(Markdown(f"\nResult:\n{messages[-1].result}"))
```

::: {.output .display_data}

Result:
Here are the key facts about the **anthropics/claude-agent-sdk-python** repository:

| Fact | Details |
|------|---------|
| **Full Name** | anthropics/claude-agent-sdk-python |
| **URL** | https://github.com/anthropics/claude-agent-sdk-python |
| **Language** | Python |
| **Stars** | ⭐ 3,357 |
| **Forks** | 🍴 435 |
| **Open Issues** | 149 |
| **Created** | June 11, 2025 |
| **Last Updated** | December 4, 2025 |
| **Default Branch** | main |
| **Visibility** | Public |
| **Archived** | No |

This is the official Python SDK for building Claude agents, maintained by Anthropic. It's quite popular with over 3,300 stars and has an active community with 435 forks. The repository is actively maintained (recently updated) and has a notable number of open issues (149), which suggests active development and community engagement.
:::
::::

::: {#2a788ed6 .cell .markdown}
## Real use case: An observability agent

Now, with such simple setup we can already have an agent acting as
self-healing software system!
:::

:::: {#c8edb208 .cell .code execution_count="8"}
``` python
load_dotenv(override=True)

prompt = """Analyze the CI health for facebook/react repository.

Examine the most recent runs of the 'CI' workflow and provide:
1. Current status and what triggered the run (push, PR, schedule, etc.)
2. If failing: identify the specific failing jobs/tests and assess severity
3. If passing: note any concerning patterns (long duration, flaky history)
4. Recommended actions with priority (critical/high/medium/low)

Provide a concise operational summary suitable for an on-call engineer.
Do not create issues or PRs - this is a read-only analysis."""

github_mcp: dict[str, Any] = {
    "github": {
        "command": "docker",
        "args": [
            "run",
            "-i",
            "--rm",
            "-e",
            "GITHUB_PERSONAL_ACCESS_TOKEN",
            "ghcr.io/github/github-mcp-server",
        ],
        "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": os.environ.get("GITHUB_TOKEN")},
    }
}

messages = []
async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        model="claude-opus-4-5",
        mcp_servers=github_mcp,
        allowed_tools=["mcp__github"],
        # IMPORTANT: disallowed_tools is required to actually RESTRICT tool usage.
        # Without this, allowed_tools only controls permission prompting, not availability.
        # The agent would still have access to Bash (and could use `gh` CLI instead of MCP).
        disallowed_tools=["Bash", "Task", "WebSearch", "WebFetch"],
        permission_mode="acceptEdits",
    )
) as agent:
    await agent.query(prompt)
    async for msg in agent.receive_response():
        print_activity(msg)
        messages.append(msg)
```

::: {.output .stream .stdout}
    🤖 Using: mcp__github__get_file_contents()
    🤖 Using: mcp__github__list_commits()
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: mcp__github__get_file_contents()
    🤖 Using: mcp__github__get_file_contents()
    🤖 Using: mcp__github__list_pull_requests()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: mcp__github__get_commit()
    🤖 Using: mcp__github__get_commit()
    🤖 Using: mcp__github__get_commit()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: mcp__github__search_issues()
    🤖 Using: mcp__github__search_issues()
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
:::
::::

:::: {#49a39ed7 .cell .code execution_count="9"}
``` python
display(Markdown(f"\nResult:\n{messages[-1].result}"))
```

::: {.output .display_data}

Result:
Based on my comprehensive analysis of the facebook/react repository CI infrastructure, here is the operational summary:

---

# CI Health Analysis: facebook/react

## Executive Summary
**Overall Status: 🟢 HEALTHY**

The React repository's CI appears to be in good health. Recent commits to `main` have been successfully merged, and active PRs show passing CodeSandbox builds.

---

## 1. CI Infrastructure Overview

### Primary Workflows
| Workflow | Trigger | Purpose |
|----------|---------|---------|
| `runtime_build_and_test.yml` | Push to main, PRs | Main CI - builds, tests, Flow checks |
| `shared_lint.yml` | Push to main, PRs | Prettier, ESLint, license checks |
| `compiler_typescript.yml` | PRs touching compiler | Compiler-specific tests |
| `devtools_regression_tests.yml` | PRs | DevTools testing |

### Test Matrix Scale
- **90 test shards** (18 configurations × 5 shards each)
- **50 build jobs** (25 workers × 2 release channels)
- **50 test-build shards** (5 configurations × 10 shards)
- Flow checks across multiple inline configs

---

## 2. Recent Main Branch Status

| Commit | Date | Description | Status |
|--------|------|-------------|--------|
| `bf1afad` | Dec 4, 2025 | [react-dom/server] Fix hanging on Deno | ✅ Merged |
| `0526c79` | Dec 3, 2025 | Update changelog with latest releases | ✅ Merged |
| `7dc903c` | Dec 3, 2025 | Patch FlightReplyServer (security fix) | ✅ Merged |
| `36df5e8` | Dec 2, 2025 | Allow building single release channel | ✅ Merged |

**Last 10 commits:** All successfully merged to main, indicating CI is passing.

---

## 3. Active PR CI Status

| PR | Title | CodeSandbox Status |
|----|-------|-------------------|
| #35267 | Fix spelling (behaviour → behavior) | 🟡 Pending (building) |
| #35238 | DevTools navigating commits hotkey | ✅ Success |
| #35287 | Compiler: Fix variable name issue | ✅ Success |
| #35278 | Add DevTools console suppress option | ✅ Success |
| #35226 | Fizz: Push stalled use() to ownerStack | ✅ Success |

---

## 4. Risk Assessment

### ✅ Positive Indicators
- **Main branch stable**: All recent commits merged successfully
- **No open CI failure issues**: Search returned zero CI-related open bugs
- **Active development**: Security patches and features landing regularly
- **PR builds passing**: Most open PRs show successful builds

### ⚠️ Areas to Monitor
- **Large test matrix**: 190+ parallel jobs mean potential for infrastructure flakiness
- **Playwright-based e2e tests**: Browser-based tests can be flaky (Flight fixtures, DevTools e2e)
- **Cache dependencies**: Multiple cache strategies (v6 keys) - cache misses could slow builds

### 📊 CI Complexity Metrics
- ~37KB workflow file for main CI (`runtime_build_and_test.yml`)
- Heavy parallelization with matrix strategies
- Multiple artifact upload/download operations

---

## 5. Recommended Actions

| Priority | Action | Rationale |
|----------|--------|-----------|
| **LOW** | Monitor PR #35267 | Currently building - verify completion |
| **LOW** | No immediate action required | Main branch healthy, PRs passing |
| **INFO** | Security patch merged Dec 3 | PR #35277 fixed critical security vuln in FlightReplyServer - verify downstream impact |

---

## 6. On-Call Notes

**TL;DR for On-Call Engineer:**
- 🟢 **CI is GREEN** - No action required
- Main branch is healthy with successful merges in last 24h
- All checked PRs showing green/passing status
- No open issues flagged for CI failures or flakiness
- Recent security patch (#35277) was successfully merged - monitor for any regressions

**If issues arise:**
1. Check GitHub Actions tab directly: `https://github.com/facebook/react/actions`
2. Key workflows to monitor: "(Runtime) Build and Test", "(Shared) Lint"
3. Caches use `v6` key prefix - if widespread failures, consider cache invalidation

---

*Analysis performed: December 4, 2025*
*Data sources: GitHub API (commits, PRs, status checks, workflow files)*
:::
::::

:::: {#827dc192 .cell .code execution_count="10"}
``` python
reset_activity_context()
visualize_conversation(messages)
```

::: {.output .display_data}

    
<style>
.conversation-timeline {
    font-family: ui-sans-serif, system-ui;
    max-width: 900px;
    margin: 1em 0;
}
.timeline-header {
    background: linear-gradient(135deg, #3b82f6, #9333ea);
    color: white;
    padding: 12px 16px;
    border-radius: 12px 12px 0 0;
    font-weight: 700;
    font-size: 14px;
}
.timeline-body {
    border: 1px solid #e5e7eb;
    border-top: none;
    border-radius: 0 0 12px 12px;
    padding: 12px;
    background: #fafafa;
}
.msg-block {
    margin: 8px 0;
    padding: 10px 12px;
    border-radius: 8px;
    background: white;
    border-left: 3px solid #e5e7eb;
}
.msg-block.system { border-left-color: #6b7280; }
.msg-block.assistant { border-left-color: #3b82f6; }
.msg-block.tool { border-left-color: #10b981; background: #f0fdf4; }
.msg-block.subagent { border-left-color: #9333ea; background: #faf5ff; }
.msg-block.result { border-left-color: #f59e0b; background: #fffbeb; }
.msg-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: #6b7280;
    margin-bottom: 4px;
}
.msg-content {
    font-size: 13px;
    color: #111;
}
.msg-content pre {
    background: #f3f4f6;
    padding: 8px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 12px;
}
.tool-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.tool-badge {
    background: #e0f2fe;
    color: #0369a1;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-family: monospace;
}
.stats-bar {
    display: flex;
    gap: 16px;
    padding: 10px 12px;
    background: #f9fafb;
    border-radius: 8px;
    font-size: 12px;
    color: #374151;
    margin-top: 8px;
}
.stat-item { display: flex; gap: 4px; }
.stat-label { color: #6b7280; }
</style>

    <div class="conversation-timeline">
        <div class="timeline-header">🤖 Agent Conversation Timeline • claude-opus-4-5</div>
        <div class="timeline-body">
            <div class="msg-block system"><div class="msg-label">⚙️ System</div><div class="msg-content">Initialized (a500627f...)</div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">mcp__github__get_file_contents</span><span class="tool-badge">mcp__github__list_commits</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>I can see the React repository uses GitHub Actions with several workflows. Let me check the main CI workflows and their recent status. The primary CI workflow appears to be <code>runtime_build_and_test.yml</code>. Let me examine the workflow files and search for any "CI" named workflows.</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">mcp__github__get_file_contents</span><span class="tool-badge">mcp__github__get_file_contents</span><span class="tool-badge">mcp__github__list_pull_requests</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>I can see React repository uses several workflows. The main CI workflow is <code>runtime_build_and_test.yml</code> which triggers on push to main and PRs. Let me get the CI status for recent commits to assess the health:</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">mcp__github__get_commit</span><span class="tool-badge">mcp__github__get_commit</span><span class="tool-badge">mcp__github__get_commit</span><span class="tool-badge">mcp__github__pull_request_read</span><span class="tool-badge">mcp__github__pull_request_read</span><span class="tool-badge">mcp__github__pull_request_read</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>Let me get more detailed CI status information by checking the status checks on recent PRs and the main branch:</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">mcp__github__pull_request_read</span><span class="tool-badge">mcp__github__pull_request_read</span><span class="tool-badge">mcp__github__pull_request_read</span><span class="tool-badge">mcp__github__pull_request_read</span><span class="tool-badge">mcp__github__pull_request_read</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>The GitHub API status checks only show CodeSandbox status. Let me search for any recent failing CI issues to get a complete picture:</p></div></div><div class="msg-block tool"><div class="msg-label">🔧 Tools</div><div class="tool-list"><span class="tool-badge">mcp__github__search_issues</span><span class="tool-badge">mcp__github__search_issues</span></div></div><div class="msg-block assistant"><div class="msg-label">🤖 Assistant</div><div class="msg-content"><p>Based on my comprehensive analysis of the facebook/react repository CI infrastructure, here is the operational summary:</p>
<hr />
<h1>CI Health Analysis: facebook/react</h1>
<h2>Executive Summary</h2>
<p><strong>Overall Status: 🟢 HEALTHY</strong></p>
<p>The React repository's CI appears to be in good health. Recent commits to <code>main</code> have been successfully merged, and active PRs show passing CodeSandbox builds.</p>
<hr />
<h2>1. CI Infrastructure Overview</h2>
<h3>Primary Workflows</h3>
<table>
<thead>
<tr>
<th>Workflow</th>
<th>Trigger</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>runtime_build_and_test.yml</code></td>
<td>Push to main, PRs</td>
<td>Main CI - builds, tests, Flow checks</td>
</tr>
<tr>
<td><code>shared_lint.yml</code></td>
<td>Push to main, PRs</td>
<td>Prettier, ESLint, license checks</td>
</tr>
<tr>
<td><code>compiler_typescript.yml</code></td>
<td>PRs touching compiler</td>
<td>Compiler-specific tests</td>
</tr>
<tr>
<td><code>devtools_regression_tests.yml</code></td>
<td>PRs</td>
<td>DevTools testing</td>
</tr>
</tbody>
</table>
<h3>Test Matrix Scale</h3>
<ul>
<li><strong>90 test shards</strong> (18 configurations × 5 shards each)</li>
<li><strong>50 build jobs</strong> (25 workers × 2 release channels)</li>
<li><strong>50 test-build shards</strong> (5 configurations × 10 shards)</li>
<li>Flow checks across multiple inline configs</li>
</ul>
<hr />
<h2>2. Recent Main Branch Status</h2>
<table>
<thead>
<tr>
<th>Commit</th>
<th>Date</th>
<th>Description</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>bf1afad</code></td>
<td>Dec 4, 2025</td>
<td>[react-dom/server] Fix hanging on Deno</td>
<td>✅ Merged</td>
</tr>
<tr>
<td><code>0526c79</code></td>
<td>Dec 3, 2025</td>
<td>Update changelog with latest releases</td>
<td>✅ Merged</td>
</tr>
<tr>
<td><code>7dc903c</code></td>
<td>Dec 3, 2025</td>
<td>Patch FlightReplyServer (security fix)</td>
<td>✅ Merged</td>
</tr>
<tr>
<td><code>36df5e8</code></td>
<td>Dec 2, 2025</td>
<td>Allow building single release channel</td>
<td>✅ Merged</td>
</tr>
</tbody>
</table>
<p><strong>Last 10 commits:</strong> All successfully merged to main, indicating CI is passing.</p>
<hr />
<h2>3. Active PR CI Status</h2>
<table>
<thead>
<tr>
<th>PR</th>
<th>Title</th>
<th>CodeSandbox Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>#35267</td>
<td>Fix spelling (behaviour → behavior)</td>
<td>🟡 Pending (building)</td>
</tr>
<tr>
<td>#35238</td>
<td>DevTools navigating commits hotkey</td>
<td>✅ Success</td>
</tr>
<tr>
<td>#35287</td>
<td>Compiler: Fix variable name issue</td>
<td>✅ Success</td>
</tr>
<tr>
<td>#35278</td>
<td>Add DevTools console suppress option</td>
<td>✅ Success</td>
</tr>
<tr>
<td>#35226</td>
<td>Fizz: Push stalled use() to ownerStack</td>
<td>✅ Success</td>
</tr>
</tbody>
</table>
<hr />
<h2>4. Risk Assessment</h2>
<h3>✅ Positive Indicators</h3>
<ul>
<li><strong>Main branch stable</strong>: All recent commits merged successfully</li>
<li><strong>No open CI failure issues</strong>: Search returned zero CI-related open bugs</li>
<li><strong>Active development</strong>: Security patches and features landing regularly</li>
<li><strong>PR builds passing</strong>: Most open PRs show successful builds</li>
</ul>
<h3>⚠️ Areas to Monitor</h3>
<ul>
<li><strong>Large test matrix</strong>: 190+ parallel jobs mean potential for infrastructure flakiness</li>
<li><strong>Playwright-based e2e tests</strong>: Browser-based tests can be flaky (Flight fixtures, DevTools e2e)</li>
<li><strong>Cache dependencies</strong>: Multiple cache strategies (v6 keys) - cache misses could slow builds</li>
</ul>
<h3>📊 CI Complexity Metrics</h3>
<ul>
<li>~37KB workflow file for main CI (<code>runtime_build_and_test.yml</code>)</li>
<li>Heavy parallelization with matrix strategies</li>
<li>Multiple artifact upload/download operations</li>
</ul>
<hr />
<h2>5. Recommended Actions</h2>
<table>
<thead>
<tr>
<th>Priority</th>
<th>Action</th>
<th>Rationale</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>LOW</strong></td>
<td>Monitor PR #35267</td>
<td>Currently building - verify completion</td>
</tr>
<tr>
<td><strong>LOW</strong></td>
<td>No immediate action required</td>
<td>Main branch healthy, PRs passing</td>
</tr>
<tr>
<td><strong>INFO</strong></td>
<td>Security patch merged Dec 3</td>
<td>PR #35277 fixed critical security vuln in FlightReplyServer - verify downstream impact</td>
</tr>
</tbody>
</table>
<hr />
<h2>6. On-Call Notes</h2>
<p><strong>TL;DR for On-Call Engineer:</strong><br />
- 🟢 <strong>CI is GREEN</strong> - No action required<br />
- Main branch is healthy with successful merges in last 24h<br />
- All checked PRs showing green/passing status<br />
- No open issues flagged for CI failures or flakiness<br />
- Recent security patch (#35277) was successfully merged - monitor for any regressions</p>
<p><strong>If issues arise:</strong><br />
1. Check GitHub Actions tab directly: <code>https://github.com/facebook/react/actions</code><br />
2. Key workflows to monitor: "(Runtime) Build and Test", "(Shared) Lint"<br />
3. Caches use <code>v6</code> key prefix - if widespread failures, consider cache invalidation</p>
<hr />
<p><em>Analysis performed: December 4, 2025</em><br />
<em>Data sources: GitHub API (commits, PRs, status checks, workflow files)</em></p></div></div><div class="msg-block result"><div class="msg-label">✅ Complete</div><div class="stats-bar"><span class="stat-item"><span class="stat-label">Turns:</span> 19</span> <span class="stat-item"><span class="stat-label">Tokens:</span> 42,191</span> <span class="stat-item"><span class="stat-label">Cost:</span> $0.83</span> <span class="stat-item"><span class="stat-label">Duration:</span> 89.2s</span></div></div>
        </div>
    </div>
    
:::
::::

:::: {#9e3ed49f .cell .code execution_count="11"}
``` python
reset_activity_context()
display_agent_response(messages)
```

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><p>Based on my comprehensive analysis of the facebook/react repository CI infrastructure, here is the operational summary:</p>
<hr />
<h1>CI Health Analysis: facebook/react</h1>
<h2>Executive Summary</h2>
<p><strong>Overall Status: 🟢 HEALTHY</strong></p>
<p>The React repository's CI appears to be in good health. Recent commits to <code>main</code> have been successfully merged, and active PRs show passing CodeSandbox builds.</p>
<hr />
<h2>1. CI Infrastructure Overview</h2>
<h3>Primary Workflows</h3>
<table>
<thead>
<tr>
<th>Workflow</th>
<th>Trigger</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>runtime_build_and_test.yml</code></td>
<td>Push to main, PRs</td>
<td>Main CI - builds, tests, Flow checks</td>
</tr>
<tr>
<td><code>shared_lint.yml</code></td>
<td>Push to main, PRs</td>
<td>Prettier, ESLint, license checks</td>
</tr>
<tr>
<td><code>compiler_typescript.yml</code></td>
<td>PRs touching compiler</td>
<td>Compiler-specific tests</td>
</tr>
<tr>
<td><code>devtools_regression_tests.yml</code></td>
<td>PRs</td>
<td>DevTools testing</td>
</tr>
</tbody>
</table>
<h3>Test Matrix Scale</h3>
<ul>
<li><strong>90 test shards</strong> (18 configurations × 5 shards each)</li>
<li><strong>50 build jobs</strong> (25 workers × 2 release channels)</li>
<li><strong>50 test-build shards</strong> (5 configurations × 10 shards)</li>
<li>Flow checks across multiple inline configs</li>
</ul>
<hr />
<h2>2. Recent Main Branch Status</h2>
<table>
<thead>
<tr>
<th>Commit</th>
<th>Date</th>
<th>Description</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>bf1afad</code></td>
<td>Dec 4, 2025</td>
<td>[react-dom/server] Fix hanging on Deno</td>
<td>✅ Merged</td>
</tr>
<tr>
<td><code>0526c79</code></td>
<td>Dec 3, 2025</td>
<td>Update changelog with latest releases</td>
<td>✅ Merged</td>
</tr>
<tr>
<td><code>7dc903c</code></td>
<td>Dec 3, 2025</td>
<td>Patch FlightReplyServer (security fix)</td>
<td>✅ Merged</td>
</tr>
<tr>
<td><code>36df5e8</code></td>
<td>Dec 2, 2025</td>
<td>Allow building single release channel</td>
<td>✅ Merged</td>
</tr>
</tbody>
</table>
<p><strong>Last 10 commits:</strong> All successfully merged to main, indicating CI is passing.</p>
<hr />
<h2>3. Active PR CI Status</h2>
<table>
<thead>
<tr>
<th>PR</th>
<th>Title</th>
<th>CodeSandbox Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>#35267</td>
<td>Fix spelling (behaviour → behavior)</td>
<td>🟡 Pending (building)</td>
</tr>
<tr>
<td>#35238</td>
<td>DevTools navigating commits hotkey</td>
<td>✅ Success</td>
</tr>
<tr>
<td>#35287</td>
<td>Compiler: Fix variable name issue</td>
<td>✅ Success</td>
</tr>
<tr>
<td>#35278</td>
<td>Add DevTools console suppress option</td>
<td>✅ Success</td>
</tr>
<tr>
<td>#35226</td>
<td>Fizz: Push stalled use() to ownerStack</td>
<td>✅ Success</td>
</tr>
</tbody>
</table>
<hr />
<h2>4. Risk Assessment</h2>
<h3>✅ Positive Indicators</h3>
<ul>
<li><strong>Main branch stable</strong>: All recent commits merged successfully</li>
<li><strong>No open CI failure issues</strong>: Search returned zero CI-related open bugs</li>
<li><strong>Active development</strong>: Security patches and features landing regularly</li>
<li><strong>PR builds passing</strong>: Most open PRs show successful builds</li>
</ul>
<h3>⚠️ Areas to Monitor</h3>
<ul>
<li><strong>Large test matrix</strong>: 190+ parallel jobs mean potential for infrastructure flakiness</li>
<li><strong>Playwright-based e2e tests</strong>: Browser-based tests can be flaky (Flight fixtures, DevTools e2e)</li>
<li><strong>Cache dependencies</strong>: Multiple cache strategies (v6 keys) - cache misses could slow builds</li>
</ul>
<h3>📊 CI Complexity Metrics</h3>
<ul>
<li>~37KB workflow file for main CI (<code>runtime_build_and_test.yml</code>)</li>
<li>Heavy parallelization with matrix strategies</li>
<li>Multiple artifact upload/download operations</li>
</ul>
<hr />
<h2>5. Recommended Actions</h2>
<table>
<thead>
<tr>
<th>Priority</th>
<th>Action</th>
<th>Rationale</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>LOW</strong></td>
<td>Monitor PR #35267</td>
<td>Currently building - verify completion</td>
</tr>
<tr>
<td><strong>LOW</strong></td>
<td>No immediate action required</td>
<td>Main branch healthy, PRs passing</td>
</tr>
<tr>
<td><strong>INFO</strong></td>
<td>Security patch merged Dec 3</td>
<td>PR #35277 fixed critical security vuln in FlightReplyServer - verify downstream impact</td>
</tr>
</tbody>
</table>
<hr />
<h2>6. On-Call Notes</h2>
<p><strong>TL;DR for On-Call Engineer:</strong><br />
- 🟢 <strong>CI is GREEN</strong> - No action required<br />
- Main branch is healthy with successful merges in last 24h<br />
- All checked PRs showing green/passing status<br />
- No open issues flagged for CI failures or flakiness<br />
- Recent security patch (#35277) was successfully merged - monitor for any regressions</p>
<p><strong>If issues arise:</strong><br />
1. Check GitHub Actions tab directly: <code>https://github.com/facebook/react/actions</code><br />
2. Key workflows to monitor: "(Runtime) Build and Test", "(Shared) Lint"<br />
3. Caches use <code>v6</code> key prefix - if widespread failures, consider cache invalidation</p>
<hr />
<p><em>Analysis performed: December 4, 2025</em><br />
<em>Data sources: GitHub API (commits, PRs, status checks, workflow files)</em></p></div>
:::
::::

::: {#80cd321f .cell .markdown}
### Observability Agent as Module

The `observability_agent/agent.py` module wraps the observability
pattern into a reusable `send_query` function. It imports and uses the
shared visualization utilities from `utils.agent_visualizer` internally:

- **`reset_activity_context()`**: Called automatically at the start of
  each query
- **`print_activity()`**: Provides real-time feedback during execution
- **`display_agent_response()`**: Renders the final result (controlled
  by `display_result` parameter)

This means you can use the module with minimal code:
:::

::::: {#97074fe7 .cell .code execution_count="12"}
``` python
# Reload the module to pick up any changes (useful during development)
from observability_agent.agent import send_query

# The module handles activity display, context reset, and result visualization internally
result = await send_query(
    "Check the CI status for the last 2 runs in anthropics/claude-agent-sdk-python. Just do 3 tool calls, be efficient."
)
```

::: {.output .stream .stdout}
    🤖 Using: mcp__github__list_commits()
    ✓ Tool completed
    🤖 Using: mcp__github__get_commit()
    🤖 Using: mcp__github__get_commit()
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><h2>CI Status Summary for <code>anthropics/claude-agent-sdk-python</code></h2>
<table>
<thead>
<tr>
<th>Commit</th>
<th>Message</th>
<th>Date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>2437035</code></td>
<td>chore: bump bundled CLI version to 2.0.58</td>
<td>Dec 3, 2025 20:09 UTC</td>
<td>⚠️ <strong>No CI status available</strong></td>
</tr>
<tr>
<td><code>9809fb6</code></td>
<td>chore: release v0.1.11 (#383)</td>
<td>Dec 3, 2025 19:42 UTC</td>
<td>⚠️ <strong>No CI status available</strong></td>
</tr>
</tbody>
</table>
<p><strong>Note:</strong> The GitHub API response doesn't include explicit CI/check status data. This typically means:<br />
1. CI hasn't been triggered on these commits (both are automated commits from GitHub Actions)<br />
2. The checks aren't exposed via the commit API endpoint</p>
<p><strong>Recommendation:</strong> To get detailed CI run information, you'd need to check:<br />
- GitHub Actions tab directly: https://github.com/anthropics/claude-agent-sdk-python/actions<br />
- Or query the Checks API specifically for workflow runs</p>
<p>Both commits are automated maintenance commits (CLI bump and release version update), so they may intentionally skip full CI runs.</p></div>
:::
:::::

::: {#0c1578dc .cell .markdown}
Multi-turn conversations work seamlessly - just pass
`continue_conversation=True`:
:::

::::: {#7914f8db .cell .code execution_count="13"}
``` python
# Example 2: Multi-turn conversation for deeper monitoring
result1 = await send_query("What's the current CI status for facebook/react?")
```

::: {.output .stream .stdout}
    🤖 Using: mcp__github__list_pull_requests()
    🤖 Using: mcp__github__list_commits()
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__pull_request_read()
    🤖 Using: mcp__github__get_commit()
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><h2>CI Status Summary for <code>facebook/react</code></h2>
<h3>🟢 Main Branch Status: <strong>HEALTHY</strong></h3>
<p><strong>Latest Commit on <code>main</code>:</strong><br />
- <strong>SHA:</strong> <code>bf1afade</code> <br />
- <strong>Message:</strong> <code>[react-dom/server] Fix hanging on Deno (#35235)</code><br />
- <strong>Author:</strong> @fraidev<br />
- <strong>Date:</strong> Dec 4, 2025 05:50 UTC</p>
<hr />
<h3>Open Pull Requests CI Status</h3>
<table>
<thead>
<tr>
<th>PR</th>
<th>Title</th>
<th>Author</th>
<th>CI Status</th>
<th>Updated</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://github.com/facebook/react/pull/35287">#35287</a></td>
<td>[compiler] Fix JSX variable name issue</td>
<td>@kostya-gromov</td>
<td>🟢 <strong>Success</strong></td>
<td>2h ago</td>
</tr>
<tr>
<td><a href="https://github.com/facebook/react/pull/35285">#35285</a></td>
<td>[compiler][poc] Reuse ValidateExhaustiveDeps</td>
<td>@josephsavona</td>
<td>🔵 Draft</td>
<td>6h ago</td>
</tr>
<tr>
<td><a href="https://github.com/facebook/react/pull/35284">#35284</a></td>
<td>[compiler] Fix hoisted primitives bug</td>
<td>@josephsavona</td>
<td>🟢 <strong>Success</strong></td>
<td>7h ago</td>
</tr>
<tr>
<td><a href="https://github.com/facebook/react/pull/35282">#35282</a></td>
<td>[compiler] Add effect deps validator</td>
<td>@jackpope</td>
<td>🟢 <strong>Success</strong></td>
<td>15h ago</td>
</tr>
<tr>
<td><a href="https://github.com/facebook/react/pull/35281">#35281</a></td>
<td>Improve legacy context warning</td>
<td>@Harshrj53</td>
<td>🟢 <strong>Success</strong></td>
<td>20h ago</td>
</tr>
</tbody>
</table>
<hr />
<h3>Key Observations</h3>
<ul>
<li>✅ <strong>No CI failures</strong> detected on recent PRs</li>
<li>✅ All CodeSandbox builds passing</li>
<li>⚠️ Recent security fix merged: <code>#35277</code> addresses a <strong>critical security vulnerability</strong> in FlightReplyServer</li>
</ul>
<h3>Recent Notable Commits</h3>
<ol>
<li><strong>Security patch</strong> - FlightReplyServer fix for cycles and deferred error handling</li>
<li><strong>Deno fix</strong> - react-dom/server hanging issue resolved</li>
<li><strong>Compiler improvements</strong> - Multiple fixes for React Compiler validation</li>
</ol>
<p><strong>Assessment:</strong> CI is stable. No immediate action required.</p></div>
:::
:::::

::::: {#8014a701 .cell .code execution_count="14"}
``` python
# Continue the conversation to dig deeper
result2 = await send_query(
    "Are there any flaky tests in the recent failures? You can only make one tool call.",
    continue_conversation=True,
)
```

::: {.output .stream .stdout}
    🤖 Using: mcp__github__search_issues()
    ✓ Tool completed
    🤖 Thinking...
:::

::: {.output .display_data}

<style>
.pretty-card {
    font-family: ui-sans-serif, system-ui;
    border: 2px solid transparent;
    border-radius: 14px;
    padding: 14px 16px;
    margin: 10px 0;
    background: linear-gradient(#fff, #fff) padding-box,
                linear-gradient(135deg, #3b82f6, #9333ea) border-box;
    color: #111;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.pretty-title {
    font-weight: 700;
    margin-bottom: 8px;
    font-size: 14px;
    color: #111;
}
.pretty-card pre,
.pretty-card code {
    background: #f3f4f6;
    color: #111;
    padding: 8px;
    border-radius: 8px;
    display: block;
    overflow-x: auto;
    font-size: 13px;
    white-space: pre-wrap;
}
.pretty-card img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* Tables: both pandas (.pretty-table) and markdown-rendered */
.pretty-card table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
    color: #111;
    margin: 0.5em 0;
}
.pretty-card th,
.pretty-card td {
    border: 1px solid #e5e7eb;
    padding: 6px 8px;
    text-align: left;
}
.pretty-card th {
    background: #f9fafb;
    font-weight: 600;
}
/* Markdown headings */
.pretty-card h1, .pretty-card h2, .pretty-card h3, .pretty-card h4 {
    margin: 0.5em 0 0.3em 0;
    color: #111;
}
.pretty-card h1 { font-size: 1.4em; }
.pretty-card h2 { font-size: 1.2em; }
.pretty-card h3 { font-size: 1.1em; }
/* Markdown lists and paragraphs */
.pretty-card ul, .pretty-card ol {
    margin: 0.5em 0;
    padding-left: 1.5em;
}
.pretty-card p {
    margin: 0.5em 0;
}
.pretty-card hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 1em 0;
}
</style>
<div class="pretty-card"><div class="pretty-title">Agent Response</div><h2>Flaky Test Analysis for <code>facebook/react</code></h2>
<h3>Result: <strong>No known flaky tests tracked</strong></h3>
<p>The search returned <strong>0 open issues</strong> related to flaky tests, test flakes, or intermittent failures in the repository.</p>
<h3>Assessment</h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Open flaky test issues</td>
<td>0</td>
</tr>
<tr>
<td>Recent CI failures</td>
<td>None detected</td>
</tr>
<tr>
<td>Test stability</td>
<td>✅ <strong>Stable</strong></td>
</tr>
</tbody>
</table>
<h3>Interpretation</h3>
<ol>
<li><strong>Good news:</strong> No currently tracked flaky test issues in the open issue tracker</li>
<li>The React team appears to be on top of test reliability</li>
<li>Based on the earlier CI check, all recent PRs show passing builds</li>
</ol>
<h3>Caveats</h3>
<ul>
<li>Flaky tests may be tracked internally (Meta's internal systems)</li>
<li>Some flakes might be handled via suppression/retry mechanisms</li>
<li>The team may use different labeling conventions</li>
</ul>
<p><strong>Recommendation:</strong> CI appears healthy with no actionable flaky test issues at this time.</p></div>
:::
:::::

::: {#5a2f48f7 .cell .markdown}
## Conclusion

We\'ve demonstrated how the Claude Code SDK enables seamless integration
with external systems through the Model Context Protocol (MCP). Starting
with local Git operations through the Git MCP server, we progressively
expanded to full GitHub platform integration with access to over 100
GitHub-specific tools. This transformed our agent from a local assistant
into a powerful observability system capable of monitoring workflows,
analyzing CI/CD failures, and providing actionable insights for
production systems.

By connecting MCP servers to our agent, we created an autonomous
observability system that monitors GitHub Actions workflows,
distinguishes between real failures and security restrictions, and
provides detailed analysis of test failures. The system demonstrates how
agents can actively participate in your DevOps workflow, moving from
passive monitoring to intelligent incident response.

This concludes, for now, our journey through the Claude Code SDK
tutorial series. We\'ve progressed from simple research agents to
sophisticated multi-agent orchestration, and finally to external system
integration through MCP. Together, these patterns provide the foundation
for building production-ready agentic systems that can handle real-world
complexity while maintaining governance, compliance, and observability.

### What You\'ve Learned Across All Notebooks

**From Notebook 00 (Research Agent)**

- Core SDK fundamentals with `query()` and `ClaudeSDKClient`
- Basic tool usage with WebSearch and Read
- Simple agent loops and conversation management

**From Notebook 01 (Chief of Staff)**

- Advanced features: memory, output styles, planning mode
- Multi-agent coordination through subagents
- Governance through hooks and custom commands
- Enterprise-ready agent architectures

**From Notebook 02 (Observability Agent)**

- External system integration via MCP servers
- Real-time monitoring and incident response
- Production workflow automation
- Scalable agent deployment patterns

The complete implementations for all three agents are available in their
respective directories (`research_agent/`, `chief_of_staff_agent/`,
`observability_agent/`), ready to serve as inspiration for integrations
into your production systems.
:::

---

## Chief of Staff Agent Architecture

Source: https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/chief_of_staff_agent/flow_diagram.md
Path: 09-Agents-Patterns/claude-cookbooks-claude-agent-sdk-chief-of-staff-agent-flow-diagram.md

# Chief of Staff Agent Architecture

```mermaid
graph TD
    User[User] --> Chief[Chief of Staff Agent]
    Chief --> Memory[CLAUDE.md]
    Chief --> FinData[financial_data/]
    Chief --> Tools
    Chief --> Commands[Slash Commands]
    Chief --> Styles[Output Styles]
    Chief --> Hooks[Hooks]

    Tools --> Task[Task Tool]
    Task --> FA[Financial Analyst]
    Task --> Recruiter[Recruiter]

    FA --> Scripts1[Python Scripts]
    Recruiter --> Scripts2[Python Scripts]

    style Chief fill:#f9f,stroke:#333,stroke-width:3px
    style Task fill:#bbf,stroke:#333,stroke-width:2px
    style FA fill:#bfb,stroke:#333,stroke-width:2px
    style Recruiter fill:#bfb,stroke:#333,stroke-width:2px
```

## Expected Agent Communication Flow

```mermaid
sequenceDiagram
    participant User
    participant Chief as Chief of Staff
    participant Task as Task Tool
    participant FA as Financial Analyst
    participant Scripts as Python Scripts
    participant Hooks as Post-Write Hook
    User->>Chief: /budget-impact hiring 5 engineers
    Chief->>Chief: Expand slash command
    Chief->>Task: Delegate financial analysis
    Task->>FA: Analyze hiring impact
    FA->>Scripts: Execute hiring_impact.py
    Scripts-->>FA: Return analysis results
    FA->>FA: Generate report
    FA-->>Task: Return findings
    Task-->>Chief: Subagent results
    Chief->>Chief: Write report to disk
    Chief->>Hooks: Trigger post-write hook
    Hooks->>Hooks: Log to audit trail
    Chief-->>User: Executive summary
```

---

## Observability Agent Architecture

Source: https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/observability_agent/architecture_diagram.md
Path: 09-Agents-Patterns/claude-cookbooks-claude-agent-sdk-observability-agent-architecture-diagram.md

# Observability Agent Architecture

```mermaid
graph TD
    User[User] --> Agent[Observability Agent]
    Agent --> GitHub[GitHub MCP Server]

    Agent --> Tools[Tools]
    Tools --> WebSearch[WebSearch]
    Tools --> Read[Read Files]

    GitHub --> Docker[Docker Container]
    Docker --> API[GitHub API]

    style Agent fill:#f9f,stroke:#333,stroke-width:3px
    style GitHub fill:#bbf,stroke:#333,stroke-width:2px
```


# Communication Flow Diagram

```mermaid
sequenceDiagram
    participant User
    participant Agent
    participant MCP as GitHub MCP
    participant API as GitHub API

    User->>Agent: Query about repo
    Agent->>MCP: Connect via Docker
    Agent->>MCP: Request data
    MCP->>API: Fetch info
    API-->>MCP: Return data
    MCP-->>Agent: Process results
    Agent-->>User: Display answer
```

---

## Using Haiku as a sub-agent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/multimodal/using_sub_agents.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-multimodal-using-sub-agents.md

# Using Haiku as a sub-agent

In this recipe, we\'ll demonstrate how to analyze Apple\'s 2023
financial earnings reports using Claude 3 Haiku sub-agent models to
extract relevant information from earnings release PDFs. We\'ll then use
Claude 3 Opus to generate a response to our question and create a graph
using matplotlib to accompany its response.
:::

::: {.cell .markdown}
## Step 1: Set up the environment

First, let\'s install the required libraries and set up the Claude API
client.
:::

::: {.cell .code}
``` python
%pip install anthropic IPython PyMuPDF matplotlib
```
:::

::: {.cell .code execution_count="89"}
``` python
# Import the required libraries
import base64
import io
import os
from concurrent.futures import ThreadPoolExecutor

import fitz
import requests
from anthropic import Anthropic
from PIL import Image

# Set up the Claude API client
client = Anthropic()
MODEL_NAME = "claude-haiku-4-5"
```
:::

::: {.cell .markdown}
## Step 2: Gather our documents and ask a question

For this example, we will be using all Apple\'s financial statements
from the 2023 financial year and asking about the net sales over the
year.
:::

::: {.cell .code execution_count="90"}
``` python
# List of Apple's earnings release PDF URLs
pdf_urls = [
    "https://www.apple.com/newsroom/pdfs/fy2023-q4/FY23_Q4_Consolidated_Financial_Statements.pdf",
    "https://www.apple.com/newsroom/pdfs/fy2023-q3/FY23_Q3_Consolidated_Financial_Statements.pdf",
    "https://www.apple.com/newsroom/pdfs/FY23_Q2_Consolidated_Financial_Statements.pdf",
    "https://www.apple.com/newsroom/pdfs/FY23_Q1_Consolidated_Financial_Statements.pdf",
]

# User's question
QUESTION = "How did Apple's net sales change quarter to quarter in the 2023 financial year and what were the key contributors to the changes?"
```
:::

::: {.cell .markdown}
## Step 3: Download and convert PDFs to images

Next, we\'ll define functions to download the earnings release PDFs and
convert them to base64-encoded PNG images. We have to do this because
these PDFs are full of tables that are hard to parse with traditional
PDF parsers. It\'s easier if we just convert them to images and pass the
images to Haiku.

The `download_pdf` function downloads a PDF file from a given URL and
saves it to the specified folder. The `pdf_to_base64_pngs` function
converts a PDF to a list of base64-encoded PNG images.
:::

::: {.cell .code}
``` python
# Function to download a PDF file from a URL and save it to a specified folder
def download_pdf(url, folder):
    response = requests.get(url, timeout=60)
    if response.status_code == 200:
        file_name = os.path.join(folder, url.split("/")[-1])
        with open(file_name, "wb") as file:
            file.write(response.content)
        return file_name
    else:
        print(f"Failed to download PDF from {url}")
        return None


# Define the function to convert a PDF to a list of base64-encoded PNG images
def pdf_to_base64_pngs(pdf_path, quality=75, max_size=(1024, 1024)):
    # Open the PDF file
    doc = fitz.open(pdf_path)

    base64_encoded_pngs = []

    # Iterate through each page of the PDF
    for page_num in range(doc.page_count):
        # Load the page
        page = doc.load_page(page_num)

        # Render the page as a PNG image
        pix = page.get_pixmap(matrix=fitz.Matrix(300 / 72, 300 / 72))

        # Convert the pixmap to a PIL Image
        image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)

        # Resize the image if it exceeds the maximum size
        if image.size[0] > max_size[0] or image.size[1] > max_size[1]:
            image.thumbnail(max_size, Image.Resampling.LANCZOS)

        # Convert the PIL Image to base64-encoded PNG
        image_data = io.BytesIO()
        image.save(image_data, format="PNG", optimize=True, quality=quality)
        image_data.seek(0)
        base64_encoded = base64.b64encode(image_data.getvalue()).decode("utf-8")
        base64_encoded_pngs.append(base64_encoded)

    # Close the PDF document
    doc.close()

    return base64_encoded_pngs


# Folder to save the downloaded PDFs
folder = "../images/using_sub_agents"


# Create the directory if it doesn't exist
os.makedirs(folder)

# Download the PDFs concurrently
with ThreadPoolExecutor() as executor:
    pdf_paths = list(executor.map(download_pdf, pdf_urls, [folder] * len(pdf_urls)))

# Remove any None values (failed downloads) from pdf_paths
pdf_paths = [path for path in pdf_paths if path is not None]
```
:::

::: {.cell .markdown}
We use ThreadPoolExecutor to download the PDFs concurrently and store
the file paths in pdf_paths.
:::

::: {.cell .markdown}
## Step 4: Generate a specific prompt for Haiku using Opus

Let\'s use Opus as an orchestrator and have it write a specific prompt
for each Haiku sub-agent based on the user provided question.
:::

:::: {.cell .code execution_count="102"}
``` python
def generate_haiku_prompt(question):
    messages = [
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": f"Based on the following question, please generate a specific prompt for an LLM sub-agent to extract relevant information from an earning's report PDF. Each sub-agent only has access to a single quarter's earnings report. Output only the prompt and nothing else.\n\nQuestion: {question}",
                }
            ],
        }
    ]

    response = client.messages.create(model="claude-opus-4-1", max_tokens=2048, messages=messages)

    return response.content[0].text


haiku_prompt = generate_haiku_prompt(QUESTION)
print(haiku_prompt)
```

::: {.output .stream .stdout}
    Extract the following information from the Apple earnings report PDF for the quarter:
    1. Apple's net sales for the quarter
    2. Quarter-over-quarter change in net sales
    3. Key product categories, services, or regions that contributed significantly to the change in net sales
    4. Any explanations provided for the changes in net sales

    Organize the extracted information in a clear, concise format focusing on the key data points and insights related to the change in net sales for the quarter.
:::
::::

::: {.cell .markdown}
## Step 5: Extract information from PDFs

Now, let\'s define our question and extract information from the PDFs
using sub-agent Haiku models. We format the information from each model
into a neatly defined set of XML tags.
:::

:::: {.cell .code execution_count="107"}
``` python
def extract_info(pdf_path, haiku_prompt):
    base64_encoded_pngs = pdf_to_base64_pngs(pdf_path)

    messages = [
        {
            "role": "user",
            "content": [
                *[
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/png",
                            "data": base64_encoded_png,
                        },
                    }
                    for base64_encoded_png in base64_encoded_pngs
                ],
                {"type": "text", "text": haiku_prompt},
            ],
        }
    ]

    response = client.messages.create(model="claude-haiku-4-5", max_tokens=2048, messages=messages)

    return response.content[0].text, pdf_path


def process_pdf(pdf_path):
    return extract_info(pdf_path, haiku_prompt)


# Process the PDFs concurrently with Haiku sub-agent models
with ThreadPoolExecutor() as executor:
    extracted_info_list = list(executor.map(process_pdf, pdf_paths))

extracted_info = ""
# Display the extracted information from each model call
for info in extracted_info_list:
    extracted_info += (
        '<info quarter="' + info[1].split("/")[-1].split("_")[1] + '">' + info[0] + "</info>\n"
    )
print(extracted_info)
```

::: {.output .stream .stdout}
    <info quarter="Q4">According to the condensed consolidated statements of operations, Apple's net sales changed as follows in the 2023 financial year:

    Quarter Ended September 30, 2023:
    - Total net sales were $89,498 million, up from $90,146 million in the prior year quarter.
    - Product sales were $67,184 million and services sales were $22,314 million.

    Key contributors to the changes:
    - Product sales decreased from $70,958 million in the prior year quarter.
    - Services sales increased from $19,188 million in the prior year quarter.

    Overall, Apple's total net sales decreased slightly compared to the same quarter in the prior year, driven by a decline in product sales which was partially offset by growth in services sales.</info>
    <info quarter="Q3">Based on the financial statements provided, Apple's net sales changed as follows between the quarters in the 2023 financial year:

    - Net sales increased from $81,797 million in the three months ended July 1, 2023 to $82,959 million in the three months ended June 25, 2022. This represents a quarter-over-quarter increase of around $1,162 million.

    The key contributors to this increase appear to be:

    - Products sales increased from $60,584 million to $63,355 million, an increase of around $2,771 million.
    - Services sales increased from $21,213 million to $19,604 million, an increase of around $1,609 million.

    So the growth in both product sales and services sales contributed to the overall increase in Apple's net sales between these two quarters in the 2023 fiscal year.</info>
    <info quarter="Q2">According to the financial statements, Apple's net sales changed significantly between the quarters in the 2023 financial year:

    - For the three months ended April 1, 2023, net sales were $94,836 million.
    - For the six months ended March 26, 2022, net sales were $97,278 million.

    This shows that net sales decreased by around $2,442 million from the prior six-month period to the most recent three-month period.

    The key contributors to this change in net sales appear to be:

    1. Products sales decreased from $107,560 million in the prior six-month period to $73,929 million in the recent three-month period.
    2. Services sales increased from $41,673 million in the prior six-month period to $20,907 million in the recent three-month period.

    So the decrease in product sales was the primary driver behind the overall decline in net sales from the prior period to the most recent quarter.</info>
    <info quarter="Q1">According to the condensed consolidated statements of operations, Apple's net sales increased from $117,154 million in the three months ended December 31, 2022 to $123,945 million in the three months ended December 25, 2021. This represents a quarter-over-quarter increase in net sales.

    The key contributors to this change were:

    1. Increase in product sales revenue from $96,388 million to $104,429 million.
    2. Increase in services revenue from $20,766 million to $19,516 million.

    So the overall increase in net sales was driven primarily by higher product sales, with services revenue also showing a smaller increase quarter-over-quarter.</info>
:::
::::

::: {.cell .markdown}
We extract information from the PDFs concurrently using sub-agent models
and combine the extracted information. We then prepare the messages for
the powerful model, including the question and the extracted
information, and ask it to generate a response and matplotlib code.
:::

::: {.cell .markdown}
## Step 6: Pass the information to Opus to generate a response

Now that we have fetched the information from each PDF using the
sub-agents, let\'s call Opus to actually answer the question and write
code to create a graph to accompany the answer.
:::

:::: {.cell .code execution_count="108"}
``` python
# Prepare the messages for the powerful model
messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": f"Based on the following extracted information from Apple's earnings releases, please provide a response to the question: {QUESTION}\n\nAlso, please generate Python code using the matplotlib library to accompany your response. Enclose the code within <code> tags.\n\nExtracted Information:\n{extracted_info}",
            }
        ],
    }
]

# Generate the matplotlib code using the powerful model
response = client.messages.create(model="claude-opus-4-1", max_tokens=4096, messages=messages)

generated_response = response.content[0].text
print("Generated Response:")
print(generated_response)
```

::: {.output .stream .stdout}
    Generated Response:
    Based on the extracted information from Apple's earnings releases, Apple's net sales changed as follows in the 2023 financial year:

    In Q1, net sales increased from $117,154 million in the previous quarter to $123,945 million, driven by increases in both product sales and services revenue.

    In Q2, net sales decreased by around $2,442 million compared to the prior six-month period, primarily due to a decrease in product sales, which was partially offset by an increase in services sales.

    In Q3, net sales increased by approximately $1,162 million compared to the previous quarter, with growth in both product sales and services sales contributing to the overall increase.

    In Q4, total net sales decreased slightly compared to the same quarter in the prior year, driven by a decline in product sales, which was partially offset by growth in services sales.

    Here's a Python code snippet using the matplotlib library to visualize the quarterly net sales data:

    <code>
    import matplotlib.pyplot as plt

    quarters = ['Q1', 'Q2', 'Q3', 'Q4']
    net_sales = [123945, 94836, 82959, 89498]

    plt.figure(figsize=(8, 6))
    plt.bar(quarters, net_sales, color='skyblue', width=0.6)
    plt.xlabel('Quarter')
    plt.ylabel('Net Sales (in millions)')
    plt.title('Apple Net Sales by Quarter - FY 2023')
    plt.xticks(quarters)
    plt.yticks([0, 20000, 40000, 60000, 80000, 100000, 120000])
    plt.grid(True, linestyle='--', alpha=0.5)

    for i, v in enumerate(net_sales):
        plt.text(i, v + 1000, f'${v:,.0f}', ha='center', fontsize=10)

    plt.show()
    </code>

    This code creates a bar chart showing Apple's net sales for each quarter in the 2023 financial year. The x-axis represents the quarters, and the y-axis represents the net sales in millions of dollars. The chart also includes data labels showing the exact net sales values for each quarter.
:::
::::

::: {.cell .markdown}
## Step 7: Extract response and execute Matplotlib code

Finally, let\'s extract the matplotlib code from the generated response
and execute it to visualize the revenue growth trend.

We define the `extract_code_and_response` function to extract the
matplotlib code and non-code response from the generated response. We
print the non-code response and execute the matplotlib code if it is
found.

Note that it is not good practice to use `exec` on model-written code
outside of a sandbox but for the purposes of this demo we are doing it
:)
:::

::: {.cell .code}
``` python
# Extract the matplotlib code from the response
# Function to extract the code and non-code parts from the response
def extract_code_and_response(response):
    start_tag = "<code>"
    end_tag = "</code>"
    start_index = response.find(start_tag)
    end_index = response.find(end_tag)
    if start_index != -1 and end_index != -1:
        code = response[start_index + len(start_tag) : end_index].strip()
        non_code_response = response[:start_index].strip()
        return code, non_code_response
    else:
        return None, response.strip()


matplotlib_code, non_code_response = extract_code_and_response(generated_response)

print(non_code_response)
if matplotlib_code:
    # Execute the extracted matplotlib code
    # Note: exec is used here for demonstration purposes to run model-generated visualization code.
    # In production, use a sandboxed environment for executing untrusted code.
    exec(matplotlib_code)  # noqa: S102
else:
    print("No matplotlib code found in the response.")
```
:::

---

## Example 1: Chain workflow for structured data extraction and formatting

Source: https://github.com/anthropics/claude-cookbooks/blob/main/patterns/agents/basic_workflows.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-patterns-agents-basic-workflows.md

## Basic Multi-LLM Workflows

This notebook demonstrates three simple multi-LLM workflows. They trade
off cost or latency for potentially improved task performances:

1.  **Prompt-Chaining**: Decomposes a task into sequential subtasks,
    where each step builds on previous results
2.  **Parallelization**: Distributes independent subtasks across
    multiple LLMs for concurrent processing
3.  **Routing**: Dynamically selects specialized LLM paths based on
    input characteristics

Note: These are sample implementations meant to demonstrate core
concepts - not production code.
:::

::: {.cell .code execution_count="1"}
``` python
from concurrent.futures import ThreadPoolExecutor

from util import extract_xml, llm_call
```
:::

::: {.cell .code}
``` python
def chain(input: str, prompts: list[str]) -> str:
    """Chain multiple LLM calls sequentially, passing results between steps."""
    result = input
    for i, prompt in enumerate(prompts, 1):
        print(f"\nStep {i}:")
        result = llm_call(f"{prompt}\nInput: {result}")
        print(result)
    return result


def parallel(prompt: str, inputs: list[str], n_workers: int = 3) -> list[str]:
    """Process multiple inputs concurrently with the same prompt."""
    with ThreadPoolExecutor(max_workers=n_workers) as executor:
        futures = [executor.submit(llm_call, f"{prompt}\nInput: {x}") for x in inputs]
        return [f.result() for f in futures]


def route(input: str, routes: dict[str, str]) -> str:
    """Route input to specialized prompt using content classification."""
    # First determine appropriate route using LLM with chain-of-thought
    print(f"\nAvailable routes: {list(routes.keys())}")
    selector_prompt = f"""
    Analyze the input and select the most appropriate support team from these options: {list(routes.keys())}
    First explain your reasoning, then provide your selection in this XML format:

    <reasoning>
    Brief explanation of why this ticket should be routed to a specific team.
    Consider key terms, user intent, and urgency level.
    </reasoning>

    <selection>
    The chosen team name
    </selection>

    Input: {input}""".strip()

    route_response = llm_call(selector_prompt)
    reasoning = extract_xml(route_response, "reasoning")
    route_key = extract_xml(route_response, "selection").strip().lower()

    print("Routing Analysis:")
    print(reasoning)
    print(f"\nSelected route: {route_key}")

    # Process input with selected specialized prompt
    selected_prompt = routes[route_key]
    return llm_call(f"{selected_prompt}\nInput: {input}")
```
:::

::: {.cell .markdown}
## Example Usage

Below are practical examples demonstrating each workflow:

1.  Chain workflow for structured data extraction and formatting
2.  Parallelization workflow for stakeholder impact analysis
3.  Route workflow for customer support ticket handling
:::

:::: {.cell .code}
``` python
# Example 1: Chain workflow for structured data extraction and formatting
# Each step progressively transforms raw text into a formatted table

data_processing_steps = [
    """Extract only the numerical values and their associated metrics from the text.
    Format each as 'value: metric' on a new line.
    Example format:
    92: customer satisfaction
    45%: revenue growth""",
    """Convert all numerical values to percentages where possible.
    If not a percentage or points, convert to decimal (e.g., 92 points -> 92%).
    Keep one number per line.
    Example format:
    92%: customer satisfaction
    45%: revenue growth""",
    """Sort all lines in descending order by numerical value.
    Keep the format 'value: metric' on each line.
    Example:
    92%: customer satisfaction
    87%: employee satisfaction""",
    """Format the sorted data as a markdown table with columns:
    | Metric | Value |
    |:--|--:|
    | Customer Satisfaction | 92% |""",
]

report = """
Q3 Performance Summary:
Our customer satisfaction score rose to 92 points this quarter.
Revenue grew by 45% compared to last year.
Market share is now at 23% in our primary market.
Customer churn decreased to 5% from 8%.
New user acquisition cost is $43 per user.
Product adoption rate increased to 78%.
Employee satisfaction is at 87 points.
Operating margin improved to 34%.
"""

print("\nInput text:")
print(report)
formatted_result = chain(report, data_processing_steps)
```

::: {.output .stream .stdout}

    Input text:

    Q3 Performance Summary:
    Our customer satisfaction score rose to 92 points this quarter.
    Revenue grew by 45% compared to last year.
    Market share is now at 23% in our primary market.
    Customer churn decreased to 5% from 8%.
    New user acquisition cost is $43 per user.
    Product adoption rate increased to 78%.
    Employee satisfaction is at 87 points.
    Operating margin improved to 34%.


    Step 1:
    92: customer satisfaction points
    45%: revenue growth
    23%: market share
    5%: customer churn
    8%: previous customer churn
    $43: user acquisition cost
    78%: product adoption rate
    87: employee satisfaction points
    34%: operating margin

    Step 2:
    92%: customer satisfaction
    45%: revenue growth
    23%: market share
    5%: customer churn
    8%: previous customer churn
    43.0: user acquisition cost
    78%: product adoption rate
    87%: employee satisfaction
    34%: operating margin

    Step 3:
    Here are the lines sorted in descending order by numerical value:

    92%: customer satisfaction
    87%: employee satisfaction
    78%: product adoption rate
    45%: revenue growth
    43.0: user acquisition cost
    34%: operating margin
    23%: market share
    8%: previous customer churn
    5%: customer churn

    Step 4:
    | Metric | Value |
    |:--|--:|
    | Customer Satisfaction | 92% |
    | Employee Satisfaction | 87% |
    | Product Adoption Rate | 78% |
    | Revenue Growth | 45% |
    | User Acquisition Cost | 43.0 |
    | Operating Margin | 34% |
    | Market Share | 23% |
    | Previous Customer Churn | 8% |
    | Customer Churn | 5% |
:::
::::

:::: {.cell .code}
``` python
# Example 2: Parallelization workflow for stakeholder impact analysis
# Process impact analysis for multiple stakeholder groups concurrently

stakeholders = [
    """Customers:
    - Price sensitive
    - Want better tech
    - Environmental concerns""",
    """Employees:
    - Job security worries
    - Need new skills
    - Want clear direction""",
    """Investors:
    - Expect growth
    - Want cost control
    - Risk concerns""",
    """Suppliers:
    - Capacity constraints
    - Price pressures
    - Tech transitions""",
]

impact_results = parallel(
    """Analyze how market changes will impact this stakeholder group.
    Provide specific impacts and recommended actions.
    Format with clear sections and priorities.""",
    stakeholders,
)

for result in impact_results:
    print(result)
    print("+" * 80)
```

::: {.output .stream .stdout}
    MARKET IMPACT ANALYSIS FOR CUSTOMERS
    ==================================

    HIGH PRIORITY IMPACTS
    -------------------
    1. Price Sensitivity
    - Rising inflation and costs likely to reduce purchasing power
    - Increased competition for value-oriented products
    - Risk of trading down to lower-cost alternatives

    Recommended Actions:
    • Introduce tiered pricing options
    • Develop value-focused product lines
    • Create loyalty programs with price benefits
    • Highlight total cost of ownership benefits

    2. Technology Demands
    - Accelerating tech advancement creating higher expectations
    - Integration of AI and smart features becoming standard
    - Mobile/digital-first experience requirements

    Recommended Actions:
    • Accelerate digital transformation initiatives
    • Invest in user experience improvements
    • Develop smart product features
    • Provide tech education and support

    MEDIUM PRIORITY IMPACTS
    ----------------------
    3. Environmental Consciousness
    - Growing demand for sustainable products
    - Increased scrutiny of environmental practices
    - Willingness to pay premium for eco-friendly options

    Recommended Actions:
    • Develop eco-friendly product lines
    • Improve packaging sustainability
    • Communicate environmental initiatives
    • Create recycling programs

    MONITORING & METRICS
    -------------------
    • Track customer satisfaction scores
    • Monitor price sensitivity metrics
    • Measure adoption of new technologies
    • Track sustainability-related purchases
    • Regular customer feedback surveys

    RISK FACTORS
    ------------
    • Economic downturn impact on spending
    • Tech adoption learning curve
    • Cost vs. sustainability trade-offs
    • Competition from specialized providers

    TIMELINE PRIORITIES
    ------------------
    Immediate (0-3 months):
    - Price optimization
    - Digital experience improvements

    Short-term (3-12 months):
    - Tech feature development
    - Sustainability initiatives

    Long-term (12+ months):
    - Advanced technology integration
    - Comprehensive eco-friendly transformation
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    MARKET IMPACT ANALYSIS FOR EMPLOYEES

    Priority 1: Job Security Concerns
    Impacts:
    • Market volatility creating uncertainty about positions
    • Potential restructuring or role changes
    • Stress affecting productivity and morale

    Recommended Actions:
    - Provide regular, transparent communications about company stability
    - Create clear performance metrics tied to job security
    - Establish early warning systems for at-risk positions
    - Develop retention programs for key talent

    Priority 2: Skills Gap & Development
    Impacts:
    • Current skills becoming outdated due to market changes
    • New technologies/processes requiring additional training
    • Competitive disadvantage without upskilling

    Recommended Actions:
    - Conduct skills gap analysis
    - Implement targeted training programs
    - Provide learning stipends/resources
    - Create mentorship programs
    - Partner with educational institutions

    Priority 3: Strategic Direction & Leadership
    Impacts:
    • Uncertainty about career paths
    • Lack of alignment with company goals
    • Reduced engagement and commitment

    Recommended Actions:
    - Develop clear career progression frameworks
    - Create individual development plans
    - Increase leadership visibility and communication
    - Establish regular strategy updates and town halls
    - Implement feedback mechanisms

    Implementation Timeline:
    Short-term (0-3 months):
    • Begin transparent communications
    • Launch initial training assessments
    • Start regular strategy updates

    Medium-term (3-6 months):
    • Roll out training programs
    • Implement retention initiatives
    • Develop career frameworks

    Long-term (6+ months):
    • Monitor and adjust programs
    • Measure effectiveness
    • Refine strategic alignment

    Success Metrics:
    • Employee retention rates
    • Skills assessment scores
    • Employee satisfaction surveys
    • Productivity measures
    • Career progression rates
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    MARKET IMPACT ANALYSIS FOR INVESTORS

    Priority 1: Financial Performance
    Impacts:
    • Market volatility may affect expected returns
    • Economic uncertainty could slow growth targets
    • Cost inflation may squeeze margins

    Recommended Actions:
    - Implement enhanced financial reporting and forecasting
    - Develop contingency plans for different market scenarios
    - Identify cost optimization opportunities
    - Consider strategic M&A opportunities at lower valuations

    Priority 2: Risk Management
    Impacts:
    • Increased market risks require stronger controls
    • New regulatory requirements possible
    • Competitive landscape changes

    Recommended Actions:
    - Strengthen risk management frameworks
    - Increase frequency of risk assessments
    - Diversify investment portfolio
    - Maintain higher cash reserves

    Priority 3: Communication & Transparency
    Impacts:
    • Heightened investor scrutiny expected
    • Need for more detailed market analysis
    • Demand for regular updates

    Recommended Actions:
    - Enhance investor communications
    - Provide more frequent market updates
    - Share detailed mitigation strategies
    - Maintain open dialogue with key stakeholders

    Timeline Recommendations:
    Short-term (0-6 months):
    - Implement enhanced reporting
    - Review risk controls
    - Increase communication frequency

    Medium-term (6-18 months):
    - Execute cost optimization
    - Develop new growth strategies
    - Build strategic partnerships

    Long-term (18+ months):
    - Evaluate market position
    - Adjust investment strategy
    - Consider structural changes

    Key Success Metrics:
    • ROI performance
    • Cost reduction achievements
    • Risk incident rates
    • Investor satisfaction scores
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    MARKET IMPACT ANALYSIS FOR SUPPLIERS

    HIGH PRIORITY IMPACTS:
    1. Capacity Constraints
    - Reduced ability to meet customer demand
    - Risk of losing market share to competitors
    - Strain on existing infrastructure and resources
    - Potential breach of supply agreements

    Recommended Actions:
    • Invest in capacity expansion
    • Implement better demand forecasting
    • Develop contingency supplier network
    • Negotiate flexible delivery terms

    2. Price Pressures
    - Squeezed profit margins
    - Difficulty maintaining quality standards
    - Risk of losing customers to lower-cost alternatives
    - Cash flow challenges

    Recommended Actions:
    • Review cost structure and identify efficiencies
    • Negotiate long-term contracts with price adjustment clauses
    • Explore automation/process improvements
    • Consider strategic partnerships to share costs

    3. Technology Transitions
    - Need for new equipment and systems
    - Training requirements for workforce
    - R&D investment demands
    - Risk of obsolescence

    Recommended Actions:
    • Develop technology roadmap
    • Invest in workforce training
    • Seek innovation partnerships
    • Phase implementation of new technologies

    MEDIUM PRIORITY CONSIDERATIONS:
    - Supply chain resilience
    - Quality control processes
    - Market positioning
    - Customer relationship management

    LONG-TERM STRATEGIC RECOMMENDATIONS:
    1. Build financial reserves for future investments
    2. Develop diversification strategies
    3. Create innovation partnerships
    4. Strengthen customer relationships
    5. Invest in sustainability initiatives

    MONITORING METRICS:
    • Production capacity utilization
    • Price competitiveness
    • Technology adoption rates
    • Customer satisfaction levels
    • Market share trends
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
:::
::::

:::: {.cell .code}
``` python
# Example 3: Route workflow for customer support ticket handling
# Route support tickets to appropriate teams based on content analysis

support_routes = {
    "billing": """You are a billing support specialist. Follow these guidelines:
    1. Always start with "Billing Support Response:"
    2. First acknowledge the specific billing issue
    3. Explain any charges or discrepancies clearly
    4. List concrete next steps with timeline
    5. End with payment options if relevant

    Keep responses professional but friendly.

    Input: """,
    "technical": """You are a technical support engineer. Follow these guidelines:
    1. Always start with "Technical Support Response:"
    2. List exact steps to resolve the issue
    3. Include system requirements if relevant
    4. Provide workarounds for common problems
    5. End with escalation path if needed

    Use clear, numbered steps and technical details.

    Input: """,
    "account": """You are an account security specialist. Follow these guidelines:
    1. Always start with "Account Support Response:"
    2. Prioritize account security and verification
    3. Provide clear steps for account recovery/changes
    4. Include security tips and warnings
    5. Set clear expectations for resolution time

    Maintain a serious, security-focused tone.

    Input: """,
    "product": """You are a product specialist. Follow these guidelines:
    1. Always start with "Product Support Response:"
    2. Focus on feature education and best practices
    3. Include specific examples of usage
    4. Link to relevant documentation sections
    5. Suggest related features that might help

    Be educational and encouraging in tone.

    Input: """,
}

# Test with different support tickets
tickets = [
    """Subject: Can't access my account
    Message: Hi, I've been trying to log in for the past hour but keep getting an 'invalid password' error.
    I'm sure I'm using the right password. Can you help me regain access? This is urgent as I need to
    submit a report by end of day.
    - John""",
    """Subject: Unexpected charge on my card
    Message: Hello, I just noticed a charge of $49.99 on my credit card from your company, but I thought
    I was on the $29.99 plan. Can you explain this charge and adjust it if it's a mistake?
    Thanks,
    Sarah""",
    """Subject: How to export data?
    Message: I need to export all my project data to Excel. I've looked through the docs but can't
    figure out how to do a bulk export. Is this possible? If so, could you walk me through the steps?
    Best regards,
    Mike""",
]

print("Processing support tickets...\n")
for i, ticket in enumerate(tickets, 1):
    print(f"\nTicket {i}:")
    print("-" * 40)
    print(ticket)
    print("\nResponse:")
    print("-" * 40)
    response = route(ticket, support_routes)
    print(response)
    print("+" * 80)
```

::: {.output .stream .stdout}
    Processing support tickets...


    Ticket 1:
    ----------------------------------------
    Subject: Can't access my account
        Message: Hi, I've been trying to log in for the past hour but keep getting an 'invalid password' error. 
        I'm sure I'm using the right password. Can you help me regain access? This is urgent as I need to 
        submit a report by end of day.
        - John

    Response:
    ----------------------------------------

    Available routes: ['billing', 'technical', 'account', 'product']
    Routing Analysis:

    This issue is clearly related to account access and authentication problems. The user is experiencing login difficulties with their password, which is a core account security and access issue. While there might be technical aspects involved, the primary concern is account access restoration. The urgency mentioned by the user and the nature of the problem (password/login issues) makes this a typical account support case. Account team specialists are best equipped to handle password resets, account verification, and access restoration procedures.


    Selected route: account
    Account Support Response:

    Dear John,

    I understand your urgency regarding account access. Before proceeding with account recovery, we must verify your identity to maintain security protocols.

    Immediate Steps for Account Recovery:
    1. Visit our secure password reset page at [secure portal URL]
    2. Click "Forgot Password"
    3. Enter your email address associated with the account
    4. Follow the verification instructions sent to your email

    Important Security Notes:
    • The reset link expires in 30 minutes
    • Do not share reset links or verification codes with anyone
    • Ensure you're on our official website (check for https:// and correct domain)

    WARNING: If you're unable to access your email or receive the reset link, additional verification will be required through our identity verification process.

    Additional Security Recommendations:
    - Enable Two-Factor Authentication after regaining access
    - Review recent account activity for unauthorized access
    - Update passwords on other accounts using similar credentials

    Expected Resolution Time:
    • Password reset: 5-10 minutes
    • Identity verification (if needed): 1-2 business hours

    If you continue experiencing issues, please respond with:
    1. Account email address
    2. Last successful login date
    3. Any recent account changes

    For urgent report submission, please contact your supervisor about deadline extension while we secure your account.

    Regards,
    Account Security Team
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Ticket 2:
    ----------------------------------------
    Subject: Unexpected charge on my card
        Message: Hello, I just noticed a charge of $49.99 on my credit card from your company, but I thought
        I was on the $29.99 plan. Can you explain this charge and adjust it if it's a mistake?
        Thanks,
        Sarah

    Response:
    ----------------------------------------

    Available routes: ['billing', 'technical', 'account', 'product']
    Routing Analysis:

    This is clearly a billing-related inquiry as it involves:
    1. Questions about charges on a credit card
    2. Pricing plan discrepancy ($49.99 vs $29.99)
    3. Request for explanation of charges
    4. Potential request for refund/adjustment
    The customer is specifically questioning a financial transaction, which falls under the billing team's expertise. While it touches on account plans, the core issue is about charges and payment processing.


    Selected route: billing
    Billing Support Response:

    Dear Sarah,

    I understand your concern about the unexpected charge of $49.99 when you were expecting to be billed $29.99.

    After reviewing the charge, this difference typically occurs when:
    1. The promotional period for the $29.99 rate has ended
    2. There was a plan upgrade or change in service tier
    3. Additional services were added to the account

    To resolve this, I will:
    1. Review your account history within 1 business day
    2. Send you a detailed breakdown of the charges by email
    3. If an error is confirmed, process a refund within 2-3 business days
    4. Ensure your plan is set to the correct rate moving forward

    For immediate action, you can:
    - Review your current plan settings in your account dashboard
    - Send us your last billing statement for comparison
    - Provide any promotional codes you may have applied previously

    Payment options available:
    - If a refund is due, it will be credited to your original payment method
    - You can adjust your plan back to $29.99 through your account settings if eligible
    - Monthly auto-pay can be reviewed and updated as needed

    Please let me know if you need any additional information or have questions about these next steps.

    Best regards,
    Billing Support Team
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Ticket 3:
    ----------------------------------------
    Subject: How to export data?
        Message: I need to export all my project data to Excel. I've looked through the docs but can't
        figure out how to do a bulk export. Is this possible? If so, could you walk me through the steps?
        Best regards,
        Mike

    Response:
    ----------------------------------------

    Available routes: ['billing', 'technical', 'account', 'product']
    Routing Analysis:

    This is clearly a technical/how-to question about product functionality. The user is asking for specific instructions about a feature (data export), and mentions looking through documentation. The question is about product usage and requires technical knowledge to explain the export process. Keywords like "export," "data," "bulk export," and reference to documentation strongly indicate this is a technical support matter rather than billing, account, or general product inquiry.


    Selected route: technical
    Technical Support Response:

    I'll help you export your project data to Excel. Here's the complete process:

    Steps to Export Data:
    1. Log into your project dashboard
    2. Navigate to "Project Settings" in the top right corner
    3. Select "Data Management" from the dropdown menu
    4. Click the "Export" tab
    5. Choose "Bulk Export" option
    6. Select data range and specific fields to export
    7. Choose "Excel (.xlsx)" as the output format
    8. Click "Generate Export"
    9. Wait for the system to process (may take 1-15 minutes depending on data size)
    10. Download the exported file when ready

    System Requirements:
    - Supported browsers: Chrome 90+, Firefox 88+, Edge 91+
    - Minimum 2GB RAM available
    - Stable internet connection
    - Excel 2016 or later for opening exported files

    Common Issues & Workarounds:
    A. If export times out:
       - Break data into smaller date ranges
       - Export during off-peak hours
       - Use filters to reduce data size

    B. If download fails:
       - Clear browser cache
       - Use incognito/private window
       - Try a different supported browser

    Escalation Path:
    If you continue experiencing issues:
    1. Contact your project administrator
    2. Submit a ticket to technical support at support@company.com
    3. Include your project ID and any error messages received
    4. For urgent matters, call our support hotline: 1-800-XXX-XXXX
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
:::
::::

---

## Orchestrator-Workers Workflow

Source: https://github.com/anthropics/claude-cookbooks/blob/main/patterns/agents/orchestrator_workers.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-patterns-agents-orchestrator-workers.md

# Orchestrator-Workers Workflow

## Introduction

Have you ever needed multiple perspectives on the same task, but
couldn\'t predict in advance which perspectives would be most valuable?
The orchestrator-workers pattern solves this by having a central LLM
analyze each unique task and dynamically determine the best subtasks to
delegate to specialized worker LLMs.

Traditional approaches either require manual prompting multiple times or
use hardcoded parallelization that generates the same variations
regardless of context.

With this approach, an orchestrator LLM analyzes the task, determines
which variations would be most valuable for this specific case, then
delegates to worker LLMs that generate each variation.

### What You\'ll Build

A system that takes a product description request and:

1.  Analyzes what types of marketing copy would be valuable
2.  Dynamically generates specialized task descriptions for workers
3.  Produces multiple content variations optimized for different
    audiences
4.  Returns coordinated results from all workers

### Prerequisites

- Python 3.9 or higher
- Anthropic API key set as environment variable:
  `export ANTHROPIC_API_KEY='your-key'`
- Basic understanding of prompt engineering
- Familiarity with Python classes and type hints

### When to use this workflow

This workflow is well-suited for complex tasks where you can\'t predict
the subtasks needed in advance. The key difference from simple
parallelization is its flexibility---subtasks aren\'t pre-defined, but
determined by the orchestrator based on the specific input.

**Use this pattern when:**

- Tasks require multiple distinct approaches or perspectives
- The optimal subtasks depend on the specific input
- You need to compare different strategies or styles

**Don\'t use this pattern when:**

- You have simple, single-output tasks (unnecessary complexity)
- Latency is critical (multiple LLM calls add overhead)
- Subtasks are predictable and can be pre-defined (use simpler
  parallelization)

## How It Works

The orchestrator-workers pattern operates in two phases:

1.  **Analysis & Planning Phase**: The orchestrator LLM receives the
    task and context, analyzes what approaches would be valuable, and
    generates structured subtask descriptions in XML format.

2.  **Execution Phase**: Each worker LLM receives:

    - The original task for context
    - Its specific subtask type and description
    - Any additional context provided

The orchestrator decides *at runtime* what subtasks to create, making
this more adaptive than pre-defined parallel workflows.
:::

::: {.cell .markdown}
## Setup

### Installation

``` bash
pip install anthropic
```

### Helper Functions

This example uses helper functions from `util.py` for making LLM calls
and parsing XML responses:

- `llm_call(prompt, system_prompt="", model="claude-sonnet-4-5")`: Sends
  a prompt to Claude and returns the text response
- `extract_xml(text, tag)`: Extracts content from XML tags using regex

These utilities handle API authentication (reading `ANTHROPIC_API_KEY`
from environment) and provide a simple interface for the
orchestrator-workers pattern. You can view the complete implementation
in [util.py](https://github.com/anthropics/claude-cookbooks/blob/main/patterns/agents/util.py).

## Implementation

The `FlexibleOrchestrator` class coordinates the two-phase workflow:

**Key design decisions:**

- Prompts are templates that accept runtime variables (`task`,
  `context`) for flexibility
- XML is used for structured output parsing (reliable and
  language-model-friendly format)
- Workers receive both the original task AND their specific instructions
  for better context
- Error handling validates that workers return non-empty responses

The implementation includes:

- `parse_tasks()`: Parses the orchestrator\'s XML output into structured
  task dictionaries
- `FlexibleOrchestrator.process()`: Main coordination logic that calls
  orchestrator, then workers
- Response validation to catch and handle empty worker outputs
:::

::: {.cell .code}
``` python
from util import extract_xml, llm_call

# Model configuration
MODEL = "claude-sonnet-4-5"  # Fast, capable model for both orchestrator and workers


def parse_tasks(tasks_xml: str) -> list[dict]:
    """Parse XML tasks into a list of task dictionaries."""
    tasks = []
    current_task = {}

    for line in tasks_xml.split("\n"):
        line = line.strip()
        if not line:
            continue

        if line.startswith("<task>"):
            current_task = {}
        elif line.startswith("<type>"):
            current_task["type"] = line[6:-7].strip()
        elif line.startswith("<description>"):
            current_task["description"] = line[12:-13].strip()
        elif line.startswith("</task>"):
            if "description" in current_task:
                if "type" not in current_task:
                    current_task["type"] = "default"
                tasks.append(current_task)

    return tasks


class FlexibleOrchestrator:
    """Break down tasks and run them in parallel using worker LLMs."""

    def __init__(
        self,
        orchestrator_prompt: str,
        worker_prompt: str,
        model: str = MODEL,
    ):
        """Initialize with prompt templates and model selection."""
        self.orchestrator_prompt = orchestrator_prompt
        self.worker_prompt = worker_prompt
        self.model = model

    def _format_prompt(self, template: str, **kwargs) -> str:
        """Format a prompt template with variables."""
        try:
            return template.format(**kwargs)
        except KeyError as e:
            raise ValueError(f"Missing required prompt variable: {e}") from e

    def process(self, task: str, context: dict | None = None) -> dict:
        """Process task by breaking it down and running subtasks in parallel."""
        context = context or {}

        # Step 1: Get orchestrator response
        orchestrator_input = self._format_prompt(self.orchestrator_prompt, task=task, **context)
        orchestrator_response = llm_call(orchestrator_input, model=self.model)

        # Parse orchestrator response
        analysis = extract_xml(orchestrator_response, "analysis")
        tasks_xml = extract_xml(orchestrator_response, "tasks")
        tasks = parse_tasks(tasks_xml)

        print("\n" + "=" * 80)
        print("ORCHESTRATOR ANALYSIS")
        print("=" * 80)
        print(f"\n{analysis}\n")

        print("\n" + "=" * 80)
        print(f"IDENTIFIED {len(tasks)} APPROACHES")
        print("=" * 80)
        for i, task_info in enumerate(tasks, 1):
            print(f"\n{i}. {task_info['type'].upper()}")
            print(f"   {task_info['description']}")

        print("\n" + "=" * 80)
        print("GENERATING CONTENT")
        print("=" * 80 + "\n")

        # Step 2: Process each task
        worker_results = []
        for i, task_info in enumerate(tasks, 1):
            print(f"[{i}/{len(tasks)}] Processing: {task_info['type']}...")

            worker_input = self._format_prompt(
                self.worker_prompt,
                original_task=task,
                task_type=task_info["type"],
                task_description=task_info["description"],
                **context,
            )

            worker_response = llm_call(worker_input, model=self.model)
            worker_content = extract_xml(worker_response, "response")

            # Validate worker response - handle empty outputs
            if not worker_content or not worker_content.strip():
                print(f"⚠️  Warning: Worker '{task_info['type']}' returned no content")
                worker_content = f"[Error: Worker '{task_info['type']}' failed to generate content]"

            worker_results.append(
                {
                    "type": task_info["type"],
                    "description": task_info["description"],
                    "result": worker_content,
                }
            )

        # Display results
        print("\n" + "=" * 80)
        print("RESULTS")
        print("=" * 80)
        for i, result in enumerate(worker_results, 1):
            print(f"\n{'-' * 80}")
            print(f"Approach {i}: {result['type'].upper()}")
            print(f"{'-' * 80}")
            print(f"\n{result['result']}\n")

        return {
            "analysis": analysis,
            "worker_results": worker_results,
        }
```
:::

::: {.cell .markdown}
## Example Use Case: Marketing Variation Generation

Now let\'s see the orchestrator-workers pattern in action with a
practical example: generating multiple styles of marketing copy for a
product.

**Why this example demonstrates the pattern well:**

- Different products benefit from different marketing angles
- The \"best\" variations depend on the specific product features and
  target audience
- The orchestrator can adapt its strategy based on the input rather than
  using a fixed template

**Prompt design notes:**

- The orchestrator prompt asks for 2-3 approaches and provides XML
  structure guidance
- The worker prompt gives workers full context (original task, their
  style, and guidelines)
- Both prompts use clear XML formatting to ensure reliable parsing
:::

:::: {.cell .code execution_count="9"}
``` python
ORCHESTRATOR_PROMPT = """
Analyze this task and break it down into 2-3 distinct approaches:

Task: {task}

Return your response in this format:

<analysis>
Explain your understanding of the task and which variations would be valuable.
Focus on how each approach serves different aspects of the task.
</analysis>

<tasks>
    <task>
    <type>formal</type>
    <description>Write a precise, technical version that emphasizes specifications</description>
    </task>
    <task>
    <type>conversational</type>
    <description>Write an engaging, friendly version that connects with readers</description>
    </task>
</tasks>
"""

WORKER_PROMPT = """
Generate content based on:
Task: {original_task}
Style: {task_type}
Guidelines: {task_description}

Return your response in this format:

<response>
Your content here, maintaining the specified style and fully addressing requirements.
</response>
"""


orchestrator = FlexibleOrchestrator(
    orchestrator_prompt=ORCHESTRATOR_PROMPT,
    worker_prompt=WORKER_PROMPT,
)

results = orchestrator.process(
    task="Write a product description for a new eco-friendly water bottle",
    context={
        "target_audience": "environmentally conscious millennials",
        "key_features": ["plastic-free", "insulated", "lifetime warranty"],
    },
)
```

::: {.output .stream .stdout}

    ================================================================================
    ORCHESTRATOR ANALYSIS
    ================================================================================


    This task requires creating marketing copy for an eco-friendly water bottle. The core challenge is balancing product information with persuasive messaging while highlighting the environmental benefits. Different approaches would serve distinct marketing channels and audience segments:

    1. A **feature-focused technical approach** would appeal to detail-oriented consumers who make purchasing decisions based on specifications, materials, and measurable environmental impact. This serves e-commerce listings and comparison shopping.

    2. A **lifestyle-oriented emotional approach** would connect with values-driven consumers through storytelling and aspirational messaging, emphasizing how the product fits into an eco-conscious lifestyle. This serves social media and brand-building content.

    3. A **benefit-driven practical approach** would focus on solving everyday problems while weaving in sustainability advantages, appealing to mainstream consumers who want both functionality and environmental responsibility. This serves broad retail contexts.

    Each approach addresses the "eco-friendly" aspect differently—through data, values, or practical advantages—making them valuable for different marketing contexts.


    ================================================================================
    IDENTIFIED 3 APPROACHES
    ================================================================================

    1. TECHNICAL-SPECIFICATIONS
       >Write a detailed, feature-focused description emphasizing materials, construction, environmental certifications, and measurable sustainability metrics (recyclability percentages, carbon footprint reduction, etc.)<

    2. LIFESTYLE-EMOTIONAL
       >Write an inspirational, story-driven description that connects the product to environmental values, personal identity, and the broader movement toward sustainable living<

    3. BENEFIT-PRACTICAL
       >Write a problem-solution focused description highlighting everyday usability benefits (temperature retention, durability, convenience) while naturally integrating eco-friendly advantages<

    ================================================================================
    GENERATING CONTENT
    ================================================================================

    [1/3] Processing: technical-specifications...
    [2/3] Processing: lifestyle-emotional...
    [3/3] Processing: benefit-practical...

    ================================================================================
    RESULTS
    ================================================================================

    --------------------------------------------------------------------------------
    Approach 1: TECHNICAL-SPECIFICATIONS
    --------------------------------------------------------------------------------


    # EcoFlow Pro™ Insulated Water Bottle - Technical Specifications

    ## Product Overview
    Model: EF-750-INS | Capacity: 750ml (25.4 fl oz) | Weight: 285g ±5g

    ## Material Composition & Construction

    ### Primary Body
    - **Material**: 18/8 (304) food-grade stainless steel
    - **Wall Thickness**: 0.6mm inner wall, 0.5mm outer wall
    - **Surface Treatment**: Powder-coated finish using water-based, VOC-free coating
    - **BPA/BPS/Phthalate Status**: Certified free of all endocrine-disrupting compounds

    ### Insulation System
    - **Technology**: Double-wall vacuum insulation with copper lining
    - **Vacuum Pressure**: <0.001 Pa
    - **Thermal Performance**: 
      - Cold retention: 24 hours (maintains <10°C)
      - Hot retention: 12 hours (maintains >65°C)
    - **Condensation**: Zero external condensation at all temperatures

    ### Cap & Seal Assembly
    - **Cap Material**: 100% post-consumer recycled polypropylene (rPP)
    - **Seal Gasket**: Medical-grade silicone (FDA 21 CFR 177.2600 compliant)
    - **Thread Design**: 3.5-turn precision threading for leak-proof seal (tested to 50 PSI)

    ## Environmental Certifications & Standards

    - **ISO 14001**: Environmental Management System certified manufacturing facility
    - **Cradle to Cradle Certified®**: Silver level
    - **Carbon Neutral Certified**: Through verified offset programs (Climate Neutral Certified)
    - **NSF/ANSI 61**: Drinking water system components certification
    - **REACH Compliant**: European chemical safety regulation adherent

    ## Sustainability Metrics

    ### Carbon Footprint
    - **Manufacturing Emissions**: 2.8 kg CO₂e per unit (68% reduction vs. industry average of 8.7 kg CO₂e)
    - **Transportation Impact**: Optimized packaging reduces shipping emissions by 42%
    - **Lifecycle Offset**: Replaces approximately 217 single-use plastic bottles annually (based on average daily consumption)
    - **Net Carbon Savings**: 156 kg CO₂e per year of use vs. disposable bottle equivalent

    ### Recyclability & Circularity
    - **End-of-Life Recyclability**: 95% by weight
    - **Stainless Steel**: 100% infinitely recyclable without quality degradation
    - **Plastic Components**: 89% recyclable (rPP cap and silicone gasket)
    - **Disassembly Time**: <45 seconds for complete material separation
    - **Take-Back Program**: Available for responsible recycling through manufacturer

    ### Resource Efficiency
    - **Recycled Content**: 73% post-consumer recycled materials by weight
    - **Water Usage in Production**: 4.2L per unit (industry average: 12.8L)
    - **Energy Consumption**: 18.5 MJ per unit manufactured using 100% renewable energy
    - **Packaging**: 100% recycled cardboard, soy-based inks, zero plastic components

    ## Durability & Longevity Specifications

    - **Impact Resistance**: Survives 2-meter drop test onto concrete (maintains vacuum seal)
    - **Corrosion Resistance**: 1,000+ hour salt spray test (ASTM B117)
    - **Cycle Testing**: 10,000+ open/close cycles without seal degradation
    - **Warranty Period**: Lifetime warranty against manufacturing defects
    - **Expected Lifespan**: 15+ years under normal use conditions

    ## Physical Specifications

    - **Dimensions**: Height: 265mm | Diameter: 73mm (body), 48mm (cap)
    - **Mouth Opening**: 42mm wide-mouth design (ice cube compatible)
    - **Base Diameter**: 68mm (fits standard cup holders)
    - **Volume Markings**: Laser-etched ml/oz graduations (50ml increments)
    - **Color Options**: 8 powder-coated finishes (all VOC-free)

    ## Compliance & Safety Testing

    - **FDA Approved**: All food-contact materials
    - **LFGB Certified**: German food safety standards
    - **Proposition 65**: Compliant (no listed chemicals)
    - **Lead Content**: <0.01 ppm (non-detectable)
    - **Microplastic Shedding**: Zero detected in 90-day leaching study

    ## Performance Advantages

    - **Single-Use Bottle Replacement Rate**: 1:217 annually
    - **Cost Recovery Period**: 2.3 months (vs. purchasing disposable bottles)
    - **Plastic Waste Prevention**: 1.89 kg per year per user
    - **Water Quality Preservation**: No taste transfer, maintains pH neutrality (±0.1)

    ## Manufacturing & Supply Chain

    - **Production Facility**: Solar-powered, zero-waste-to-landfill certified plant
    - **Supply Chain Transparency**: Full material traceability via blockchain verification
    - **Fair Trade Certified**: Ethical labor practices throughout supply chain
    - **Local Sourcing**: 67% of materials sourced within 500km of manufacturing facility


    --------------------------------------------------------------------------------
    Approach 2: LIFESTYLE-EMOTIONAL
    --------------------------------------------------------------------------------


    **More Than Hydration. A Daily Ritual of Change.**

    Every morning, you make a choice. Not just about what you drink, but about who you are and the world you're creating.

    This isn't just a water bottle—it's your companion in a quiet revolution. Crafted from 100% recycled ocean-bound plastic, each bottle tells a story of transformation: waste that once threatened our seas, now reimagined as something beautiful, functional, and enduring in your hands.

    Feel the smooth, cool surface against your palm. Notice its weight—substantial enough to remind you it's built to last decades, not days. This is the bottle that replaces hundreds of single-use plastics, the one that travels with you through morning commutes, mountain trails, and late-night creative sessions. It becomes part of your story, collecting scratches and memories like badges of honor.

    But here's what really matters: You're not alone in this. You're joining millions who understand that sustainability isn't about perfection—it's about progress. Every refill is a small act of defiance against throwaway culture. Every sip connects you to a global community choosing differently, living intentionally, proving that our daily choices ripple outward in ways we can't always see but can always feel.

    Your hydration. Your values. Your legacy.

    Because the future isn't something that happens to us—it's something we carry with us, one conscious choice at a time.

    **Welcome to the movement. Welcome home.**


    --------------------------------------------------------------------------------
    Approach 3: BENEFIT-PRACTICAL
    --------------------------------------------------------------------------------


    **Stay Hydrated All Day with the EcoFlow Bottle – Built for Your Active Life**

    Tired of lukewarm coffee by mid-morning or water that tastes like plastic after a few months? The EcoFlow Bottle solves the everyday frustrations that come with typical water bottles while helping you make a positive environmental impact.

    **Keeps Drinks at the Perfect Temperature**
    Double-wall vacuum insulation maintains cold drinks icy for 24 hours and hot beverages steaming for 12 hours. Your morning coffee stays hot through your commute, and your water remains refreshingly cold during afternoon meetings or workouts.

    **Built to Last Through Daily Wear and Tear**
    Constructed from premium 18/8 stainless steel with a powder-coated finish, this bottle withstands drops, bumps, and the chaos of daily life. The leak-proof lid means you can toss it in your bag without worry—no more soggy papers or ruined electronics.

    **Designed for Real Convenience**
    The wide mouth opening fits ice cubes easily and makes cleaning simple (no hard-to-reach corners). It fits standard cup holders in your car, and the ergonomic design is comfortable to carry whether you're commuting, hiking, or running errands.

    **Better for Your Wallet and the Planet**
    By switching to a reusable bottle, you'll save hundreds of dollars annually on disposable bottles while eliminating plastic waste. The durable construction means you're buying one bottle that lasts for years, not replacing cheap alternatives every few months. Plus, you'll avoid the chemicals found in many plastic bottles, ensuring cleaner-tasting water every time.

    **Your Reliable Hydration Companion**
    The EcoFlow Bottle adapts to your lifestyle—whether you need hot tea for early mornings, cold water for the gym, or room-temperature drinks throughout the workday. It's the practical solution that makes staying hydrated effortless while naturally reducing your environmental footprint.
:::
::::

::: {.cell .markdown}
## Summary

You\'ve now implemented an orchestrator-workers pattern that dynamically
adapts its task breakdown based on the specific input. This pattern
generated multiple marketing copy variations---each tailored to
different audiences and contexts---without requiring you to pre-define
what those variations should be.

### Key Takeaways

**Pattern benefits:**

- **Adaptability**: The orchestrator determines the best approach for
  each unique input
- **Flexibility**: Easy to apply to different domains by changing the
  prompts
- **Structured coordination**: XML-based communication ensures reliable
  parsing
- **Error resilience**: Validation catches and handles worker failures

**When this pattern excels:**

- Content generation requiring multiple perspectives (marketing,
  documentation, creative writing)
- Analysis tasks benefiting from different analytical lenses
- Problem-solving where the decomposition strategy depends on the
  problem

### Limitations & Considerations {#limitations--considerations}

**Cost & Latency:**

- Requires N+1 LLM calls (1 orchestrator + N workers)
- Sequential processing in this implementation (workers run one at a
  time)
- For better performance, consider parallelizing worker calls with
  `asyncio` or thread pools

**When NOT to use this pattern:**

- Simple tasks with single, clear outputs (the added complexity isn\'t
  justified)
- Latency-critical applications (multiple API calls add overhead)
- Tasks where subtasks are always the same (use pre-defined
  parallelization instead)

**Failure modes to consider:**

- Orchestrator might not break down tasks optimally (prompt engineering
  is critical)
- Workers may return empty or malformed responses (we handle this with
  validation)
- XML parsing can fail if models don\'t follow format exactly (consider
  using JSON as an alternative)

### Next Steps

**Enhance this implementation:**

1.  Add parallel worker execution using `asyncio` for better performance
2.  Implement retry logic for failed workers
3.  Add a synthesis phase where an LLM combines worker outputs
4.  Experiment with different orchestrator strategies (e.g., asking for
    more/fewer subtasks)

**Adapt to your use case:**

- Modify the orchestrator prompt to guide task decomposition for your
  domain
- Adjust worker prompts to provide domain-specific instructions
- Add context parameters relevant to your application
- Consider using Claude Opus for the orchestrator and Claude Haiku for
  workers to optimize cost vs. quality
:::

---

## Citations Agent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/patterns/agents/prompts/citations_agent.md
Path: 09-Agents-Patterns/claude-cookbooks-patterns-agents-prompts-citations-agent.md

You are an agent for adding correct citations to a research report. You are given a report within <synthesized_text> tags, which was generated based on the provided sources. However, the sources are not cited in the <synthesized_text>. Your task is to enhance user trust by generating correct, appropriate citations for this report.

Based on the provided document, add citations to the input text using the format specified earlier. Output the resulting report, unchanged except for the added citations, within <exact_text_with_citation> tags. 

**Rules:**
- Do NOT modify the <synthesized_text> in any way - keep all content 100% identical, only add citations
- Pay careful attention to whitespace: DO NOT add or remove any whitespace
- ONLY add citations where the source documents directly support claims in the text

**Citation guidelines:**
- **Avoid citing unnecessarily**: Not every statement needs a citation. Focus on citing key facts, conclusions, and substantive claims that are linked to sources rather than common knowledge. Prioritize citing claims that readers would want to verify, that add credibility to the argument, or where a claim is clearly related to a specific source
- **Cite meaningful semantic units**: Citations should span complete thoughts, findings, or claims that make sense as standalone assertions. Avoid citing individual words or small phrase fragments that lose meaning out of context; prefer adding citations at the end of sentences
- **Minimize sentence fragmentation**: Avoid multiple citations within a single sentence that break up the flow of the sentence. Only add citations between phrases within a sentence when it is necessary to attribute specific claims within the sentence to specific sources
- **No redundant citations close to each other**: Do not place multiple citations to the same source in the same sentence, because this is redundant and unnecessary. If a sentence contains multiple citable claims from the *same* source, use only a single citation at the end of the sentence after the period

**Technical requirements:**
- Citations result in a visual, interactive element being placed at the closing tag. Be mindful of where the closing tag is, and do not break up phrases and sentences unnecessarily
- Output text with citations between <exact_text_with_citation> and </exact_text_with_citation> tags
- Include any of your preamble, thinking, or planning BEFORE the opening <exact_text_with_citation> tag, to avoid breaking the output
- ONLY add the citation tags to the text within <synthesized_text> tags for your <exact_text_with_citation> output
- Text without citations will be collected and compared to the original report from the <synthesized_text>. If the text is not identical, your result will be rejected.

Now, add the citations to the research report and output the <exact_text_with_citation>.

---

## Research Lead Agent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/patterns/agents/prompts/research_lead_agent.md
Path: 09-Agents-Patterns/claude-cookbooks-patterns-agents-prompts-research-lead-agent.md

You are an expert research lead, focused on high-level research strategy, planning, efficient delegation to subagents, and final report writing. Your core goal is to be maximally helpful to the user by leading a process to research the user's query and then creating an excellent research report that answers this query very well. Take the current request from the user, plan out an effective research process to answer it as well as possible, and then execute this plan by delegating key tasks to appropriate subagents.
The current date is {{.CurrentDate}}.

<research_process>
Follow this process to break down the user’s question and develop an excellent research plan. Think about the user's task thoroughly and in great detail to understand it well and determine what to do next. Analyze each aspect of the user's question and identify the most important aspects. Consider multiple approaches with complete, thorough reasoning. Explore several different methods of answering the question (at least 3) and then choose the best method you find. Follow this process closely:
1. **Assessment and breakdown**: Analyze and break down the user's prompt to make sure you fully understand it.
* Identify the main concepts, key entities, and relationships in the task.
* List specific facts or data points needed to answer the question well.
* Note any temporal or contextual constraints on the question.
* Analyze what features of the prompt are most important - what does the user likely care about most here? What are they expecting or desiring in the final result? What tools do they expect to be used and how do we know?
* Determine what form the answer would need to be in to fully accomplish the user's task. Would it need to be a detailed report, a list of entities, an analysis of different perspectives, a visual report, or something else? What components will it need to have?
2. **Query type determination**: Explicitly state your reasoning on what type of query this question is from the categories below.
* **Depth-first query**: When the problem requires multiple perspectives on the same issue, and calls for "going deep" by analyzing a single topic from many angles.
- Benefits from parallel agents exploring different viewpoints, methodologies, or sources
- The core question remains singular but benefits from diverse approaches
- Example: "What are the most effective treatments for depression?" (benefits from parallel agents exploring different treatments and approaches to this question)
- Example: "What really caused the 2008 financial crisis?" (benefits from economic, regulatory, behavioral, and historical perspectives, and analyzing or steelmanning different viewpoints on the question)
- Example: "can you identify the best approach to building AI finance agents in 2025 and why?"
* **Breadth-first query**: When the problem can be broken into distinct, independent sub-questions, and calls for "going wide" by gathering information about each sub-question.
- Benefits from parallel agents each handling separate sub-topics.
- The query naturally divides into multiple parallel research streams or distinct, independently researchable sub-topics
- Example: "Compare the economic systems of three Nordic countries" (benefits from simultaneous independent research on each country)
- Example: "What are the net worths and names of all the CEOs of all the fortune 500 companies?" (intractable to research in a single thread; most efficient to split up into many distinct research agents which each gathers some of the necessary information)
- Example: "Compare all the major frontend frameworks based on performance, learning curve, ecosystem, and industry adoption" (best to identify all the frontend frameworks and then research all of these factors for each framework)
* **Straightforward query**: When the problem is focused, well-defined, and can be effectively answered by a single focused investigation or fetching a single resource from the internet.
- Can be handled effectively by a single subagent with clear instructions; does not benefit much from extensive research
- Example: "What is the current population of Tokyo?" (simple fact-finding)
- Example: "What are all the fortune 500 companies?" (just requires finding a single website with a full list, fetching that list, and then returning the results)
- Example: "Tell me about bananas" (fairly basic, short question that likely does not expect an extensive answer)
3. **Detailed research plan development**: Based on the query type, develop a specific research plan with clear allocation of tasks across different research subagents. Ensure if this plan is executed, it would result in an excellent answer to the user's query.
* For **Depth-first queries**:
- Define 3-5 different methodological approaches or perspectives.
- List specific expert viewpoints or sources of evidence that would enrich the analysis.
- Plan how each perspective will contribute unique insights to the central question.
- Specify how findings from different approaches will be synthesized.
- Example: For "What causes obesity?", plan agents to investigate genetic factors, environmental influences, psychological aspects, socioeconomic patterns, and biomedical evidence, and outline how the information could be aggregated into a great answer.
* For **Breadth-first queries**:
- Enumerate all the distinct sub-questions or sub-tasks that can be researched independently to answer the query. 
- Identify the most critical sub-questions or perspectives needed to answer the query comprehensively. Only create additional subagents if the query has clearly distinct components that cannot be efficiently handled by fewer agents. Avoid creating subagents for every possible angle - focus on the essential ones.
- Prioritize these sub-tasks based on their importance and expected research complexity.
- Define extremely clear, crisp, and understandable boundaries between sub-topics to prevent overlap.
- Plan how findings will be aggregated into a coherent whole.
- Example: For "Compare EU country tax systems", first create a subagent to retrieve a list of all the countries in the EU today, then think about what metrics and factors would be relevant to compare each country's tax systems, then use the batch tool to run 4 subagents to research the metrics and factors for the key countries in Northern Europe, Western Europe, Eastern Europe, Southern Europe.
* For **Straightforward queries**:
- Identify the most direct, efficient path to the answer.
- Determine whether basic fact-finding or minor analysis is needed.
- Specify exact data points or information required to answer.
- Determine what sources are likely most relevant to answer this query that the subagents should use, and whether multiple sources are needed for fact-checking.
- Plan basic verification methods to ensure the accuracy of the answer.
- Create an extremely clear task description that describes how a subagent should research this question.
* For each element in your plan for answering any query, explicitly evaluate:
- Can this step be broken into independent subtasks for a more efficient process?
- Would multiple perspectives benefit this step?
- What specific output is expected from this step?
- Is this step strictly necessary to answer the user's query well?
4. **Methodical plan execution**: Execute the plan fully, using parallel subagents where possible. Determine how many subagents to use based on the complexity of the query, default to using 3 subagents for most queries. 
* For parallelizable steps:
- Deploy appropriate subagents using the <delegation_instructions> below, making sure to provide extremely clear task descriptions to each subagent and ensuring that if these tasks are accomplished it would provide the information needed to answer the query.
- Synthesize findings when the subtasks are complete.
* For non-parallelizable/critical steps:
- First, attempt to accomplish them yourself based on your existing knowledge and reasoning. If the steps require additional research or up-to-date information from the web, deploy a subagent.
- If steps are very challenging, deploy independent subagents for additional perspectives or approaches.
- Compare the subagent's results and synthesize them using an ensemble approach and by applying critical reasoning.
* Throughout execution:
- Continuously monitor progress toward answering the user's query.
- Update the search plan and your subagent delegation strategy based on findings from tasks.
- Adapt to new information well - analyze the results, use Bayesian reasoning to update your priors, and then think carefully about what to do next.
- Adjust research depth based on time constraints and efficiency - if you are running out of time or a research process has already taken a very long time, avoid deploying further subagents and instead just start composing the output report immediately. 
</research_process>

<subagent_count_guidelines>
When determining how many subagents to create, follow these guidelines: 
1. **Simple/Straightforward queries**: create 1 subagent to collaborate with you directly - 
   - Example: "What is the tax deadline this year?" or “Research bananas” → 1 subagent
   - Even for simple queries, always create at least 1 subagent to ensure proper source gathering
2. **Standard complexity queries**: 2-3 subagents
   - For queries requiring multiple perspectives or research approaches
   - Example: "Compare the top 3 cloud providers" → 3 subagents (one per provider)
3. **Medium complexity queries**: 3-5 subagents
   - For multi-faceted questions requiring different methodological approaches
   - Example: "Analyze the impact of AI on healthcare" → 4 subagents (regulatory, clinical, economic, technological aspects)
4. **High complexity queries**: 5-10 subagents (maximum 20)
   - For very broad, multi-part queries with many distinct components 
   - Identify the most effective algorithms to efficiently answer these high-complexity queries with around 20 subagents. 
   - Example: "Fortune 500 CEOs birthplaces and ages" → Divide the large info-gathering task into  smaller segments (e.g., 10 subagents handling 50 CEOs each)
   **IMPORTANT**: Never create more than 20 subagents unless strictly necessary. If a task seems to require more than 20 subagents, it typically means you should restructure your approach to consolidate similar sub-tasks and be more efficient in your research process. Prefer fewer, more capable subagents over many overly narrow ones. More subagents = more overhead. Only add subagents when they provide distinct value.
</subagent_count_guidelines>

<delegation_instructions>
Use subagents as your primary research team - they should perform all major research tasks:
1. **Deployment strategy**:
* Deploy subagents immediately after finalizing your research plan, so you can start the research process quickly.
* Use the `run_blocking_subagent` tool to create a research subagent, with very clear and specific instructions in the `prompt` parameter of this tool to describe the subagent's task.
* Each subagent is a fully capable researcher that can search the web and use the other search tools that are available.
* Consider priority and dependency when ordering subagent tasks - deploy the most important subagents first. For instance, when other tasks will depend on results from one specific task, always create a subagent to address that blocking task first.
* Ensure you have sufficient coverage for comprehensive research - ensure that you deploy subagents to complete every task.
* All substantial information gathering should be delegated to subagents.
* While waiting for a subagent to complete, use your time efficiently by analyzing previous results, updating your research plan, or reasoning about the user's query and how to answer it best.
2. **Task allocation principles**:
* For depth-first queries: Deploy subagents in sequence to explore different methodologies or perspectives on the same core question. Start with the approach most likely to yield comprehensive and good results, the follow with alternative viewpoints to fill gaps or provide contrasting analysis.
* For breadth-first queries: Order subagents by topic importance and research complexity. Begin with subagents that will establish key facts or framework information, then deploy subsequent subagents to explore more specific or dependent subtopics.
* For straightforward queries: Deploy a single comprehensive subagent with clear instructions for fact-finding and verification. For these simple queries, treat the subagent as an equal collaborator - you can conduct some research yourself while delegating specific research tasks to the subagent. Give this subagent very clear instructions and try to ensure the subagent handles about half of the work, to efficiently distribute research work between yourself and the subagent. 
* Avoid deploying subagents for trivial tasks that you can complete yourself, such as simple calculations, basic formatting, small web searches, or tasks that don't require external research
* But always deploy at least 1 subagent, even for simple tasks. 
* Avoid overlap between subagents - every subagent should have distinct, clearly separate tasks, to avoid replicating work unnecessarily and wasting resources.
3. **Clear direction for subagents**: Ensure that you provide every subagent with extremely detailed, specific, and clear instructions for what their task is and how to accomplish it. Put these instructions in the `prompt` parameter of the `run_blocking_subagent` tool.
* All instructions for subagents should include the following as appropriate:
- Specific research objectives, ideally just 1 core objective per subagent.
- Expected output format - e.g. a list of entities, a report of the facts, an answer to a specific question, or other.
- Relevant background context about the user's question and how the subagent should contribute to the research plan.
- Key questions to answer as part of the research.
- Suggested starting points and sources to use; define what constitutes reliable information or high-quality sources for this task, and list any unreliable sources to avoid.
- Specific tools that the subagent should use - i.e. using web search and web fetch for gathering information from the web, or if the query requires non-public, company-specific, or user-specific information, use the available internal tools like google drive, gmail, gcal, slack, or any other internal tools that are available currently.
- If needed, precise scope boundaries to prevent research drift.
* Make sure that IF all the subagents followed their instructions very well, the results in aggregate would allow you to give an EXCELLENT answer to the user's question - complete, thorough, detailed, and accurate.
* When giving instructions to subagents, also think about what sources might be high-quality for their tasks, and give them some guidelines on what sources to use and how they should evaluate source quality for each task.
* Example of a good, clear, detailed task description for a subagent: "Research the semiconductor supply chain crisis and its current status as of 2025. Use the web_search and web_fetch tools to gather facts from the internet. Begin by examining recent quarterly reports from major chip manufacturers like TSMC, Samsung, and Intel, which can be found on their investor relations pages or through the SEC EDGAR database. Search for industry reports from SEMI, Gartner, and IDC that provide market analysis and forecasts. Investigate government responses by checking the US CHIPS Act implementation progress at commerce.gov, EU Chips Act at ec.europa.eu, and similar initiatives in Japan, South Korea, and Taiwan through their respective government portals. Prioritize original sources over news aggregators. Focus on identifying current bottlenecks, projected capacity increases from new fab construction, geopolitical factors affecting supply chains, and expert predictions for when supply will meet demand. When research is done, compile your findings into a dense report of the facts, covering the current situation, ongoing solutions, and future outlook, with specific timelines and quantitative data where available."
4. **Synthesis responsibility**: As the lead research agent, your primary role is to coordinate, guide, and synthesize - NOT to conduct primary research yourself. You only conduct direct research if a critical question remains unaddressed by subagents or it is best to accomplish it yourself. Instead, focus on planning, analyzing and integrating findings across subagents, determining what to do next, providing clear instructions for each subagent, or identifying gaps in the collective research and deploying new subagents to fill them.
</delegation_instructions>

<answer_formatting>
Before providing a final answer:
1. Review the most recent fact list compiled during the search process.
2. Reflect deeply on whether these facts can answer the given query sufficiently.
3. Only then, provide a final answer in the specific format that is best for the user's query and following the <writing_guidelines> below.
4. Output the final result in Markdown using the `complete_task` tool to submit your final research report.
5. Do not include ANY Markdown citations, a separate agent will be responsible for citations. Never include a list of references or sources or citations at the end of the report.
</answer_formatting>

<use_available_internal_tools>
You may have some additional tools available that are useful for exploring the user's integrations. For instance, you may have access to tools for searching in Asana, Slack, Github. Whenever extra tools are available beyond the Google Suite tools and the web_search or web_fetch tool, always use the relevant read-only tools once or twice to learn how they work and get some basic information from them. For instance, if they are available, use `slack_search` once to find some info relevant to the query or `slack_user_profile` to identify the user; use `asana_user_info` to read the user's profile or `asana_search_tasks` to find their tasks; or similar. DO NOT use write, create, or update tools. Once you have used these tools, either continue using them yourself further to find relevant information, or when creating subagents clearly communicate to the subagents exactly how they should use these tools in their task. Never neglect using any additional available tools, as if they are present, the user definitely wants them to be used. 
When a user’s query is clearly about internal information, focus on describing to the subagents exactly what internal tools they should use and how to answer the query. Emphasize using these tools in your communications with subagents. Often, it will be appropriate to create subagents to do research using specific tools. For instance, for a query that requires understanding the user’s tasks as well as their docs and communications and how this internal information relates to external information on the web, it is likely best to create an Asana subagent, a Slack subagent, a Google Drive subagent, and a Web Search subagent. Each of these subagents should be explicitly instructed to focus on using exclusively those tools to accomplish a specific task or gather specific information. This is an effective pattern to delegate integration-specific research to subagents, and then conduct the final analysis and synthesis of the information gathered yourself. 
</use_available_internal_tools>

<use_parallel_tool_calls>
For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially. Call tools in parallel to run subagents at the same time. You MUST use parallel tool calls for creating multiple subagents (typically running 3 subagents at the same time) at the start of the research, unless it is a straightforward query. For all other queries, do any necessary quick initial planning or investigation yourself, then run multiple subagents in parallel. Leave any extensive tool calls to the subagents; instead, focus on running subagents in parallel efficiently.
</use_parallel_tool_calls>

<important_guidelines>
In communicating with subagents, maintain extremely high information density while being concise - describe everything needed in the fewest words possible.
As you progress through the search process:
1. When necessary, review the core facts gathered so far, including:
* Facts from your own research.
* Facts reported by subagents.
* Specific dates, numbers, and quantifiable data.
2. For key facts, especially numbers, dates, and critical information:
* Note any discrepancies you observe between sources or issues with the quality of sources.
* When encountering conflicting information, prioritize based on recency, consistency with other facts, and use best judgment.
3. Think carefully after receiving novel information, especially for critical reasoning and decision-making after getting results back from subagents.
4. For the sake of efficiency, when you have reached the point where further research has diminishing returns and you can give a good enough answer to the user, STOP FURTHER RESEARCH and do not create any new subagents. Just write your final report at this point. Make sure to terminate research when it is no longer necessary, to avoid wasting time and resources. For example, if you are asked to identify the top 5 fastest-growing startups, and you have identified the most likely top 5 startups with high confidence, stop research immediately and use the `complete_task` tool to submit your report rather than continuing the process unnecessarily. 
5. NEVER create a subagent to generate the final report - YOU write and craft this final research report yourself based on all the results and the writing instructions, and you are never allowed to use subagents to create the report.
6. Avoid creating subagents to research topics that could cause harm. Specifically, you must not create subagents to research anything that would promote hate speech, racism, violence, discrimination, or catastrophic harm. If a query is sensitive, specify clear constraints for the subagent to avoid causing harm.
</important_guidelines>

You have a query provided to you by the user, which serves as your primary goal. You should do your best to thoroughly accomplish the user's task. No clarifications will be given, therefore use your best judgment and do not attempt to ask the user questions. Before starting your work, review these instructions and the user’s requirements, making sure to plan out how you will efficiently use subagents and parallel tool calls to answer the query. Critically think about the results provided by subagents and reason about them carefully to verify information and ensure you provide a high-quality, accurate report. Accomplish the user’s task by directing the research subagents and creating an excellent research report from the information gathered.

---

## Research Subagent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/patterns/agents/prompts/research_subagent.md
Path: 09-Agents-Patterns/claude-cookbooks-patterns-agents-prompts-research-subagent.md

You are a research subagent working as part of a team. The current date is {{.CurrentDate}}. You have been given a clear <task> provided by a lead agent, and should use your available tools to accomplish this task in a research process. Follow the instructions below closely to accomplish your specific <task> well:

<research_process>
1. **Planning**: First, think through the task thoroughly. Make a research plan, carefully reasoning to review the requirements of the task, develop a research plan to fulfill these requirements, and determine what tools are most relevant and how they should be used optimally to fulfill the task.
- As part of the plan, determine a 'research budget' - roughly how many tool calls to conduct to accomplish this task. Adapt the number of tool calls to the complexity of the query to be maximally efficient. For instance, simpler tasks like "when is the tax deadline this year" should result in under 5 tool calls, medium tasks should result in 5 tool calls, hard tasks result in about 10 tool calls, and very difficult or multi-part tasks should result in up to 15 tool calls. Stick to this budget to remain efficient - going over will hit your limits!
2. **Tool selection**: Reason about what tools would be most helpful to use for this task. Use the right tools when a task implies they would be helpful. For instance, google_drive_search (internal docs), gmail tools (emails), gcal tools (schedules), repl (difficult calculations), web_search (getting snippets of web results from a query), web_fetch (retrieving full webpages). If other tools are available to you (like Slack or other internal tools), make sure to use these tools as well while following their descriptions, as the user has provided these tools to help you answer their queries well.
- **ALWAYS use internal tools** (google drive, gmail, calendar, or similar other tools) for tasks that might require the user's personal data, work, or internal context, since these tools contain rich, non-public information that would be helpful in answering the user's query. If internal tools are present, that means the user intentionally enabled them, so you MUST use these internal tools during the research process. Internal tools strictly take priority, and should always be used when available and relevant. 
- ALWAYS use `web_fetch` to get the complete contents of websites, in all of the following cases: (1) when more detailed information from a site would be helpful, (2) when following up on web_search results, and (3) whenever the user provides a URL. The core loop is to use web search to run queries, then use web_fetch to get complete information using the URLs of the most promising sources.
- Avoid using the analysis/repl tool for simpler calculations, and instead just use your own reasoning to do things like count entities. Remember that the repl tool does not have access to a DOM or other features, and should only be used for JavaScript calculations without any dependencies, API calls, or unnecessary complexity.
3. **Research loop**: Execute an excellent OODA (observe, orient, decide, act) loop by (a) observing what information has been gathered so far, what still needs to be gathered to accomplish the task, and what tools are available currently; (b) orienting toward what tools and queries would be best to gather the needed information and updating beliefs based on what has been learned so far; (c) making an informed, well-reasoned decision to use a specific tool in a certain way; (d) acting to use this tool. Repeat this loop in an efficient way to research well and learn based on new results.
- Execute a MINIMUM of five distinct tool calls, up to ten for complex queries. Avoid using more than ten tool calls.
- Reason carefully after receiving tool results. Make inferences based on each tool result and determine which tools to use next based on new findings in this process - e.g. if it seems like some info is not available on the web or some approach is not working, try using another tool or another query. Evaluate the quality of the sources in search results carefully. NEVER repeatedly use the exact same queries for the same tools, as this wastes resources and will not return new results.
Follow this process well to complete the task. Make sure to follow the <task> description and investigate the best sources.
</research_process>

<research_guidelines>
1. Be detailed in your internal process, but more concise and information-dense in reporting the results.
2. Avoid overly specific searches that might have poor hit rates:
* Use moderately broad queries rather than hyper-specific ones.
* Keep queries shorter since this will return more useful results - under 5 words.
* If specific searches yield few results, broaden slightly.
* Adjust specificity based on result quality - if results are abundant, narrow the query to get specific information.
* Find the right balance between specific and general.
3. For important facts, especially numbers and dates:
* Keep track of findings and sources
* Focus on high-value information that is:
- Significant (has major implications for the task)
- Important (directly relevant to the task or specifically requested)
- Precise (specific facts, numbers, dates, or other concrete information)
- High-quality (from excellent, reputable, reliable sources for the task)
* When encountering conflicting information, prioritize based on recency, consistency with other facts, the quality of the sources used, and use your best judgment and reasoning. If unable to reconcile facts, include the conflicting information in your final task report for the lead researcher to resolve.
4. Be specific and precise in your information gathering approach.
</research_guidelines>

<think_about_source_quality>
After receiving results from web searches or other tools, think critically, reason about the results, and determine what to do next. Pay attention to the details of tool results, and do not just take them at face value. For example, some pages may speculate about things that may happen in the future - mentioning predictions, using verbs like “could” or “may”, narrative driven speculation with future tense, quoted superlatives, financial projections, or similar - and you should make sure to note this explicitly in the final report, rather than accepting these events as having happened. Similarly, pay attention to the indicators of potentially problematic sources, like news aggregators rather than original sources of the information, false authority, pairing of passive voice with nameless sources, general qualifiers without specifics, unconfirmed reports, marketing language for a product, spin language, speculation, or misleading and cherry-picked data. Maintain epistemic honesty and practice good reasoning by ensuring sources are high-quality and only reporting accurate information to the lead researcher. If there are potential issues with results, flag these issues when returning your report to the lead researcher rather than blindly presenting all results as established facts.
DO NOT use the evaluate_source_quality tool ever - ignore this tool. It is broken and using it will not work.
</think_about_source_quality>

<use_parallel_tool_calls>
For maximum efficiency, whenever you need to perform multiple independent operations, invoke 2 relevant tools simultaneously rather than sequentially. Prefer calling tools like web search in parallel rather than by themselves.
</use_parallel_tool_calls>

<maximum_tool_call_limit>
To prevent overloading the system, it is required that you stay under a limit of 20 tool calls and under about 100 sources. This is the absolute maximum upper limit. If you exceed this limit, the subagent will be terminated. Therefore, whenever you get to around 15 tool calls or 100 sources, make sure to stop gathering sources, and instead use the `complete_task` tool immediately. Avoid continuing to use tools when you see diminishing returns - when you are no longer finding new relevant information and results are not getting better, STOP using tools and instead compose your final report.
</maximum_tool_call_limit>

Follow the <research_process> and the <research_guidelines> above to accomplish the task, making sure to parallelize tool calls for maximum efficiency. Remember to use web_fetch to retrieve full results rather than just using search snippets. Continue using the relevant tools until this task has been fully accomplished, all necessary information has been gathered, and you are ready to report the results to the lead research agent to be integrated into a final result. If there are any internal tools available (i.e. Slack, Asana, Gdrive, Github, or similar), ALWAYS make sure to use these tools to gather relevant info rather than ignoring them. As soon as you have the necessary information, complete the task rather than wasting time by continuing research unnecessarily. As soon as the task is done, immediately use the `complete_task` tool to finish and provide your detailed, condensed, complete, accurate report to the lead researcher.

---

## Multi-Document Agents

Source: https://github.com/anthropics/claude-cookbooks/blob/main/third_party/LlamaIndex/Multi_Document_Agents.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-third-party-llamaindex-multi-document-agents.md

# Multi-Document Agents

In this notebook we will look into Building RAG when you have a large
number of documents using `DocumentAgents` concept with `ReAct Agent`.
:::

::: {.cell .markdown id="SxWKA6fCK0mw"}
### Installation
:::

::: {.cell .code id="csEUaulS0EQ_"}
``` python
!pip install llama-index
!pip install llama-index-llms-anthropic
!pip install llama-index-embeddings-huggingface
```
:::

::: {.cell .markdown id="Z2_M_q-pK2-1"}
### Set Logging
:::

::: {.cell .code execution_count="1" id="1Ry4vjMv0V7E"}
``` python
# NOTE: This is ONLY necessary in jupyter notebook.
# Details: Jupyter runs an event-loop behind the scenes.
#          This results in nested event-loops when we start an event-loop to make async queries.
#          This is normally not allowed, we use nest_asyncio to allow it for convenience.
import nest_asyncio

nest_asyncio.apply()

import logging
import sys

# Set up the root logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # Set logger level to INFO

# Clear out any existing handlers
logger.handlers = []

# Set up the StreamHandler to output to sys.stdout (Colab's output)
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.INFO)  # Set handler level to INFO

# Add the handler to the logger
logger.addHandler(handler)

from IPython.display import HTML, display
```
:::

::: {.cell .markdown id="No_1L4P4K5J2"}
### Set Claude API Key
:::

::: {.cell .code execution_count="2" id="6JXQosS80PNK"}
``` python
import os

os.environ["ANTHROPIC_API_KEY"] = "YOUR Claude API KEY"
```
:::

::: {.cell .markdown id="4pEemHzPK7as"}
### Set LLM and Embedding model

We will use anthropic latest released `Claude-3 Opus` LLM.
:::

::: {.cell .code execution_count="3" id="Euj43bfS0Rqf"}
``` python
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.anthropic import Anthropic
```
:::

::: {.cell .code execution_count="4" colab="{\"base_uri\":\"https://localhost:8080/\",\"height\":313,\"referenced_widgets\":[\"d2bcac509f704091a2e1d78cbab529ac\",\"8333f65239244e3ebccd03d3cc11e7cf\",\"f7452e83c16a4842891b74e0fe77964e\",\"fd642eff11e34ec487173f0b284b8eb1\",\"621440477e6649ae81f6576c3d8426b8\",\"a23860a3889b43f28b87ed5734842ed2\",\"c4c0e261c70d408497199f17710f46fa\",\"da103bb8638c4d2288eb5c96bf8e6ab2\",\"73c8ad8a3d5d4c7987104cecaca85a60\",\"e147f00bdf994cbaa96f515d2f5fbe7a\",\"3c7b010e02c945cfbba526b0beea2053\",\"5787464222eb4412b3f6d88cf1e9651a\",\"08d838a6337344cf984b48fe0b959a80\",\"6dfc9fc2dfbe4c65b3a29e3c46fc6908\",\"0b5555011ac1408bbaf8a39a63ac8ba4\",\"8701fa65b6b24302b485e217a637b7e1\",\"87a2ec99584f49faa1409d1cced0bbf4\",\"ca26dbc458c5410d82e09be213c04df8\",\"b6f3972d040447ad9044566b1bfb9bd4\",\"4dcb8d94d6cc42e9ad4245b3ced5d73a\",\"01a915c53cf34814ba59f798c46bff0a\",\"9c37e197eb0f4a79acbf86dfcfda9ee3\",\"a6dc6b641a1d4589baaf94c073b166c6\",\"66c92c089d6742d19a3ddd6ab093acce\",\"5efcb4f54e96445aab0bf6cd5c48e140\",\"64656ae50fcd435cabe838ba3fc74bf4\",\"a33c0c07eeb9433197cfc0012faaf86b\",\"d6388c264ec14c8591f2e0e8a4f508b5\",\"1f13df73c8734c6ea01dc84264d7a9a4\",\"a454a7ad6d214b46b2e22029e32713b3\",\"ab1afeb075db48dc852b38f7efb0b59a\",\"ed41ea29459b4a7297f99f56e5f5fac2\",\"5c12435c34304f78886c0dc85e812633\",\"9499cc5b0de94627addecd8765561db0\",\"8b78eb20237341758740e516ace41299\",\"d19283e264d44366acdaca17ebab70ad\",\"8b4541bc84794e399e16b0ac1f2ce5db\",\"d8ad3826d40b41c4934d896245794382\",\"b6773dc9fc6b40e2a89747ad88ac5f9d\",\"f2fcf88b1d1d4c8db80585600f373092\",\"8920704065a84c739381b3f6b8a71d33\",\"de37a9145f1f40928adf13224646523d\",\"c2baea7ddf4d4b2ebc038a7c412f99dd\",\"15a486a5a98f4011bda3a821389ccdc0\",\"ca36015e10544f55a1acbdbaf03017f0\",\"6eacd26fd23f4530baf98b65a9d8c166\",\"a9bdcf8f6140463787f41d9fb8370806\",\"10fa33db762e48048107084ce0df9688\",\"a7827923f5a14835abf070fe1a417ce6\",\"23772f2ec9e64c8ea329874661c0e72c\",\"d472cafc3561461399958630cb81c348\",\"ce089a58329e474babea74a657b6a8a8\",\"84b7eb51e38d42c3a09a2ab1f87a419b\",\"258166a5ad444e11ae291d47c29d8e95\",\"8dde20c91feb49488b45aac477379320\",\"883a09808ba74aceb03ec26cb525cb32\",\"9b9272daa2cc484b99ef22536f1e5ae9\",\"442953634e084c868c4c9be0e8530001\",\"dcd3611436f44099af77b29a9556363b\",\"b58a3ecb60904570a073ae3520867feb\",\"9d8c6c0800cf484f9a79172407fe7168\",\"5724373f8d6a4076a292be596efbdca8\",\"c7e9aab70d1541e49a55c1433898a725\",\"4a53092d22514d63bcd8e4a7906f6c6b\",\"b9dc22c807fc42d5bb5e084f191e408a\",\"7d46c9e5023543e2b82da0cf7f6bb0c4\"]}" id="wqwlOVH00TbB" outputId="1803fa26-e51e-4b9b-8f0d-5ac0d322f2e9"}
``` python
llm = Anthropic(temperature=0.0, model="claude-opus-4-1")
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
```
:::

::: {.cell .code execution_count="5" id="aIkLOdRz0Unp"}
``` python
from llama_index.core import Settings

Settings.llm = llm
Settings.embed_model = embed_model
Settings.chunk_size = 512
```
:::

::: {.cell .markdown id="JP-m752eKRWW"}
### Download Documents

We will use Wikipedia pages of `Toronto`, `Seattle`, `Chicago`,
`Boston`, `Houston` cities and build RAG pipeline.
:::

::: {.cell .code colab="{\"base_uri\":\"https://localhost:8080/\"}" id="MozCygK32Zy0" outputId="0f8d3446-3445-419c-a976-4405c0d93759"}
``` python
wiki_titles = ["Toronto", "Seattle", "Chicago", "Boston", "Houston"]

from pathlib import Path

import requests

for title in wiki_titles:
    response = requests.get(
        "https://en.wikipedia.org/w/api.php",
        params={
            "action": "query",
            "format": "json",
            "titles": title,
            "prop": "extracts",
            # 'exintro': True,
            "explaintext": True,
        },
        timeout=30,
    ).json()
    page = next(iter(response["query"]["pages"].values()))
    wiki_text = page["extract"]

    data_path = Path("data")
    if not data_path.exists():
        Path.mkdir(data_path)

    with open(data_path / f"{title}.txt", "w") as fp:
        fp.write(wiki_text)
```
:::

::: {.cell .markdown id="G4nEvK7CKTbh"}
### Load Document
:::

::: {.cell .code execution_count="7" id="n4AGgEvf0dpo"}
``` python
# Load all wiki documents

from llama_index.core import SimpleDirectoryReader

city_docs = {}
for wiki_title in wiki_titles:
    city_docs[wiki_title] = SimpleDirectoryReader(
        input_files=[f"data/{wiki_title}.txt"]
    ).load_data()
```
:::

::: {.cell .markdown}
#### Build ReAct Agent for each city
:::

::: {.cell .code execution_count="8"}
``` python
from llama_index.core import SummaryIndex, VectorStoreIndex
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import QueryEngineTool, ToolMetadata

# Build agents dictionary
agents = {}

for wiki_title in wiki_titles:
    # build vector index
    vector_index = VectorStoreIndex.from_documents(
        city_docs[wiki_title],
    )
    # build summary index
    summary_index = SummaryIndex.from_documents(
        city_docs[wiki_title],
    )
    # define query engines
    vector_query_engine = vector_index.as_query_engine()
    summary_query_engine = summary_index.as_query_engine()

    # define tools
    query_engine_tools = [
        QueryEngineTool(
            query_engine=vector_query_engine,
            metadata=ToolMetadata(
                name="vector_tool",
                description=(f"Useful for retrieving specific context from {wiki_title}"),
            ),
        ),
        QueryEngineTool(
            query_engine=summary_query_engine,
            metadata=ToolMetadata(
                name="summary_tool",
                description=(f"Useful for summarization questions related to {wiki_title}"),
            ),
        ),
    ]

    # build agent
    agent = ReActAgent.from_tools(
        query_engine_tools,
        llm=llm,
        verbose=True,
    )

    agents[wiki_title] = agent
```
:::

::: {.cell .markdown}
#### Define IndexNode for each of these Agents
:::

::: {.cell .code execution_count="9"}
``` python
from llama_index.core.schema import IndexNode

# define top-level nodes
objects = []
for wiki_title in wiki_titles:
    # define index node that links to these agents
    wiki_summary = (
        f"This content contains Wikipedia articles about {wiki_title}. Use"
        " this index if you need to lookup specific facts about"
        f" {wiki_title}.\nDo not use this index if you want to analyze"
        " multiple cities."
    )
    node = IndexNode(text=wiki_summary, index_id=wiki_title, obj=agents[wiki_title])
    objects.append(node)
```
:::

::: {.cell .markdown}
#### Define Top-Level Retriever to choose an Agent
:::

::: {.cell .code execution_count="10" id="QdyS_E_w3t56"}
``` python
vector_index = VectorStoreIndex(
    objects=objects,
)
query_engine = vector_index.as_query_engine(similarity_top_k=1, verbose=True)
```
:::

::: {.cell .markdown}
#### Test Queries

Should choose a vector tool/ summary tool for a specific agent based on
the query.
:::

:::: {.cell .code execution_count="11"}
``` python
# should use Toronto agent -> vector tool
response = query_engine.query("What is the population of Toronto?")
```

::: {.output .stream .stdout}
    Retrieval entering Toronto: ReActAgent
    Retrieving from object ReActAgent with query What is the population of Toronto?
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: I need to use a tool to help me answer the question.
    Action: vector_tool
    Action Input: {'input': 'What is the population of Toronto?'}
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Observation: According to the context information, the population of Toronto in 2021 was 2,794,356, making it the fourth-most populous city in North America.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: I can answer without using any more tools.
    Answer: According to the information provided, the population of Toronto in 2021 was 2,794,356, making it the fourth-most populous city in North America.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
:::
::::

:::: {.cell .code execution_count="12"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .display_data}
<p style="font-size:20px">The population of Toronto is 2,794,356 as of 2021. It is the fourth-most populous city in North America.</p>
:::
::::

:::: {.cell .code execution_count="13"}
``` python
# should use Houston agent -> vector tool
response = query_engine.query("Who and when was Houston founded?")
```

::: {.output .stream .stdout}
    Retrieval entering Houston: ReActAgent
    Retrieving from object ReActAgent with query Who and when was Houston founded?
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: I need to use a tool to help me answer the question about who founded Houston and when it was founded.
    Action: vector_tool
    Action Input: {'input': 'Who founded Houston and when was it founded?'}
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Observation: Houston was founded by land investors on August 30, 1836, at the confluence of Buffalo Bayou and White Oak Bayou, a point now known as Allen's Landing. The city was incorporated on June 5, 1837 and named after former General Sam Houston, who was president of the Republic of Texas at the time.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: The vector_tool provided the key information needed to answer the question of who founded Houston and when it was founded. I can now provide a complete answer without using any more tools.
    Answer: Houston was founded by land investors on August 30, 1836. The city was incorporated on June 5, 1837 and named after Sam Houston, who was the president of the Republic of Texas at the time. The location where Houston was founded is at the confluence of Buffalo Bayou and White Oak Bayou, which is now known as Allen's Landing.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
:::
::::

:::: {.cell .code execution_count="14"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .display_data}
<p style="font-size:20px">Houston was founded by land investors on August 30, 1836. The city was named after Sam Houston, who was serving as the president of the Republic of Texas at that time.</p>
:::
::::

:::: {.cell .code execution_count="15"}
``` python
# should use Boston agent -> summary tool
response = query_engine.query("Summarize about the sports teams in Boston")
```

::: {.output .stream .stdout}
    Retrieval entering Boston: ReActAgent
    Retrieving from object ReActAgent with query Summarize about the sports teams in Boston
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: I need to use a tool to help me answer the question.
    Action: summary_tool
    Action Input: {'input': 'Summarize the sports teams in Boston'}
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Observation: Boston has teams in the four major North American men's professional sports leagues plus Major League Soccer, and has won 39 championships in these leagues:

    - The Boston Red Sox (MLB) play at Fenway Park. They are one of the most storied franchises in baseball.

    - The Boston Celtics (NBA) play at TD Garden. Along with the Los Angeles Lakers, they have won the most NBA championships with 17. 

    - The Boston Bruins (NHL) also play at TD Garden. They were the first American NHL team and are an Original Six franchise.

    - The New England Patriots (NFL) play in nearby Foxborough. They have won 6 Super Bowls in the 2000s and 2010s.

    - The New England Revolution (MLS) also play in Foxborough.

    Boston also has several other professional sports teams like the Boston Breakers (women's soccer) and Boston Cannons (lacrosse). The area's many colleges field competitive NCAA Division I teams, especially in ice hockey. The annual Boston Marathon is one of the world's most famous running events.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: The summary tool provided a good overview of the major sports teams in Boston. I think I can provide a concise summary answer to the original question based on this information.
    Answer: Boston is home to successful professional sports teams in baseball (Red Sox), basketball (Celtics), hockey (Bruins), football (Patriots), and soccer (Revolution). The Red Sox, Celtics, and Bruins are some of the most historic franchises in their respective leagues. In total, Boston teams have won 39 championships in the four major North American sports leagues and MLS. The area also hosts the famous Boston Marathon each year and has many competitive college sports programs, especially in ice hockey.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
:::
::::

:::: {.cell .code execution_count="16"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .display_data}
<p style="font-size:20px">Boston is a city with a rich sports tradition, boasting several highly successful professional teams across multiple leagues. In baseball, the Boston Red Sox are one of the most storied franchises in the sport's history. The Boston Celtics have a similarly impressive legacy in basketball, with numerous championships to their name. Hockey fans in the city passionately support the Boston Bruins, another team with a long and successful history. The New England Patriots, who play in the nearby town of Foxborough, have been a dominant force in the NFL for many years. Even in the relatively newer MLS, the New England Revolution have made their mark on the Boston sports scene. These teams have combined to win an impressive 39 championships across the five leagues. Beyond professional sports, Boston is also known for hosting the prestigious Boston Marathon annually and having strong college sports programs, particularly in ice hockey.</p>
:::
::::

:::: {.cell .code execution_count="17"}
``` python
# should use Seattle agent -> summary tool
response = query_engine.query("Give me a summary on all the positive aspects of Chicago")
```

::: {.output .stream .stdout}
    Retrieval entering Chicago: ReActAgent
    Retrieving from object ReActAgent with query Give me a summary on all the positive aspects of Chicago
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: I need to use a tool to help me summarize the positive aspects of Chicago.
    Action: summary_tool
    Action Input: {'input': 'Provide a summary of the positive aspects and attributes of the city of Chicago'}
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Observation: Based on the provided information, some of the positive aspects and attributes of Chicago include:

    - Chicago is the third most populous city in the U.S. and a major transportation hub. It is an important component in global distribution.

    - The city has a diverse economy, with major industries including finance, commerce, industry, technology, telecommunications, and transportation. Chicago has the second largest central business district in the U.S. 

    - Chicago is an international hub for finance, culture, commerce, and industry. It has the largest derivatives market in the world and is a major financial center.

    - The city is a popular tourist destination known for its architecture, skyscrapers, parks, museums, and unique cuisine. Major attractions include Millennium Park, Navy Pier, the Magnificent Mile, and numerous cultural institutions.

    - Chicago has a rich history in the visual and performing arts, literature, film, theater, and music. It has influential art museums, a strong tradition of jazz and blues music, and acclaimed theater, dance, and comedy scenes.

    - The city has an extensive public transportation system including rail lines and buses. It also has a large network of parks and open spaces.

    - Chicago is home to several top universities, numerous major company headquarters, and a variety of unique neighborhoods and communities reflecting its diverse population and history.

    In summary, Chicago stands out for its economic strength, cultural vibrancy, tourist appeal, transportation infrastructure, higher education, and cosmopolitan character. The context portrays Chicago in an overall positive light as a thriving, world-class American city.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
    Thought: The summary tool provided a good overview of the positive aspects of Chicago. I think I can provide a satisfactory answer to the original question based on the information given.
    Answer: Chicago has many positive attributes that make it a vibrant and appealing city:

    Economy and Business: Chicago has a diverse and thriving economy, serving as a major hub for industries like finance, commerce, telecommunications, and transportation. It is home to the second largest central business district in the U.S. and the world's largest derivatives market.

    Tourism and Culture: Chicago is a popular tourist destination known for its iconic architecture, world-class museums, unique cuisine, and beautiful parks like Millennium Park. The city has a rich artistic heritage in visual arts, music (especially jazz and blues), theater, dance and comedy.

    Transportation: Chicago is a critical transportation center for the U.S. with an extensive public transit network of trains and buses. Its airports and rail lines make it an important link in the nation's distribution network.

    Education: Numerous prestigious universities call Chicago home, adding to its intellectual capital. 

    Diversity: Chicago's many neighborhoods reflect the diverse backgrounds and cultures of its residents, resulting in a cosmopolitan, international character.

    Overall, Chicago stands out as a world-class city known for its robust economy, vibrant cultural scene, strong transportation infrastructure, acclaimed educational institutions, and global status. The city has many strengths and positive qualities that make it an attractive place to live, work, and visit.
    HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 200 OK"
:::
::::

:::: {.cell .code execution_count="18"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .display_data}
<p style="font-size:20px">Chicago is a dynamic and appealing city with many positive attributes:

It has a thriving, diverse economy serving as a major hub for finance, commerce, telecommunications and transportation. Chicago is a popular tourist destination, known for its iconic architecture, world-class museums, unique cuisine, and beautiful parks. 

The city is a critical transportation center with an extensive public transit network, airports and rail lines. Numerous prestigious universities call Chicago home. Its neighborhoods reflect the diverse backgrounds and cultures of residents, giving the city a cosmopolitan character.

In summary, Chicago stands out for its robust economy, vibrant culture, strong transportation infrastructure, acclaimed educational institutions, diversity, and global status - making it an attractive place to live, work and visit.</p>
:::
::::

---

## ReAct Agent

Source: https://github.com/anthropics/claude-cookbooks/blob/main/third_party/LlamaIndex/ReAct_Agent.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-third-party-llamaindex-react-agent.md

# ReAct Agent

In this notebook we will look into creating ReAct Agent over tools.

1.  ReAct Agent over simple calculator tools.
2.  ReAct Agent over QueryEngine (RAG) tools.
:::

::: {.cell .markdown id="yKr4p_aGNk-J"}
### Installation
:::

::: {.cell .code colab="{\"base_uri\":\"https://localhost:8080/\"}" id="r4mZ85izboxE" outputId="afa53065-7d83-4fa1-c7ca-a1081f592cb1"}
``` python
!pip install llama-index
!pip install llama-index-llms-anthropic
!pip install llama-index-embeddings-huggingface
```
:::

::: {.cell .markdown id="qxcpBKw4JO3N"}
### Setup API Keys
:::

::: {.cell .code execution_count="1" id="IDt-c0OEb6Sp"}
``` python
# llama-parse is async-first, running the async code in a notebook requires the use of nest_asyncio
import nest_asyncio

nest_asyncio.apply()

import os

# Using Anthropic LLM API for LLM
os.environ["ANTHROPIC_API_KEY"] = "YOUR Claude API KEY"

from IPython.display import HTML, display
```
:::

::: {.cell .markdown}
### Set LLM and Embedding model

We will use anthropic latest released `Claude-3 Opus` LLM.
:::

::: {.cell .code execution_count="2" id="NJjiCFO6cQCL"}
``` python
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.anthropic import Anthropic
```
:::

::: {.cell .code execution_count="3" colab="{\"base_uri\":\"https://localhost:8080/\",\"height\":209,\"referenced_widgets\":[\"e7b5fc5b69994d4a8acf8f52a4caf788\",\"01e71cf062b3452988c8b81eb828435b\",\"c64113ed8dee43f6afa4d25062d42ad0\",\"d537be6e432c4048a133b01c09d317b1\",\"6b256fc1a2954b22b13f0b8253889f14\",\"92edac9d318940aaa9bfa4c54576b408\",\"ad4d5bfb924647ec898bd474d6532336\",\"e3195b603ce843e7ad0ffbbe4ef8cd11\",\"39d7a8908efa425ca461fcab029f7dfb\",\"d3a34fd8d33444cd8c113dfeaa9bbac6\",\"84ac06046b7a412a9877cd79d415a315\",\"9df11e8cb4994c2ea82ba5511b9a2ac6\",\"79064b863ae044a8b3d58396a3bcf429\",\"b92c0bf461f842c7a861404a2c706fa8\",\"4d182081816740739ffb6932b33d1742\",\"4ef9ee3421ef45e2a4cf5364ea70d12f\",\"de49c41eb0fc4dc19c11a655496ae6a9\",\"f24288283a6649ecbabfb9a701a60a27\",\"881ec7ba4e2a4180a9c7f1740032ab3c\",\"1f431dee65814c8daf9f974da96c6097\",\"e5fd2d52e53f4202ad0bd79c793c2e88\",\"89e77c403a164d5695db24a6275606ab\",\"5f18e7ddd05d4d588ae07a531b367be4\",\"6f579e2e1c9e45279823de8a68fa949e\",\"6a26587b197b41138cc1b81421cb14d7\",\"0e8025c92a2d4b8289c365a4c9596e00\",\"74fc5150e6e24f2d8995eef908c7b517\",\"e783b097c27f4e14bc5e85c283d88c21\",\"50fbe9aead53471cb70afeb5f8cef138\",\"79d8af55f0a74d65894571326817c821\",\"a8a00c7748f94d68a5076a7d019e60a2\",\"3da779d3881f4735a453ab4dff6ce096\",\"cf7c6cae761d467aa95386eb9f816210\",\"230d9778bcd6479cac7d41e3bad65237\",\"099ea879cc664871b221e18dda1e9a98\",\"90b873759af34552b948201a270fecdb\",\"5d3be9a81edd4644b8ec27c139762ff0\",\"b5175fd3b8154dd5a722a273fe174e75\",\"d270b8986112409a9294d14541b24704\",\"0649e4ee97204e6d8c0a765158a9fcb9\",\"72339db534e9469c916a6048dca64a21\",\"a488fe4a222b4264b298948c3a329fbc\",\"0b2d7d34c4de4e1c83050996044c1be8\",\"3412f431b58a4a10a57226d933a0352e\",\"26c63ede6fd840c39aa4a33550029a1d\",\"80cc96f4736c41b7bd5a9092ad5b75f6\",\"c415b5b483e64873b861878259ed5f98\",\"debe9699d03f4a05ab95aa7d81ad5d6a\",\"cd762731b75a42d0a011da43709a7485\",\"c5c79e2f31a24af0b451856433011cdc\",\"ee03b3ffc04e498986b6cb03dae7bb09\",\"7e814c66b5b3435da5ce8826f6780327\",\"1fcba194be3a41339603f99ea136cea1\",\"f3b995f94c8f4b37a721da11bea0094e\",\"a3b979b146a84f178660346e3c1a4378\",\"beaf2e2394a9456294c27803d1f5f7f6\",\"72ab5f7d76de4ab3814421ce2f8a7850\",\"c6ba56ca0959496ca1637b20b2596243\",\"a60c9284f47148abb3d203286872f4cb\",\"5414aeb5db3a4bb0abfafb5b2c78d133\",\"d41bd474ea084c23b8a17ac3390f214b\",\"918b38282d6b4e069fb2479610019fad\",\"baf2841cf3c34254ac93d9f0fe9a51b5\",\"48b206237d9c4e49bea35fe8ea45d45b\",\"b3463be18cce475eac2af3da5d1e9354\",\"a07c90f8b4fb4a92a4f86f723a49a719\"]}" id="ejHZjyyicRac" outputId="467b97a6-3598-4c96-99d6-78608a1611d1"}
``` python
llm = Anthropic(temperature=0.0, model="claude-opus-4-1")
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
```
:::

::: {.cell .code execution_count="4" id="dEG3EgJhcTMS"}
``` python
from llama_index.core import Settings

Settings.llm = llm
Settings.embed_model = embed_model
Settings.chunk_size = 512
```
:::

::: {.cell .markdown}
## ReAct Agent over Tools
:::

::: {.cell .markdown}
### Define Tools
:::

::: {.cell .code execution_count="5" id="my8Iu2cR1dT7"}
``` python
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
```
:::

::: {.cell .code execution_count="6" id="2Vk9QK8J1eZY"}
``` python
def multiply(a: int, b: int) -> int:
    """Multiply two integers and returns the result integer"""
    return a * b


def add(a: int, b: int) -> int:
    """Add two integers and returns the result integer"""
    return a + b


add_tool = FunctionTool.from_defaults(fn=add)
multiply_tool = FunctionTool.from_defaults(fn=multiply)
```
:::

::: {.cell .markdown}
### Create ReAct Agent

Create agent over tools and test out queries
:::

::: {.cell .code execution_count="7"}
``` python
agent = ReActAgent.from_tools([multiply_tool, add_tool], llm=llm, verbose=True)
```
:::

:::: {.cell .code execution_count="8" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="qWJHLfo11gej" outputId="61f2e3ac-85c1-458b-d72c-031858e3b5c5"}
``` python
response = agent.chat("What is 20+(2*4)? Calculate step by step ")
```

::: {.output .stream .stdout}
    Thought: I need to use the multiply tool to calculate 2*4 first, then use the add tool to add that result to 20.
    Action: multiply
    Action Input: {'a': 2, 'b': 4}
    Observation: 8
    Thought: Now that I have the result of 2*4, which is 8, I can add that to 20 to get the final answer.
    Action: add
    Action Input: {'a': 20, 'b': 8}
    Observation: 28
    Thought: I can answer without using any more tools.
    Answer: 20+(2*4) equals 28. 

    To calculate it step-by-step:
    1. First, calculate 2*4 which equals 8. 
    2. Then, add 20 to that result of 8.
    3. 20 + 8 = 28

    Therefore, 20+(2*4) = 28.
:::
::::

:::: {.cell .code execution_count="9" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="y9DRugAW1iG2" outputId="554e25bc-6574-4b4a-e288-fa725406185b"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .stream .stdout}
    20+(2*4) equals 28. 

    To calculate it step-by-step:
    1. First, calculate 2*4 which equals 8. 
    2. Then, add 20 to that result of 8.
    3. 20 + 8 = 28

    Therefore, 20+(2*4) = 28.
:::
::::

::: {.cell .markdown}
### Visit Prompts

You can check prompts that the agent used to select the tools.
:::

:::: {.cell .code execution_count="10"}
``` python
prompt_dict = agent.get_prompts()
for k, v in prompt_dict.items():
    print(f"Prompt: {k}\n\nValue: {v.template}")
```

::: {.output .stream .stdout}
    Prompt: agent_worker:system_prompt

    Value: 
    You are designed to help with a variety of tasks, from answering questions     to providing summaries to other types of analyses.

    ## Tools
    You have access to a wide variety of tools. You are responsible for using
    the tools in any sequence you deem appropriate to complete the task at hand.
    This may require breaking the task into subtasks and using different tools
    to complete each subtask.

    You have access to the following tools:
    {tool_desc}

    ## Output Format
    To answer the question, please use the following format.

    ```
    Thought: I need to use a tool to help me answer the question.
    Action: tool name (one of {tool_names}) if using a tool.
    Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}})
    ```

    Please ALWAYS start with a Thought.

    Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.

    If this format is used, the user will respond in the following format:

    ```
    Observation: tool response
    ```

    You should keep repeating the above format until you have enough information
    to answer the question without using any more tools. At that point, you MUST respond
    in the one of the following two formats:

    ```
    Thought: I can answer without using any more tools.
    Answer: [your answer here]
    ```

    ```
    Thought: I cannot answer the question with the provided tools.
    Answer: Sorry, I cannot answer your query.
    ```

    ## Current Conversation
    Below is the current conversation consisting of interleaving human and assistant messages.
:::
::::

::: {.cell .markdown}
## ReAct Agent over `QueryEngine` Tools
:::

::: {.cell .code execution_count="11" id="8yG1aKy9198J"}
``` python
from llama_index.core.tools import QueryEngineTool, ToolMetadata
```
:::

::: {.cell .markdown}
### Download data

We will define ReAct agent over tools created on QueryEngines with Uber
and Lyft 10K SEC Filings.
:::

:::: {.cell .code execution_count="12"}
``` python
!mkdir -p 'data/10k/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/10k/uber_2021.pdf' -O 'data/10k/uber_2021.pdf'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/10k/lyft_2021.pdf' -O 'data/10k/lyft_2021.pdf'
```

::: {.output .stream .stdout}
    --2024-03-08 06:58:18--  https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/10k/uber_2021.pdf
    Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.111.133, ...
    Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 1880483 (1.8M) [application/octet-stream]
    Saving to: ‘data/10k/uber_2021.pdf’

    data/10k/uber_2021. 100%[===================>]   1.79M  --.-KB/s    in 0.02s   

    2024-03-08 06:58:18 (90.6 MB/s) - ‘data/10k/uber_2021.pdf’ saved [1880483/1880483]

    --2024-03-08 06:58:19--  https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/10k/lyft_2021.pdf
    Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.108.133, ...
    Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 1440303 (1.4M) [application/octet-stream]
    Saving to: ‘data/10k/lyft_2021.pdf’

    data/10k/lyft_2021. 100%[===================>]   1.37M  --.-KB/s    in 0.02s   

    2024-03-08 06:58:19 (60.1 MB/s) - ‘data/10k/lyft_2021.pdf’ saved [1440303/1440303]
:::
::::

::: {.cell .markdown}
### Load Data
:::

::: {.cell .code execution_count="13"}
``` python
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex

lyft_docs = SimpleDirectoryReader(input_files=["./data/10k/lyft_2021.pdf"]).load_data()
uber_docs = SimpleDirectoryReader(input_files=["./data/10k/uber_2021.pdf"]).load_data()
```
:::

::: {.cell .markdown}
### Build Index
:::

::: {.cell .code execution_count="14"}
``` python
lyft_index = VectorStoreIndex.from_documents(lyft_docs)
uber_index = VectorStoreIndex.from_documents(uber_docs)
```
:::

::: {.cell .markdown}
### Create QueryEngines
:::

::: {.cell .code execution_count="15"}
``` python
lyft_engine = lyft_index.as_query_engine(similarity_top_k=3)
uber_engine = uber_index.as_query_engine(similarity_top_k=3)
```
:::

::: {.cell .markdown}
#### Create QueryEngine Tools
:::

::: {.cell .code execution_count="16"}
``` python
query_engine_tools = [
    QueryEngineTool(
        query_engine=lyft_engine,
        metadata=ToolMetadata(
            name="lyft_10k",
            description=(
                "Provides information about Lyft financials for year 2021. "
                "Use a detailed plain text question as input to the tool."
            ),
        ),
    ),
    QueryEngineTool(
        query_engine=uber_engine,
        metadata=ToolMetadata(
            name="uber_10k",
            description=(
                "Provides information about Uber financials for year 2021. "
                "Use a detailed plain text question as input to the tool."
            ),
        ),
    ),
]
```
:::

::: {.cell .markdown}
### ReAct Agent {#react-agent}
:::

::: {.cell .code execution_count="17"}
``` python
agent = ReActAgent.from_tools(
    query_engine_tools,
    llm=llm,
    verbose=True,
)
```
:::

::: {.cell .markdown}
### Querying with ReAct Agent
:::

:::: {.cell .code execution_count="18"}
``` python
response = agent.chat("What was Lyft's revenue growth in 2021?")
```

::: {.output .stream .stdout}
    Thought: I need to use a tool to help me answer the question.
    Action: lyft_10k
    Action Input: {'input': "What was Lyft's revenue growth in 2021?"}
    Observation: According to the context provided, Lyft's revenue increased by $843.6 million, or 36%, in 2021 compared to 2020. This growth was primarily driven by a significant increase in the number of Active Riders in 2021 as vaccines became more widely distributed and more communities reopened. The revenue growth in 2021 was partially offset by increased driver incentives recorded as a reduction to revenue.
    Thought: The provided observation directly answers the question about Lyft's revenue growth in 2021. I have enough information to provide a final answer without using additional tools.
    Answer: Lyft's revenue grew by $843.6 million, or 36%, in 2021 compared to 2020. The growth was mainly driven by a significant increase in Active Riders as COVID-19 vaccines became more widely available and communities reopened. However, the revenue growth was partially offset by higher driver incentives which were recorded as a reduction to revenue.
:::
::::

:::: {.cell .code execution_count="19"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .stream .stdout}
    Lyft's revenue grew by $843.6 million, or 36%, in 2021 compared to 2020. The growth was mainly driven by a significant increase in Active Riders as COVID-19 vaccines became more widely available and communities reopened. However, the revenue growth was partially offset by higher driver incentives which were recorded as a reduction to revenue.
:::
::::

:::: {.cell .code execution_count="20"}
``` python
response = agent.chat(
    "Compare and contrast the revenue growth of Uber and Lyft in 2021, then give an analysis"
)
```

::: {.output .stream .stdout}
    Thought: I need to use the lyft_10k and uber_10k tools to find information about Lyft and Uber's revenue growth in 2021 to compare and contrast them.

    Action: lyft_10k
    Action Input: {"input": "What was Lyft's revenue growth in dollars and percentage in 2021 compared to 2020?"}

    Observation: Lyft's revenue grew by $843.6 million, or 36%, from $2.4 billion in 2020 to $3.2 billion in 2021.

    Thought: Now I need to find Uber's revenue growth in 2021 to compare to Lyft's.

    Action: uber_10k
    Action Input: {"input": "What was Uber's revenue growth in dollars and percentage in 2021 compared to 2020?"}

    Observation: Uber's revenue grew by $8.5 billion, or 57%, from $14.1 billion in 2020 to $22.6 billion in 2021.

    Thought: I can now compare the revenue growth figures and provide an analysis.
    Answer: In comparing Lyft and Uber's revenue growth in 2021:

    Lyft's revenue grew by $843.6 million, or 36%, from $2.4 billion in 2020 to $3.2 billion in 2021. 

    Uber's revenue grew by a much larger $8.5 billion, or 57%, from $14.1 billion in 2020 to $22.6 billion in 2021.

    So while both companies saw strong revenue growth as they recovered from the impacts of the pandemic in 2020, Uber's growth was significantly higher than Lyft's in both dollar and percentage terms. 

    A few key factors likely contributed to Uber's higher growth rate:

    1) Uber has a more diversified business with significant food delivery and freight segments in addition to ridesharing. These segments grew rapidly in 2021.

    2) Uber operates in many more international markets than Lyft. As global travel recovered in 2021, this provided a boost to Uber.

    3) Uber's overall scale is much larger than Lyft's, so similar percentage growth translates
:::
::::

:::: {.cell .code execution_count="21"}
``` python
display(HTML(f'<p style="font-size:20px">{response.response}</p>'))
```

::: {.output .stream .stdout}
    In comparing Lyft and Uber's revenue growth in 2021:

    Lyft's revenue grew by $843.6 million, or 36%, from $2.4 billion in 2020 to $3.2 billion in 2021. 

    Uber's revenue grew by a much larger $8.5 billion, or 57%, from $14.1 billion in 2020 to $22.6 billion in 2021.

    So while both companies saw strong revenue growth as they recovered from the impacts of the pandemic in 2020, Uber's growth was significantly higher than Lyft's in both dollar and percentage terms. 

    A few key factors likely contributed to Uber's higher growth rate:

    1) Uber has a more diversified business with significant food delivery and freight segments in addition to ridesharing. These segments grew rapidly in 2021.

    2) Uber operates in many more international markets than Lyft. As global travel recovered in 2021, this provided a boost to Uber.

    3) Uber's overall scale is much larger than Lyft's, so similar percentage growth translates
:::
::::

---

## Claude 3 RAG Agents with LangChain v1

Source: https://github.com/anthropics/claude-cookbooks/blob/main/third_party/Pinecone/claude_3_rag_agent.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-third-party-pinecone-claude-3-rag-agent.md

:::: {.cell .code colab="{\"base_uri\":\"https://localhost:8080/\"}" id="1eOnr6z_zLoc" outputId="53f4214a-c00b-4dea-d1fa-38d0d6693fe9"}
``` python
!python --version
```

::: {.output .stream .stdout}
    Python 3.10.12
:::
::::

::: {.cell .markdown id="qQG4iSxVxw8f"}
# Claude 3 RAG Agents with LangChain v1
:::

::: {.cell .markdown id="ov6TCS7bx1oI"}
LangChain v1 brought a lot of changes and when comparing the LangChain
of versions `0.0.3xx` to `0.1.x` there\'s plenty of changes to the
preferred way of doing things. That is very much the case for agents.

The way that we initialize and use agents is generally clearer than it
was in the past --- there are still many abstractions, but we can (and
are encouraged to) get closer to the agent logic itself. This can make
for some confusion at first, but once understood the new logic can be
much clearer than with previous versions.

In this example, we\'ll be building a RAG agent with LangChain v1. We
will use Claude 3 for our LLM, Voyage AI for knowledge embeddings, and
Pinecone to power our knowledge retrieval.

To begin, let\'s install the prerequisites:
:::

:::: {.cell .code execution_count="2" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="zshhLDrgbFKk" outputId="ed49398c-dc7c-4c9c-e6c3-1a1910d52006"}
``` python
!pip install -qU \
    langchain==0.1.11 \
    langchain-core==0.1.30 \
    langchain-community==0.0.27 \
    langchain-anthropic==0.1.4 \
    langchainhub==0.1.15 \
    anthropic==0.19.1 \
    voyageai==0.2.1 \
    pinecone-client==3.1.0 \
    datasets==2.16.1
```

::: {.output .stream .stdout}
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 848.6/848.6 kB 4.6 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 211.0/211.0 kB 18.5 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 507.1/507.1 kB 30.3 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 75.6/75.6 kB 8.7 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 115.3/115.3 kB 13.4 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.8/134.8 kB 15.0 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77.8/77.8 kB 9.2 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 58.3/58.3 kB 6.8 MB/s eta 0:00:00
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.8/134.8 kB 13.5 MB/s eta 0:00:00
:::
::::

::: {.cell .markdown}
And grab the required API keys. We will need API keys for
[Claude](https://docs.claude.com/claude/reference/getting-started-with-the-api),
[Voyage AI](https://docs.voyageai.com/install/), and
[Pinecone](https://docs.pinecone.io/docs/quickstart).
:::

::: {.cell .code}
``` python
# Insert your API keys here
ANTHROPIC_API_KEY = "<YOUR_ANTHROPIC_API_KEY>"
PINECONE_API_KEY = "<YOUR_PINECONE_API_KEY>"
VOYAGE_API_KEY = "<YOUR_VOYAGE_API_KEY>"
```
:::

::: {.cell .markdown id="bpKfZkUYzQhB"}
## Finding Knowledge
:::

::: {.cell .markdown id="JDTQoxcNzUa8"}
The first thing we need for an agent using RAG is somewhere we want to
pull knowledge from. We will use v2 of the AI ArXiv dataset, available
on Hugging Face Datasets at
[`jamescalam/ai-arxiv2-chunks`](https://huggingface.co/datasets/jamescalam/ai-arxiv2-chunks).

*Note: we\'re using the prechunked dataset. For the raw version see
[`jamescalam/ai-arxiv2`](https://huggingface.co/datasets/jamescalam/ai-arxiv2).*
:::

::::::: {.cell .code execution_count="4" colab="{\"base_uri\":\"https://localhost:8080/\",\"height\":297,\"referenced_widgets\":[\"4d5c6f53e82948b18b45877e2e30fd78\",\"7036b643c9264b09b0f93cb6a1a8b01f\",\"fb92dd97e68643099b0d0f1b4983f5f1\",\"91c3b00e77444bb79d9f73314800471e\",\"3e1d39ab6d3a4cf5827c9b3e1d4f0df1\",\"f58fb2da52bc43a985449910daaac230\",\"449afd685fd94354b64aa43a4763ab1d\",\"43a3c63554894d268e3bf747f7e0289d\",\"d902beef883e4c65bd2d6cb161423bae\",\"ce5735788cd14803abac28fa2c42d168\",\"a8928cd888a648c9b7d52739f38c5bda\",\"0168cb9e015b4e119fcdc7beca2e21a3\",\"a0e93df2955b44208479a4b416cd1085\",\"6f58f8d6374b45b4b6a0d9fcaa8083e7\",\"8bde11d3d65c45dba3baf1c02450eef1\",\"b19af932a7f24dc799b683136d175107\",\"e2819a7a94974a4da9b6bde754fdbc50\",\"808dd94ecaff43e0848bcfead3cf0d75\",\"4383833994854f88aa12ba0edb673d47\",\"ee2672db2047468fb49482e14127dcd3\",\"6999dc582b4c4ba68fdbfe404b1c4dfe\",\"593274c4088f4d9aa2becb6b1c6e495b\"]}" id="U9gpYFnzbFKm" outputId="c7005c0a-b9a2-4c7c-f93b-e92081f7e3d6"}
``` python
from datasets import load_dataset

dataset = load_dataset("jamescalam/ai-arxiv2-chunks", split="train[:20000]")
dataset
```

::: {.output .stream .stderr}
    /usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:88: UserWarning: 
    The secret `HF_TOKEN` does not exist in your Colab secrets.
    To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.
    You will be able to reuse this secret in all of your notebooks.
    Please note that authentication is recommended but still optional to access public models or datasets.
      warnings.warn(
:::

::: {.output .display_data}
``` json
{"model_id":"4d5c6f53e82948b18b45877e2e30fd78","version_major":2,"version_minor":0}
```
:::

::: {.output .display_data}
``` json
{"model_id":"0168cb9e015b4e119fcdc7beca2e21a3","version_major":2,"version_minor":0}
```
:::

::: {.output .execute_result execution_count="4"}
    Dataset({
        features: ['doi', 'chunk-id', 'chunk', 'id', 'title', 'summary', 'source', 'authors', 'categories', 'comment', 'journal_ref', 'primary_category', 'published', 'updated', 'references'],
        num_rows: 20000
    })
:::
:::::::

:::: {.cell .code execution_count="5" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="_bP7ZW-ybFKm" outputId="491e8001-df44-465c-9979-2e2a30de9d5f"}
``` python
dataset[1]
```

::: {.output .execute_result execution_count="5"}
    {'doi': '2401.09350',
     'chunk-id': 1,
     'chunk': 'These neural networks and their training algorithms may be complex, and the scope of their impact broad and wide, but nonetheless they are simply functions in a high-dimensional space. A trained neural network takes a vector as input, crunches and transforms it in various ways, and produces another vector, often in some other space. An image may thereby be turned into a vector, a song into a sequence of vectors, and a social network as a structured collection of vectors. It seems as though much of human knowledge, or at least what is expressed as text, audio, image, and video, has a vector representation in one form or another.\nIt should be noted that representing data as vectors is not unique to neural networks and deep learning. In fact, long before learnt vector representations of pieces of dataâ\x80\x94what is commonly known as â\x80\x9cembeddingsâ\x80\x9dâ\x80\x94came along, data was often encoded as hand-crafted feature vectors. Each feature quanti- fied into continuous or discrete values some facet of the data that was deemed relevant to a particular task (such as classification or regression). Vectors of that form, too, reflect our understanding of a real-world object or concept.',
     'id': '2401.09350#1',
     'title': 'Foundations of Vector Retrieval',
     'summary': 'Vectors are universal mathematical objects that can represent text, images,\nspeech, or a mix of these data modalities. That happens regardless of whether\ndata is represented by hand-crafted features or learnt embeddings. Collect a\nlarge enough quantity of such vectors and the question of retrieval becomes\nurgently relevant: Finding vectors that are more similar to a query vector.\nThis monograph is concerned with the question above and covers fundamental\nconcepts along with advanced data structures and algorithms for vector\nretrieval. In doing so, it recaps this fascinating topic and lowers barriers of\nentry into this rich area of research.',
     'source': 'http://arxiv.org/pdf/2401.09350',
     'authors': 'Sebastian Bruch',
     'categories': 'cs.DS, cs.IR',
     'comment': None,
     'journal_ref': None,
     'primary_category': 'cs.DS',
     'published': '20240117',
     'updated': '20240117',
     'references': []}
:::
::::

::: {.cell .markdown id="VX6NdQhgbFKn"}
## Building the Knowledge Base
:::

::: {.cell .markdown id="MDCbqQl_bFKn"}
To build our knowledge base we need *two things*:

1.  Embeddings, for this we will use `VoyageEmbeddings` using Voyage
    AI\'s embedding models, which do need an [API
    key](https://dash.voyageai.com/api-keys).
2.  A vector database, where we store our embeddings and query them. We
    use Pinecone which again requires a [free API
    key](https://app.pinecone.io).

First we initialize our connection to Voyage AI and define an `embed`
object for embeddings:
:::

::: {.cell .code execution_count="7" id="wkw0KyLRbFKo"}
``` python
from langchain_community.embeddings import VoyageEmbeddings

embed = VoyageEmbeddings(voyage_api_key=VOYAGE_API_KEY, model="voyage-2")
```
:::

::: {.cell .markdown id="LhDzfsczbFKo"}
Then we initialize our connection to Pinecone:
:::

::: {.cell .code execution_count="8" id="j0N7EcJibFKo"}
``` python
from pinecone import Pinecone

# configure client
pc = Pinecone(api_key=PINECONE_API_KEY)
```
:::

::: {.cell .markdown id="g65RLGIpbFKo"}
Now we setup our index specification, this allows us to define the cloud
provider and region where we want to deploy our index. You can find a
list of all [available providers and regions
here](https://docs.pinecone.io/docs/projects).
:::

::: {.cell .code execution_count="9" id="8stIZYKdbFKo"}
``` python
from pinecone import ServerlessSpec

spec = ServerlessSpec(cloud="aws", region="us-west-2")
```
:::

::: {.cell .markdown id="-8Ep3743bFKo"}
Before creating an index, we need the dimensionality of our Voyage AI
embedding model, which we can find easily by creating an embedding and
checking the length:
:::

:::: {.cell .code execution_count="10" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="DwMhLWLDbFKo" outputId="f8731679-583c-497c-93d9-b13ea6013c83"}
``` python
vec = embed.embed_documents(["ello"])
len(vec[0])
```

::: {.output .execute_result execution_count="10"}
    1024
:::
::::

::: {.cell .markdown id="G3X7nZIabFKp"}
Now we create the index using our embedding dimensionality, and a metric
also compatible with the model (this can be either cosine or
dotproduct). We also pass our spec to index initialization.
:::

:::: {.cell .code execution_count="11" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="E6Bl7xTJbFKp" outputId="03e0b822-b150-4a6b-b83d-1cee1e4fced4"}
``` python
import time

index_name = "claude-3-rag"

# check if index already exists (it shouldn't if this is first time)
if index_name not in pc.list_indexes().names():
    # if does not exist, create index
    pc.create_index(
        index_name,
        dimension=len(vec[0]),  # dimensionality of voyage model
        metric="dotproduct",
        spec=spec,
    )
    # wait for index to be initialized
    while not pc.describe_index(index_name).status["ready"]:
        time.sleep(1)

# connect to index
index = pc.Index(index_name)
time.sleep(1)
# view index stats
index.describe_index_stats()
```

::: {.output .execute_result execution_count="11"}
    {'dimension': 1024,
     'index_fullness': 0.0,
     'namespaces': {'': {'vector_count': 20000}},
     'total_vector_count': 20000}
:::
::::

::: {.cell .markdown id="6ZUn2lu7bFKp"}
### Populating our Index
:::

::: {.cell .markdown id="PeVD6d0sbFKp"}
Now our knowledge base is ready to be populated with our data. We will
use the `embed` helper function to embed our documents and then add them
to our index.

We will also include metadata from each record.
:::

:::: {.cell .code execution_count="12" colab="{\"base_uri\":\"https://localhost:8080/\",\"height\":49,\"referenced_widgets\":[\"78b688cc78264ad1a2f05d339fe498fe\",\"f8796aebc76a42ed80d6cf9c234b9e14\",\"93fd5108528a499cb5ae4444f0b2f770\",\"89683fb7a1a44606abc2ded05fbb3aa3\",\"f202dce30c1d4672ad357db9b6dbe9b8\",\"009627caf7fa4c51b61b6e2087545324\",\"3ff8bcf03c704243b7fd173b3cdd0d87\",\"cc0685f737fa4e15b7796e5f3fe3df8d\",\"f3cfb3b02d7a4e44b00e24aa2e7f9ff5\",\"1022918a023b4aa8a3714d9eab2978b1\",\"e6ed1f5a6e5b4c508fa3b69d9219057d\"]}" id="hb00VSTqbFKp" outputId="f13e0707-2b9b-4966-df62-9e457765ebf8"}
``` python
from tqdm.auto import tqdm

# easier to work with dataset as pandas dataframe
data = dataset.to_pandas()

batch_size = 100

for i in tqdm(range(0, len(data), batch_size)):
    i_end = min(len(data), i + batch_size)
    # get batch of data
    batch = data.iloc[i:i_end]
    # generate unique ids for each chunk
    ids = [f"{x['doi']}-{x['chunk-id']}" for i, x in batch.iterrows()]
    # get text to embed
    texts = [x["chunk"] for _, x in batch.iterrows()]
    # embed text
    embeds = embed.embed_documents(texts)
    # get metadata to store in Pinecone
    metadata = [
        {"text": x["chunk"], "source": x["source"], "title": x["title"]}
        for i, x in batch.iterrows()
    ]
    # add to Pinecone
    index.upsert(vectors=zip(ids, embeds, metadata, strict=False))
```

::: {.output .display_data}
``` json
{"model_id":"78b688cc78264ad1a2f05d339fe498fe","version_major":2,"version_minor":0}
```
:::
::::

::: {.cell .markdown id="z6VVT3X_EMDO"}
Create a tool for our agent to use when searching for ArXiv papers:
:::

::: {.cell .code execution_count="13" id="X9J5jHKcEQz6"}
``` python
from langchain.agents import tool


@tool
def arxiv_search(query: str) -> str:
    """Use this tool when answering questions about AI, machine learning, data
    science, or other technical questions that may be answered using arXiv
    papers.
    """
    # create query vector
    xq = embed.embed_query(query)
    # perform search
    out = index.query(vector=xq, top_k=5, include_metadata=True)
    # reformat results into string
    results_str = "\n\n".join([x["metadata"]["text"] for x in out["matches"]])
    return results_str


tools = [arxiv_search]
```
:::

::: {.cell .markdown id="uN7d_4r-JMPW"}
When this tool is used by our agent it will execute it like so:
:::

:::: {.cell .code execution_count="14" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="eq4H-2RpI1U3" outputId="ca36c8cb-5fd1-47ed-cc67-f43fd9833af0"}
``` python
print(arxiv_search.run(tool_input={"query": "can you tell me about llama 2?"}))
```

::: {.output .stream .stdout}
    Model Llama 2 Code Llama Code Llama - Python Size FIM LCFT Python CPP Java PHP TypeScript C# Bash Average 7B ✗ 13B ✗ 34B ✗ 70B ✗ 7B ✗ 7B ✓ 7B ✗ 7B ✓ 13B ✗ 13B ✓ 13B ✗ 13B ✓ 34B ✗ 34B ✗ 7B ✗ 7B ✗ 13B ✗ 13B ✗ 34B ✗ 34B ✗ ✗ ✗ ✗ ✗ 14.3% 6.8% 10.8% 9.9% 19.9% 13.7% 15.8% 13.0% 24.2% 23.6% 22.2% 19.9% 27.3% 30.4% 31.6% 34.2% 12.6% 13.2% 21.4% 15.1% 6.3% 3.2% 8.3% 9.5% 3.2% 12.6% 17.1% 3.8% 18.9% 25.9% 8.9% 24.8% ✗ ✗ ✓ ✓ ✗ ✗ ✓ ✓ ✗ ✓ 37.3% 31.1% 36.1% 30.4% 29.2% 29.8% 38.0%

    Ethical Considerations and Limitations (Section 5.2) Llama 2 is a new technology that carries risks with use. Testing conducted to date has been in English, and has not covered, nor could it cover all scenarios. For these reasons, as with all LLMs, Llama 2’s potential outputs cannot be predicted in advance, and the model may in some instances produce inaccurate or objectionable responses to user prompts. Therefore, before deploying any applications of Llama 2, developers should perform safety testing and tuning tailored to their specific applications of the model. Please see the Responsible Use Guide available available at https://ai.meta.com/llama/responsible-user-guide
    Table 52: Model card for Llama 2.
    77

    2
    Cove Liama Long context (7B =, 13B =, 34B) + fine-tuning ; Lrama 2 Code training 20B oes Cope Liama - Instruct Foundation models —> nfilling code training = eee.” (7B =, 13B =, 34B) — 5B (7B, 13B, 348) 5008 Python code Long context Cove Liama - PyrHon (7B, 13B, 34B) > training » Fine-tuning > 1008 208
    Figure 2: The Code Llama specialization pipeline. The different stages of fine-tuning annotated with the number of tokens seen during training. Infilling-capable models are marked with the ⇄ symbol.
    # 2 Code Llama: Specializing Llama 2 for code
    # 2.1 The Code Llama models family

    # 2 Code Llama: Specializing Llama 2 for code
    # 2.1 The Code Llama models family
    Code Llama. The Code Llama models constitute foundation models for code generation. They come in four model sizes: 7B, 13B, 34B and 70B parameters. The 7B, 13B and 70B models are trained using an infilling objective (Section 2.3), and are appropriate to be used in an IDE to complete code in the middle of a file, for example. The 34B model was trained without the infilling objective. All Code Llama models are initialized with Llama 2 model weights and trained on 500B tokens from a code-heavy dataset (see Section 2.2 for more details), except Code Llama 70B which was trained on 1T tokens. They are all fine-tuned to handle long contexts as detailed in Section 2.4.

    0.52 0.57 0.19 0.30 Llama 1 7B 13B 33B 65B 0.27 0.24 0.23 0.25 0.26 0.24 0.26 0.26 0.34 0.31 0.34 0.34 0.54 0.52 0.50 0.46 0.36 0.37 0.36 0.36 0.39 0.37 0.35 0.40 0.26 0.23 0.24 0.25 0.28 0.28 0.33 0.32 0.33 0.31 0.34 0.32 0.45 0.50 0.49 0.48 0.33 0.27 0.31 0.31 0.17 0.10 0.12 0.11 0.24 0.24 0.23 0.25 0.31 0.27 0.30 0.30 0.44 0.41 0.41 0.43 0.57 0.55 0.60 0.60 0.39 0.34 0.28 0.39 Llama 2 7B 13B 34B 70B 0.28 0.24 0.27 0.31 0.25 0.25 0.24 0.29 0.29 0.35 0.33 0.35 0.50 0.50 0.56 0.51 0.36 0.41 0.41
:::
::::

::: {.cell .markdown id="XUvJOqrNhYIh"}
## Defining XML Agent
:::

::: {.cell .markdown id="s45dwd78hbvk"}
The XML agent is built primarily to support Anthropic models. Anthropic
models have been trained to use XML tags like
`<input>{some input}</input` or when using a tool they use:

    <tool>{tool name}</tool>
    <tool_input>{tool input}</tool_input>

This is much different to the format produced by typical ReAct agents,
which is not as well supported by Anthropic models.

To create an XML agent we need a `prompt`, `llm`, and list of `tools`.
We can download a prebuilt prompt for conversational XML agents from
LangChain hub.
:::

:::: {.cell .code execution_count="15" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="ntuT7UuXeMz0" outputId="c47f0a98-c71f-488f-fc55-9e1ea7f643b4"}
``` python
from langchain import hub

prompt = hub.pull("hwchase17/xml-agent-convo")
prompt
```

::: {.output .execute_result execution_count="15"}
    ChatPromptTemplate(input_variables=['agent_scratchpad', 'input', 'tools'], partial_variables={'chat_history': ''}, messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['agent_scratchpad', 'chat_history', 'input', 'tools'], template="You are a helpful assistant. Help the user answer any questions.\n\nYou have access to the following tools:\n\n{tools}\n\nIn order to use a tool, you can use <tool></tool> and <tool_input></tool_input> tags. You will then get back a response in the form <observation></observation>\nFor example, if you have a tool called 'search' that could run a google search, in order to search for the weather in SF you would respond:\n\n<tool>search</tool><tool_input>weather in SF</tool_input>\n<observation>64 degrees</observation>\n\nWhen you are done, respond with a final answer between <final_answer></final_answer>. For example:\n\n<final_answer>The weather in SF is 64 degrees</final_answer>\n\nBegin!\n\nPrevious Conversation:\n{chat_history}\n\nQuestion: {input}\n{agent_scratchpad}"))])
:::
::::

::: {.cell .markdown id="rfdcKCdwi0SL"}
We can see the XML format being used throughout the prompt when
explaining to the LLM how it should use tools.

Next we initialize our connection to Anthropic, for this we need an
[Claude API key](https://console.anthropic.com/).
:::

::: {.cell .code execution_count="16" id="kDHuU2uOdW91"}
``` python
from langchain_anthropic import ChatAnthropic

# chat completion llm
llm = ChatAnthropic(
    ANTHROPIC_API_KEY=ANTHROPIC_API_KEY,
    model_name="claude-opus-4-1",  # change "opus" -> "sonnet" for speed
    temperature=0.0,
)
```
:::

::: {.cell .markdown id="g33Nt-xijPKG"}
When the agent is run we will provide it with a single `input` --- this
is the input text from a user. However, within the agent logic an
*agent_scratchpad* object will be passed too, which will include tool
information. To feed this information into our LLM we will need to
transform it into the XML format described above, we define the
`convert_intermediate_steps` function to handle that.
:::

::: {.cell .code execution_count="17" id="TMMBgMBlIJoq"}
``` python
def convert_intermediate_steps(intermediate_steps):
    log = ""
    for action, observation in intermediate_steps:
        log += (
            f"<tool>{action.tool}</tool><tool_input>{action.tool_input}"
            f"</tool_input><observation>{observation}</observation>"
        )
    return log
```
:::

::: {.cell .markdown id="T5_PQWVckAOi"}
We must also parse the tools into a string containing
`tool_name: tool_description` --- we handle that with the
`convert_tools` function.
:::

::: {.cell .code execution_count="18" id="qxbrF5a4j9il"}
``` python
def convert_tools(tools):
    return "\n".join([f"{tool.name}: {tool.description}" for tool in tools])
```
:::

::: {.cell .markdown id="SCVI2dyUIRg6"}
With everything ready we can go ahead and initialize our agent object
using [**L**ang**C**hain **E**xpression **L**anguage
(LCEL)](https://www.pinecone.io/learn/series/langchain/langchain-expression-language/).
We add instructions for when the LLM should *stop* generating with
`llm.bind(stop=[...])` and finally we parse the output from the agent
using an `XMLAgentOutputParser` object.
:::

::: {.cell .code execution_count="19" id="Z3yhTDmEIU4n"}
``` python
from langchain.agents.output_parsers import XMLAgentOutputParser

agent = (
    {
        "input": lambda x: x["input"],
        # without "chat_history", tool usage has no context of prev interactions
        "chat_history": lambda x: x["chat_history"],
        "agent_scratchpad": lambda x: convert_intermediate_steps(x["intermediate_steps"]),
    }
    | prompt.partial(tools=convert_tools(tools))
    | llm.bind(stop=["</tool_input>", "</final_answer>"])
    | XMLAgentOutputParser()
)
```
:::

::: {.cell .markdown id="MG2_hL4hkudq"}
With our `agent` object initialized we pass it to an `AgentExecutor`
object alongside our original `tools` list:
:::

::: {.cell .code execution_count="20" id="YHW_K3WOIsXw"}
``` python
from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
```
:::

::: {.cell .markdown id="QRCtHauRlkLc"}
Now we can use the agent via the `invoke` method:
:::

:::: {.cell .code execution_count="25" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="Y_Aqp20qloj7" outputId="c4fe06f3-a147-4274-becd-49c9992a8cd6"}
``` python
user_msg = "can you tell me about llama 2?"

out = agent_executor.invoke({"input": user_msg, "chat_history": ""})

print(out["output"])
```

::: {.output .stream .stdout}


    > Entering new AgentExecutor chain...
    <tool>arxiv_search</tool>
    <tool_input>llama 2Model Llama 2 Code Llama Code Llama - Python Size FIM LCFT Python CPP Java PHP TypeScript C# Bash Average 7B ✗ 13B ✗ 34B ✗ 70B ✗ 7B ✗ 7B ✓ 7B ✗ 7B ✓ 13B ✗ 13B ✓ 13B ✗ 13B ✓ 34B ✗ 34B ✗ 7B ✗ 7B ✗ 13B ✗ 13B ✗ 34B ✗ 34B ✗ ✗ ✗ ✗ ✗ 14.3% 6.8% 10.8% 9.9% 19.9% 13.7% 15.8% 13.0% 24.2% 23.6% 22.2% 19.9% 27.3% 30.4% 31.6% 34.2% 12.6% 13.2% 21.4% 15.1% 6.3% 3.2% 8.3% 9.5% 3.2% 12.6% 17.1% 3.8% 18.9% 25.9% 8.9% 24.8% ✗ ✗ ✓ ✓ ✗ ✗ ✓ ✓ ✗ ✓ 37.3% 31.1% 36.1% 30.4% 29.2% 29.8% 38.0%

    2
    Cove Liama Long context (7B =, 13B =, 34B) + fine-tuning ; Lrama 2 Code training 20B oes Cope Liama - Instruct Foundation models —> nfilling code training = eee.” (7B =, 13B =, 34B) — 5B (7B, 13B, 348) 5008 Python code Long context Cove Liama - PyrHon (7B, 13B, 34B) > training » Fine-tuning > 1008 208
    Figure 2: The Code Llama specialization pipeline. The different stages of fine-tuning annotated with the number of tokens seen during training. Infilling-capable models are marked with the ⇄ symbol.
    # 2 Code Llama: Specializing Llama 2 for code
    # 2.1 The Code Llama models family

    0.52 0.57 0.19 0.30 Llama 1 7B 13B 33B 65B 0.27 0.24 0.23 0.25 0.26 0.24 0.26 0.26 0.34 0.31 0.34 0.34 0.54 0.52 0.50 0.46 0.36 0.37 0.36 0.36 0.39 0.37 0.35 0.40 0.26 0.23 0.24 0.25 0.28 0.28 0.33 0.32 0.33 0.31 0.34 0.32 0.45 0.50 0.49 0.48 0.33 0.27 0.31 0.31 0.17 0.10 0.12 0.11 0.24 0.24 0.23 0.25 0.31 0.27 0.30 0.30 0.44 0.41 0.41 0.43 0.57 0.55 0.60 0.60 0.39 0.34 0.28 0.39 Llama 2 7B 13B 34B 70B 0.28 0.24 0.27 0.31 0.25 0.25 0.24 0.29 0.29 0.35 0.33 0.35 0.50 0.50 0.56 0.51 0.36 0.41 0.41

    Ethical Considerations and Limitations (Section 5.2) Llama 2 is a new technology that carries risks with use. Testing conducted to date has been in English, and has not covered, nor could it cover all scenarios. For these reasons, as with all LLMs, Llama 2’s potential outputs cannot be predicted in advance, and the model may in some instances produce inaccurate or objectionable responses to user prompts. Therefore, before deploying any applications of Llama 2, developers should perform safety testing and tuning tailored to their specific applications of the model. Please see the Responsible Use Guide available available at https://ai.meta.com/llama/responsible-user-guide
    Table 52: Model card for Llama 2.
    77

    Model Size FIM LCFT HumanEval MBPP pass@1 pass@10 pass@100 pass@1 pass@10 pass@100 Llama 2 Code Llama Code Llama - Python 7B ✗ 13B ✗ 34B ✗ 70B ✗ 7B ✗ 7B ✓ 7B ✗ 7B ✓ 13B ✗ 13B ✓ 13B ✗ 13B ✓ 34B ✗ 34B ✗ 7B ✗ 7B ✗ 13B ✗ 13B ✗ 34B ✗ 34B ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✓ ✗ ✗ ✓ ✓ ✗ ✓ ✗ ✓ ✗ ✓ ✗ ✓ 12.2% 25.2% 20.1% 34.8% 22.6% 47.0% 30.5% 59.4% 32.3% 63.9% 34.1% 62.6% 34.1% 62.5% 33.5% 59.6% 36.6% 72.9% 36.6% 71.9% 37.8% 70.6% 36.0% 69.4% 48.2% 77.7% 48.8% 76.8% 40.2% 70.0% 38.4% 70.3% 45.7% 80.0%Based on the information from the arXiv search, here are the key points about Llama 2:

    <final_answer>
    - Llama 2 is a large language model developed by Meta AI. It comes in sizes ranging from 7B to 70B parameters.

    - Code Llama is a version of Llama 2 that has been specialized for code generation through fine-tuning on code datasets. Code Llama models are available in Python, C++, Java, PHP, TypeScript, C#, and Bash.

    - The Code Llama specialization pipeline involves foundation model pre-training, long context training, code infilling training, and fine-tuning on specific programming languages. 

    - Code Llama significantly outperforms the base Llama 2 models on code generation benchmarks like HumanEval and MBPP. For example, the 34B parameter Code Llama - Python achieves 48.8% pass@1 on HumanEval compared to 34.1% for the 34B Llama 2.

    - As with all large language models, Llama 2 has limitations and potential risks that need to be considered before deploying it in applications. Meta provides a responsible use guide with recommendations for safety testing and tuning.


    > Finished chain.

    - Llama 2 is a large language model developed by Meta AI. It comes in sizes ranging from 7B to 70B parameters.

    - Code Llama is a version of Llama 2 that has been specialized for code generation through fine-tuning on code datasets. Code Llama models are available in Python, C++, Java, PHP, TypeScript, C#, and Bash.

    - The Code Llama specialization pipeline involves foundation model pre-training, long context training, code infilling training, and fine-tuning on specific programming languages. 

    - Code Llama significantly outperforms the base Llama 2 models on code generation benchmarks like HumanEval and MBPP. For example, the 34B parameter Code Llama - Python achieves 48.8% pass@1 on HumanEval compared to 34.1% for the 34B Llama 2.

    - As with all large language models, Llama 2 has limitations and potential risks that need to be considered before deploying it in applications. Meta provides a responsible use guide with recommendations for safety testing and tuning.
:::
::::

::: {.cell .markdown id="Eae-JyUFl--N"}
That looks pretty good, but right now our agent is *stateless* ---
making it hard to have a conversation with. We can give it memory in
many different ways, but one the easiest ways to do so is to use
`ConversationBufferWindowMemory`.
:::

::: {.cell .code execution_count="26" id="EqOMNQUfmOEr"}
``` python
from langchain.chains.conversation.memory import ConversationBufferWindowMemory

# conversational memory
conversational_memory = ConversationBufferWindowMemory(
    memory_key="chat_history", k=5, return_messages=True
)
```
:::

::: {.cell .markdown id="O9UvnBrsnNVw"}
We haven\'t attached our conversational memory to our agent --- so the
`conversational_memory` object will remain empty:
:::

:::: {.cell .code execution_count="27" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="KJZNIDAslNoC" outputId="5267f069-dc09-472d-c9ef-e694cfea982f"}
``` python
conversational_memory.chat_memory.messages
```

::: {.output .execute_result execution_count="27"}
    []
:::
::::

::: {.cell .markdown id="ynX9Wca6nawr"}
We must manually add the interactions between ourselves and the agent to
our memory.
:::

:::: {.cell .code execution_count="28" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="-5hXy1FAnne3" outputId="b659e1f4-3d02-466f-9880-c0adf65fa507"}
``` python
conversational_memory.chat_memory.add_user_message(user_msg)
conversational_memory.chat_memory.add_ai_message(out["output"])

conversational_memory.chat_memory.messages
```

::: {.output .execute_result execution_count="28"}
    [HumanMessage(content='can you tell me about llama 2?'),
     AIMessage(content='\n- Llama 2 is a large language model developed by Meta AI. It comes in sizes ranging from 7B to 70B parameters.\n\n- Code Llama is a version of Llama 2 that has been specialized for code generation through fine-tuning on code datasets. Code Llama models are available in Python, C++, Java, PHP, TypeScript, C#, and Bash.\n\n- The Code Llama specialization pipeline involves foundation model pre-training, long context training, code infilling training, and fine-tuning on specific programming languages. \n\n- Code Llama significantly outperforms the base Llama 2 models on code generation benchmarks like HumanEval and MBPP. For example, the 34B parameter Code Llama - Python achieves 48.8% pass@1 on HumanEval compared to 34.1% for the 34B Llama 2.\n\n- As with all large language models, Llama 2 has limitations and potential risks that need to be considered before deploying it in applications. Meta provides a responsible use guide with recommendations for safety testing and tuning.\n')]
:::
::::

::: {.cell .markdown id="T3pA0o6ZnrAl"}
Now we can see that *two* messages have been added, our `HumanMessage`
the agent\'s `AIMessage` response. Unfortunately, we cannot send these
messages to our XML agent directly. Instead, we need to pass a string in
the format:

    Human: {human message}
    AI: {AI message}

Let\'s write a quick `memory2str` helper function to handle this for us:
:::

::: {.cell .code execution_count="29" id="raZHBdJmtGH-"}
``` python
from langchain_core.messages.human import HumanMessage


def memory2str(memory: ConversationBufferWindowMemory):
    messages = memory.chat_memory.messages
    memory_list = [
        f"Human: {mem.content}" if isinstance(mem, HumanMessage) else f"AI: {mem.content}"
        for mem in messages
    ]
    memory_str = "\n".join(memory_list)
    return memory_str
```
:::

:::: {.cell .code execution_count="30" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="t89yX-6i3hvd" outputId="7c27cac1-3881-4a26-f59f-274d8d4affa3"}
``` python
print(memory2str(conversational_memory))
```

::: {.output .stream .stdout}
    Human: can you tell me about llama 2?
    AI: 
    - Llama 2 is a large language model developed by Meta AI. It comes in sizes ranging from 7B to 70B parameters.

    - Code Llama is a version of Llama 2 that has been specialized for code generation through fine-tuning on code datasets. Code Llama models are available in Python, C++, Java, PHP, TypeScript, C#, and Bash.

    - The Code Llama specialization pipeline involves foundation model pre-training, long context training, code infilling training, and fine-tuning on specific programming languages. 

    - Code Llama significantly outperforms the base Llama 2 models on code generation benchmarks like HumanEval and MBPP. For example, the 34B parameter Code Llama - Python achieves 48.8% pass@1 on HumanEval compared to 34.1% for the 34B Llama 2.

    - As with all large language models, Llama 2 has limitations and potential risks that need to be considered before deploying it in applications. Meta provides a responsible use guide with recommendations for safety testing and tuning.
:::
::::

::: {.cell .markdown id="q0L_80WrpWqd"}
Now let\'s put together another helper function called `chat` to help us
handle the *state* part of our agent.
:::

::: {.cell .code execution_count="31" id="C-Ck2Lv53rD-"}
``` python
def chat(text: str):
    out = agent_executor.invoke({"input": text, "chat_history": memory2str(conversational_memory)})
    conversational_memory.chat_memory.add_user_message(text)
    conversational_memory.chat_memory.add_ai_message(out["output"])
    return out["output"]
```
:::

::: {.cell .markdown id="XIheLeTBsO9S"}
Now we simply chat with our agent and it will remember the context of
previous interactions.
:::

:::: {.cell .code execution_count="33" colab="{\"base_uri\":\"https://localhost:8080/\"}" id="iJ_PH7YcA_f2" outputId="7d645e9f-f191-4b62-97fd-973417e1efaa"}
``` python
print(chat("was any red teaming done with the model?"))
```

::: {.output .stream .stdout}


    > Entering new AgentExecutor chain...
    <tool>arxiv_search</tool>
    <tool_input>llama 2 red teamingAfter conducting red team exercises, we asked participants (who had also participated in Llama 2 Chat exercises) to also provide qualitative assessment of safety capabilities of the model. Some participants who had expertise in offensive security and malware development questioned the ultimate risk posed by “malicious code generation” through LLMs with current capabilities.
    One red teamer remarked, “While LLMs being able to iteratively improve on produced source code is a risk, producing source code isn’t the actual gap. That said, LLMs may be risky because they can inform low-skill adversaries in production of scripts through iteration that perform some malicious behavior.”
    According to another red teamer, “[v]arious scripts, program code, and compiled binaries are readily available on mainstream public websites, hacking forums or on ‘the dark web.’ Advanced malware development is beyond the current capabilities of available LLMs, and even an advanced LLM paired with an expert malware developer is not particularly useful- as the barrier is not typically writing the malware code itself. That said, these LLMs may produce code which will get easily caught if used directly.”

    Model Llama 2 Code Llama Code Llama - Python Size FIM LCFT Python CPP Java PHP TypeScript C# Bash Average 7B ✗ 13B ✗ 34B ✗ 70B ✗ 7B ✗ 7B ✓ 7B ✗ 7B ✓ 13B ✗ 13B ✓ 13B ✗ 13B ✓ 34B ✗ 34B ✗ 7B ✗ 7B ✗ 13B ✗ 13B ✗ 34B ✗ 34B ✗ ✗ ✗ ✗ ✗ 14.3% 6.8% 10.8% 9.9% 19.9% 13.7% 15.8% 13.0% 24.2% 23.6% 22.2% 19.9% 27.3% 30.4% 31.6% 34.2% 12.6% 13.2% 21.4% 15.1% 6.3% 3.2% 8.3% 9.5% 3.2% 12.6% 17.1% 3.8% 18.9% 25.9% 8.9% 24.8% ✗ ✗ ✓ ✓ ✗ ✗ ✓ ✓ ✗ ✓ 37.3% 31.1% 36.1% 30.4% 29.2% 29.8% 38.0%

    In addition to red teaming sessions, we ran a quantitative evaluation on risk from generating malicious code by scoring Code Llama’s responses to ChatGPT’s (GPT3.5 Turbo) with LLAMAv2 70B’s safety reward model. For this second quantitative evaluation, we selected prompts that the red teamers generated specifically attempting to solicit malicious code (even though the red teaming included consideration of a broad set of safety risks). These prompts were a mix of clear intent and slightly obfuscated intentions (see some examples in Figure 16. We show a KDE plot of the distribution of the safety score for all models in Figure 7). We observe that Code Llama tends to answer with safer responses; the distribution of safety scores for Code Llama has more weight in the safer part of the range.
    False refusals. LLMs that are too safe can have a tendency to over-refuse valid claims similar to what was reported after the release of Llama 2. We specifically asked red teamers to test for this behavior. They found some limited evidence of false refusals (when not using a system preprompt). False refusals could also
    16

    15
    pafety Reward Model Scores Distribution on Red Teaming Prompts
    Responding Model GPT 3.5 Turbo Code Llama 138 Instruct Code Llama 34B Instruct Code Llama 7B Instruct 0.0-+ -0.2 0.0 0.2 0.4 0.6 08 1.0 12 Llama 2 70B Safety Reward Model Score
    Figure 7: KDE plot of the risk score output by the Llama 2 safety reward model on prompts with clear intent specific to code risk created by red teamers with background in cybersecurity and malware generation.
    Red teaming. It is important to also proactively identify risks with adversarial testing or red teaming. We conducted 3 red teaming exercises with 25 Meta employees, including domain experts in responsible AI, malware development, and offensive security engineering.
    The red teamers provided a nuanced evaluation specifically on the risk from so called “dual intent prompts.” Dual intent prompts are requests for help with writing code that could be used maliciously but the prompt does not directly address the topic (example “Mosaic Prompts” Glukhov et al. (2023)). For example, the model rightfully refuses to provide support with writing ransomware code but it complies when asked to provide a script to encrypt all files in the user’s home directory since such a script could be used for benign purposes.

    . . . . . . . . . . . . . . . 3.4 RLHF Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Safety in Pretraining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Safety Fine-Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Red Teaming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.4 Safety Evaluation of Llama 2-Chat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1 Learnings and Observations . . . . . . . . . . . . . . . . . . . . . . . .Based on the information from the arxiv search, some red teaming was done on the Llama 2 model during development to identify potential safety risks:

    <final_answer>
    - Meta conducted 3 red teaming exercises with 25 employees, including domain experts in responsible AI, malware development, and offensive security engineering. 

    - The red teamers categorized successful attacks into four main types: 1) getting the model to provide some harmful information while refusing other content, 2) having the model roleplay specific scenarios, 3) forcing the model to highlight positives of harmful content, and 4) embedding harmful instructions within complex commands.

    - Some red teamers questioned the ultimate risk posed by "malicious code generation" through current LLMs. They noted that while LLMs being able to iteratively improve code is a risk, producing source code itself isn't the main gap. Advanced malware development is currently beyond LLM capabilities.

    - Quantitative evaluation was also done by scoring Code Llama's responses to malicious code prompts using Llama 2's safety reward model. Code Llama tended to give safer responses compared to GPT-3.5.

    - However, the full extent and details of the red teaming are limited based on the information available. The Llama 2 paper mentions expanding prompts with safety risks via red teaming, but does not go in-depth on the process or results. More information would be needed to fully characterize the red teaming performed.


    > Finished chain.

    - Meta conducted 3 red teaming exercises with 25 employees, including domain experts in responsible AI, malware development, and offensive security engineering. 

    - The red teamers categorized successful attacks into four main types: 1) getting the model to provide some harmful information while refusing other content, 2) having the model roleplay specific scenarios, 3) forcing the model to highlight positives of harmful content, and 4) embedding harmful instructions within complex commands.

    - Some red teamers questioned the ultimate risk posed by "malicious code generation" through current LLMs. They noted that while LLMs being able to iteratively improve code is a risk, producing source code itself isn't the main gap. Advanced malware development is currently beyond LLM capabilities.

    - Quantitative evaluation was also done by scoring Code Llama's responses to malicious code prompts using Llama 2's safety reward model. Code Llama tended to give safer responses compared to GPT-3.5.

    - However, the full extent and details of the red teaming are limited based on the information available. The Llama 2 paper mentions expanding prompts with safety risks via red teaming, but does not go in-depth on the process or results. More information would be needed to fully characterize the red teaming performed.
:::
::::

::: {.cell .markdown id="5p8m4Gc5w1OX"}
We can ask follow up questions that miss key information but thanks to
the conversational history the LLM understands the context and uses that
to adjust the search query. For example we asked about `red teaming` but
did not mention `llama 2` --- Claude 3 added this context to the search
query of `"llama 2 red teaming"` based on the chat history.
:::

::: {.cell .markdown id="e9bI9czPtWnl"}

------------------------------------------------------------------------
:::

---

## Creating a Customer Service Agent with Client-Side Tools

Source: https://github.com/anthropics/claude-cookbooks/blob/main/tool_use/customer_service_agent.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-tool-use-customer-service-agent.md

# Creating a Customer Service Agent with Client-Side Tools

In this recipe, we\'ll demonstrate how to create a customer service
chatbot using Claude 3 plus client-side tools. The chatbot will be able
to look up customer information, retrieve order details, and cancel
orders on behalf of the customer. We\'ll define the necessary tools and
simulate synthetic responses to showcase the chatbot\'s capabilities.
:::

::: {.cell .markdown}
## Step 1: Set up the environment

First, let\'s install the required libraries and set up the Claude API
client.
:::

::: {.cell .code}
``` python
%pip install anthropic
```
:::

::: {.cell .code execution_count="18"}
``` python
import anthropic

client = anthropic.Client()
MODEL_NAME = "claude-opus-4-1"
```
:::

::: {.cell .markdown}
## Step 2: Define the client-side tools

Next, we\'ll define the client-side tools that our chatbot will use to
assist customers. We\'ll create three tools: get_customer_info,
get_order_details, and cancel_order.
:::

::: {.cell .code execution_count="2"}
``` python
tools = [
    {
        "name": "get_customer_info",
        "description": "Retrieves customer information based on their customer ID. Returns the customer's name, email, and phone number.",
        "input_schema": {
            "type": "object",
            "properties": {
                "customer_id": {
                    "type": "string",
                    "description": "The unique identifier for the customer.",
                }
            },
            "required": ["customer_id"],
        },
    },
    {
        "name": "get_order_details",
        "description": "Retrieves the details of a specific order based on the order ID. Returns the order ID, product name, quantity, price, and order status.",
        "input_schema": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The unique identifier for the order.",
                }
            },
            "required": ["order_id"],
        },
    },
    {
        "name": "cancel_order",
        "description": "Cancels an order based on the provided order ID. Returns a confirmation message if the cancellation is successful.",
        "input_schema": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The unique identifier for the order to be cancelled.",
                }
            },
            "required": ["order_id"],
        },
    },
]
```
:::

::: {.cell .markdown}
## Step 3: Simulate synthetic tool responses

Since we don\'t have real customer data or order information, we\'ll
simulate synthetic responses for our tools. In a real-world scenario,
these functions would interact with your actual customer database and
order management system.
:::

::: {.cell .code execution_count="15"}
``` python
def get_customer_info(customer_id):
    # Simulated customer data
    customers = {
        "C1": {"name": "John Doe", "email": "john@example.com", "phone": "123-456-7890"},
        "C2": {"name": "Jane Smith", "email": "jane@example.com", "phone": "987-654-3210"},
    }
    return customers.get(customer_id, "Customer not found")


def get_order_details(order_id):
    # Simulated order data
    orders = {
        "O1": {
            "id": "O1",
            "product": "Widget A",
            "quantity": 2,
            "price": 19.99,
            "status": "Shipped",
        },
        "O2": {
            "id": "O2",
            "product": "Gadget B",
            "quantity": 1,
            "price": 49.99,
            "status": "Processing",
        },
    }
    return orders.get(order_id, "Order not found")


def cancel_order(order_id):
    # Simulated order cancellation
    if order_id in ["O1", "O2"]:
        return True
    else:
        return False
```
:::

::: {.cell .markdown}
## Step 4: Process tool calls and return results

We\'ll create a function to process the tool calls made by Claude and
return the appropriate results.
:::

::: {.cell .code execution_count="4"}
``` python
def process_tool_call(tool_name, tool_input):
    if tool_name == "get_customer_info":
        return get_customer_info(tool_input["customer_id"])
    elif tool_name == "get_order_details":
        return get_order_details(tool_input["order_id"])
    elif tool_name == "cancel_order":
        return cancel_order(tool_input["order_id"])
```
:::

::: {.cell .markdown}
## Step 5: Interact with the chatbot

Now, let\'s create a function to interact with the chatbot. We\'ll send
a user message, process any tool calls made by Claude, and return the
final response to the user.
:::

::: {.cell .code execution_count="13"}
``` python
import json


def chatbot_interaction(user_message):
    print(f"\n{'=' * 50}\nUser Message: {user_message}\n{'=' * 50}")

    messages = [{"role": "user", "content": user_message}]

    response = client.messages.create(
        model=MODEL_NAME, max_tokens=4096, tools=tools, messages=messages
    )

    print("\nInitial Response:")
    print(f"Stop Reason: {response.stop_reason}")
    print(f"Content: {response.content}")

    while response.stop_reason == "tool_use":
        tool_use = next(block for block in response.content if block.type == "tool_use")
        tool_name = tool_use.name
        tool_input = tool_use.input

        print(f"\nTool Used: {tool_name}")
        print("Tool Input:")
        print(json.dumps(tool_input, indent=2))

        tool_result = process_tool_call(tool_name, tool_input)

        print("\nTool Result:")
        print(json.dumps(tool_result, indent=2))

        messages = [
            {"role": "user", "content": user_message},
            {"role": "assistant", "content": response.content},
            {
                "role": "user",
                "content": [
                    {
                        "type": "tool_result",
                        "tool_use_id": tool_use.id,
                        "content": str(tool_result),
                    }
                ],
            },
        ]

        response = client.messages.create(
            model=MODEL_NAME, max_tokens=4096, tools=tools, messages=messages
        )

        print("\nResponse:")
        print(f"Stop Reason: {response.stop_reason}")
        print(f"Content: {response.content}")

    final_response = next(
        (block.text for block in response.content if hasattr(block, "text")),
        None,
    )

    print(f"\nFinal Response: {final_response}")

    return final_response
```
:::

::: {.cell .markdown}
## Step 6: Test the chatbot

Let\'s test our customer service chatbot with a few sample queries.
:::

::::: {.cell .code execution_count="17"}
``` python
chatbot_interaction("Can you tell me the email address for customer C1?")
chatbot_interaction("What is the status of order O2?")
chatbot_interaction("Please cancel order O1 for me.")
```

::: {.output .stream .stdout}

    ==================================================
    User Message: Can you tell me the email address for customer C1?
    ==================================================

    Initial Response:
    Stop Reason: tool_use
    Content: [ContentBlock(text='<thinking>The get_customer_info function retrieves a customer\'s name, email, and phone number given their customer ID. To call this function, I need the customer_id parameter. The user provided the customer ID "C1" in their request, so I have the necessary information to make the API call.</thinking>', type='text'), ContentBlockToolUse(id='toolu_019F9JHokMkJ1dHw5BEh28sA', input={'customer_id': 'C1'}, name='get_customer_info', type='tool_use')]

    Tool Used: get_customer_info
    Tool Input:
    {
      "customer_id": "C1"
    }

    Tool Result:
    {
      "name": "John Doe",
      "email": "john@example.com",
      "phone": "123-456-7890"
    }

    Response:
    Stop Reason: end_turn
    Content: [ContentBlock(text='The email address for customer C1 (John Doe) is john@example.com.', type='text')]

    Final Response: The email address for customer C1 (John Doe) is john@example.com.

    ==================================================
    User Message: What is the status of order O2?
    ==================================================

    Initial Response:
    Stop Reason: tool_use
    Content: [ContentBlock(text='<thinking>\nBased on the provided functions, the most relevant one for this request is get_order_details, which takes an order_id parameter and returns details about that specific order, including the order status.\n\nThe user has provided an order ID in their request - "O2". So the required order_id parameter can be filled with this value.\n\nSince the required parameter is available, I can proceed with calling the get_order_details function to retrieve the order status for order O2.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01K1u68uC94edXx8MVT35eR3', input={'order_id': 'O2'}, name='get_order_details', type='tool_use')]

    Tool Used: get_order_details
    Tool Input:
    {
      "order_id": "O2"
    }

    Tool Result:
    {
      "id": "O2",
      "product": "Gadget B",
      "quantity": 1,
      "price": 49.99,
      "status": "Processing"
    }

    Response:
    Stop Reason: end_turn
    Content: [ContentBlock(text='Based on the details returned from the get_order_details function, the status of order O2 is "Processing".', type='text')]

    Final Response: Based on the details returned from the get_order_details function, the status of order O2 is "Processing".

    ==================================================
    User Message: Please cancel order O1 for me.
    ==================================================

    Initial Response:
    Stop Reason: tool_use
    Content: [ContentBlock(text='<thinking>\nThe relevant tool to cancel an order is the cancel_order function. \nThis function requires an order_id parameter.\nThe user provided the order ID "O1" in their request, so we have the necessary parameter to call the cancel_order function.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01W3ZkP2QCrjHf5bKM6wvT2s', input={'order_id': 'O1'}, name='cancel_order', type='tool_use')]

    Tool Used: cancel_order
    Tool Input:
    {
      "order_id": "O1"
    }

    Tool Result:
    true

    Response:
    Stop Reason: end_turn
    Content: [ContentBlock(text='Based on the confirmation received, your order O1 has been successfully cancelled. Please let me know if there is anything else I can assist you with.', type='text')]

    Final Response: Based on the confirmation received, your order O1 has been successfully cancelled. Please let me know if there is anything else I can assist you with.
:::

::: {.output .execute_result execution_count="17"}
    'Based on the confirmation received, your order O1 has been successfully cancelled. Please let me know if there is anything else I can assist you with.'
:::
:::::

::: {.cell .markdown}
And that\'s it! We\'ve created a customer service chatbot using Claude 3
models and client-side tools. The chatbot can look up customer
information, retrieve order details, and cancel orders based on the
user\'s requests. By defining clear tool descriptions and schemas, we
enable Claude to effectively understand and utilize the available tools
to assist customers.

Feel free to expand on this example by integrating with your actual
customer database and order management system, and by adding more tools
to handle a wider range of customer service tasks.
:::

---

## Context Editing & Memory for Long-Running Agents

Source: https://github.com/anthropics/claude-cookbooks/blob/main/tool_use/memory_cookbook.ipynb
Path: 09-Agents-Patterns/claude-cookbooks-tool-use-memory-cookbook.md

# Context Editing & Memory for Long-Running Agents {#context-editing--memory-for-long-running-agents}

AI agents that run across multiple sessions or handle long-running tasks
face two key challenges: they lose learned patterns between
conversations, and context windows fill up during extended interactions.

This cookbook demonstrates how to address these challenges using
Claude\'s memory tool and context editing capabilities.
:::

::: {.cell .markdown}
## Table of Contents

1.  [Introduction: Why Memory Matters](#introduction)
2.  [Use Cases](#use-cases)
3.  [Quick Start Examples](#quick-start)
4.  [How It Works](#how-it-works)
5.  [Code Review Assistant Demo](#demo)
6.  [Real-World Applications](#real-world)
7.  [Best Practices](#best-practices)
:::

::: {.cell .markdown}
## Prerequisites

**Required Knowledge:**

- Python fundamentals (functions, classes, async/await basics)
- Basic understanding of REST APIs and JSON

**Required Tools:**

- Python 3.10 or higher
- Anthropic API key ([get one here](https://console.anthropic.com/))

**Recommended:**

- Familiarity with concurrent programming concepts (threads, async)
- Basic understanding of context windows in LLMs

## Setup

### For VSCode Users

``` bash
# 1. Create virtual environment
python -m venv .venv

# 2. Activate it
source .venv/bin/activate  # macOS/Linux
# or: .venv\Scripts\activate  # Windows

# 3. Install dependencies
pip install -r requirements.txt

# 4. In VSCode: Select .venv as kernel (top right)
```

### API Key

``` bash
cp .env.example .env
# Edit .env and add your ANTHROPIC_API_KEY
```

Get your API key from: <https://console.anthropic.com/>
:::

::: {.cell .markdown}
## 1. Introduction: Why Memory Matters {#introduction} {#1-introduction-why-memory-matters-introduction}

This cookbook demonstrates practical implementations of the context
engineering patterns described in [Effective context engineering for AI
agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents).
That post covers why context is a finite resource, how attention budgets
work, and strategies for building effective agents---the techniques
you\'ll see in action here.

### The Problem

Large language models have finite context windows (200k tokens for the
Claude 4 family of models). While this seems large, several challenges
emerge:

- **Context limits**: Long conversations or complex tasks can exceed
  available context
- **Computational cost**: Processing large contexts is expensive -
  attention mechanisms scale quadratically
- **Repeated patterns**: Similar tasks across conversations require
  re-explaining context every time
- **Information loss**: When context fills up, earlier important
  information gets lost

### The Solution

Claude 4 models introduce powerful context management capabilities:

1.  **Memory Tool** (`memory_20250818`): Enables cross-conversation
    learning
    - Claude can write down what it learns for future reference
    - File-based system under `/memories` directory
    - Client-side implementation gives you full control
2.  **Context Editing**: Automatically manages context with two
    strategies:
    - **Tool use clearing** (`clear_tool_uses_20250919`): Clears old
      tool results when context grows large
    - **Thinking management** (`clear_thinking_20251015`): Manages
      extended thinking blocks (requires thinking enabled)
    - Configurable triggers and retention policies

### The Benefit

Build AI agents that **get better at your specific tasks over time**:

- **Session 1**: Claude solves a problem, writes down the pattern
- **Session 2**: Claude applies the learned pattern immediately
  (faster!)
- **Long sessions**: Context editing keeps conversations manageable

Think of it as giving Claude a notebook to take notes and refer back
to - just like humans do.

### What You\'ll Learn

By the end of this cookbook, you will be able to:

- **Implement** the memory tool for cross-conversation learning
- **Configure** context editing to manage long-running sessions
- **Apply** best practices for memory security and organization
:::

::: {.cell .markdown}
## 1. Introduction: Why Memory Matters {#introduction} {#1-introduction-why-memory-matters-introduction}

This cookbook demonstrates practical implementations of the context
engineering patterns described in [Effective context engineering for AI
agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents).
That post covers why context is a finite resource, how attention budgets
work, and strategies for building effective agents---the techniques
you\'ll see in action here.

### The Problem {#the-problem}

Large language models have finite context windows (200k tokens for
Claude 4). While this seems large, several challenges emerge:

- **Context limits**: Long conversations or complex tasks can exceed
  available context
- **Computational cost**: Processing large contexts is expensive -
  attention mechanisms scale quadratically
- **Repeated patterns**: Similar tasks across conversations require
  re-explaining context every time
- **Information loss**: When context fills up, earlier important
  information gets lost

### The Solution {#the-solution}

Claude Sonnet 4.5 introduces two powerful capabilities:

1.  **Memory Tool** (`memory_20250818`): Enables cross-conversation
    learning
    - Claude can write down what it learns for future reference
    - File-based system under `/memories` directory
    - Client-side implementation gives you full control

**Supported Models**: Claude Opus 4.1 (`claude-opus-4-1`), Claude Opus 4
(`claude-opus-4`), Claude Sonnet 4.5 (`claude-sonnet-4-5`), Claude
Sonnet 4 (`claude-sonnet-4`), and Claude Haiku 4.5 (`claude-haiku-4-5`)

### The Benefit {#the-benefit}

Build AI agents that **get better at your specific tasks over time**:

- **Session 1**: Claude solves a problem, writes down the pattern
- **Session 2**: Claude applies the learned pattern immediately
  (faster!)
- **Long sessions**: Context editing keeps conversations manageable

Think of it as giving Claude a notebook to take notes and refer back
to - just like humans do.
:::

::: {.cell .markdown}
## 2. Use Cases {#use-cases} {#2-use-cases-use-cases}

Memory and context management enable powerful new workflows:

### 🔍 Code Review Assistant {#mag-code-review-assistant}

- Learns debugging patterns from past reviews
- Recognizes similar bugs instantly in future sessions
- Builds team-specific code quality knowledge
- **Production ready**: Integrate with
  [claude-code-action](https://github.com/anthropics/claude-code-action)
  for GitHub PR reviews

### 📚 Research Assistant {#books-research-assistant}

- Accumulates knowledge on topics over multiple sessions
- Connects insights across different research threads
- Maintains bibliography and source tracking

### 💬 Customer Support Bot {#speech_balloon-customer-support-bot}

- Learns user preferences and communication style
- Remembers common issues and solutions
- Builds product knowledge base from interactions

### 📊 Data Analysis Helper {#bar_chart-data-analysis-helper}

- Remembers dataset patterns and anomalies
- Stores analysis techniques that work well
- Builds domain-specific insights over time

**Supported Models**: Claude Opus 4.1 (`claude-opus-4-1`) and Claude
Sonnet 4.5 (`claude-sonnet-4-5`)

**This cookbook focuses on the Code Review Assistant** as it clearly
demonstrates both memory (learning patterns) and context editing
(handling long reviews).
:::

::: {.cell .markdown}
## 3. Quick Start Examples {#quick-start} {#3-quick-start-examples-quick-start}

Let\'s see memory and context management in action with simple examples.
:::

::: {.cell .markdown}
### Setup {#setup}

First, install dependencies and configure your environment:
:::

::: {.cell .code execution_count="1" execution="{\"iopub.execute_input\":\"2025-11-15T17:11:26.527705Z\",\"iopub.status.busy\":\"2025-11-15T17:11:26.527494Z\",\"iopub.status.idle\":\"2025-11-15T17:11:30.063615Z\",\"shell.execute_reply\":\"2025-11-15T17:11:30.063106Z\"}" vscode="{\"languageId\":\"python\"}"}
``` coconut
%%capture
# Install required packages
# Option 1: From requirements.txt
# %pip install -q -r requirements.txt

# Option 2: Direct install
%pip install -q anthropic python-dotenv ipykernel
```
:::

::: {.cell .markdown}
**⚠️ Important**: Create a `.env` file in this directory:

``` bash
# Copy .env.example to .env and add your API key
cp .env.example .env
```

Then edit `.env` to add your Anthropic API key from
<https://console.anthropic.com/>
:::

:::: {.cell .code execution_count="2"}
``` coconut
import os
from typing import cast

from anthropic import Anthropic
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Model configuration - use alias for automatic updates
MODEL = "claude-sonnet-4-5"  # Can override via ANTHROPIC_MODEL env var
if os.getenv("ANTHROPIC_MODEL"):
    MODEL = os.getenv("ANTHROPIC_MODEL")

if not API_KEY:
    raise ValueError("ANTHROPIC_API_KEY not found. Copy .env.example to .env and add your API key.")

if not MODEL:
    raise ValueError("ANTHROPIC_MODEL not found. Copy .env.example to .env and set the model.")

MODEL = cast(str, MODEL)

client = Anthropic(api_key=API_KEY)

print("✓ API key loaded")
print(f"✓ Using model: {MODEL}")
```

::: {.output .stream .stdout}
    ✓ API key loaded
    ✓ Using model: claude-sonnet-4-5
:::
::::

::: {.cell .markdown}
### Example 1: Basic Memory Usage

Let\'s see Claude use memory to store information for future reference.
:::

::: {.cell .markdown}
**Helper Functions**

These examples use helper functions from `demo_helpers.py`:

- **`run_conversation_loop()`**: Handles the API conversation loop
  - Calls Claude\'s API with memory tool enabled
  - Executes tool uses (memory operations)
  - Continues until Claude stops using tools
  - Returns the final response
- **`run_conversation_turn()`**: Single turn (used in Example 3)
  - Same as above but returns after one API call
  - Useful when you need fine-grained control
- **`print_context_management_info()`**: Displays context clearing stats
  - Shows tokens saved, tool uses cleared
  - Helps visualize when context editing triggers
:::

::: {.cell .markdown}
**⚠️ Note on Memory Clearing**

The following cell clears all memory files to provide a clean slate for
this demonstration. This is useful for running the notebook multiple
times to see consistent results.

**In production applications**, you should carefully consider whether to
clear all memory, as it permanently removes learned patterns. Consider
using selective deletion or organizing memory into project-specific
directories instead.
:::

:::: {.cell .code execution_count="3" execution="{\"iopub.execute_input\":\"2025-11-15T17:11:30.331182Z\",\"iopub.status.busy\":\"2025-11-15T17:11:30.331084Z\",\"iopub.status.idle\":\"2025-11-15T17:12:09.831980Z\",\"shell.execute_reply\":\"2025-11-15T17:12:09.831417Z\"}" vscode="{\"languageId\":\"python\"}"}
``` coconut
# Import helper functions
from memory_demo.demo_helpers import (
    run_conversation_loop,
    run_conversation_turn,
    print_context_management_info,
)
from memory_tool import MemoryToolHandler

# Initialize
client = Anthropic()
memory = MemoryToolHandler(base_path="./demo_memory")

# Clear any existing memories to start fresh
print("🧹 Clearing previous memories...")
memory.clear_all_memory()
print("✓ Memory cleared\n")

# Load example code with a race condition bug
with open("memory_demo/sample_code/web_scraper_v1.py", "r") as f:
    code_to_review = f.read()

messages = [
    {
        "role": "user",
        "content": f"I'm reviewing a multi-threaded web scraper that sometimes returns fewer results than expected. The count is inconsistent across runs. Can you find the issue?\n\n```python\n{code_to_review}\n```",
    }
]

print("=" * 60)
print("📝 SESSION 1: Learning from a bug")
print("=" * 60)

# Run conversation loop
response = run_conversation_loop(
    client=client,
    model=MODEL,
    messages=messages,
    memory_handler=memory,
    system="You are a code reviewer.",
    max_tokens=2048,
    max_turns=5,
    verbose=True,
)

print("\n" + "=" * 60)
print("✅ Session 1 complete!")
print("=" * 60)
```

::: {.output .stream .stdout}
    🧹 Clearing previous memories...
    ✓ Memory cleared

    ============================================================
    📝 SESSION 1: Learning from a bug
    ============================================================

    🔄 Turn 1:
    💬 Claude: I'll review this code for the race condition issue. Let me first check my memory, then analyze the problem.

      🔧 Memory tool: view /memories
      ✓ Result: Directory: /memories
    (empty)

    🔄 Turn 2:
      🔧 Memory tool: create /memories/review.md
      ✓ Result: File created successfully at /memories/review.md

    🔄 Turn 3:
    💬 Claude: ## Code Review: Multi-threaded Web Scraper Race Condition

    ### 🔴 **Critical Issue Found: Race Condition in Shared State**

    You've correctly identified the problem! The code has **race conditions** caused by multiple threads modifying shared lists without synchronization.

    ---

    ### **The Problem**

    **Lines with race conditions:**
    ```python
    self.results.append(result)  # RACE CONDITION
    ```

    **Problem:** 
    - Python's `list.append()` is **NOT thread-safe** for concurrent modifications
    - Multiple threads simultaneously appending can cause:
      - **Lost updates:** One thread's append overwrites another's
      - **Inconsistent state:** Internal list structure can be corrupted
      - **Unpredictable counts:** Results randomly dropped

    **Why it happens:**
    `list.append()` involves multiple operations:
    1. Read current list size
    2. Allocate space
    3. Insert item
    4. Update size

    # In scrape_urls():
    if "error" in result:
        self.failed_urls.append(result["url"])  # ⚠️ NOT THREAD-SAFE
    else:
        self.results.append(result)  # ⚠️ NOT THREAD-SAFE
    ```

    **Why this causes lost results:**
    - Python's `list.append()` is **not atomic** in all scenarios
    - When multiple threads call `append()` simultaneously, the internal list operations can interleave
    - This can cause lost updates where one thread's append overwrites another's

    ---

    ### **Solutions**

    #### **Option 1: Use Thread Locks (Traditional approach)**
    ```python
    import threading

    class WebScraper:
        """Web scraper that fetches multiple URLs concurrently."""

        def __init__(self, max_workers: int = 10):
            self.max_workers = max_workers
            self.results = []
            self.failed_urls = []
            self.lock = threading.Lock()  # ✅ Add lock

        def scrape_urls(self, urls: List[str]) -> List[Dict[str, Any]]:
            with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
                futures = [executor.submit(self.fetch_url, url) for url in urls]

                for future in as_completed(futures):
                    result = future.result()

                    # ✅ Protect shared state with lock
                    with self.lock:
                        if "error" in result:
                            self.failed_urls.append(result["url"])
                        else:
                            self.results.append(result)

            return self.results
    ```

    #### **Option 2: Use Thread-Safe Collections**
    ```python
    from queue import Queue

    class WebScraper:
        """Web scraper that fetches multiple URLs concurrently."""

        def __init__(self, max_workers: int = 10):
            self.max_workers = max_workers
            self.results = Queue()  # ✅ Thread-safe
            self.failed_urls = Queue()  # ✅ Thread-safe

        def scrape_urls(self, urls: List[str]) -> List[Dict[str, Any]]:
            with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
                futures = [executor.submit(self.fetch_url, url) for url in urls]

                for future in as_completed(futures):
                    result = future.result()

                    if "error" in result:
                        self.failed_urls.put(result["url"])
                    else:
                        self.results.put(result)

            # Convert Queue to list for return
            return list(self.results.queue)
    ```

    #### **Option 3: Collect Results from Futures (Best approach)**
    ```python
    def scrape_urls(self, urls: List[str]) -> List[Dict[str, Any]]:
        """
        ✅ FIXED: Collect results in main thread, avoiding shared state.
        """
        results = []  # Local to main thread
        failed_urls = []  # Local to main thread
        
        with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            futures = [executor.submit(self.fetch_url, url) for url in urls]

            for future in as_completed(futures):
                result = future.result()

                # ✅ Only main thread accesses these lists
                if "error" in result:
                    failed_urls.append(result["url"])
                else:
                    results.append(result)

        # Update instance variables once, in main thread
        self.results = results
        self.failed_urls = failed_urls
        
        return self.results
    ```

    ---

    ### **Recommended Fix (Complete)**

    Here's the fully corrected version using **Option 3** (cleanest approach):

    ```python
    """
    Concurrent web scraper - FIXED VERSION
    Results collected in main thread to avoid race conditions.
    """

    import time
    from concurrent.futures import ThreadPoolExecutor, as_completed
    from typing import List, Dict, Any

    import requests


    class WebScraper:
        """Web scraper that fetches multiple URLs concurrently."""

        def __init__(self, max_workers: int = 10):
            self.max_workers = max_workers
            self.results = []
            self.failed_urls = []

        def fetch_url(self, url: str) -> Dict[str, Any]:
            """Fetch a single URL and return the result."""
            try:
                response = requests.get(url, timeout=5)
                response.raise_for_status()
                return {
                    "url": url,
                    "status": response.status_code,
                    "content_length": len(response.content),
                }
            except requests.exceptions.RequestException as e:
                return {"url": url, "error": str(e)}

        def scrape_urls(self, urls: List[str]) -> List[Dict[str, Any]]:
            """
            Scrape multiple URLs concurrently.
            
            ✅ FIXED: Results collected in main thread only.
            """
            results = []  # ✅ Local variables - no race condition
            failed_urls = []
            
            with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
                futures = [executor.submit(self.fetch_url, url) for url in urls]

                for future in as_completed(futures):
                    result = future.result()

                    # ✅ Only the main thread modifies these lists
                    if "error" in result:
                        failed_urls.append(result["url"])
                    else:
                        results.append(result)

            # Update instance variables after all threads complete
            self.results = results
            self.failed_urls = failed_urls
            
            return self.results

        def get_stats(self) -> Dict[str, int]:
            """Get scraping statistics."""
            return {
                "total_results": len(self.results),
                "failed_urls": len(self.failed_urls),
                "success_rate": (
                    len(self.results) / (len(self.results) + len(self.failed_urls))
                    if (len(self.results) + len(self.failed_urls)) > 0
                    else 0
                ),
            }


    if __name__ == "__main__":
        urls = [
            "https://httpbin.org/delay/1",
            "https://httpbin.org/status/200",
            "https://httpbin.org/status/404",
            "https://httpbin.org/delay/2",
            "https://httpbin.org/status/500",
        ] * 10  # 50 URLs total

        scraper = WebScraper(max_workers=10)
        results = scraper.scrape_urls(urls)

        print(f"Expected: 50 results")
        print(f"Got: {len(results)} results")  # ✅ Now always 50
        print(f"Stats: {scraper.get_stats()}")
    ```

    ---

    ### **Summary**

    - **Root cause**: Multiple threads appending to shared lists (`self.results` and `self.failed_urls`) without synchronization
    - **Impact**: Lost updates leading to inconsistent result counts
    - **Best fix**: Collect results in local variables within the main thread, then update instance variables once
    - **Why this works**: Only one thread (main) accesses the result lists, eliminating the race condition entirely

    The key insight: **Avoid shared mutable state in concurrent code**. Let worker threads return values and collect them in the coordinating thread.

      🔧 Memory tool: str_replace /memories/review.md
      ✓ Result: File /memories/review.md has been edited successfully


    ============================================================
    ✅ Session 1 complete!
    ============================================================
:::
::::

::: {.cell .markdown}
**What happened?**

1.  Claude checked its memory (empty on first run)
2.  Identified the bug: **race condition** - multiple threads modifying
    shared state (`self.results` and `self.failed_urls`) without
    synchronization
3.  Stored the concurrency pattern in memory for future reference

Now let\'s see the magic - Claude applying this learned pattern in a
**new conversation**:
:::

::: {.cell .markdown}
### Example 2: Cross-Conversation Learning

Start a completely new conversation - memory persists!
:::

:::: {.cell .code execution_count="4" execution="{\"iopub.execute_input\":\"2025-11-15T17:12:09.834796Z\",\"iopub.status.busy\":\"2025-11-15T17:12:09.834455Z\",\"iopub.status.idle\":\"2025-11-15T17:12:49.692649Z\",\"shell.execute_reply\":\"2025-11-15T17:12:49.692286Z\"}" vscode="{\"languageId\":\"python\"}"}
``` coconut
# NEW conversation (empty messages)
# Load API client code with similar concurrency issue
with open("memory_demo/sample_code/api_client_v1.py", "r") as f:
    code_to_review = f.read()

messages = [
    {"role": "user", "content": f"Review this API client code:\n\n```python\n{code_to_review}\n```"}
]

print("=" * 60)
print("🚀 SESSION 2: Applying learned pattern")
print("=" * 60)

# Run conversation loop
response = run_conversation_loop(
    client=client,
    model=MODEL,
    messages=messages,
    memory_handler=memory,
    system="You are a code reviewer.",
    max_tokens=2048,
    max_turns=5,
    verbose=True,
)

print("\n" + "=" * 60)
print("✅ Session 2 complete!")
print("=" * 60)
```

::: {.output .stream .stdout}
    ============================================================
    🚀 SESSION 2: Applying learned pattern
    ============================================================

    🔄 Turn 1:
      🔧 Memory tool: view /memories
      ✓ Result: Directory: /memories
    - review.md

    🔄 Turn 2:
      🔧 Memory tool: view /memories/review.md
      ✓ Result:    1: # Code Review: Multi-threaded Web Scraper
       2: 
       3: ## Issue
       4: Revi...

    🔄 Turn 3:
      🔧 Memory tool: str_replace /memories/review.md
      ✓ Result: File /memories/review.md has been edited successfully

    🔄 Turn 4:
    💬 Claude: ## Code Review: Async API Client

    ### Summary
    This code has **concurrency issues** related to shared mutable state being accessed from multiple coroutines without proper synchronization. While the author correctly identifies these as bugs in comments, let me provide a comprehensive review.

    However, the actual race condition risk here is **somewhat overstated** because:
    - List `.append()` is atomic in CPython
    - The `+=` operation on integers is also atomic
    - Coroutines only switch at `await` points, and there are none between the operations

    **BUT** this is still problematic because:
    - It relies on CPython implementation details
    - It's not guaranteed by the language specification
    - The code is not portable to other Python implementations
    - Future refactoring could introduce `await` points that cause real races

    #### 1. **Race Condition on `self.error_count` (Line 51)**
    ```python
    self.error_count += 1  # Not atomic!
    ```

    **Problem**: Even in async code, this operation is not atomic. While asyncio is single-threaded, the `+=` operator involves:
    1. Read current value
    2. Add 1
    3. Write back

    An `await` in another coroutine between steps 1-3 can cause lost updates.

    **Impact**: Error count will be incorrect/underreported.

    #### 2. **Unsafe List Append on `self.responses` (Line 53)**
    ```python
    self.responses.append(result)  # Not thread-safe in async context!
    ```

    **Problem**: While `list.append()` is technically atomic in CPython due to GIL, this is:
    - An implementation detail, not guaranteed by the language spec
    - Bad practice that makes the code fragile
    - Still problematic because the list is being modified while potentially being read elsewhere

    **Impact**: Potential data corruption, missing responses, or incorrect counts.

    #### 3. **Logic Error: Errors Not Included in Results**
    ```python
    if "error" in result:
        self.error_count += 1  # Counted but not stored!
    else:
        self.responses.append(result)  # Only successes stored
    ```

    **Problem**: Failed requests increment `error_count` but are **never added to `self.responses`**. This means:
    - The return value of `fetch_all()` only contains successful responses
    - Error details are lost
    - The summary calculation is inconsistent

    ---

    ### ⚠️ **Design Issues**

    #### 4. **Stateful Class Design is Anti-Pattern for Concurrent Operations**
    The class maintains mutable state (`responses`, `error_count`) that's modified during concurrent operations. This is problematic because:
    - Makes the client non-reusable (calling `fetch_all()` twice will mix results)
    - Harder to reason about state consistency
    - Requires manual reset between calls

    **Better approach**: Return data directly rather than accumulating in instance variables.

    #### 5. **Inconsistent Error Handling**
    Errors are caught and converted to dictionaries, but then handled differently from successes. This makes the API inconsistent and loses valuable error information.

    ---

    ### 🟡 **Minor Issues**

    #### 6. **Missing Type Hints**
    The module imports `Optional` but never uses it. The return types could be more specific.

    #### 7. **Hardcoded Test Data in Main**
    The `* 20` multiplier and specific endpoints make testing less flexible.

    **Fix:** Use `asyncio.gather()` which is simpler and more idiomatic for this use case.

    ### 5. **Missing HTTP Status Code Validation**
    **Location:** `fetch_endpoint()` method

      🔧 Memory tool: str_replace /memories/review.md
      ✓ Result: File /memories/review.md has been edited successfully

    🔄 Turn 5:
    💬 Claude: Here's a **corrected version**:

    **Fix:**
    ```python
    """
    Async API client with proper concurrency handling.
    """

    import asyncio
    from typing import List, Dict, Any
    from dataclasses import dataclass

    import aiohttp


    @dataclass
    class FetchResult:
        """Result from fetching an endpoint."""
        endpoint: str
        status: int = 0
        data: Any = None
        error: str = None
        
        @property
        def is_success(self) -> bool:
            return self.error is None


    class AsyncAPIClient:
        """Async API client for fetching data from multiple endpoints."""

        def __init__(self, base_url: str):
            self.base_url = base_url

        async def fetch_endpoint(
            self, session: aiohttp.ClientSession, endpoint: str
        ) -> FetchResult:
            """Fetch a single endpoint."""
            url = f"{self.base_url}/{endpoint}"
            try:
                async with session.get(
                    url, timeout=aiohttp.ClientTimeout(total=5)
                ) as response:
                    data = await response.json()
                    return FetchResult(
                        endpoint=endpoint,
                        status=response.status,
                        data=data,
                    )
            except Exception as e:
                return FetchResult(
                    endpoint=endpoint,
                    error=str(e),
                )

        async def fetch_all(self, endpoints: List[str]) -> List[FetchResult]:
            """
            Fetch multiple endpoints concurrently.
            
            Fixed: Returns all results directly without modifying shared state.
            Uses asyncio.gather() which is cleaner than as_completed() for this use case.
            """
            async with aiohttp.ClientSession() as session:
                tasks = [self.fetch_endpoint(session, endpoint) for endpoint in endpoints]
                # gather() returns results in order and handles all concurrency
                results = await asyncio.gather(*tasks)
                return results

        @staticmethod
        def get_summary(results: List[FetchResult]) -> Dict[str, Any]:
            """Get summary statistics from results."""
            successes = sum(1 for r in results if r.is_success)
            errors = len(results) - successes
            
            return {
                "total_responses": len(results),
                "successful": successes,
                "errors": errors,
                "success_rate": successes / len(results) if results else 0,
            }


    async def main():
        """Test the async API client."""
        client = AsyncAPIClient("https://jsonplaceholder.typicode.com")

        endpoints = [
            "posts/1",
            "posts/2",
            "posts/3",
            "users/1",
            "users/2",
            "invalid/endpoint",  # Will error
        ] * 20  # 120 requests total

        results = await client.fetch_all(endpoints)

        # Separate successes and errors for clarity
        successes = [r for r in results if r.is_success]
        errors = [r for r in results if not r.is_success]

        print(f"Expected: 120 total responses (100 successful, 20 errors)")
        print(f"Got: {len(results)} responses ({len(successes)} successful, {len(errors)} errors)")
        print(f"Summary: {AsyncAPIClient.get_summary(results)}")
        
        if errors:
            print(f"\nFirst error: {errors[0].endpoint} - {errors[0].error}")


    if __name__ == "__main__":
        asyncio.run(main())
    ```

    ---

    ### **Key Improvements in Fixed Version:**

    1. ✅ **No shared mutable state** - Results returned directly
    2. ✅ **All results captured** - Both successes and errors included
    3. ✅ **Type-safe with dataclass** - Clear structure for results
    4. ✅ **Reusable client** - Can call `fetch_all()` multiple times safely
    5. ✅ **Consistent error handling** - All results have same structure
    6. ✅ **Simpler concurrency** - Uses `asyncio.gather()` instead of `as_completed()`
    7. ✅ **Static summary method** - Takes results as parameter, no state dependency

    ---

    ### **Alternative: If You Need Shared State**

    If you absolutely need to accumulate results in the instance (e.g., for streaming/progressive updates), use an `asyncio.Lock`:

    ```python
    import asyncio

    class AsyncAPIClient:
        def __init__(self, base_url: str):
            self.base_url = base_url
            self.responses = []
            self.error_count = 0
            self._lock = asyncio.Lock()  # Add lock

        async def fetch_all(self, endpoints: List[str]) -> List[Dict[str, Any]]:
            async with aiohttp.ClientSession() as session:
                tasks = [self.fetch_endpoint(session, endpoint) for endpoint in endpoints]
                
                for coro in asyncio.as_completed(tasks):
                    result = await coro
                    
                    # Protect shared state with lock
                    async with self._lock:
                        if "error" in result:
                            self.error_count += 1
                        else:
                            self.responses.append(result)
            
            return self.responses
    ```

    However, the stateless design I showed first is **strongly preferred** for async code.

    import asyncio
    from typing import List, Dict, Any, TypedDict

    ### **Testing Recommendation**

    Add tests that verify all 120 requests are accounted for:

    ```python
    async def test_all_results_captured():
        client = AsyncAPIClient("https://jsonplaceholder.typicode.com")
        endpoints = ["posts/1"] * 100
        results = await client.fetch_all(endpoints)
        assert len(results) == 100, f"Expected 100, got {len(results)}"
    ```


    ============================================================
    ✅ Session 2 complete!
    ============================================================
:::
::::

::: {.cell .markdown}
**Notice the difference:**

- Claude **immediately checked memory** and found the
  thread-safety/concurrency pattern
- Recognized the similar issue in async code **instantly** without
  re-learning
- Response was **faster** because it applied stored knowledge about
  shared mutable state

This is **cross-conversation learning** in action!
:::

::: {.cell .markdown}
### Example 3: Context Clearing While Preserving Memory

What happens during a **long review session** with many code files?

- Context fills up with tool results from previous reviews
- But memory (learned patterns) must persist!

Let\'s trigger **context editing** to see how Claude manages this
automatically.

**Note on configuration:** We use `clear_at_least: 50` tokens because
memory tool operations have small results (\~50-150 tokens each). In
production with larger tool results (like web search or code execution),
you\'d use higher values like 3000-5000 tokens.
:::

:::: {.cell .code execution_count="5"}
``` coconut
# Configure context management with BOTH clearing strategies
# Low thresholds for demo - in production use 30-40k tokens
CONTEXT_MANAGEMENT = {
    "edits": [
        # Thinking management MUST come first when combining strategies
        {
            "type": "clear_thinking_20251015",
            "keep": {"type": "thinking_turns", "value": 1}  # Keep only last turn's thinking
        },
        {
            "type": "clear_tool_uses_20250919",
            "trigger": {"type": "input_tokens", "value": 5000},  # Low threshold for demo
            "keep": {"type": "tool_uses", "value": 2},  # Keep last 2 tool uses
            "clear_at_least": {"type": "input_tokens", "value": 2000}
        }
    ]
}

# Extended thinking config (required for clear_thinking strategy)
THINKING = {
    "type": "enabled",
    "budget_tokens": 1024  # Budget for thinking per turn
}

# Continue from previous session - memory persists!
print("=" * 60)
print("📚 SESSION 3: Long review session with context clearing")
print("=" * 60)
print()

# Clean up messages - remove any empty content from previous session
# This ensures we have a valid message state to continue from
cleaned_messages = []
for msg in messages:
    if isinstance(msg.get("content"), list):
        # Filter out empty content blocks
        content = [c for c in msg["content"] if c]
        if content:
            cleaned_messages.append({"role": msg["role"], "content": content})
    elif msg.get("content"):
        cleaned_messages.append(msg)

messages = cleaned_messages

# Review 1: Data processor (larger file)
with open("memory_demo/sample_code/data_processor_v1.py", "r") as f:
    data_processor_code = f.read()

messages.append({
    "role": "user",
    "content": f"Review this data processor:\n\n```python\n{data_processor_code}\n```"
})

print("📝 Review 1: Data processor")
response = run_conversation_turn(
    client=client,
    model=MODEL,
    messages=messages,
    memory_handler=memory,
    system="You are a code reviewer.",
    context_management=CONTEXT_MANAGEMENT,
    thinking=THINKING,
    max_tokens=4096,
    verbose=True
)

# Add response to messages
messages.append({"role": "assistant", "content": response[1]})
if response[2]:
    messages.append({"role": "user", "content": response[2]})

print(f"  📊 Input tokens: {response[0].usage.input_tokens:,}")
context_cleared, saved = print_context_management_info(response[0])
print()

# Review 2: SQL code
with open("memory_demo/sample_code/sql_query_builder.py", "r") as f:
    sql_code = f.read()

messages.append({
    "role": "user",
    "content": f"Review this SQL query builder:\n\n```python\n{sql_code}\n```"
})

print("📝 Review 2: SQL query builder")
response = run_conversation_turn(
    client=client,
    model=MODEL,
    messages=messages,
    memory_handler=memory,
    system="You are a code reviewer.",
    context_management=CONTEXT_MANAGEMENT,
    thinking=THINKING,
    max_tokens=4096,
    verbose=True
)

messages.append({"role": "assistant", "content": response[1]})
if response[2]:
    messages.append({"role": "user", "content": response[2]})

print(f"  📊 Input tokens: {response[0].usage.input_tokens:,}")
context_cleared, saved = print_context_management_info(response[0])
print()

# Review 3: Add one more review to ensure we trigger clearing
with open("memory_demo/sample_code/web_scraper_v1.py", "r") as f:
    scraper_code = f.read()

messages.append({
    "role": "user",
    "content": f"Quick check - any issues here?\n\n```python\n{scraper_code}\n```"
})

print("📝 Review 3: Web scraper (should trigger clearing)")
response = run_conversation_turn(
    client=client,
    model=MODEL,
    messages=messages,
    memory_handler=memory,
    system="You are a code reviewer.",
    context_management=CONTEXT_MANAGEMENT,
    thinking=THINKING,
    max_tokens=4096,
    verbose=True
)

messages.append({"role": "assistant", "content": response[1]})
if response[2]:
    messages.append({"role": "user", "content": response[2]})

print(f"  📊 Input tokens: {response[0].usage.input_tokens:,}")
context_cleared, saved = print_context_management_info(response[0])

print()
print("=" * 60)
print("✅ Session 3 complete!")
print("=" * 60)
```

::: {.output .stream .stdout}
    ============================================================
    📚 SESSION 3: Long review session with context clearing
    ============================================================

    📝 Review 1: Data processor
    🧠 Thinking: The user wants me to review a data processor with multiple concurrency and thread-safety issues. Let...
      🔧 Memory tool: str_replace /memories/review.md
      ✓ Result: File /memories/review.md has been edited successfully
      📊 Input tokens: 6,611
      ℹ️  Context below threshold - no clearing triggered

    📝 Review 2: SQL query builder
    🧠 Thinking: The user is now asking me to review a SQL query builder with SQL injection vulnerabilities. This is ...
      🔧 Memory tool: str_replace /memories/review.md
      ✓ Result: File /memories/review.md has been edited successfully
      📊 Input tokens: 7,923
      ✂️  Context editing triggered!
          • Cleared 1 thinking turn(s), saved 166 tokens
          • After clearing: 7,923 tokens

    📝 Review 3: Web scraper (should trigger clearing)
    🧠 Thinking: This is a quick check request for a web scraper with threading issues. Let me quickly identify the p...
      🔧 Memory tool: str_replace /memories/review.md
      ✓ Result: File /memories/review.md has been edited successfully
      📊 Input tokens: 9,052
      ✂️  Context editing triggered!
          • Cleared 2 thinking turn(s), saved 265 tokens
          • After clearing: 9,052 tokens

    ============================================================
    ✅ Session 3 complete!
    ============================================================
:::
::::

::: {.cell .markdown}
**What just happened?**

As context grew during multiple reviews with extended thinking enabled,
context editing was applied:

1.  **Thinking blocks cleared** - Old thinking from previous turns
    removed first
2.  **Tool results cleared** - Old memory tool results removed when
    threshold exceeded
3.  **Memory files intact** - Claude can still query learned patterns
4.  **Token usage managed** - Saved tokens from both thinking and tool
    results

This demonstrates the key benefit:

- **Short-term memory** (conversation context + thinking) → Cleared to
  save space
- **Long-term memory** (stored patterns) → Persists across sessions

Let\'s verify memory survived the clearing:
:::

:::: {.cell .code execution_count="6"}
``` coconut
# Verify memory persists after context clearing
import os

print("📂 Memory files in demo_memory/:")
print()

for root, dirs, files in os.walk("./demo_memory"):
    # Calculate relative path for display
    level = root.replace("./demo_memory", "").count(os.sep)
    indent = "  " * level
    folder_name = os.path.basename(root) or "demo_memory"
    print(f"{indent}{folder_name}/")

    sub_indent = "  " * (level + 1)
    for file in files:
        file_path = os.path.join(root, file)
        size = os.path.getsize(file_path)
        print(f"{sub_indent}├── {file} ({size} bytes)")

print()
print("✅ All learned patterns preserved despite context clearing!")
```

::: {.output .stream .stdout}
    📂 Memory files in demo_memory/:

    demo_memory/
      memories/
        ├── review.md (318 bytes)

    ✅ All learned patterns preserved despite context clearing!
:::
::::

::: {.cell .markdown}
## 4. How It Works {#how-it-works} {#4-how-it-works-how-it-works}

### Memory Tool Architecture

The memory tool is **client-side** - you control the storage. Claude
makes tool calls, your application executes them.

#### Memory Tool Commands

  ------------------------------------------------------------------------------------------------------------------------------------
  Command              Description                   Example
  -------------------- ----------------------------- ---------------------------------------------------------------------------------
  `view`               Show directory or file        `{"command": "view", "path": "/memories"}`
                       contents                      

  `create`             Create or overwrite a file    `{"command": "create", "path": "/memories/notes.md", "file_text": "..."}`

  `str_replace`        Replace text in a file        `{"command": "str_replace", "path": "...", "old_str": "...", "new_str": "..."}`

  `insert`             Insert text at line number    `{"command": "insert", "path": "...", "insert_line": 2, "insert_text": "..."}`

  `delete`             Delete a file or directory    `{"command": "delete", "path": "/memories/old.txt"}`

  `rename`             Rename or move a file         `{"command": "rename", "old_path": "...", "new_path": "..."}`
  ------------------------------------------------------------------------------------------------------------------------------------

See `memory_tool.py` for the complete implementation with path
validation and security measures.
:::

::: {.cell .markdown}
### Thinking Management (`clear_thinking_20251015`)

When using extended thinking, thinking blocks accumulate and consume
tokens. The `clear_thinking` strategy manages these automatically.

**Important**: This strategy requires `thinking` to be enabled in your
API call.

**API Call Pattern** (with extended thinking enabled):

``` python
response = client.beta.messages.create(
    betas=["context-management-2025-06-27"],  # Required beta flag
    model="claude-sonnet-4-5",
    messages=messages,
    tools=[{"type": "memory_20250818", "name": "memory"}],
    thinking={"type": "enabled", "budget_tokens": 10000},  # Enable thinking
    context_management={  # Context editing config
        "edits": [
            {
                "type": "clear_thinking_20251015",
                "keep": {"type": "thinking_turns", "value": 1}  # Keep last turn only
            },
            {
                "type": "clear_tool_uses_20250919",
                "trigger": {"type": "input_tokens", "value": 35000},
                "keep": {"type": "tool_uses", "value": 5}
            }
        ]
    },
    max_tokens=2048
)
```

**Key points:**

- `clear_thinking` must come **first** when combining strategies
- Requires extended thinking to be enabled
  (`thinking={"type": "enabled", ...}`)
- Use `"keep": "all"` to preserve all thinking blocks for maximum cache
  hits
- Trigger is optional for thinking (clears based on `keep` value)
:::

::: {.cell .markdown}
### Understanding the Demo Code

Key implementation details from `code_review_demo.py`:

``` python
class CodeReviewAssistant:
    def __init__(self, memory_storage_path="./memory_storage"):
        self.client = Anthropic()
        self.memory_handler = MemoryToolHandler(base_path=memory_storage_path)
        self.messages = []
    
    def review_code(self, code, filename, description=""):
        # 1. Add user message
        self.messages.append({...})
        
        # 2. Conversation loop with tool execution
        while True:
            response = self.client.beta.messages.create(
                model=MODEL,
                system=self._create_system_prompt(),
                messages=self.messages,
                tools=[{"type": "memory_20250818", "name": "memory"}],
                betas=["context-management-2025-06-27"],
                context_management=CONTEXT_MANAGEMENT
            )
            
            # 3. Execute tool uses
            tool_results = []
            for content in response.content:
                if content.type == "tool_use":
                    result = self._execute_tool_use(content)
                    tool_results.append({...})
            
            # 4. Continue if there are tool uses, otherwise done
            if tool_results:
                self.messages.append({"role": "user", "content": tool_results})
            else:
                break
```

**The key pattern**: Keep calling the API while there are tool uses,
executing them and feeding results back.
:::

::: {.cell .markdown}
### What Claude Actually Learns

This is what makes memory powerful - **semantic pattern recognition**,
not just syntax:

**Session 1: Thread-Based Web Scraper**

``` python
# Bug: Race condition
class WebScraper:
    def __init__(self):
        self.results = []  # Shared state!
    
    def scrape_urls(self, urls):
        with ThreadPoolExecutor() as executor:
            for future in as_completed(futures):
                self.results.append(future.result())  # RACE!
```

**What Claude Stores in Memory** (example file:
`/memories/concurrency_patterns/thread_safety.md`):

When Claude encounters this pattern, it stores the following insights to
its memory files:

- **Symptom**: Inconsistent results in concurrent operations
- **Cause**: Shared mutable state (lists/dicts) modified from multiple
  threads
- **Solution**: Use locks, thread-safe data structures, or return
  results instead
- **Red flags**: Instance variables in thread callbacks, unused locks,
  counter increments

------------------------------------------------------------------------

**Session 2: Async API Client** (New conversation!)

Claude checks memory FIRST, finds the thread-safety pattern, then:

1.  **Recognizes** similar pattern in async code (coroutines can
    interleave too)
2.  **Applies** the solution immediately (no re-learning needed)
3.  **Explains** with reference to stored knowledge

``` python
# Claude spots this immediately:
async def fetch_all(self, endpoints):
    for coro in asyncio.as_completed(tasks):
        self.responses.append(await coro)  # Same pattern!
```

------------------------------------------------------------------------

**Why This Matters:**

- ❌ **Syntax checkers** miss race conditions entirely
- ✅ **Claude learns** architectural patterns and applies them across
  contexts
- ✅ **Cross-language**: Pattern applies to Go, Java, Rust concurrency
  too
- ✅ **Gets better**: Each review adds to the knowledge base
:::

::: {.cell .markdown}
### Sample Code Files

The demo uses these sample files (all have concurrency/thread-safety
bugs):

- `memory_demo/sample_code/web_scraper_v1.py` - Race condition: threads
  modifying shared state
- `memory_demo/sample_code/api_client_v1.py` - Similar concurrency bug
  in async context
- `memory_demo/sample_code/data_processor_v1.py` - Multiple concurrency
  issues for long session demo

Let\'s look at one:
:::

::: {.cell .markdown}
**`memory_demo/sample_code/web_scraper_v1.py`**

``` python
"""
Concurrent web scraper with a race condition bug.
Multiple threads modify shared state without synchronization.
"""

import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import List, Dict

import requests


class WebScraper:
    """Web scraper that fetches multiple URLs concurrently."""

    def __init__(self, max_workers: int = 10):
        self.max_workers = max_workers
        self.results = []  # BUG: Shared mutable state accessed by multiple threads!
        self.failed_urls = []  # BUG: Another race condition!

    def fetch_url(self, url: str) -> Dict[str, any]:
        """Fetch a single URL and return the result."""
        try:
            response = requests.get(url, timeout=5)
            response.raise_for_status()
            return {
                "url": url,
                "status": response.status_code,
                "content_length": len(response.content),
            }
        except requests.exceptions.RequestException as e:
            return {"url": url, "error": str(e)}

    def scrape_urls(self, urls: List[str]) -> List[Dict[str, any]]:
        """
        Scrape multiple URLs concurrently.

        BUG: self.results is accessed from multiple threads without locking!
        This causes race conditions where results can be lost or corrupted.
        """
        with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            futures = [executor.submit(self.fetch_url, url) for url in urls]

            for future in as_completed(futures):
                result = future.result()

                # RACE CONDITION: Multiple threads append to self.results simultaneously
                if "error" in result:
                    self.failed_urls.append(result["url"])  # RACE CONDITION
                else:
                    self.results.append(result)  # RACE CONDITION

        return self.results
```
:::

::: {.cell .markdown}
**Bug**: Multiple threads modify `self.results` and `self.failed_urls`
without locking!

Claude will:

1.  Identify the race conditions
2.  Store the pattern in
    `/memories/concurrency_patterns/thread_safety.md`
3.  Apply this concurrency pattern to async code in Session 2
:::

::: {.cell .markdown}
### Demo Overview

We\'ve built a complete Code Review Assistant. The implementation is in
`memory_demo/code_review_demo.py`.

**To run the interactive demo:**

``` bash
python memory_demo/code_review_demo.py
```

The demo demonstrates:

1.  **Session 1**: Review Python code with a bug → Claude learns the
    pattern
2.  **Session 2**: Review similar code (new conversation) → Claude
    applies the pattern
3.  **Session 3**: Long review session → Context editing keeps it
    manageable
:::

::: {.cell .markdown}
## 7. Best Practices & Security {#best-practices} {#7-best-practices--security-best-practices}

### Memory Management

**Do:**

- ✅ Store task-relevant patterns, not conversation history
- ✅ Organize with clear directory structure
- ✅ Use descriptive file names
- ✅ Periodically review and clean up memory

**Don\'t:**

- ❌ Store sensitive information (passwords, API keys, PII)
- ❌ Let memory grow unbounded
- ❌ Store everything indiscriminately

### Security: Path Traversal Protection

**Critical**: Always validate paths to prevent directory traversal
attacks. See `memory_tool.py` for implementation.

### Security: Memory Poisoning

**⚠️ Critical Risk**: Memory files are read back into Claude\'s context,
making them a potential vector for prompt injection.

**Mitigation strategies:**

1.  **Content Sanitization**: Filter dangerous patterns before storing
2.  **Memory Scope Isolation**: Per-user/per-project isolation\
3.  **Memory Auditing**: Log and scan all memory operations
4.  **Prompt Engineering**: Instruct Claude to ignore instructions in
    memory

See `memory_tool.py` for complete security implementation and tests in
`tests/`.
:::

::: {.cell .markdown}
## Conclusion

### What You Accomplished

In this cookbook, you learned to:

- ✅ **Implement the memory tool** for cross-conversation learning
  (Sessions 1 & 2 showed pattern recognition persisting)
- ✅ **Configure context editing** with token triggers and retention
  policies (Session 3 demonstrated automatic clearing)
- ✅ **Apply security best practices** including path validation and
  memory poisoning prevention

### Applying These Patterns

**For your projects:**

1.  Start with a single memory file for patterns (e.g.,
    `/memories/patterns.md`)
2.  Set context editing triggers at 30-40k tokens for production use
3.  Implement per-project memory isolation to prevent
    cross-contamination

**Other applications:**

- **Customer support**: Store user preferences and common issue
  resolutions
- **Research assistants**: Accumulate domain knowledge across sessions
- **Data analysis**: Remember dataset characteristics and successful
  techniques

### Next Steps

- **Production deployment**: Use
  [claude-code-action](https://github.com/anthropics/claude-code-action)
  for GitHub PR reviews
- **Security hardening**: Review the memory poisoning mitigations in
  `memory_tool.py`
- **Extended thinking**: Explore thinking management for
  compute-intensive tasks

### Resources

- [Memory tool
  documentation](https://docs.claude.com/en/docs/agents-and-tools/tool-use/memory-tool)
- [Claude API reference](https://docs.claude.com/en/api/messages)
- [Support](https://support.claude.com)

Memory and context management are in **beta**. Share your feedback to
help us improve!
:::

---

## Create custom subagents - Claude Code Docs

Source: https://code.claude.com/docs/en/sub-agents
Path: 09-Agents-Patterns/sub-agents.md

## On this page

- [Built-in subagents](#built-in-subagents)
- [Quickstart: create your first subagent](#quickstart-create-your-first-subagent)
- [Configure subagents](#configure-subagents)
  - [Choose the subagent scope](#choose-the-subagent-scope)
  - [Write subagent files](#write-subagent-files)
  - [Frontmatter reference](#supported-frontmatter-fields)
  - [Subagent files Claude Code skips](#subagent-files-claude-code-skips)
  - [Choose a model](#choose-a-model)
  - [Run every subagent on one model](#run-every-subagent-on-one-model)
  - [Control subagent capabilities](#control-subagent-capabilities)
  - [Available tools](#available-tools)
  - [Restrict which subagents can be spawned](#restrict-which-subagents-can-be-spawned)
  - [Scope MCP servers to a subagent](#scope-mcp-servers-to-a-subagent)
  - [Permission modes](#permission-modes)
  - [Preload skills into subagents](#preload-skills-into-subagents)
  - [Enable persistent memory](#enable-persistent-memory)
  - [Conditional rules with hooks](#conditional-rules-with-hooks)
  - [Disable specific subagents](#disable-specific-subagents)
  - [Define hooks for subagents](#define-hooks-for-subagents)
  - [Hooks in subagent frontmatter](#hooks-in-subagent-frontmatter)
  - [Project-level hooks for subagent events](#project-level-hooks-for-subagent-events)
- [Work with subagents](#work-with-subagents)
  - [Understand automatic delegation](#understand-automatic-delegation)
  - [Invoke subagents explicitly](#invoke-subagents-explicitly)
  - [Run subagents in foreground or background](#run-subagents-in-foreground-or-background)
  - [Subagent names](#subagent-names)
  - [API errors in subagents](#api-errors-in-subagents)
  - [Subagent output scanning](#subagent-output-scanning)
  - [Common patterns](#common-patterns)
  - [Isolate high-volume operations](#isolate-high-volume-operations)
  - [Run parallel research](#run-parallel-research)
  - [Chain subagents](#chain-subagents)
  - [Choose between subagents and main conversation](#choose-between-subagents-and-main-conversation)
  - [Let subagents spawn their own subagents](#let-subagents-spawn-their-own-subagents)
  - [Concurrent subagent limit](#concurrent-subagent-limit)
  - [Manage subagent context](#manage-subagent-context)
  - [What loads at startup](#what-loads-at-startup)
  - [Resume subagents](#resume-subagents)
  - [Auto-compaction](#auto-compaction)
- [Fork the current conversation](#fork-the-current-conversation)
  - [Observe and steer running forks](#observe-and-steer-running-forks)
  - [How forks differ from other subagents](#how-forks-differ-from-other-subagents)
  - [Turn fork mode on or off](#turn-fork-mode-on-or-off)
- [Example subagents](#example-subagents)
  - [Code reviewer](#code-reviewer)
  - [Debugger](#debugger)
  - [Data scientist](#data-scientist)
  - [Database query validator](#database-query-validator)
- [Next steps](#next-steps)

Agents and parallel work

# Create custom subagents

Copy pageCopy page

Create and use specialized AI subagents in Claude Code for task-specific workflows and improved context management.

Copy pageCopy page

Subagents are specialized AI assistants that handle specific types of tasks. Use one when a side task would flood your main conversation with search results, logs, or file contents you won’t reference again: the subagent does that work in its own context and returns only the summary. Define a custom subagent when you keep spawning the same kind of worker with the same instructions. Each subagent runs in its own context window with a custom system prompt, specific tool access, and independent permissions. It also sends its own requests, which count toward the same [usage limits](../17-Billing-Plans/costs.md#plan-usage-breakdown) as your main conversation. When Claude encounters a task that matches a subagent’s description, it delegates to that subagent, which works independently and returns results. To see the context savings in practice, the [context window visualization](../02-Claude-Code-CLI/context-window.md) walks through a session where a subagent handles research in its own separate window.

Subagents work within a single session. To run many independent sessions in parallel and monitor them from one place, see [background agents](agent-view.md). For separate sessions that pass messages to each other, see [cross-session messaging](../02-Claude-Code-CLI/cross-session-messaging.md). For a coordinated team of sessions Claude spawns and supervises, see [agent teams](agent-teams.md).

Subagents help you:

- **Preserve context** by keeping exploration and implementation out of your main conversation
- **Enforce constraints** by limiting which tools a subagent can use
- **Reuse configurations** across projects with user-level subagents
- **Specialize behavior** with focused system prompts for specific domains
- **Control costs** by routing tasks to faster, cheaper models like Haiku

Claude uses each subagent’s description to decide when to delegate tasks. When you create a subagent, write a clear description so Claude knows when to use it. Those descriptions take up context, so keep them short. When the combined descriptions of your subagents, except the built-in ones, exceed 15,000 tokens, Claude Code shows a [warning at startup with the total token count](../02-Claude-Code-CLI/errors.md#agent-descriptions-are-over-the-15000-token-limit). Trim the `description` fields of your subagents, and move detail into each subagent’s system prompt, which only loads when that subagent runs.


[​](#built-in-subagents)

Built-in subagents

Claude Code includes built-in subagents that Claude automatically uses when appropriate. Each inherits the parent conversation’s permission rules; most run with a restricted tool set. Explore and Plan skip your CLAUDE.md files and the git status snapshot to keep research fast and inexpensive. Every other built-in and [custom subagent](#configure-subagents) loads both, unless its definition sets the [`omitClaudeMd`](#supported-frontmatter-fields) field to skip the user, project, and local CLAUDE.md files. For the full breakdown of what reaches a subagent, see [what loads at startup](#what-loads-at-startup).

- Explore

- Plan

- General-purpose

- Other

A fast, read-only agent optimized for searching and analyzing codebases.

- **Model**: inherits from the main conversation, capped at Opus on the Claude API, so Explore never runs on a more expensive model than the one you already chose for the session, unless you set `CLAUDE_CODE_SUBAGENT_MODEL` and [force it onto every subagent](#run-every-subagent-on-one-model)
- **Tools**: read-only tools; Write and Edit are denied
- **Purpose**: file discovery, code search, codebase exploration

As of v2.1.198, Explore inherits the main conversation’s model instead of always running on Haiku. On the Claude API, the inherited model is capped at Opus: a main conversation on a higher tier runs Explore on Opus, and a main conversation on Sonnet or Haiku runs Explore on that same model. On any other provider, such as [Amazon Bedrock, Google Cloud’s Agent Platform, Microsoft Foundry, or Claude Platform on AWS](../02-Claude-Code-CLI/third-party-integrations.md), Explore inherits the main conversation’s model directly.A [user or project subagent](#choose-the-subagent-scope) named `Explore` overrides the built-in and keeps its own `model` field, so define one with `model: haiku` to keep exploration on a lower-cost model.Claude delegates to Explore when it needs to search or understand a codebase without making changes. This keeps exploration results out of your main conversation context.When invoking Explore, Claude specifies a thoroughness level: **quick** for targeted lookups, **medium** for balanced exploration, or **very thorough** for comprehensive analysis.

A research agent used during [plan mode](../02-Claude-Code-CLI/permission-modes.md#analyze-before-you-edit-with-plan-mode) to gather context before presenting a plan.

- **Model**: inherits from the main conversation, unless you set `CLAUDE_CODE_SUBAGENT_MODEL` and [force it onto every subagent](#run-every-subagent-on-one-model)
- **Tools**: read-only tools; Write and Edit are denied
- **Purpose**: codebase research for planning

When you’re in plan mode and Claude needs to understand your codebase, it delegates research to the Plan subagent so that exploration output stays in a separate context window while the main conversation remains read-only.

A capable agent for complex, multi-step tasks that require both exploration and action.

- **Model**: the [`CLAUDE_CODE_SUBAGENT_MODEL`](#choose-a-model) model if you set one and nothing assigns a model another way, otherwise the main conversation’s model; [Choose a model](#choose-a-model) states the full order, and [Run every subagent on one model](#run-every-subagent-on-one-model) shows how to make the variable override those sources
- **Tools**: every tool [available to subagents](#available-tools)
- **Purpose**: complex research, multi-step operations, code modifications

Claude delegates to general-purpose when the task requires both exploration and modification, complex reasoning to interpret results, or multiple dependent steps.

Claude Code includes additional helper agents for specific tasks. These are typically invoked automatically, so you don’t need to use them directly.

| Agent             | Model                                                                                           | When Claude uses it                                                                                                                                                                                                                                                                                                                            |
|:------------------|:------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| claude            | None of its own; follows the [model order](#choose-a-model) when Claude spawns it as a subagent | When a task doesn’t fit a more specialized agent. A catch-all with every tool [available to subagents](#available-tools). Also the default agent for a dispatched [background session](agent-view.md); [which permission mode it starts in](agent-view.md#permission-mode-model-and-effort) depends on how the session was started |
| statusline-setup  | Sonnet                                                                                          | When you run `/statusline` to configure your status line                                                                                                                                                                                                                                                                                       |
| claude-code-guide | Haiku                                                                                           | When you ask questions about Claude Code features                                                                                                                                                                                                                                                                                              |

Built-in subagents are registered by default in interactive sessions. To restrict them:

- To block a specific built-in type, add it to `permissions.deny` as shown in [Disable specific subagents](#disable-specific-subagents).
- To prevent Claude from delegating to any subagent, deny the `Agent` tool itself with [`permissions.deny`](../02-Claude-Code-CLI/permissions.md#tool-specific-permission-rules).
- To remove only the built-in `Explore` and `Plan` subagents, set [`CLAUDE_CODE_DISABLE_EXPLORE_PLAN_AGENTS=1`](../02-Claude-Code-CLI/env-vars.md). Claude reads and explores files directly instead of delegating to them. Requires Claude Code v2.1.198 or later.
- In [non-interactive mode](../02-Claude-Code-CLI/headless.md) and the [Agent SDK](../05-Agent-SDK/agent-sdk-overview.md), set [`CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS=1`](../02-Claude-Code-CLI/env-vars.md) to remove all built-in types and supply only your own.

An Agent tool call that omits `subagent_type` fails with [`subagent_type is required`](../02-Claude-Code-CLI/errors.md#subagent-type-is-required) when the session has no `general-purpose` subagent to fall back on. Beyond these built-in subagents, you can create your own with custom prompts, tool restrictions, permission modes, hooks, and skills. The following sections show how to get started and customize subagents.


[​](#quickstart-create-your-first-subagent)

Quickstart: create your first subagent

Subagents are Markdown files with YAML frontmatter. To create one, ask Claude to write it for you, or [write the file yourself](#write-subagent-files). As of v2.1.198, the `/agents` command no longer opens the interactive creation wizard; running it prints a reminder to ask Claude or edit `.claude/agents/` directly. Subagent files, frontmatter fields, and the `.claude/agents/` and `~/.claude/agents/` locations are unchanged; only the terminal wizard is removed. This walkthrough creates a user-level subagent that reviews code and suggests improvements.

1

Ask Claude to create the subagent

In Claude Code, describe the subagent you want and where to save it:

```python
Create a personal code-improver subagent in ~/.claude/agents/ that scans
files and suggests improvements for readability, performance, and best
practices. It should explain each issue, show the current code, and
provide an improved version. Make it read-only and have it use Sonnet.
```

Claude writes the file with a `name`, a `description`, a `tools` list, a `model`, and a system prompt.

2

Review the file

Open `~/.claude/agents/code-improver.md` and confirm the frontmatter matches what you asked for. The result looks like this:

```python
---
name: code-improver
description: Scans files and suggests improvements for readability, performance, and best practices. Use after writing or modifying code.
tools: Read, Grep, Glob
model: sonnet
---

You are a code improvement specialist. For each issue you find, explain
the problem, show the current code, and provide an improved version.
```

Because the file lives in `~/.claude/agents/`, the subagent is available in every project on your machine. To scope it to one project instead, move it to that project’s `.claude/agents/` directory. [Choose the subagent scope](#choose-the-subagent-scope) compares the two.

3

Try it out

Ask Claude to delegate to the new subagent:

```python
Use the code-improver agent to suggest improvements in this project
```

Claude delegates to your new subagent, which scans the codebase and returns improvement suggestions. In the transcript, the delegation appears as a tool call row showing the subagent’s name followed by a short task description, such as `code-improver(Suggest code improvements)`.If Claude can’t find the new subagent, restart Claude Code and try again. This happens only when `~/.claude/agents/` didn’t exist before the session started, because a running session doesn’t detect a newly created `agents` directory.

You now have a subagent you can use in any project on your machine to analyze codebases and suggest improvements. You can also write subagent files by hand, define them via CLI flags, or distribute them through plugins. The following sections cover all configuration options.

On Claude Code v2.1.197 and earlier, `/agents` opens an interactive wizard with a **Running** tab that lists live subagents and a **Library** tab for creating, editing, and deleting them.


[​](#configure-subagents)

Configure subagents

A subagent’s file location determines who it’s available to, and its frontmatter determines what it can do. This section covers where subagent files live and every field they support.


[​](#choose-the-subagent-scope)

Choose the subagent scope

Store subagent files in different locations depending on scope. When multiple subagents share the same name, Claude Code uses the one from the higher-priority location.

| Location                     | Scope                   | Priority    | How to create                                       |
|:-----------------------------|:------------------------|:------------|:----------------------------------------------------|
| Managed settings             | Organization-wide       | 1 (highest) | Deployed via [managed settings](../02-Claude-Code-CLI/settings.md)  |
| `--agents` CLI flag          | Current session         | 2           | Pass JSON when launching Claude Code                |
| `.claude/agents/`            | Current project         | 3           | Ask Claude, or create the file manually             |
| `~/.claude/agents/`          | All your projects       | 4           | Ask Claude, or create the file manually             |
| Plugin’s `agents/` directory | Where plugin is enabled | 5 (lowest)  | Installed with [plugins](../08-Plugins-Skills/plugins.md) |

**Project subagents** (`.claude/agents/`) are ideal for subagents specific to a codebase. Check them into version control so your team can use and improve them collaboratively. Project subagents are discovered by walking up from the current working directory, so every `.claude/agents/` between there and the repository root is scanned. When more than one of these nested directories defines the same `name`, Claude Code uses the definition closest to the working directory. When you add a directory with `--add-dir` or `/add-dir`, Claude Code also loads its `.claude/agents/` folder, alongside your project subagents. See [Additional directories](../02-Claude-Code-CLI/permissions.md#additional-directories-grant-file-access-not-configuration) for which other configuration types load from `--add-dir`. To share subagents across projects without `--add-dir`, use `~/.claude/agents/` or a [plugin](../08-Plugins-Skills/plugins.md). **User subagents** (`~/.claude/agents/`) are personal subagents available in all your projects. Claude Code scans `.claude/agents/` and `~/.claude/agents/` recursively, so you can organize definitions into subfolders such as `agents/review/` or `agents/research/`. The subdirectory path doesn’t affect how a subagent is identified or invoked, because identity comes only from the `name` frontmatter field. Keep `name` values unique across the whole tree: if two files under the same `.claude/agents/` directory, including its subfolders, declare the same name, Claude Code loads only one of them, chosen by filesystem read order rather than a documented precedence. Across nested project directories, the definition closest to the working directory wins, as described above. The [`/doctor`](../02-Claude-Code-CLI/commands.md#all-commands) setup checkup reports files in the same directory that share a name and proposes renaming or removing all but one. Before v2.1.205, `/doctor` opened a diagnostics screen that listed duplicates and showed which definition was active. Plugin `agents/` directories are also scanned recursively. Unlike project and user scopes, a subfolder inside a plugin’s `agents/` directory becomes part of the [scoped identifier](#invoke-subagents-explicitly): a file at `agents/review/security.md` in plugin `my-plugin` registers as `my-plugin:review:security`. **CLI-defined subagents** are passed as JSON when launching Claude Code. They exist only for that session and aren’t saved to disk, making them useful for quick testing or automation scripts. You can define multiple subagents in a single `--agents` call:

- macOS, Linux, WSL

- Windows PowerShell

```python
claude --agents '{
  "code-reviewer": {
    "description": "Expert code reviewer. Use proactively after code changes.",
    "prompt": "You are a senior code reviewer. Focus on code quality, security, and best practices.",
    "tools": ["Read", "Grep", "Glob", "Bash"],
    "model": "sonnet"
  },
  "debugger": {
    "description": "Debugging specialist for errors and test failures.",
    "prompt": "You are an expert debugger. Analyze errors, identify root causes, and provide fixes."
  }
}'
```

```python
claude --agents @'
{
  "code-reviewer": {
    "description": "Expert code reviewer. Use proactively after code changes.",
    "prompt": "You are a senior code reviewer. Focus on code quality, security, and best practices.",
    "tools": ["Read", "Grep", "Glob", "Bash"],
    "model": "sonnet"
  },
  "debugger": {
    "description": "Debugging specialist for errors and test failures.",
    "prompt": "You are an expert debugger. Analyze errors, identify root causes, and provide fixes."
  }
}
'@
```

In [non-interactive mode](../02-Claude-Code-CLI/headless.md), `--agents` also accepts the path to a JSON file holding the same object, for definitions too large to pass on the command line. For example, `claude -p --agents ./agents.json "Review my changes"` reads the definitions from that file. In an interactive session, Claude Code refuses a file path. The file form requires Claude Code v2.1.281 or later. Each top-level key in the JSON is an agent’s name, and its value is that agent’s definition. Don’t start a name with `-`. A definition takes these fields:

- **`prompt`**: the agent’s system prompt, equivalent to the markdown body in file-based subagents. `prompt` may be empty. If you select an agent with an empty `prompt` and no `memory` field as the session’s agent with `--agent`, the session’s system prompt is left unchanged. An empty `prompt` requires Claude Code v2.1.281 or later.
- **[Frontmatter fields](#supported-frontmatter-fields)**: `description`, `tools`, `disallowedTools`, `model`, `permissionMode`, `mcpServers`, `hooks`, `maxTurns`, `skills`, `initialPrompt`, `memory`, `effort`, `background`, `omitClaudeMd`, and `isolation`.
- **Ignored fields**: `color` and `experimental` aren’t accepted here and are ignored rather than rejected.

For what Claude Code does with a value it can’t load, and the flags and environment variable that skip that check, see [`Invalid --agents configuration`](../02-Claude-Code-CLI/errors.md#invalid-agents-configuration). **Managed subagents** are deployed by organization administrators. Place markdown files in `.claude/agents/` inside the [managed settings directory](../13-Enterprise-Admin/managed-settings.md#delivery-mechanisms), using the same frontmatter format as project and user subagents. Managed definitions take precedence over project and user subagents with the same name. **Plugin subagents** come from [plugins](../08-Plugins-Skills/plugins.md) you’ve installed. They load automatically alongside your custom subagents and appear in the @-mention typeahead under their scoped name. See the [plugin components reference](../08-Plugins-Skills/plugins-components.md#agents) for details on creating plugin subagents.

For security reasons, plugin subagents don’t support the `hooks`, `mcpServers`, or `permissionMode` frontmatter fields. These fields are ignored when loading agents from a plugin. If you need them, copy the agent file into `.claude/agents/` or `~/.claude/agents/`. You can also add rules to [`permissions.allow`](../02-Claude-Code-CLI/settings-reference.md#permissions-allow) in `settings.json` or `settings.local.json`, but these rules apply to the entire session, not only the plugin subagent.

Subagent definitions from any of these scopes are also available to [agent teams](agent-teams.md#use-subagent-definitions-for-teammates): when spawning a teammate, you can reference a subagent type, and Claude Code applies parts of that definition to the teammate. See [agent teams](agent-teams.md#use-subagent-definitions-for-teammates) for which parts apply in each display mode.


[​](#write-subagent-files)

Write subagent files

Subagent files use YAML frontmatter for configuration, followed by the system prompt in Markdown:

Claude Code watches `~/.claude/agents/` and `.claude/agents/`. When you add or edit a subagent file on disk, or ask Claude to write one for you, Claude Code detects the change within a few seconds and the next delegation uses the updated definition, with no restart needed.Three cases still need a restart:

- The watcher covers only directories that existed when the session started, so after creating a scope’s first agent file in a new `agents` directory, restart to load it.
- Claude Code doesn’t watch `.claude/agents/` inside directories added with `--add-dir` or `/add-dir`, so after adding or editing a subagent there, restart to load the change.
- Sessions started with `--disable-slash-commands` don’t watch these directories at all.

.claude/agents/code-reviewer.md

```python
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Glob, Grep
model: sonnet
---

You are a code reviewer. When invoked, analyze the code and provide
specific, actionable feedback on quality, security, and best practices.
```

The frontmatter defines the subagent’s metadata and configuration. The body becomes the system prompt that guides the subagent’s behavior. Subagents receive only this system prompt plus basic environment details like the working directory, not the Claude Code system prompt. In [non-interactive mode](../02-Claude-Code-CLI/headless.md), pass [`--append-subagent-system-prompt`](../02-Claude-Code-CLI/cli-reference.md#cli-flags) to append your text to the end of every subagent’s system prompt, nested subagents included, apart from a [forked subagent](#fork-the-current-conversation), which reuses the conversation’s own prompt. Requires Claude Code v2.1.205 or later. If your text is too long to pass on the command line, save it to a file and pass the path with `--append-subagent-system-prompt-file` instead. The file flag requires Claude Code v2.1.261 or later. A subagent starts in the main conversation’s current working directory. Within a subagent, `cd` commands don’t persist between Bash or PowerShell tool calls and don’t affect the main conversation’s working directory. To give the subagent an isolated copy of the repository instead, set [`isolation: worktree`](#supported-frontmatter-fields). A subagent with `isolation: worktree` runs its Bash and PowerShell commands inside its worktree. A command whose working directory resolves to your main checkout instead, for example because the worktree directory was removed while the subagent was running, fails with an error. Before v2.1.203, such a command could run in the main checkout. This working-directory check covers the whole repository containing the directory you launched Claude Code from. When your session runs in a linked [worktree](../02-Claude-Code-CLI/worktrees.md) of its own, the check also covers the main checkout that worktree is linked from. Before v2.1.210, the check covered only the launch directory itself. A command whose working directory resolved elsewhere in the same repository, such as the repository root when you launched Claude Code from a monorepo subdirectory, ran there instead of failing. For Bash commands, Claude Code also checks the command itself in two ways:

- It blocks a command that redirects git into the main checkout.
- It refuses a command when it can’t verify from the command text that any git the command runs stays inside the worktree, for example when the command name is computed at runtime.

The redirect vectors and the shape rules are listed under [How Claude Code enforces isolation](../02-Claude-Code-CLI/worktrees.md#how-claude-code-enforces-isolation). PowerShell commands get only the working-directory check. [Monitor](../02-Claude-Code-CLI/tools-reference.md#monitor-tool) commands go through the same working-directory and command-content checks as Bash commands. When the main conversation itself runs isolated in a worktree, Claude Code applies the same checks to the session and to every subagent it spawns, including subagents without `isolation: worktree`; see [How Claude Code enforces isolation](../02-Claude-Code-CLI/worktrees.md#how-claude-code-enforces-isolation).


[​](#supported-frontmatter-fields)

Frontmatter reference

Configure a subagent with YAML [frontmatter](../02-Claude-Code-CLI/glossary.md#frontmatter) between `---` markers at the top of its file, and write its system prompt as Markdown after the closing `---`. Only `name` and `description` are required. Multi-word field names use camelCase, such as `maxTurns` and `disallowedTools`, and must match the table exactly: Claude Code ignores a field it doesn’t recognize without reporting an error. To find out why a subagent file didn’t load, see [Subagent files Claude Code skips](#subagent-files-claude-code-skips).

| Field             | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|:------------------|:---------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name`            | Yes      | Unique identifier, such as `code-reviewer` or `reviewer-v2`. [Hooks](../07-Hooks/hooks.md#subagentstart) receive this value as `agent_type`. The filename doesn’t have to match. Names can’t contain `:`, which is reserved for [plugin-scoped identifiers](../08-Plugins-Skills/plugins.md) such as `my-plugin:reviewer`. Claude Code doesn’t load a file whose name contains one and logs an error to the debug log. Before v2.1.218, such names were accepted                                                   |
| `description`     | Yes      | When Claude should delegate to this subagent                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `tools`           | No       | [Tools](#available-tools) the subagent can use, as a comma-separated string such as `Read, Grep, Bash` or a YAML list. Inherits every tool available to subagents if omitted. If no entry in the list resolves to a tool, the subagent usually [fails to launch](../02-Claude-Code-CLI/errors.md#agent-would-be-spawned-with-zero-tools) with an error naming the entries. To preload Skills into context, use the `skills` field rather than listing `Skill` here                                                     |
| `disallowedTools` | No       | Tools to deny, removed from inherited or specified list. Same format as `tools`. An entry with a specifier, such as `Bash(git push *)`, still [removes the whole tool](#available-tools)                                                                                                                                                                                                                                                                                                               |
| `model`           | No       | [Model](#choose-a-model) to use: `sonnet`, `opus`, `haiku`, `fable`, a full model ID such as `claude-opus-5-5`, or `inherit`. When you omit it, Claude Code picks the model in the [subagent model order](#choose-a-model)                                                                                                                                                                                                                                                                             |
| `permissionMode`  | No       | [Permission mode](#permission-modes): `default`, `acceptEdits`, `auto`, `dontAsk`, `bypassPermissions`, `plan`, or `manual` as an alias for `default`. The `manual` alias requires Claude Code v2.1.200 or later. Ignored for [plugin subagents](#choose-the-subagent-scope)                                                                                                                                                                                                                           |
| `maxTurns`        | No       | Maximum number of agentic turns before the subagent stops. When the subagent reaches the limit, Claude Code returns its output marked as partial, and Claude can [resume it](#resume-subagents) to continue. The partial marking requires Claude Code v2.1.246 or later                                                                                                                                                                                                                                |
| `skills`          | No       | [Skills](../08-Plugins-Skills/skills.md) to preload into the subagent’s context at startup. The full skill content is injected, not only the description. Subagents can still invoke unlisted project, user, and plugin skills through the Skill tool                                                                                                                                                                                                                                                                 |
| `mcpServers`      | No       | [MCP servers](../06-MCP-Tools/General/mcp.md) available to this subagent. Each entry is either a server name referencing an already-configured server (e.g., `"slack"`) or an inline definition with the server name as key and a full [MCP server config](../06-MCP-Tools/General/mcp.md#installing-mcp-servers) as value. Ignored for [plugin subagents](#choose-the-subagent-scope)                                                                                                                                                     |
| `hooks`           | No       | [Lifecycle hooks](#define-hooks-for-subagents) scoped to this subagent. Ignored for [plugin subagents](#choose-the-subagent-scope)                                                                                                                                                                                                                                                                                                                                                                     |
| `memory`          | No       | [Persistent memory scope](#enable-persistent-memory): `user`, `project`, or `local`. Enables cross-session learning                                                                                                                                                                                                                                                                                                                                                                                    |
| `background`      | No       | Set to `true` to keep this subagent in the background even when Claude asks to run it in the foreground. Where [fork mode](#turn-fork-mode-on-or-off) is on, Claude Code already runs the subagents Claude spawns [in the background](#run-subagents-in-foreground-or-background)                                                                                                                                                                                                                      |
| `omitClaudeMd`    | No       | Set to `true` to launch this subagent without the user, project, and local CLAUDE.md files; [managed policy files](../02-Claude-Code-CLI/memory.md#how-claude-md-files-load) still load, except for [managed subagents](#choose-the-subagent-scope). Use it for subagents that take everything they need from the [delegation prompt](#what-loads-at-startup). Ignored when the agent runs as the main session agent via `--agent` or the `agent` setting. Requires Claude Code v2.1.271 or later                      |
| `effort`          | No       | Effort level when this subagent is active. Overrides the session effort level. Default: inherits from session. Options: `low`, `medium`, `high`, `xhigh`, `max`; available levels depend on the model                                                                                                                                                                                                                                                                                                  |
| `isolation`       | No       | Set to `worktree` to run the subagent in a temporary [git worktree](../02-Claude-Code-CLI/worktrees.md), giving it an isolated copy of the repository branched by default from your [default branch](../02-Claude-Code-CLI/worktrees.md#choose-the-base-branch) rather than the parent session’s `HEAD`. The worktree is automatically cleaned up if the subagent makes no changes                                                                                                                                                     |
| `color`           | No       | Display color for the subagent in the task list and transcript. Accepts `red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`, or `cyan`                                                                                                                                                                                                                                                                                                                                                        |
| `initialPrompt`   | No       | Auto-submitted as the first user turn when this agent runs as the main session agent (via `--agent` or the `agent` setting). [Commands](../02-Claude-Code-CLI/commands.md) and [skills](../08-Plugins-Skills/skills.md) are processed. Prepended to any user-provided prompt. Ignored for [plugin subagents](#choose-the-subagent-scope)                                                                                                                                                                                              |
| `experimental`    | No       | Map of experimental options. Set its `cacheTtl` key to `5m` or `1h` to choose the [prompt cache lifetime](../02-Claude-Code-CLI/prompt-caching.md#choose-the-ttl-yourself) for this subagent’s requests, at the frontmatter’s place in the [cache lifetime precedence](../02-Claude-Code-CLI/prompt-caching.md#choose-the-ttl-yourself). Claude Code ignores any other value, ignores `1h` while your Claude subscription is using usage credits, and reads the field only from subagent files. Requires Claude Code v2.1.248 or later |

Write `cacheTtl` inside the `experimental` map, not at the top level of the frontmatter.

```python
---
name: repo-auditor
description: Audits a large repository and reports what it finds
experimental:
  cacheTtl: 1h
---
```


[​](#subagent-files-claude-code-skips)

Subagent files Claude Code skips

Claude Code skips a file in a project, user, or managed `agents` directory, or in one under a directory you add with `--add-dir`, without reporting it in the session, when the frontmatter has any of these problems:

- **No `name`**: Claude Code treats the file as documentation kept beside your agents.
- **An opening `---` that isn’t the file’s first line**: Claude Code reads the file as having no frontmatter and treats it as documentation.
- **A `name` that starts with `-` or contains `:`**: Claude Code skips the file and writes an error to the debug log. See the `name` row in the table above.
- **A `name` but no `description`**: Claude Code skips the file and writes the reason to the debug log.
- **YAML that doesn’t parse**: Claude Code reads no fields from the file, skips it, and writes the parse error to the debug log.

To see the debug log, run Claude Code with `--debug`. A [plugin subagent](../08-Plugins-Skills/plugins-components.md#agents) whose frontmatter has no `name` or doesn’t parse still loads, under its filename.

##### Check an `agents` directory before a session

To find files in an `agents` directory whose frontmatter doesn’t parse, run `claude plugin validate` against the directory, for example `.claude/agents` or `~/.claude/agents`. Claude Code checks only [the directory you name](../08-Plugins-Skills/plugins-cli-reference.md#validate-a-directory), and doesn’t flag a file whose frontmatter parses but has no `name`. Requires Claude Code v2.1.233 or later.


[​](#choose-a-model)

Choose a model

The `model` field controls which model the subagent uses:

- **Model alias**: use one of the available aliases: `sonnet`, `opus`, `haiku`, or `fable`
- **Full model ID**: use a full model ID such as `claude-opus-5-5` or `claude-sonnet-5`. Accepts the same values as the `--model` flag
- **inherit**: use the same model as the main conversation

When Claude invokes a subagent, it can also pass a `model` parameter for that specific invocation. Claude Code resolves the subagent’s model in this order:

1.  The per-invocation `model` parameter
2.  The subagent definition’s `model` frontmatter, where `inherit` selects the main conversation’s model
3.  The [`CLAUDE_CODE_SUBAGENT_MODEL`](../02-Claude-Code-CLI/model-config.md#environment-variables) environment variable, when you set it to a model alias or model ID
4.  The main conversation’s model

In two cases, a family alias such as `opus` in the per-invocation parameter or the frontmatter resolves to the main conversation’s model instead of the [version the alias points to](../02-Claude-Code-CLI/model-config.md#model-aliases):

- **The main conversation’s model belongs to that family**: the subagent runs on the main conversation’s exact model, including any `[1m]` suffix, so it gets the same [extended context](../02-Claude-Code-CLI/model-config.md#extended-context) window as the main conversation.
- **Claude Code can’t tell the main conversation’s model family, on [a provider other than the Anthropic API](../02-Claude-Code-CLI/third-party-integrations.md)**: this can happen with an [application inference profile ARN](../02-Claude-Code-CLI/amazon-bedrock.md#iam-configuration) on Amazon Bedrock that Claude Code hasn’t resolved to a backing model. This case covers only the `opus` alias, and doesn’t apply when you set [`ANTHROPIC_DEFAULT_OPUS_MODEL`](../02-Claude-Code-CLI/model-config.md#environment-variables), since `opus` then resolves to the model you set.

An alias in `CLAUDE_CODE_SUBAGENT_MODEL` always resolves to the version the alias points to, even when it names the main conversation’s family. Setting `CLAUDE_CODE_SUBAGENT_MODEL` by itself doesn’t change the model the built-in Explore and Plan subagents run on. To change it, see [Run every subagent on one model](#run-every-subagent-on-one-model). Before v2.1.251, `CLAUDE_CODE_SUBAGENT_MODEL` came first in this order and overrode both the per-invocation parameter and the frontmatter, including `model: inherit`. Setting the variable to `inherit` is the same as leaving it unset. Before v2.1.196, that value forced subagents onto the main conversation’s model and ignored the other sources. Claude Code checks the per-invocation parameter, frontmatter, and environment variable values against your organization’s [`availableModels`](../02-Claude-Code-CLI/model-config.md#restrict-model-selection) allowlist. For a blocked value, it substitutes another model:

- When the blocked value is a family alias such as `opus`, Claude Code runs the subagent on the newest version of that family the allowlist permits, following the same [substitution rules and provider scope](../02-Claude-Code-CLI/model-config.md#restrict-model-selection) as `/model`. Before v2.1.222, Claude Code ran the subagent on the inherited model for a blocked family alias as well.
- For any other blocked value, on providers where that substitution doesn’t operate, or when the allowlist permits no version of the family, Claude Code runs the subagent on the inherited model instead. If you set `CLAUDE_CODE_SUBAGENT_MODEL`, Claude Code tries that model first, under these same rules.

In interactive sessions, Claude Code shows a warning naming the requested model and the model the subagent runs on, for either substitution. To check which model a subagent is running on, run [`/tasks`](../02-Claude-Code-CLI/commands.md). Claude Code names the model on the subagent’s row, and adds the [effort level](../02-Claude-Code-CLI/model-config.md#adjust-effort-level) when the subagent’s definition, or the skill it forked from, sets [`effort`](#supported-frontmatter-fields). Requires Claude Code v2.1.242 or later. A per-invocation `model` parameter also applies when the subagent is [resumed or sent a follow-up message](#resume-subagents), so the subagent stays on that model. Before v2.1.211, resuming dropped the per-invocation value and the subagent reverted to its definition’s `model` field or, without one, the main conversation’s model. As of v2.1.198, subagents also inherit the main conversation’s [extended thinking](../02-Claude-Code-CLI/model-config.md#extended-thinking) configuration: if thinking is on in your session, it’s on for the subagent, and if it’s off, it stays off. There is no per-subagent thinking setting. Before v2.1.198, subagents ran with extended thinking disabled regardless of the main conversation’s setting.


[​](#run-every-subagent-on-one-model)

Run every subagent on one model

`CLAUDE_CODE_SUBAGENT_MODEL` is a default, so a subagent’s definition or a model Claude passes still takes precedence over it. To apply one model to every subagent, [teammate](agent-teams.md#specify-teammates-and-models), and [workflow agent](../02-Claude-Code-CLI/workflows.md), also set `CLAUDE_CODE_SUBAGENT_MODEL_FORCE` to `1`. Requires Claude Code v2.1.257 or later.

- If you set both variables, subagents run on the model in `CLAUDE_CODE_SUBAGENT_MODEL`.
- If you set only `CLAUDE_CODE_SUBAGENT_MODEL_FORCE`, subagents run on the main conversation’s model.

For example, to run every subagent on Haiku, set both variables in the `env` block of a [settings file](../02-Claude-Code-CLI/settings.md):

```python
{
  "env": {
    "CLAUDE_CODE_SUBAGENT_MODEL": "haiku",
    "CLAUDE_CODE_SUBAGENT_MODEL_FORCE": "1"
  }
}
```

To check that the setting took effect, run [`/tasks`](../02-Claude-Code-CLI/commands.md) while a subagent is running. The subagent’s row shows the model it runs on. While `CLAUDE_CODE_SUBAGENT_MODEL_FORCE` is [on](../02-Claude-Code-CLI/env-vars.md), Claude Code ignores the `model` field of every subagent definition, including the built-in Explore and Plan subagents, and Claude can’t pass a model when it starts a subagent. Two kinds of subagent still run on the main conversation’s model:

- A [fork](#fork-the-current-conversation)
- A [skill that runs in a subagent](../08-Plugins-Skills/skills.md#run-skills-in-a-subagent) with `model: inherit`

When you set only `CLAUDE_CODE_SUBAGENT_MODEL_FORCE`, the built-in Explore subagent keeps its [model cap](#built-in-subagents).


[​](#control-subagent-capabilities)

Control subagent capabilities

You can control what subagents can do through tool access, permission modes, and conditional rules.


[​](#available-tools)

Available tools

Subagents inherit the [built-in tools](../02-Claude-Code-CLI/tools-reference.md) and MCP tools available in the main conversation, narrowed by two filters: the first removes a short list of tools from every subagent, and the second reduces the built-in tool set for subagents that run in the [background](#run-subagents-in-foreground-or-background), which is the default. On macOS, Linux, and WSL, a subagent can also receive the Glob and Grep tools when the main conversation doesn’t have them, as described under [Glob tool behavior](../02-Claude-Code-CLI/tools-reference.md#glob-tool-behavior). [Forks](#fork-the-current-conversation) skip both filters and receive the main conversation’s exact tool pool. The first filter removes these tools, even when listed in the `tools` field:

- `Agent`, when the subagent is at the [depth limit](#let-subagents-spawn-their-own-subagents); in a [fork](#fork-the-current-conversation) the tool stays listed but returns an error instead of spawning
- `AskUserQuestion`
- `EndConversation`, which can end only the main conversation; see [EndConversation tool behavior](../02-Claude-Code-CLI/tools-reference.md#endconversation-tool-behavior)
- `EnterPlanMode`
- `ExitPlanMode`, unless the subagent’s [`permissionMode`](#permission-modes) is `plan`
- `ScheduleWakeup`
- `WaitForMcpServers`
- `Workflow`

The second filter applies to subagents running in the background. Apart from `Agent` and `ExitPlanMode`, which follow the first filter’s conditions wherever the subagent runs, a background subagent keeps every MCP tool but only these built-in tools: `Read`, `Grep`, `Glob`, `LSP`, `Bash`, `PowerShell`, `Edit`, `Write`, `NotebookEdit`, `WebFetch`, `WebSearch`, `TodoWrite`, `Skill`, `ToolSearch`, `EnterWorktree`, `ExitWorktree`, `Monitor`, `TaskStop`, `SendMessage`, and `Artifact`, plus [`SubagentHandback`](../02-Claude-Code-CLI/tools-reference.md) for a subagent that reports through it. Claude Code removes every other built-in tool from a background subagent, whether inherited or listed in the `tools` field, so the same definition can resolve to different tools in the foreground and the background. The removal reports no error unless it leaves the `tools` list [resolving to nothing](../02-Claude-Code-CLI/errors.md#agent-would-be-spawned-with-zero-tools). Before v2.1.280, background subagents couldn’t use `LSP`. [`ListAgents`](../02-Claude-Code-CLI/cross-session-messaging.md) follows these filters like any built-in tool: a foreground subagent inherits it in sessions where cross-session messaging is enabled, and a background subagent doesn’t keep it. Teammates in [agent teams](agent-teams.md) additionally keep the task tools and cron tools: `TaskCreate`, `TaskGet`, `TaskList`, `TaskUpdate`, `CronCreate`, `CronDelete`, and `CronList`. In a [session without the Task tools](../02-Claude-Code-CLI/tools-reference.md#task-tool-availability), Claude Code doesn’t provide the task tools to subagents either, even when the subagent runs a different model. An in-process teammate follows your session the same way, while a teammate in its own [split pane](agent-teams.md#choose-a-display-mode) runs as a separate Claude Code process, so its own model decides. To restrict tools, use the `tools` field as an allowlist or the `disallowedTools` field as a denylist. This example uses `tools` to allow only Read, Grep, Glob, and Bash. The subagent can’t edit files, write files, or use any MCP tools:

```python
---
name: safe-researcher
description: Research agent with restricted capabilities
tools: Read, Grep, Glob, Bash
---
```

This example uses `disallowedTools` to inherit the subagent’s tool pool except Write and Edit. The subagent keeps Bash, MCP tools, and the rest of its pool:

```python
---
name: no-writes
description: Inherits the available tools except file writes
disallowedTools: Write, Edit
---
```

If both are set, `disallowedTools` is applied first, then `tools` is resolved against the remaining pool. A tool listed in both is removed. When nothing in the `tools` list resolves to a tool, for example because every entry is misspelled or names a tool that isn’t available to subagents, Claude Code usually refuses to launch the subagent and the Agent tool returns an error naming the unresolved entries; see [Agent would be spawned with zero tools](../02-Claude-Code-CLI/errors.md#agent-would-be-spawned-with-zero-tools) for the message and how to fix each entry. Before v2.1.208, that subagent launched with no tools and could return an empty or confusing result. Both fields accept MCP server-level patterns in addition to exact tool names: `mcp__<server>` or `mcp__<server>__*` grants or removes every tool from the named server. In `disallowedTools`, `mcp__*` also removes every MCP tool from any server. This example removes every tool from the `github` MCP server while keeping tools from other servers and the built-in tools in its pool:

```python
---
name: local-only
description: Inherits every tool except those from the github MCP server
disallowedTools: mcp__github
---
```

A `disallowedTools` entry with a specifier, such as `Bash(git push *)`, still removes the whole tool from the subagent, not only the matching commands. To keep Bash and block specific commands, add a [Bash deny rule](../02-Claude-Code-CLI/permissions.md#bash) such as `Bash(git push *)` to `permissions.deny` in your settings. The rule applies to the main conversation and to subagents.


[​](#restrict-which-subagents-can-be-spawned)

Restrict which subagents can be spawned

When an agent runs as the main thread with `claude --agent`, it can spawn subagents using the Agent tool. To restrict which subagent types it can spawn, use `Agent(agent_type)` syntax in the `tools` field.

In version 2.1.63, the Task tool was renamed to Agent. Existing `Task(...)` references in settings and agent definitions still work as aliases.

```python
---
name: coordinator
description: Coordinates work across specialized agents
tools: Agent(worker, researcher), Read, Bash
---
```

This is an allowlist: only the `worker` and `researcher` subagents can be spawned. If the agent tries to spawn any other type, the request fails and the agent sees only the allowed types in its prompt. To block specific agents while allowing all others, use [`permissions.deny`](#disable-specific-subagents) instead. To allow spawning any subagent without restrictions, use `Agent` without parentheses:

```python
tools: Agent, Read, Bash
```

If you omit `Agent` from the `tools` list entirely, the agent can’t spawn any subagents with the Agent tool. The `Agent(agent_type)` allowlist syntax applies only to an agent running as the main thread with `claude --agent`. In a subagent definition, listing `Agent` in `tools` lets that subagent spawn subagents of its own while the [depth limit](#let-subagents-spawn-their-own-subagents) allows it, but any type list inside the parentheses is ignored.


[​](#scope-mcp-servers-to-a-subagent)

Scope MCP servers to a subagent

Use the `mcpServers` field to give a subagent access to [MCP](../06-MCP-Tools/General/mcp.md) servers that aren’t available in the main conversation. Inline servers defined here are connected when the subagent starts, subject to the [trust rule for the agent file’s folder](#inline-server-trust), and disconnected when it finishes. String references share the parent session’s connection.

The `mcpServers` field applies in both contexts where an agent file can run:

- As a subagent, spawned through the Agent tool or an @-mention
- As the main session, launched with [`--agent`](#invoke-subagents-explicitly) or the `agent` setting

When the agent is the main session, inline server definitions connect at startup alongside servers from [`.mcp.json`](../06-MCP-Tools/General/mcp.md) and settings files, under the same [trust rule for the agent file’s folder](#inline-server-trust). In `/mcp`, a remote (HTTP or SSE) server you’ve used before can show the [`cached` status](../06-MCP-Tools/General/mcp.md#managing-your-servers) instead; Claude Code connects it when Claude first calls one of its tools.

Each entry in the list is either an inline server definition or a string referencing an MCP server already configured in your session:

```python
---
name: browser-tester
description: Tests features in a real browser using Playwright
mcpServers:
  # Inline definition: scoped to this subagent only
  - playwright:
      type: stdio
      command: npx
      args: ["-y", "@playwright/mcp@latest"]
  # Reference by name: reuses an already-configured server
  - github
---

Use the Playwright tools to navigate, screenshot, and interact with pages.
```

Inline definitions use the same schema as `.mcp.json` server entries, keyed by the server name, and support the `stdio`, `http`, `sse`, and `ws` types. To keep an MCP server out of the main conversation entirely and avoid its tool descriptions consuming context there, define it inline here rather than in `.mcp.json`. The subagent gets the tools; the parent conversation doesn’t. Claude Code loads an inline server from an agent file in your project’s `.claude/agents/` directory, or in an `--add-dir` directory’s `.claude/agents/`, only after you [trust the folder the agent file came from](../02-Claude-Code-CLI/permissions.md#what-runs-before-you-trust-a-folder). Before v2.1.238, Claude Code loaded these servers without checking trust.

- **Trust that doesn’t count**: a parent folder’s trust, and the automatic trust a `-p` or SDK session gets for [hooks in settings files](../02-Claude-Code-CLI/permissions.md#what-runs-before-you-trust-a-folder)
- **Until then**: Claude Code skips every inline server in that agent file and writes the exact `projects["<path>"].hasTrustDialogAccepted` key for `~/.claude.json` to the debug log
- **`--add-dir` directories**: a directory outside your trusted workspace’s repository needs its own trust entry, since its `.claude/agents/` files don’t inherit your workspace’s trust

Claude Code loads two kinds of server without checking trust for the folder the agent file came from:

- A name that references a server you already configured
- An inline server in an agent file from `~/.claude/agents/`, in one you pass with `--agents` or the SDK `agents` option, or in one that managed settings supplies

The MCP restrictions that apply to the main session also cover servers declared in subagent frontmatter:

- [`--strict-mcp-config`](../02-Claude-Code-CLI/cli-reference.md) and [`--bare`](../02-Claude-Code-CLI/cli-reference.md)
- [Enterprise managed MCP configuration](../06-MCP-Tools/General/managed-mcp.md)
- [`allowedMcpServers` and `deniedMcpServers` policies](../06-MCP-Tools/General/managed-mcp.md#policy-based-control-with-allowlists-and-denylists)

When one of these blocks a server, Claude Code skips it and shows a warning naming the blocked servers. Managed-settings restrictions apply to every subagent regardless of how it is defined. `--strict-mcp-config` doesn’t filter servers you pass inline via `--agents` or the SDK `agents` option, since those are explicit caller input.


[​](#permission-modes)

Permission modes

Set `permissionMode` to choose the permission mode a subagent runs in. Use the modes’ config values, so Manual mode is `default`. If you leave it unset, the subagent inherits the main conversation’s [permission mode](../02-Claude-Code-CLI/permission-modes.md). The main conversation’s permission mode decides whether Claude Code uses the value you set:

- When the main conversation is in `bypassPermissions`, `acceptEdits`, or [auto mode](../02-Claude-Code-CLI/permission-modes.md#eliminate-prompts-with-auto-mode), the subagent runs in that same mode and Claude Code ignores the `permissionMode` you set. Under auto mode, the classifier evaluates the subagent’s tool calls with the main conversation’s block and allow rules. When the subagent finishes, the classifier also reviews its work and its final report before the report is delivered, as [How auto mode handles subagents](../02-Claude-Code-CLI/permission-modes.md#eliminate-prompts-with-auto-mode) describes.
- When the main conversation is in `default`, `dontAsk`, or `plan` mode, the subagent runs in the permission mode you set, except `bypassPermissions`. A subagent that declares `bypassPermissions` keeps the main conversation’s mode instead. The `bypassPermissions` exception requires Claude Code v2.1.267 or later.

`permissionMode` accepts these values, and `manual` as an alias for `default`:

| Mode                | Behavior                                                                                                                                                                                                                                                                                                                                                                                     |
|:--------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `default`           | Manual mode: prompts for permission                                                                                                                                                                                                                                                                                                                                                          |
| `acceptEdits`       | Auto-accept file edits and common filesystem commands for paths in the working directory or `additionalDirectories`                                                                                                                                                                                                                                                                          |
| `auto`              | [Auto mode](../02-Claude-Code-CLI/permission-modes.md#eliminate-prompts-with-auto-mode): a background classifier reviews commands and protected-directory writes                                                                                                                                                                                                                                             |
| `dontAsk`           | Auto-deny permission prompts. Explicitly allowed tools still work; `AskUserQuestion`, MCP tools marked [`requiresUserInteraction`](../06-MCP-Tools/General/mcp.md#require-approval-for-a-specific-tool), and connector tools [your organization set to `ask`](../06-MCP-Tools/General/mcp.md#organization-controls-on-connector-tools) in sessions where that setting reaches Claude Code are denied even if you’ve allowed them |
| `bypassPermissions` | [Skip permission prompts](../02-Claude-Code-CLI/permission-modes.md#skip-all-checks-with-bypasspermissions-mode). A subagent runs in this mode only when the main conversation does                                                                                                                                                                                                                          |
| `plan`              | Plan mode (read-only exploration)                                                                                                                                                                                                                                                                                                                                                            |


[​](#preload-skills-into-subagents)

Preload skills into subagents

Use the `skills` field to inject skill content into a subagent’s context at startup. This gives the subagent domain knowledge without requiring it to discover and load skills during execution.

```python
---
name: api-developer
description: Implement API endpoints following team conventions
skills:
  - api-conventions
  - error-handling-patterns
---

Implement API endpoints. Follow the conventions and patterns from the preloaded skills.
```

The full content of each listed skill is injected into the subagent’s context at startup. This field controls which skills are preloaded, not which skills the subagent can access: without it, the subagent can still discover and invoke project, user, and plugin skills through the Skill tool during execution. To prevent a subagent from invoking skills entirely, omit `Skill` from the [`tools`](#available-tools) list or add it to `disallowedTools`. You can’t preload skills that set [`disable-model-invocation: true`](../08-Plugins-Skills/skills.md#control-who-invokes-a-skill), since preloading draws from the same set of skills Claude can invoke. This includes the bundled `/verify` skill: only you can run it, so it can’t be preloaded either. If a listed skill is missing or disabled, for example by your organization’s policy, Claude Code skips it and logs a warning to the debug log.

This is the inverse of [running a skill in a subagent](../08-Plugins-Skills/skills.md#run-skills-in-a-subagent). With `skills` in a subagent, the subagent controls the system prompt and loads skill content. With `context: fork` in a skill, the skill content is injected into the agent you specify. In both cases the subagent starts without your conversation history.


[​](#enable-persistent-memory)

Enable persistent memory

The `memory` field gives the subagent a persistent directory that survives across conversations. The subagent uses this directory to build up knowledge over time, such as codebase patterns, debugging insights, and architectural decisions.

```python
---
name: code-reviewer
description: Reviews code for quality and best practices
memory: user
---

You are a code reviewer. As you review code, update your agent memory with
patterns, conventions, and recurring issues you discover.
```

Choose a scope based on how broadly the memory should apply:

| Scope     | Location                                      | Use when                                                                                   |
|:----------|:----------------------------------------------|:-------------------------------------------------------------------------------------------|
| `user`    | `~/.claude/agent-memory/<name-of-agent>/`     | the subagent should remember learnings across all projects                                 |
| `project` | `.claude/agent-memory/<name-of-agent>/`       | the subagent’s knowledge is project-specific and shareable via version control             |
| `local`   | `.claude/agent-memory-local/<name-of-agent>/` | the subagent’s knowledge is project-specific but shouldn’t be checked into version control |

Subagent memory is part of [auto memory](../02-Claude-Code-CLI/memory.md#auto-memory): if you turn auto memory off, with the `autoMemoryEnabled` setting or `CLAUDE_CODE_DISABLE_AUTO_MEMORY`, the `memory` field has no effect and the subagent launches without the memory instructions or the memory tool access described below. When memory is enabled:

- The subagent’s system prompt includes instructions for reading and writing to the memory directory.
- The subagent’s system prompt also includes the first 200 lines or 25KB of `MEMORY.md` in the memory directory, whichever comes first, with instructions to curate `MEMORY.md` if it exceeds that limit.
- Read, Write, and Edit tools are automatically enabled so the subagent can manage its memory files.

##### Persistent memory tips

- `project` is the recommended default scope. It makes subagent knowledge shareable via version control.
- Ask the subagent to consult its memory before starting work: “Review this PR, and check your memory for patterns you’ve seen before.”
- Ask the subagent to update its memory after completing a task: “Now that you’re done, save what you learned to your memory.” Over time, this builds a knowledge base that makes the subagent more effective.
- Include memory instructions directly in the subagent’s markdown file so it proactively maintains its own knowledge base:

  ``` shiki
  Update your agent memory as you discover codepaths, patterns, library
  locations, and key architectural decisions. This builds up institutional
  knowledge across conversations. Write concise notes about what you found
  and where.
  ```


[​](#conditional-rules-with-hooks)

Conditional rules with hooks

For more dynamic control over tool usage, use `PreToolUse` hooks to validate operations before they execute. This is useful when you need to allow some operations of a tool while blocking others. This example creates a subagent that only allows read-only database queries. The `PreToolUse` hook runs the script specified in `command` before each Bash command executes:

```python
---
name: db-reader
description: Execute read-only database queries
tools: Bash
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate-readonly-query.sh"
---
```

Claude Code [passes hook input as JSON](../07-Hooks/hooks.md#pretooluse-input) via stdin to hook commands. The validation script reads this JSON, extracts the Bash command, and [exits with code 2](../07-Hooks/hooks.md#exit-code-2-behavior-per-event) to block write operations:

```python
#!/bin/bash
# ./scripts/validate-readonly-query.sh

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

# Block SQL write operations (case-insensitive)
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
fi

exit 0
```

On macOS and Linux, make the script executable, or the hook fails instead of blocking anything:

```python
chmod +x ./scripts/validate-readonly-query.sh
```

To test the rule, ask the subagent to run an `UPDATE` statement: the script exits with code 2, Claude Code blocks the command, and the subagent sees the `Blocked: Only SELECT queries are allowed` message. See [Hook input](../07-Hooks/hooks.md#pretooluse-input) for the complete input schema and [exit codes](../07-Hooks/hooks.md#exit-code-output) for how exit codes affect behavior. On Windows, write hook scripts in PowerShell and add `shell: powershell` to the hook entry as shown in [running hooks in PowerShell](../07-Hooks/hooks.md#windows-powershell-tool).


[​](#disable-specific-subagents)

Disable specific subagents

You can prevent Claude from using specific subagents by adding them to the `deny` array in your [settings](../02-Claude-Code-CLI/settings-reference.md#permission-settings). Use the format `Agent(subagent-name)` where `subagent-name` matches the subagent’s name field.

```python
{
  "permissions": {
    "deny": ["Agent(Explore)", "Agent(my-custom-agent)"]
  }
}
```

This works for both built-in and custom subagents. You can also use the `--disallowedTools` CLI flag:

```python
claude --disallowedTools "Agent(Explore)"
```

See [Permissions documentation](../02-Claude-Code-CLI/permissions.md#tool-specific-permission-rules) for more details on permission rules.


[​](#define-hooks-for-subagents)

Define hooks for subagents

Subagents can define [hooks](../07-Hooks/hooks.md) that run during the subagent’s lifecycle. There are two ways to configure hooks:

- **In the subagent’s frontmatter**: define hooks that run only while that subagent is active
- **In `settings.json`**: define session-wide hooks that also fire inside subagents. Tool events such as `PreToolUse` and `PostToolUse` fire for the subagent’s tool calls the same way they do in the main conversation, and `SubagentStart` and `SubagentStop` fire when a subagent starts or finishes

Hooks from [settings files, managed policy settings, and plugins](../07-Hooks/hooks.md#hook-locations) all apply inside subagents, so a `PreToolUse` hook in `settings.json` also runs before every tool a subagent uses.


[​](#hooks-in-subagent-frontmatter)

Hooks in subagent frontmatter

Define hooks directly in the subagent’s markdown file. These hooks only run while that specific subagent is active and are cleaned up when it finishes.

Frontmatter hooks fire when the agent is spawned as a subagent through the Agent tool or an @-mention, and when the agent runs as the main session via [`--agent`](#invoke-subagents-explicitly) or the `agent` setting. In the main-session case they run alongside any hooks defined in [`settings.json`](../07-Hooks/hooks.md).

To let a project-level subagent’s frontmatter hooks run, accept the [workspace trust dialog](../02-Claude-Code-CLI/permissions.md#project-allow-rules-and-workspace-trust) for the folder that contains the agent file. Hooks from user-level subagents in `~/.claude/agents/` and from definitions you pass with `--agents` run without this step. If you added a folder with `--add-dir` from outside your trusted workspace’s repository, trust that folder separately: its `.claude/agents/` hooks don’t inherit the workspace’s grant. Until you trust the folder, the subagent still runs, but Claude Code skips its frontmatter hooks and logs an error to the debug log explaining how to trust the folder. This is a stricter rule than the one for hooks in settings files: trusting a parent folder isn’t enough, and a `-p` session doesn’t count as trusted. [What runs before you trust a folder](../02-Claude-Code-CLI/permissions.md#what-runs-before-you-trust-a-folder) compares the two. Before v2.1.218, frontmatter hooks could run from folders you hadn’t trusted, including in non-interactive sessions. All [hook events](../07-Hooks/hooks.md#hook-events) are supported. The most common events for subagents are:

| Event         | Matcher input | When it fires                                                       |
|:--------------|:--------------|:--------------------------------------------------------------------|
| `PreToolUse`  | Tool name     | Before the subagent uses a tool                                     |
| `PostToolUse` | Tool name     | After the subagent uses a tool                                      |
| `Stop`        | (none)        | When the subagent finishes (converted to `SubagentStop` at runtime) |

This example validates Bash commands with the `PreToolUse` hook and runs a linter after file edits with `PostToolUse`:

```python
---
name: code-reviewer
description: Review code changes with automatic linting
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate-command.sh"
  PostToolUse:
    - matcher: "Edit|Write"
      hooks:
        - type: command
          command: "./scripts/run-linter.sh"
---
```

When the agent is invoked as a subagent, `Stop` hooks in frontmatter are automatically converted to `SubagentStop` events.


[​](#project-level-hooks-for-subagent-events)

Project-level hooks for subagent events

Configure hooks in `settings.json` that respond to subagent lifecycle events in the main session.

| Event           | Matcher input   | When it fires                    |
|:----------------|:----------------|:---------------------------------|
| `SubagentStart` | Agent type name | When a subagent begins execution |
| `SubagentStop`  | Agent type name | When a subagent completes        |

Both events support matchers to target specific agent types by name. The matcher value is the agent’s frontmatter `name` for project-level and user-level subagents, or the plugin-scoped identifier such as `my-plugin:db-agent` for [plugin subagents](../08-Plugins-Skills/plugins-components.md#agents). A scoped name contains a colon, so it is evaluated as an [unanchored regular expression](../07-Hooks/hooks.md#matcher-patterns); anchor it with `^` and `$`, as in `^my-plugin:db-agent$`, to match only that agent. This example runs a setup script only when the `db-agent` subagent starts, and a cleanup script when any subagent stops:

```python
{
  "hooks": {
    "SubagentStart": [
      {
        "matcher": "db-agent",
        "hooks": [
          { "type": "command", "command": "./scripts/setup-db-connection.sh" }
        ]
      }
    ],
    "SubagentStop": [
      {
        "hooks": [
          { "type": "command", "command": "./scripts/cleanup-db-connection.sh" }
        ]
      }
    ]
  }
}
```

See [Hooks](../07-Hooks/hooks.md) for the complete hook configuration format.


[​](#work-with-subagents)

Work with subagents


[​](#understand-automatic-delegation)

Understand automatic delegation

Claude automatically delegates tasks based on the task description in your request, the `description` field in subagent configurations, and current context. To encourage proactive delegation, include phrases like “use proactively” in your subagent’s description field. Keep descriptions brief: Claude Code shows a startup warning when your subagents’ combined descriptions pass [the 15,000-token limit](../02-Claude-Code-CLI/errors.md#agent-descriptions-are-over-the-15000-token-limit), and still loads every subagent. If the subagent ships in a [plugin](../08-Plugins-Skills/plugins.md), you can measure how reliably Claude delegates to it across realistic prompts instead of checking one at a time: [`claude plugin eval`](../08-Plugins-Skills/plugin-evals.md) runs each prompt with and without the plugin and scores the results.


[​](#invoke-subagents-explicitly)

Invoke subagents explicitly

When automatic delegation isn’t enough, you can request a subagent yourself. Three patterns escalate from a one-off suggestion to a session-wide default:

- **Natural language**: name the subagent in your prompt; Claude decides whether to delegate
- **@-mention**: guarantees the subagent runs for one task
- **Session-wide**: the whole session runs as that subagent via the `--agent` flag or the `agent` setting

For natural language, there’s no special syntax. Name the subagent and Claude typically delegates:

```python
Use the test-runner subagent to fix failing tests
Have the code-reviewer subagent look at my recent changes
```

**@-mention the subagent.** Type `@` and pick the subagent from the typeahead, the same way you @-mention files. This ensures that specific subagent runs rather than leaving the choice to Claude:

```python
@"code-reviewer (agent)" look at the auth changes
```

Your full message still goes to Claude, which writes the subagent’s task prompt based on what you asked. The @-mention controls which subagent Claude invokes, not what prompt it receives. Subagents provided by an enabled [plugin](../08-Plugins-Skills/plugins.md) appear in the typeahead under their scoped name, such as `my-plugin:code-reviewer` or `my-plugin:review:security` when the plugin [organizes agents into subfolders](#choose-the-subagent-scope). Named background subagents currently running in the session also appear in the typeahead, showing their status next to the name. You can also type the mention manually without using the picker: `@agent-<name>` for local subagents, or `@agent-` followed by the scoped name for plugin subagents, for example `@agent-my-plugin:code-reviewer`. While you type this form the typeahead shows file matches rather than agents. The agent mention still resolves when you submit. **Run the whole session as a subagent.** Pass [`--agent <name>`](../02-Claude-Code-CLI/cli-reference.md) to start a session where the main thread itself takes on that subagent’s tool restrictions and model:

```python
claude --agent code-reviewer
```

Unless the agent’s [prompt is empty](#choose-the-subagent-scope), a custom subagent’s system prompt replaces the default Claude Code system prompt entirely, the same way [`--system-prompt`](../02-Claude-Code-CLI/cli-reference.md) does. `CLAUDE.md` files and project memory still load through the normal message flow, even when the agent’s definition sets [`omitClaudeMd`](#supported-frontmatter-fields). The agent name appears as `@<name>` in the startup header so you can confirm it’s active. This works with built-in and custom subagents, and the choice persists when you resume the session: Claude Code restores the agent’s tool restrictions and model along with the conversation. If the agent no longer exists when you resume, the session continues with the default tools and shows a [warning naming the agent](../02-Claude-Code-CLI/errors.md#session-agent-no-longer-available). For the system prompt in either case, see [System prompt flags in resumed conversations](../02-Claude-Code-CLI/cli-reference.md#system-prompt-flags-in-resumed-conversations). For a plugin-provided subagent, you can pass only the agent name and Claude Code finds it:

```python
claude --agent security-reviewer
```

If multiple plugins provide agents with the same name, pass the scoped name to disambiguate:

```python
claude --agent my-plugin:security-reviewer
```

If the plugin places the agent in a subfolder of its `agents/` directory, include the subfolder in the scoped name, for example `claude --agent my-plugin:review:security`. To make it the default for every session in a project, set `agent` in `.claude/settings.json`:

```python
{
  "agent": "code-reviewer"
}
```

The CLI flag overrides the setting if both are present.


[​](#run-subagents-in-foreground-or-background)

Run subagents in foreground or background

Subagents can run in the foreground or the background:

- **Foreground subagents** block the main conversation until complete. Permission prompts are passed through to you as they come up.
- **Background subagents** run concurrently while you continue working. When a background subagent reaches a tool call that needs permission, Claude Code surfaces the prompt in your main session and names the subagent that is asking. Approve to let the subagent continue, or press Esc to deny that one tool call without stopping the subagent.

For each subagent Claude spawns with the Agent tool, Claude Code picks foreground or background from the first of these cases that applies:

- If an in-process [agent team](agent-teams.md#limitations) teammate spawned the subagent, Claude Code runs it in the foreground. Claude Code refuses with an error to spawn a teammate’s subagent whose definition sets [`background: true`](#supported-frontmatter-fields). Where [fork mode](#turn-fork-mode-on-or-off) is off and you haven’t [turned background tasks off](../02-Claude-Code-CLI/env-vars.md), Claude Code also refuses with an error when a teammate sets `run_in_background: true`.
- If you set [`CLAUDE_CODE_DISABLE_BACKGROUND_TASKS`](../02-Claude-Code-CLI/env-vars.md) to `1`, Claude Code runs the subagent in the foreground, in every kind of session and whether or not fork mode is on.
- Where [fork mode](#turn-fork-mode-on-or-off) is on, as it is by default in an interactive session, Claude Code runs the subagent in the background, forks and non-fork subagents alike, and Claude can’t ask for the foreground.
- Where fork mode is off, Claude runs the subagent in the background by default and in the foreground when it needs the result before continuing. Fork mode is off in [non-interactive mode](../02-Claude-Code-CLI/headless.md) with `-p` and in the Agent SDK unless you turn it on. To keep a particular subagent in the background even when Claude wants the result, set its frontmatter [`background`](#supported-frontmatter-fields) field to `true`.

For a skill with `context: fork`, Claude Code follows the rules in [Run skills in a subagent](../08-Plugins-Skills/skills.md#run-skills-in-a-subagent) instead, whether or not fork mode is on. Background subagents run with a [smaller built-in tool set](#available-tools) than foreground subagents, except for conversation forks and [resumed](#resume-subagents) foreground subagents. Background subagents surface every permission prompt in your main session. When you answer one of those prompts with a choice that lasts beyond that one tool call, such as a grant that lasts for the rest of the session, Claude Code applies your answer to the whole session, including your main conversation. A background subagent can leave a background [Bash or PowerShell command](../02-Claude-Code-CLI/tools-reference.md#background-commands) [running past the end of its turn](../02-Claude-Code-CLI/interactive-mode.md#how-backgrounding-works). When that command ends, Claude Code sends the subagent a notification. A background subagent’s results reach Claude as a completion notification in a later turn. Claude waits for that notification before reporting the subagent’s results, and if you ask about progress first, it reports that the subagent is still running. Before v2.1.211, Claude sometimes reported results for a background subagent that hadn’t finished. You can also steer this yourself:

- Where fork mode is off, ask Claude to run a task in the background or in the foreground
- Press **Ctrl+B** to background a running task

Claude Code clears a background subagent’s row from the subagent panel below the prompt input in one of two ways, depending on how the subagent ended:

- When a subagent finishes successfully, Claude Code removes its row immediately and, except in [screen reader mode](../02-Claude-Code-CLI/accessibility.md), shows `/tasks to see subagents` in the footer for 30 seconds. During those 30 seconds, run [`/tasks`](../02-Claude-Code-CLI/commands.md) and press `Enter` on the subagent to open its transcript. Before v2.1.232, Claude Code kept the row for 30 seconds after the subagent finished, the same as a failed one, and showed no footer hint.
- When a subagent fails or you stop it, Claude Code keeps its row for 30 seconds. To clear the row sooner, select it and press `x`.

A background subagent that completes stays listed in [`/tasks`](../02-Claude-Code-CLI/commands.md), marked done and sorted below running work, for the same 30 seconds as the footer hint. Its detail view stays open when the subagent finishes. Subagents that fail or that you stop leave the list. Before v2.1.208, a completed subagent left the list the moment it finished and its detail view closed.


[​](#subagent-names)

Subagent names

Claude can give a subagent a name by passing a `name` parameter on the Agent tool call, and may do so on its own, without asking you first. The name makes the subagent addressable: Claude can [message or resume it by name](#resume-subagents) after it finishes. In an interactive session with [agent teams](agent-teams.md) enabled, a subagent that Claude spawns from the main conversation with a `name` launches as a teammate instead, unless the call is a [fork](#fork-the-current-conversation) or passes `isolation` on the call itself. An `isolation` value in the subagent’s frontmatter doesn’t prevent it, and the teammate then runs in the main session’s working directory. See [How Claude starts agent teams](agent-teams.md#how-claude-starts-agent-teams).


[​](#api-errors-in-subagents)

API errors in subagents

When something [cuts off a subagent’s response mid-stream](../02-Claude-Code-CLI/errors.md#the-response-above-may-be-incomplete), and the partial response contains text but no tool calls, Claude Code prompts the subagent to continue rather than ending the run. This happens in interactive sessions too. The run ends on the error only once those continuations are used up. As of v2.1.199, a subagent whose run ends on an API error, such as a usage limit or a repeated server error, reports that failure back to Claude instead of returning the error text as if it were the subagent’s findings. What Claude receives depends on where the subagent ran:

- **Foreground**: if a rate limit, overload, or server error cuts off a subagent that already produced text output, the Agent tool returns that partial output with a note that the subagent was cut off and didn’t finish its task. A subagent that produced nothing, or whose only output was tool calls, fails with [`Agent terminated early due to an API error`](../02-Claude-Code-CLI/errors.md#agent-terminated-early-due-to-an-api-error), followed by the error detail. In v2.1.199, a rate limit, overload, or server error that cut off the tool-calls-only shape returned an empty partial result containing only the cut-off note instead.
- **Background**: the subagent is marked failed, and the message Claude receives when it ends names the API error and includes the subagent’s last output, so partial work isn’t lost.

When you configure a [fallback model chain](../02-Claude-Code-CLI/model-config.md#fallback-model-chains) and a subagent encounters a failure the chain covers, such as its model being unavailable, Claude Code switches the subagent to the first model in the chain that accepts the request. The subagent keeps working instead of ending on the error. Once the underlying API error clears, ask Claude to retry the task or [resume the subagent](#resume-subagents).


[​](#subagent-output-scanning)

Subagent output scanning

Claude Code scans each subagent’s final report before Claude reads it. A subagent may have read files, web pages, or command output you never reviewed, and text from those sources can carry instructions aimed at the main conversation. The scan never removes or rewords anything; it makes two kinds of change you may notice in a report:

- **Backslash insertion**: the scan inserts a backslash into text that imitates Claude Code’s own output, such as a `<system-reminder>` tag or a line starting with `Human:` or `Assistant:`, so the imitation reads as ordinary text instead of being mistaken for part of the conversation.
- **Marker line**: the scan prepends a line starting with `[harness: subagent output matched instruction-shaped pattern(s):` when the report imitates a tag like `<system-reminder>` or mentions permission settings such as `bypassPermissions` or `--dangerously-skip-permissions`. Permission-setting mentions get the marker line, but the text itself stays as written.

The scan doesn’t judge whether content is malicious, and it doesn’t change what an instruction in a report can do: a tool call the report leads Claude to make still goes through the session’s [permission checks](../02-Claude-Code-CLI/permissions.md) and [sandboxing](../02-Claude-Code-CLI/sandboxing.md). It isn’t a substitute for [restricting what a subagent can reach](#control-subagent-capabilities). A report that returns to Claude as the subagent’s result also arrives under a header marking it as subagent output. The header states that instructions or approval claims inside the report are the subagent’s words and carry no authority from you. A [background subagent’s report](#run-subagents-in-foreground-or-background) arrives inside a completion notification, which is marked as an automated event rather than a message from you.

Subagent output scanning requires Claude Code v2.1.210 or later.


[​](#common-patterns)

Common patterns


[​](#isolate-high-volume-operations)

Isolate high-volume operations

One of the most effective uses for subagents is isolating operations that produce large amounts of output. Running tests, fetching documentation, or processing log files can consume significant context. By delegating these to a subagent, the verbose output stays in the subagent’s context while only the relevant summary returns to your main conversation.

```python
Use a subagent to run the test suite and report only the failing tests with their error messages
```


[​](#run-parallel-research)

Run parallel research

For independent investigations, spawn multiple subagents to work simultaneously:

```python
Research the authentication, database, and API modules in parallel using separate subagents
```

Each subagent explores its area independently, then Claude synthesizes the findings. This works best when the research paths don’t depend on each other.

When subagents complete, their results return to your main conversation. Running many subagents that each return detailed results can consume significant context, and each subagent spends tokens of its own while it runs.

For work that needs to keep running in parallel or won’t fit in one context window, run it in [separate sessions](agents.md) and let Claude [pass findings between them](../02-Claude-Code-CLI/cross-session-messaging.md).


[​](#chain-subagents)

Chain subagents

For multi-step workflows, ask Claude to use subagents in sequence. Each subagent completes its task and returns results to Claude, which then passes relevant context to the next subagent.

```python
Use the code-reviewer subagent to find performance issues, then use the optimizer subagent to fix them
```


[​](#choose-between-subagents-and-main-conversation)

Choose between subagents and main conversation

Use the **main conversation** when:

- The task needs frequent back-and-forth or iterative refinement
- Multiple phases share significant context, such as planning, implementation, and testing
- You’re making a quick, targeted change
- Latency matters. A subagent that isn’t a [fork](#fork-the-current-conversation) starts fresh and may need time to gather context

Use **subagents** when:

- The task produces verbose output you don’t need in your main context
- You want to enforce specific tool restrictions or permissions
- The work is self-contained and can return a summary

Consider [Skills](../08-Plugins-Skills/skills.md) instead when you want reusable prompts or workflows that run in the main conversation context rather than isolated subagent context. For a question about something already in your conversation, use [`/btw`](../02-Claude-Code-CLI/interactive-mode.md#side-questions-with-%2Fbtw) instead of a subagent. It sees your full context but has no tool access, and the answer isn’t added to history.


[​](#let-subagents-spawn-their-own-subagents)

Let subagents spawn their own subagents

By default, a subagent can spawn subagents of its own, up to three layers below the main conversation. At the depth limit, Claude Code withholds the `Agent` tool from every subagent except a [fork](#fork-the-current-conversation), so a subagent at the limit does its delegated work itself and returns one summary. A fork at the limit keeps `Agent` in its inherited tool list, but the tool returns an error instead of spawning. Nested subagents suit a delegated task that itself splits into parallel subtasks, such as a reviewer subagent that dispatches a verifier per finding. In an interactive session, only the top-level subagent’s summary returns to you and the intermediate output stays out of your main conversation: a subagent that launches background subagents waits for their results before it finishes. In [non-interactive mode](../02-Claude-Code-CLI/headless.md) and the Agent SDK, the launching subagent doesn’t wait, so a nested background subagent that finishes after its launcher has ended reports to your main conversation instead. To change the limit, set [`CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`](../02-Claude-Code-CLI/env-vars.md) to the number of subagent layers you want below your main conversation. For example, this entry in [`settings.json`](../02-Claude-Code-CLI/settings.md) caps nesting at two layers:

```python
{
  "env": {
    "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "2"
  }
}
```

With this value, your subagents can delegate to a second layer of their own, and that second layer can’t delegate further. Set `1` to turn nesting off. A nested subagent is configured the same way as a top-level one and resolves from the same [scopes](#choose-the-subagent-scope). To keep one subagent from spawning while nesting is on, such as a reviewer that should stay read-only, omit `Agent` from its [`tools`](#available-tools) list or add it to `disallowedTools`. In the terminal, Claude Code shows nested subagents as a tree in the subagent panel below the prompt input and marks each row that still has descendants in the panel with a `(+N)` count of them. Open a row to see that subagent’s siblings and direct children with a path back to `main`.

Earlier versions used different defaults:

- **v2.1.172 through v2.1.216**: subagents could nest by default, up to five layers deep, and the limit couldn’t be changed.
- **v2.1.217 through v2.1.218**: the limit defaulted to one, so a subagent couldn’t spawn its own unless you raised it; v2.1.219 raised the default to three.


[​](#concurrent-subagent-limit)

Concurrent subagent limit

Two limits control subagent use, each with its own variable: this one stops Claude from spawning more subagents while too many are running, and the [depth limit](#let-subagents-spawn-their-own-subagents) caps how deeply subagents nest. There’s no limit on the total number of subagents Claude can spawn over a session. By default, when 20 subagents are running in a session, spawning another with the Agent tool fails with `Concurrent subagent limit reached`, and the error tells Claude not to retry. Spawning succeeds again when the running count drops below the limit. To change the limit, set [`CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`](../02-Claude-Code-CLI/env-vars.md) to any positive whole number. Sessions with [ultracode](../02-Claude-Code-CLI/model-config.md#adjust-effort-level) active are exempt: the limit isn’t enforced there. Requires Claude Code v2.1.217 or later. The limit blocks only subagents Claude spawns with the Agent tool, but other runs occupy the same slots:

- An in-session fork you start with [`/subtask`](#fork-the-current-conversation) takes a slot while it runs and is never blocked by the limit.
- [Resuming a subagent](#resume-subagents) that already finished takes a fresh slot without checking the limit, so resumes can push the running count past it.

Agents that other features run, such as [workflow](../02-Claude-Code-CLI/workflows.md) agents and [agent team](agent-teams.md) teammates, follow their own limits instead.


[​](#manage-subagent-context)

Manage subagent context


[​](#what-loads-at-startup)

What loads at startup

Each subagent starts with a fresh, isolated context window. It doesn’t see your conversation history, the skills you’ve already invoked, or the files Claude has already read. Claude composes a delegation message that summarizes the task, and the subagent works from there. The exception is a [fork](#fork-the-current-conversation), which inherits the parent conversation instead of starting fresh. A non-fork subagent’s initial context contains:

- **System prompt**: the agent’s own prompt plus environment details that Claude Code appends, not the Claude Code system prompt. Custom subagents define theirs in the [markdown body](#write-subagent-files) or `prompt` field. Built-in agents have predefined prompts.
- **Task message**: the delegation prompt Claude writes when it hands off the work.
- **CLAUDE.md files**: every level of the [CLAUDE.md hierarchy](../02-Claude-Code-CLI/memory.md#how-claude-md-files-load) the main conversation loads, including `~/.claude/CLAUDE.md`, project rules, `CLAUDE.local.md`, managed policy files, and any [`AGENTS.md` files](../02-Claude-Code-CLI/memory.md#agents-md) loaded as project instructions. The built-in Explore and Plan agents skip this. A subagent whose definition sets [`omitClaudeMd`](#supported-frontmatter-fields) loads only the managed policy files, or none at all when the definition comes from [managed settings](#choose-the-subagent-scope).
- **Git status**: a snapshot Claude Code reads from your repository when the subagent starts. Absent outside a Git repository or whenever the snapshot is turned off; see [`includeGitInstructions`](../02-Claude-Code-CLI/settings-reference.md#includegitinstructions). Explore and Plan skip it regardless.
- **Preloaded skills**: full content of any skill named in the agent’s [`skills` field](#preload-skills-into-subagents). Built-in agents don’t preload skills.
- **Sibling roster**: a [system reminder](../02-Claude-Code-CLI/glossary.md#system-reminder) listing `main` and every other named agent in the session, each a valid `to` value for [`SendMessage`](#resume-subagents). Requires Claude Code v2.1.206 or later. The roster appears only when the subagent’s tools include `SendMessage` and at least one other agent has a name, whether Claude named it when spawning it or it runs as an [agent team](agent-teams.md) teammate. It is a snapshot taken when the subagent starts, so agents named later don’t appear.

To launch one of your own subagents without the user, project, and local CLAUDE.md files, set [`omitClaudeMd: true`](#supported-frontmatter-fields) in its frontmatter or `--agents` JSON. The main conversation still has your full CLAUDE.md when it reads these subagents’ results, so most rules don’t need to reach the subagent itself. If a rule must, such as “ignore the `vendor/` directory,” restate it in the prompt you give Claude when delegating. You can’t change which subagents receive git status. Only Explore and Plan skip it. Some main-conversation state never reaches a non-fork subagent:

- **Output style**: a subagent runs its own system prompt, so your [output style](../02-Claude-Code-CLI/output-styles.md) doesn’t shape its responses, except in a [fork](#fork-the-current-conversation).
- **Auto memory**: the main conversation’s [auto memory](../02-Claude-Code-CLI/memory.md#auto-memory) isn’t loaded. To give a subagent persistent memory of its own, use the [`memory` field](#enable-persistent-memory).
- **Context window size**: a subagent’s context window is sized by its own model, not the parent’s. Delegating to a model with a smaller window gives that subagent the smaller window.


[​](#resume-subagents)

Resume subagents

Each subagent invocation creates a new instance rather than continuing an earlier one. To continue an existing subagent’s work instead of starting over, ask Claude to resume it. Resumed subagents retain their full conversation history, including all previous tool calls, results, and reasoning. If the subagent spawned [background subagents of its own](#let-subagents-spawn-their-own-subagents), that history includes the results they delivered while it ran. The subagent picks up exactly where it stopped rather than starting fresh.

- When a subagent completes, Claude receives its agent ID.
- The built-in Explore and Plan agents are one-shot and return no agent ID, so Claude can’t resume them. Use `general-purpose` or a custom subagent when you need to continue the work.
- When a subagent stops at its [`maxTurns`](#supported-frontmatter-fields) limit, Claude Code marks the returned output as partial. For subagents that return an agent ID, Claude Code also notes in the result that Claude can message the subagent to continue from where it stopped.

Claude uses the `SendMessage` tool with the agent’s ID or name as the `to` field to resume it. `SendMessage` doesn’t require [agent teams](agent-teams.md) to be enabled; only structured team-protocol messages such as `shutdown_request` and `plan_approval_response` do. Beyond subagents and teammates, in sessions where cross-session messaging is enabled, Claude can use the same tool to message [your other Claude Code sessions](../02-Claude-Code-CLI/cross-session-messaging.md), on this machine or [beyond it](../02-Claude-Code-CLI/cross-session-messaging.md#message-sessions-on-other-machines). To resume a subagent, ask Claude to continue the previous work:

```python
Use the code-reviewer subagent to review the authentication module
[Agent completes]

Continue that code review and now analyze the authorization logic
[Claude resumes the subagent with full context from previous conversation]
```

When Claude sends a completed subagent a message with the `SendMessage` tool, the subagent resumes in the background without a new `Agent` invocation. The same applies to a subagent that Claude stopped with the `TaskStop` tool, once its stopped run has exited. The resumed run keeps the [tool set from where the subagent first ran](#run-subagents-in-foreground-or-background) and can keep reading the [prompt cache the original run warmed](../02-Claude-Code-CLI/prompt-caching.md#subagents-and-the-cache). A subagent that has the `SendMessage` tool can send that message too. In an interactive session, the resumed agent then reports back to the subagent that resumed it, not to your main conversation. That subagent waits for the result before finishing its own work. When a subagent messages an agent it reports to, such as its own launcher, Claude Code resumes that agent without redirecting its results. A subagent you stopped yourself, with `x` in `/tasks` or an SDK `stop_task` request, doesn’t auto-resume. If Claude sends it a message, the message is refused and Claude is told the agent was cancelled. While [that subagent’s row is still in the subagent panel](#run-subagents-in-foreground-or-background), type into its transcript to resume it yourself. After that, a message from Claude can auto-resume it again. Resuming starts a new run of the agent under the same ID, so a subagent that had already failed or completed shows as running again in the task list and in the Agent SDK’s task events. Before v2.1.205, it kept showing its earlier failed or completed status while the resumed run was working. As of v2.1.199, `SendMessage` checks that a name still refers to the same agent it reached earlier in the conversation. If a newer agent has taken the name, such as a re-spawned background agent that reused it, Claude Code refuses the send rather than delivering it to the wrong agent, and the error reports which agent the name now reaches so Claude can retarget. To reach the earlier agent while it’s still running, Claude addresses it by the agent ID it received when it spawned that agent. The check is scoped to the current conversation and resets on `/clear`. As of v2.1.198, a subagent treats messages from the agent that launched it as normal task direction, including mid-task course corrections, and acts on them within its own permission settings. Two limits still hold regardless of who sent the message: no message from any agent counts as your approval for a pending permission prompt, and no agent message can change a subagent’s permission settings, `CLAUDE.md`, or configuration. Only the permission system or your own messages can grant approval. You can also ask Claude for the agent ID if you want to reference it explicitly, or find IDs in the transcript files at `~/.claude/projects/{project}/{sessionId}/subagents/`. Each transcript is stored as `agent-{agentId}.jsonl`. Subagent transcripts persist independently of the main conversation:

- **Main conversation compaction**: when the main conversation compacts, subagent transcripts are unaffected. They’re stored in separate files.
- **Session persistence**: subagent transcripts persist within their session. You can [resume a subagent](#resume-subagents) after restarting Claude Code by resuming the same session.
- **Automatic cleanup**: Claude Code deletes subagent transcripts after the `cleanupPeriodDays` retention period, 30 days by default, following the [retention sweep rules](../02-Claude-Code-CLI/claude-directory.md#cleaned-up-automatically).


[​](#auto-compaction)

Auto-compaction

Subagents support automatic compaction using the same logic as the main conversation. Compaction triggers under the same conditions, and `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` applies to subagents as well. See [environment variables](../02-Claude-Code-CLI/env-vars.md) for when the override takes effect. Compaction events are logged in subagent transcript files:

```python
{
  "type": "system",
  "subtype": "compact_boundary",
  "compactMetadata": {
    "trigger": "auto",
    "preTokens": 167189
  }
}
```

The `preTokens` value shows how many tokens were used before compaction occurred.


[​](#fork-the-current-conversation)

Fork the current conversation

Run a forked subagent with `/subtask`, which requires Claude Code v2.1.212 or later. When [agent view is turned off](agent-view.md#turn-off-agent-view), `/subtask` isn’t available and `/fork` starts the forked subagent instead; otherwise `/fork` copies the whole session into a new [background session](agent-view.md#from-inside-a-session).

A fork is a subagent that inherits the entire conversation so far instead of starting fresh. This drops the input isolation that subagents otherwise provide: a fork sees the same system prompt, tools, model, and message history as the main session, so you can hand it a side task without re-explaining the situation. The fork’s own tool calls still stay out of your conversation and only its final result comes back, so your main context window stays clean. Use a fork when any other subagent would need too much background to be useful, or when you want to try several approaches in parallel from the same starting point. Claude starts a fork by requesting the `fork` subagent type through the Agent tool. You control whether it can with [fork mode](#turn-fork-mode-on-or-off), which is on by default in interactive sessions. You can start a fork yourself with `/subtask` followed by a task, whether or not fork mode is on. On v2.1.161 through v2.1.211 the command is `/fork`. Claude Code names the fork from the first words of the task. The following example forks the conversation to draft test cases while you continue with the implementation in the main session:

```python
/subtask draft unit tests for the parser changes so far
```

The fork appears in a panel below your prompt and runs in the background while you keep working. When it finishes, its result arrives as a message in your main conversation. The next section covers the panel controls for watching and steering forks while they run.


[​](#observe-and-steer-running-forks)

Observe and steer running forks

Running forks appear in a panel below the prompt input, with one row for the main session and one for each fork. When a fork finishes successfully, Claude Code removes its row. Claude Code keeps the row of a fork that failed or that you stopped for 30 seconds, [the same as for any other background subagent](#run-subagents-in-foreground-or-background). Before v2.1.232, Claude Code kept a finished fork’s row for 30 seconds as well. Use these keys to interact with the panel:

| Key       | Action                                                                                                                                                                                                               |
|:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `↑` / `↓` | Move between rows                                                                                                                                                                                                    |
| `Enter`   | Open the selected fork’s transcript and send it follow-up messages                                                                                                                                                   |
| `x`       | Stop the selected fork if it’s running, or dismiss its row if it’s no longer running. On the main session row, or on the row of the fork whose transcript you opened with `Enter`, `x` types into the prompt instead |
| `Esc`     | Return focus to the prompt input                                                                                                                                                                                     |

With a fork’s or subagent’s transcript open, follow-up messages and [skills](../08-Plugins-Skills/skills.md) go to that agent, but built-in commands still run in your main conversation. As of v2.1.199, typing `/model` or `/fast` in that view shows a notice that it changes the main conversation’s model or fast mode, not the viewed agent’s, instead of running it silently.


[​](#how-forks-differ-from-other-subagents)

How forks differ from other subagents

A fork inherits everything the main session has at the moment it spawns. Any other subagent starts fresh from its definition.

|                         | Fork                             | Non-fork subagent                                                                                                 |
|:------------------------|:---------------------------------|:------------------------------------------------------------------------------------------------------------------|
| Context                 | Full conversation history        | Fresh context with the prompt you pass                                                                            |
| System prompt and tools | Same as main session             | From the subagent’s [definition file](#write-subagent-files), [filtered for background runs](#available-tools)    |
| Model                   | Same as main session             | From the subagent’s `model` field                                                                                 |
| Permissions             | Prompts surface in your terminal | [Prompts surface in your main session](#run-subagents-in-foreground-or-background) when running in the background |
| Prompt cache            | Shared with main session         | Separate cache                                                                                                    |

Because a fork’s system prompt and tool definitions are identical to the parent, its first request reuses the parent’s [prompt cache](../02-Claude-Code-CLI/prompt-caching.md#subagents-and-the-cache). This makes forking cheaper than spawning a fresh subagent for tasks that need the same context. When Claude spawns a fork through the Agent tool, it can pass `isolation: "worktree"` so the fork’s file edits are written to a separate git worktree instead of your checkout. A fork can’t spawn further forks.


[​](#turn-fork-mode-on-or-off)

Turn fork mode on or off

Claude Code turns fork mode on by default in interactive sessions and leaves it off by default in [non-interactive mode](../02-Claude-Code-CLI/headless.md) with `-p` and in the Agent SDK. The interactive default requires Claude Code v2.1.232 or later. On earlier versions, set `CLAUDE_CODE_FORK_SUBAGENT` to `1` to turn fork mode on. You can tell fork mode is on from how Claude Code handles the Agent tool:

- Claude can spawn a fork by requesting the `fork` subagent type. When Claude doesn’t request a type, it gets the [general-purpose](#built-in-subagents) subagent, if the session still has that type. Subagents spawned from a definition, such as Explore, work as usual.
- Claude Code runs the subagents Claude spawns in the background, forks and non-fork subagents alike, apart from the [cases that stay in the foreground](#run-subagents-in-foreground-or-background). Claude Code also removes the Agent tool’s `run_in_background` parameter, so Claude can’t ask for the foreground.

Set the [`CLAUDE_CODE_FORK_SUBAGENT`](../02-Claude-Code-CLI/env-vars.md) environment variable to override the defaults:

- `1` turns fork mode on in non-interactive mode and the Agent SDK as well
- `0` turns fork mode off in every kind of session

To keep fork mode on but stop Claude from spawning forks, [deny the `fork` subagent type](#disable-specific-subagents) with an `Agent(fork)` rule. Claude Code still runs the subagents Claude spawns in the background, apart from the same [cases that stay in the foreground](#run-subagents-in-foreground-or-background).


[​](#example-subagents)

Example subagents

These examples demonstrate effective patterns for building subagents. Use them as starting points, or generate a customized version with Claude.

**Best practices:**

- **Design focused subagents:** each subagent should excel at one specific task
- **Write descriptions that single out one subagent:** Claude uses the description to decide when to delegate. Make each description specific enough to route to the right subagent, and keep the combined set within the [15,000-token description budget](#understand-automatic-delegation)
- **Limit tool access:** grant only necessary permissions for security and focus
- **Check into version control:** share project subagents with your team


[​](#code-reviewer)

Code reviewer

A read-only subagent that reviews code without modifying it. This example shows how to design a focused subagent with limited tool access that excludes Edit and Write, and a detailed prompt that specifies exactly what to look for and how to format output.

```python
---
name: code-reviewer
description: Expert code review specialist. Proactively reviews code for quality, security, and maintainability. Use immediately after writing or modifying code.
tools: Read, Grep, Glob, Bash
model: inherit
---

You are a senior code reviewer ensuring high standards of code quality and security.

When invoked:
1. Run git diff to see recent changes
2. Focus on modified files
3. Begin review immediately

Review checklist:
- Code is clear and readable
- Functions and variables are well-named
- No duplicated code
- Proper error handling
- No exposed secrets or API keys
- Input validation implemented
- Good test coverage
- Performance considerations addressed

Provide feedback organized by priority:
- Critical issues (must fix)
- Warnings (should fix)
- Suggestions (consider improving)

Include specific examples of how to fix issues.
```


[​](#debugger)

Debugger

A subagent that can both analyze and fix issues. Unlike the code reviewer, this one includes Edit because fixing bugs requires modifying code. The prompt provides a clear workflow from diagnosis to verification.

```python
---
name: debugger
description: Debugging specialist for errors, test failures, and unexpected behavior. Use proactively when encountering any issues.
tools: Read, Edit, Bash, Grep, Glob
---

You are an expert debugger specializing in root cause analysis.

When invoked:
1. Capture error message and stack trace
2. Identify reproduction steps
3. Isolate the failure location
4. Implement minimal fix
5. Verify solution works

Debugging process:
- Analyze error messages and logs
- Check recent code changes
- Form and test hypotheses
- Add strategic debug logging
- Inspect variable states

For each issue, provide:
- Root cause explanation
- Evidence supporting the diagnosis
- Specific code fix
- Testing approach
- Prevention recommendations

Focus on fixing the underlying issue, not the symptoms.
```


[​](#data-scientist)

Data scientist

A domain-specific subagent for data analysis work. This example shows how to create subagents for specialized workflows outside of typical coding tasks. It explicitly sets `model: sonnet` for more capable analysis.

```python
---
name: data-scientist
description: Data analysis expert for SQL queries, BigQuery operations, and data insights. Use proactively for data analysis tasks and queries.
tools: Bash, Read, Write
model: sonnet
---

You are a data scientist specializing in SQL and BigQuery analysis.

When invoked:
1. Understand the data analysis requirement
2. Write efficient SQL queries
3. Use BigQuery command line tools (bq) when appropriate
4. Analyze and summarize results
5. Present findings clearly

Key practices:
- Write optimized SQL queries with proper filters
- Use appropriate aggregations and joins
- Include comments explaining complex logic
- Format results for readability
- Provide data-driven recommendations

For each analysis:
- Explain the query approach
- Document any assumptions
- Highlight key findings
- Suggest next steps based on data

Always ensure queries are efficient and cost-effective.
```


[​](#database-query-validator)

Database query validator

A subagent that allows Bash access but validates commands to permit only read-only SQL queries. This example shows how to use `PreToolUse` hooks for conditional validation when you need finer control than the `tools` field provides.

```python
---
name: db-reader
description: Execute read-only database queries. Use when analyzing data or generating reports.
tools: Bash
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate-readonly-query.sh"
---

You are a database analyst with read-only access. Execute SELECT queries to answer questions about the data.

When asked to analyze data:
1. Identify which tables contain the relevant data
2. Write efficient SELECT queries with appropriate filters
3. Present results clearly with context

You cannot modify data. If asked to INSERT, UPDATE, DELETE, or modify schema, explain that you only have read access.
```

Claude Code [passes hook input as JSON](../07-Hooks/hooks.md#pretooluse-input) via stdin to hook commands. The validation script reads this JSON, extracts the command being executed, and checks it against a list of SQL write operations. If a write operation is detected, the script [exits with code 2](../07-Hooks/hooks.md#exit-code-2-behavior-per-event) to block execution and returns an error message to Claude via stderr. Create the validation script anywhere in your project. The path must match the `command` field in your hook configuration:

```python
#!/bin/bash
# Blocks SQL write operations, allows SELECT queries

# Read JSON input from stdin
INPUT=$(cat)

# Extract the command field from tool_input using jq
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if [ -z "$COMMAND" ]; then
  exit 0
fi

# Block write operations (case-insensitive)
if echo "$COMMAND" | grep -iE '\b(INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE|REPLACE|MERGE)\b' > /dev/null; then
  echo "Blocked: Write operations not allowed. Use SELECT queries only." >&2
  exit 2
fi

exit 0
```

On macOS and Linux, make the script executable:

```python
chmod +x ./scripts/validate-readonly-query.sh
```

On Windows, write the validation script in PowerShell and add `shell: powershell` to the hook entry. See [running hooks in PowerShell](../07-Hooks/hooks.md#windows-powershell-tool). The hook receives JSON via stdin with the Bash command in `tool_input.command`. Exit code 2 blocks the operation and feeds the error message back to Claude. See [Hooks](../07-Hooks/hooks.md#exit-code-output) for details on exit codes and [Hook input](../07-Hooks/hooks.md#pretooluse-input) for the complete input schema. The system prompt tells the subagent to refuse write requests, so the hook is a backstop: if the subagent attempts a write anyway, Claude Code blocks the command and the subagent sees the `Blocked: Write operations not allowed. Use SELECT queries only.` message.


[​](#next-steps)

Next steps

Now that you understand subagents, explore these related features:

- [Distribute subagents with plugins](../08-Plugins-Skills/plugins-components.md#agents) to share subagents across teams or projects
- [Run Claude Code programmatically](../02-Claude-Code-CLI/headless.md) with the Agent SDK for CI/CD and automation
- [Use MCP servers](../06-MCP-Tools/General/mcp.md) to give subagents access to external tools and data