How AI Agents WorkCourse map

Chapter 17 · Real systems

Framework case studies

Three real agent systems, read feature by feature as answers to the design questions from the earlier chapters.

How to read a framework

Take one feature. Deep Agents moves most large tool results, over about 80,000 characters, into a file. The model sees only a short preview and the file's path. You could learn that as a setting to configure. But it is also an idea from chapter 4. Keep large data outside the context, and let the model fetch what it needs. This chapter reads real systems the second way, so each feature links back to the concept it implements.

Three systems get full profiles, because they make very different choices around the same loop. Shorter profiles of other systems follow, and chapter 17b puts everything side by side.

Versions and evidence date

The facts on this page come from research notes checked on 2026-10-19. They hold for these versions:

These projects change quickly, and docs lag behind code. For example, the Hermes loop docs still give a turn limit of 500, but the v0.22.2 code sets no step limit within a turn. Chapter 17b links the exact source behind each claim.

Support levels

Where each course idea shows up most clearly
IdeaSystemWhat to look at
Context shaped by the prompt cacheHermesA system prompt frozen for the whole session
Large outputs moved to filesDeep AgentsBig tool results and old history saved to files the model can read back
State as an append-only logPiOne JSONL file per session, shaped as a tree
Memory with a write policyHermesTwo capped files, written by the agent and by a review step after turns
Planning as a measured optionDeep AgentsThe todo tool left the standard defaults after a test showed no gain
Isolated context, shared stateDeep AgentsChild agents start fresh but share the parent's files
Choosing no subagentsPiLeft out of the core on purpose
Skills loaded on demandAll threeSkill names in the prompt, full text read when needed
Approval decided by a modelHermesA second model reviews risky shell commands by default
Security left to a containerPiNo permission system; the docs recommend a container or VM
Instructions versus enforced gatesClaude CodeCLAUDE.md is advice; hooks run every time
Durable execution as a layerLangGraphSaved steps, a cross-thread store, and pauses, under Deep Agents

Hermes Agent: an assistant that edits its own notes

Suppose you tell Hermes, in a Telegram chat, that you prefer short answers. The agent can save that preference to a small file, USER.md, right away. But the new line will not appear in the system prompt until your next session. Hermes builds the system prompt once per session, and changes it only when it compacts (summarizes) old history. So every request starts with the same text, and the provider's prompt cache can reuse its work (chapter 4).

Hermes Agent v0.22.2 is an open-source (MIT) application from Nous Research. The same agent core runs behind a CLI, a desktop app, an editor protocol, and an API server. A messaging gateway also connects it to 20+ chat platforms. You change most of its behavior in a configuration file, config.yaml.

 CLI, desktop, chat apps (20+), API server
                    |
                    v
   One agent loop per user message
   (system prompt frozen per session)
      |              |              |
      v              v              v
   Tools        state.db       Profile folder
   shell on 7   sessions,      MEMORY.md,
   backends,    messages,      USER.md,
   MCP          search         skills/
                                    ^
   Review step after turns ---------+
   rewrites memory and skills
Hermes v0.22.2, simplified.

The fourteen questions

Core mental model
A personal assistant that lives on a server. One tool loop serves every chat front door, and between conversations the agent rewrites a notebook of memory, skills, and transcripts. Its design guide keeps the core small: new abilities should arrive as skills, plugins, or MCP servers.
What it calls an agent
A profile is the stored home of one assistant: its config, keys, memory, skills, and sessions. An agent is the running assistant that uses a profile. Subagents and the review step run the same agent class.
Loop Built in
Each user message starts one turn. Hermes calls the model, runs the tool calls it asks for, adds the results, and repeats until a reply contains no tool calls. Since v0.20.5 there is no step limit within a turn by default, because limits "caused silent mid-task truncation". Other limits remain. A watchdog stops a turn after 600 seconds without progress, and per-turn caps limit web searches and subagent spawns.
State Built in
During a turn, the state is a list of messages. Each profile also has one SQLite database that stores every session and message, with keyword search. Memory, skills, and the agent's identity are plain text files in the profile folder.
Context construction Built in

The system prompt has three parts, ordered from most to least stable. Identity and tool guidance come first, then project files such as AGENTS.md, then the skills list and memory. Anything that changes per call goes into the user message instead, so the start of the prompt stays the same. When a conversation grows long, a second model summarizes the middle of the history. The old messages stay in the database, marked as compacted.

Default in v0.22.2: compaction starts at 50% of the window, or at least 75% for windows under 512K tokens.

Tools Built in
Tools register themselves, and Hermes hides any tool whose key or binary is missing. Rarely used tools sit behind a search tool that loads their definitions on demand. In v0.22.0 that cut the desktop tool definitions from 13,367 to 6,883 tokens. The shell tool runs on 7 backends, from the local machine to Docker and remote sandbox services such as Modal.
Planning Built in
There is no separate planner. A todo_list tool keeps a task list and puts it back into the context after compaction. In v0.22.2 the model has to find it through tool search first. The /goal command adds an outer loop. After each turn, another model answers done, continue, or blocked. On continue, Hermes keeps going, for up to 20 turns by default.
Subagents Built in
delegate_task starts child agents with a fresh conversation. A child does not see the parent's history or memory. It gets the goal and context the parent writes, the workspace path, and the project's instruction files. It also gets fewer tools, for example no memory and no way to ask the user. By default, children run in the background, up to 10 at once and one level deep, and both limits can be changed. Each result comes back later as a new message, with a summary of at most 24,000 characters.
Memory Built in
Two small files are always in the prompt: notes about the environment (2,200 characters) and about the user (1,375 characters). The agent writes them with a memory tool. A write over the limit fails, so the agent has to merge entries. Older conversations are found by keyword search over the session database, with no model call.
Skills Built in
A skill is a folder with a SKILL.md file. The prompt lists only skill names and descriptions, and the model loads a full skill when it needs one. The agent also writes and edits skills itself, and a curator archives unused agent-written skills after 30 days.
Permissions Built in
Hermes checks shell commands against 110 patterns for dangerous commands. By default, a second model reviews each match and approves it, denies it, or escalates it to you. A short hardcoded blocklist and your own deny rules apply even when approvals are off. In a container backend the approval check is skipped, because the container is the boundary.
Persistence Built in
Hermes saves every message during the turn, so a session survives crashes and restarts. File rollback is optional: Hermes can snapshot the working folder into a hidden git store before edits. Cron jobs run as fresh agents on a schedule.
Distinctive ideas
It improves itself through text, not training: a review step after turns edits the memory and skill files. It also offers a ladder of autonomy: one turn, a judge-driven /goal loop, a cron schedule, or a Kanban board. The board is a shared task queue in SQLite that several agent processes work from.
Hidden complexity
Hermes hides provider differences, cache management, compaction, and chat-platform plumbing. For example, if you switch models mid-conversation, Hermes converts the history to the new provider's format. Its docs warn that the next request then gets no cache hits. It also hides its own upkeep, because counters trigger the review step without being asked.

What it teaches

Deep Agents: a standard loop wrapped in layers

Suppose a custom search tool returns 200,000 characters. Deep Agents writes that result to a file. Only its first and last 5 lines, plus the file path, go into the conversation. The model can read more with its file tools if it needs to. The model did not ask for this. Middleware did it, meaning code that runs around every model call. Most of what Deep Agents adds works this way.

Deep Agents is LangChain's agent library. This profile covers the Python SDK, deepagents 0.7.28, which runs on langchain 1.4.6. Underneath is LangGraph, a LangChain library that stores the state of each run and can pause it. You call Deep Agents from your own code. A JavaScript version and a terminal coding agent, Deep Agents Code (dcode), ship as separate packages.

 create_deep_agent(model, tools, options)
                    |
                    v
 LangChain loop, run as a LangGraph graph:
   model call <---> tools   (ends when a reply
                             has no tool calls)
 Middleware wraps every call, in order:
   files, subagents, summarization,
   your middleware, prompt caching,
   plus skills, memory, and approval
   if you configure them
        |                      |
        v                      v
 One file interface      LangGraph underneath:
 (state, store, disk,    saves steps with a
 or a command backend)   checkpointer; pauses
                         for approval if set up
Deep Agents 0.7.28, simplified.

The fourteen questions

Core mental model
A standard tool loop wrapped in ordered middleware. A virtual file system serves as working memory, and subagents are throwaway context windows. It adds no new runtime of its own.
What it calls an agent
The agent is the compiled LangGraph graph that create_deep_agent() returns: a model, tools, and middleware, run as a loop. Subagents are agents too, and any LangGraph graph with a message list can serve as one.
Loop Built in
LangChain runs it: call the model, run every requested tool, and end when a reply contains no tool calls. Tool calls from one reply run in the same step. Deep Agents sets no turn limit of its own. It only sets LangGraph's recursion limit, to 9,999 steps.
State Built in
State is a typed dictionary that LangGraph keeps per conversation thread. Besides the messages, it can hold the files themselves. By default, files live in the state, not on disk.
Context construction Built in

Since 0.7.0 the SDK ships no general system prompt. The prompt is your own text, plus extra sections from a per-model profile for some models. If you configure skills and memory files, middleware adds the skills list and those files on each call. Large tool results go to files, as in the example above. When the history grows long, Deep Agents archives the oldest messages to a file and replaces them with a summary. The model sees the summary plus recent messages, while the state keeps every original message.

Defaults in 0.7.28: tool results above about 80,000 characters (20,000 tokens at 4 characters each) are offloaded. The built-in file tools are exempt. Summarization starts at 85% of the input limit in the model's profile and keeps the newest 10%. Without a profile, it starts at 170,000 tokens and keeps 6 messages.

Tools Built in
It ships file tools (ls, read_file, write_file, edit_file, glob, grep, delete), a shell tool (execute), and task for subagents. execute appears only when the storage backend can run commands. The default backend cannot, so the default setup has no shell at all. A backend that can run commands is not automatically isolated: the local shell backend runs them on your machine. You add your own tools as plain functions, and MCP tools through LangChain.
Planning Optional
Since 0.7.0, write_todos is no longer in the standard default stack, but the built-in OpenAI Codex profiles still add it. LangChain removed it after testing three models. The tool gave no significant accuracy gain, and cost went up on two of them. Even when it is on, nothing checks that the agent follows the list.
Subagents Built in
The task tool runs a child agent while the parent waits. The child starts with only the task description and returns only its final message. But with the default storage, the child reads and writes the same files as the parent. So its context is isolated, while its state is shared. The parent runs children in parallel by calling task several times in one reply.
Memory Optional
Short-term memory is the thread's saved state. Long-term memory is files stored outside any one thread. You route a folder such as /memories/ to a LangGraph store, scoped per user or per assistant. If you list an AGENTS.md file as memory, it goes into the prompt on every call. The agent edits it with the normal file tools.
Skills Optional
Skills use the Agent Skills format: a folder with a SKILL.md file. When you pass skill folders, the prompt lists each skill's name, description, and file path. The model reads the file with read_file when a task matches.
Permissions Optional
You name the tools that need approval with interrupt_on. The run pauses, which needs a checkpointer, and a person approves, edits, or rejects each gated call. You can also set allow, deny, or ask rules on file paths. They cover only the built-in file tools, not the shell. The README puts it this way: "Enforce boundaries at the tool/sandbox level, not by expecting the model to self-police."
Persistence Optional
Persistence comes from LangGraph. A checkpointer is a store that saves the state after every step. If you pass one, a run can resume after a crash without redoing finished steps. It can also wait for an approval as long as needed. Files can live in the state, in a LangGraph store, on real disk, or in a sandbox.
Distinctive ideas
One file interface serves file tools, skills, memory, offloaded results, and archived history. Changing the storage changes all of them at once. Its defaults also follow experiments, as with the todo tool above.
Hidden complexity
It hides the order of about a dozen middleware, token counting, and history archiving. For example, if a run stops while a tool call is pending, the next run adds an error result for that call. So the provider never sees a call without a result. LangGraph hides threads, checkpoints, and pausing.

What it teaches

Pi: a small core you extend

Ask Pi to plan a large refactor. It has no plan mode and no to-do tool, so the plan goes into a file such as PLAN.md. You can read that file, edit it, and commit it with your code. Pi's creator prefers it that way, because file plans "can be shared across sessions, and can be versioned with your code".

Pi calls itself "a minimal, extensible agent harness that you can make your own". This profile covers the package @earendil-works/pi-coding-agent 1.3.0. Pi is both a CLI, pi, and a set of packages you can import. One package handles model access across providers, one runs the loop, and one is the coding agent. Mario Zechner created it, and Earendil acquired the project on 2026-04-08.

 Terminal UI, print, JSON, RPC, SDK
                 |
                 v
 pi-coding-agent  short prompt, 4 tools,
                  compaction, skills list
                 |
                 v
 pi-agent-core    the loop
                 |
                 v
 pi-ai            one API, many providers
                 |
                 v
 Model            any supported provider

 Extensions add tools, gates, subagents,
 and plan mode.
 Session: an append-only JSONL tree
Pi 1.3.0, simplified. The three packages are ordinary code; only the bottom box is the model.

The fourteen questions

Core mental model
A tiny agent core with a large plugin system. The goal is control over context: its creator wrote that "Exactly controlling what goes into the model's context yields better outputs". So opinionated features such as plan mode and subagents stay out of the core. Pi can write its own extensions and load them with /reload.
What it calls an agent
An Agent object holds the model, tools, and messages, and an AgentSession wraps it with queued messages, compaction, and extensions. Pi's words differ from this course. A Pi "turn" is one model reply plus its tool calls, which chapter 1 calls a step.
Loop Built in
Pi streams a reply, runs its tool calls in parallel, records the results, and repeats while tool calls or queued user messages remain. You can steer mid-run: a message you type while Pi works is delivered after the current tool calls finish. A search of the source found no step limit.
State Built in
Each session is one append-only JSONL file. Every entry points to its parent entry, so the entries form a tree, and you can branch from any point. Even changes to the system prompt and the tool list are entries, so any branch can be replayed exactly.
Context construction Built in

The system prompt is a few short sections: one line per tool, brief rules, pointers to Pi's docs, project instructions, and skills. Project instruction files (AGENTS.md) load from a global folder and every parent directory. Prompt and tool changes are appended as system messages. On models that accept them mid-conversation, the cached prefix survives.

Compaction is separate. When the context nears the window limit, a model call summarizes older entries. Pi keeps the most recent ones word for word, and the original entries stay in the file.

Defaults in 1.3.0: compaction starts when the context passes the window minus 16,384 reserved tokens. About 20,000 recent tokens stay word for word. The prompt with tool definitions is roughly 1,000 to 1,500 tokens, by a character-count estimate.

Tools Built in
Four tools by default: read, bash, edit, and write. The creator's reason is that models already know bash and "have been trained on the read, write, and edit tools with similar input schemas". read and bash output stops at 2,000 lines or 50 KB. read can page through a long file, and bash saves its full output to a temp file. MCP is built in since 0.99.0. Its tools stay hidden until the model searches for them or calls them from a script.
Planning Extension or custom
No plan mode and no to-do tool, by design. The creator wrote that "to-do lists generally confuse models more than they help". Plans live in files, and a plan-mode extension ships as an example.
Subagents Extension or custom
Not built in. Its creator argues that a built-in subagent hides its work from you. He suggests asking Pi to run another copy of itself through bash, where you can watch it. An example extension runs each subagent as a separate pi process with its own model, tools, and prompt.
Memory Not built in
There is no memory system. What carries over between sessions is ordinary: session files you can resume, AGENTS.md files, files the agent writes, and skills.
Skills Built in
Pi follows the Agent Skills format. The prompt lists each skill's name, description, and file path. When a task matches, the model reads the SKILL.md file with the normal read tool. Skills in the project's .pi/skills/ folder load only after you trust the project.
Permissions Extension or custom
Pi has no built-in permission system and does not ask before tool calls, by design. Its docs say that watching the transcript, project trust, and reviewing changes do not create a security boundary. They recommend a container or VM instead. The only built-in prompt asks whether to trust a project's own settings and extensions. Extensions can block or change any tool call, and if such a handler crashes, Pi blocks the call.
Persistence Built in
Pi saves every session automatically, and you can resume it, branch it, or fork it into a new file. Branching rewinds the conversation but not the files on disk, so an example extension uses git to restore them. Resuming a turn that crashed is the goal of Pi Durable, an experimental separate package.
Distinctive ideas
The agent extends itself: extensions are TypeScript files that load without a build step, and Pi writes many of them. Codemode lets the model write a JavaScript script that calls tools. The script runs in QuickJS, a small JavaScript engine with no direct file, network, or Node APIs. Only its output enters the context. The tools it calls still have their normal effects, such as writing files.
Hidden complexity, and what it leaves to you
Pi hides provider differences, compaction, session-tree bookkeeping, and parallel tool scheduling. For example, when you switch to another provider's model mid-session, Pi passes text, tool calls, and results through unchanged. It drops the old model's thinking blocks, because signed reasoning only works with the model that wrote it. It leaves the rest to you: the sandbox, approval rules, planning, subagents, and memory.

What it teaches

Other systems, briefly

Claude Code: advice versus enforcement

Claude Code is Anthropic's coding agent. Its project file, CLAUDE.md, loads every session, but the docs call those instructions advisory, while hooks are deterministic. A hook is a script that the runtime runs at a fixed point. For example, a Stop hook can keep a turn from ending until a check passes. That is the difference between an instruction and an enforced gate from chapter 10.

Its sandbox shows what containment buys. Claude Code users approve 93% of permission prompts, which Anthropic calls "approval fatigue". Anthropic added an OS sandbox, using bubblewrap on Linux and Seatbelt on macOS. A proxy outside it lets traffic reach only approved domains. In internal use, this cut permission prompts by 84%, because a command that cannot reach much needs less review.

Sources: the Claude Code best practices docs page and Anthropic's sandboxing post (2025-10-20), both checked 2026-10-19.

LangGraph: the runtime under a harness

Deep Agents leaves saving and pausing to LangGraph. LangChain describes its stack in three layers. LangGraph is the runtime, create_agent is the framework, and a harness such as Deep Agents sits on top. Its list of harnesses also names the Claude Agent SDK. The split is worth copying: durable execution (chapter 12) lives in one layer, and agent defaults live in another.

Sources: LangChain's products page and LangGraph persistence docs, checked 2026-10-19.

Shared formats and protocols

Some pieces now work across systems. AGENTS.md is an open format for project instructions, "used by over 60k open-source projects". All three profiled systems can read it. In the A2A project's words, "MCP standardizes agent-to-tool communication; A2A standardizes agent-to-agent communication." Neither is an agent loop. The MCP spec also says it "cannot enforce these security principles at the protocol level", so the host program has to enforce them.

Sources: agents.md, the MCP specification (version 2026-07-28), and the A2A specification (v1.0), checked 2026-10-19.

OpenHands, the OpenAI Agents SDK, PydanticAI, and smolagents build on the same primitives: a loop, tools, state, and per-call context. The course's research did not verify their details, so read them yourself with the same fourteen questions.

Running example: Patch on each system

Patch's needs, system by system
Patch needsHermesDeep AgentsPi
Search, read, edit, runBuilt-in file tools and shellFile tools; the shell needs a command-capable backendread, edit, write, bash
Project memoryAGENTS.md, plus a 2,200-character notes fileAn AGENTS.md memory file in a storeThe AGENTS.md chain and notes in files
Skills: add-db-migration, deploy-stagingSkill folders; the agent may edit themSkill folders you pass inSkill folders in the project
Read-only explorer, write-free reviewerdelegate_task; a write-free reviewer is unverified, because children get the parent's tools minus a fixed listDeclared subagents, each with its own tool listThe example subagent extension, one file per role
Container sandboxThe Docker shell backendAn isolating sandbox backend (not the local shell), with secrets kept outside itRun Pi in a container or VM
Approval for push, migrations, deploysModel or human review of risky commands, skipped inside a containerinterrupt_on for the gated toolsA gate you write as an extension
Nightly runs from a queueCron jobs or the Kanban boardYour queue, one saved thread per issueYour queue; Pi Durable is experimental

Every system covers Patch's coding loop, but the gaps are in control. Hermes skips its approval check inside a container, so Patch's push gate belongs in branch protection on the Git host. On all three, "one PR per issue" stays Patch's own logic, because no framework deduplicates side effects for you.

Check yourself

Hermes saves a memory entry in the middle of a session. When does the entry first appear in the system prompt, and why? (Q7)

Answer

At the start of the next session. The memory files go into the system prompt once per session, and changing the prompt mid-session would break the prompt cache. The file on disk changes right away.

A Deep Agents subagent runs with the default settings. What does it share with its parent? (Q12)

  1. Nothing at all
  2. The parent's full conversation
  3. The files, but not the conversation
Answer

The child's conversation starts with only the task description. But with the default storage, parent and child read and write the same files, and the child's changes stay after it ends.

You build Patch on Pi. Where does the security boundary come from? (Q23)

  1. Pi's built-in permission prompts
  2. A container or VM you run Pi in, with gates written as extensions as an extra layer
  3. Rules written in AGENTS.md
Answer

Pi has no permission system, and its docs say that watching the transcript does not create a boundary. An extension gate only covers the tool calls it intercepts, so containment has to come from outside.

Takeaways