A hands-on tour of Deep Agents built as a series of runnable Jupyter notebooks. Each notebook is self-contained and most close with a recap, so you can work straight through or jump to the topic you care about.
- Python 3.13 (see
.python-version) - uv for dependency management
deepagents>= 0.7 — task planning became opt-in in 0.7, and the notebooks are written against that behaviour
uv sync
uv run jupyter notebookThis starts the copy of Jupyter installed in the project's .venv, so the notebooks automatically
use the same environment as the project dependencies.
Copy .env.example to .env and fill in the keys you need:
cp .env.example .envEvery notebook calls load_dotenv(override=True), so .env wins over anything already exported in
your shell — edit it mid-session and the change takes effect on the next run.
| Variable | Needed by |
|---|---|
ANTHROPIC_API_KEY |
All notebooks |
LANGSMITH_API_KEY, LANGSMITH_TRACING, LANGSMITH_PROJECT, LANGSMITH_WORKSPACE_ID |
Tracing, evaluations, and the LangSmith sandbox backend |
TAVILY_API_KEY |
Web search in the async and voice notebooks |
GEMINI_API_KEY or GOOGLE_API_KEY |
Voice |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET, S3_REGION |
The S3 mount section of Sandboxes |
OPENAI_API_KEY |
The OpenAI half of the model comparison in Evaluations |
Note: The AWS/S3 variables are only needed for the mount section of the Sandboxes notebook. Every other notebook runs without them.
Suggested order — later notebooks assume the vocabulary of earlier ones.
| # | Notebook | Topic |
|---|---|---|
| 1 | deepagents-basics.ipynb |
Core anatomy of a deep agent |
| 2 | deepagents-evals-v2.ipynb |
Offline evaluation with LangSmith |
| 3 | deepagents-skills.ipynb |
Skills and AGENTS.md memory |
| 4 | deepagents-memory-architecture.ipynb |
Routing memory by scope and owner |
| 5 | deepagents-sandboxes.ipynb |
Executing real code safely |
| 6 | deepagents-interpreters-ptc.ipynb |
Programmatic tool calling |
| 7 | deepagents-async.ipynb |
Background subagents |
| 8 | deepagents-voice.ipynb |
A realtime voice front end |
deepagents-basics.ipynb
A deep agent is a regular agent plus subagents, a filesystem, and — since 0.7, only if you ask
for it — a TODO list. Opens on that opt-in: the same agent before and after
middleware=[TodoListMiddleware()], then a plan that actually moves ☐ → ▶ → ☑. Goes on to task
delegation, dictionary vs. compiled subagents, and the backend family — default (thread-scoped
state), StoreBackend, FilesystemBackend, and CompositeBackend — closing on context isolation
and context-management techniques.
deepagents-evals-v2.ipynb
An incident-response supervisor delegates evidence gathering to an investigator subagent. The
investigator writes /investigation.json; the supervisor applies response policy and issues a
brief. A code evaluator grades the report, and an LLM judge grades the response. Six paired
incidents run against two model configurations.
deepagents-skills.ipynb
Two opposite ways to give an agent knowledge. Skills are folders loaded only when a task matches,
via three levels of progressive disclosure: frontmatter at startup, the SKILL.md body on
activation, and references/ only when the body points at them. AGENTS.md is memory injected
into every prompt. Built around an on-call assistant that delegates alerts to a triage specialist,
and demonstrates that subagents inherit neither skills nor memory — plus a writable notes.md whose
correction survives across threads, processes, and agent objects.
deepagents-memory-architecture.ipynb
Where Skills covers what to give an agent, this covers where it lives and who owns it.
One agent, one filesystem, three memory types routed by CompositeBackend to different
backends: per-user preferences, an org-wide policy file the agent is blocked from editing,
and per-user skills — with anything unmatched falling through to thread-scoped state. Each
property is proved against the store rather than the model's say-so: Alice and Bob never
see each other's memory, a write to /policies/ is refused by the harness even when the
prompt does not forbid it, and a preference mentioned in passing survives into a brand-new
thread.
Note the routing gotcha it documents:
CompositeBackendstrips the route prefix before handing the key to the backend, so/memories/preferences.mdis stored under/preferences.md. Seed the full path and reads miss silently.
deepagents-sandboxes.ipynb
A sandbox backend gives the agent a real Linux box — filesystem, shell, package installs — behind a
boundary that protects the host, and adds the execute tool. A data-analysis agent cleans a
deliberately messy CSV and renders a chart by actually running code. The second half mounts an S3
bucket into the sandbox with mount_config, using a read-only input prefix and a writable output
prefix, and shows the write-back path: an ordinary shell redirect inside the box lands an object in
S3 with no put_object call.
deepagents-interpreters-ptc.ipynb
The same task solved twice — once with direct tool calling, once with programmatic tool calling — then compared side by side on token count and tool-call volume, with the code the agent wrote shown in full.
deepagents-async.ipynb
Subagents that run in the background on an Agent Protocol server. Launching returns a task id
immediately so the supervisor stays responsive; five tools manage the lifecycle. Uses the graph in
async_agents/researcher.py, served via langgraph.json:
uv run langgraph devdeepagents-voice.ipynb
A realtime voice layer over a deep agent, driven straight from the google-genai Live API with no
web stack. The deep agent is exposed as a single deep_research tool that the voice model calls and
narrates. Covers audio plumbing, the realtime loop, and server VAD with barge-in. This is the other
notebook that opts into TodoListMiddleware, for the reason the docs recommend it: the activity
panel is a progress UI streaming the coordinator's todos straight off agent state.
Note: This notebook needs a working microphone and speaker, and installs
sounddevice.
├── deepagents-*.ipynb # the deep-dive notebooks
├── async_agents/ # graph served to the async notebook
│ └── researcher.py
├── data/ # dataset rows kept out of the notebooks
│ └── incidents.jsonl # six paired incident examples and tool fixtures
├── oncall_home/ # fixtures for the skills notebook
│ ├── AGENTS.md # always-loaded conventions
│ ├── memory/notes.md # writable learned preferences
│ └── skills/ # per-agent skill sources
├── util/ # notebook helpers (not part of the lesson)
│ ├── pretty.py # activity timelines, exchanges, file/tree/store display
│ ├── skills.py # skill and memory catalogs
│ ├── stats.py # token and tool-call stats
│ ├── charts.py # comparison bars
│ ├── voice.py # mic and speaker streams
│ └── incident_dataset.py # validates the evals dataset
├── images/ # rendered notebook artifacts
└── langgraph.json # graph config for `langgraph dev`
util/ keeps rendering and dataset checks out of the notebook cells.