Skip to content

Part II · Pi in Source / Ch. 01

Part II Chapter 1: The Map's Scale — pi-mono ​

Xia A and Lao Z study a layered map, using a magnifying glass and a blank ruler to follow one glowing orange path past a stream, a loop, and small cabins.

Xiao A finished Part I · Concepts and opened pi-mono full of confidence. Three minutes later he was staring at the screen. Under packages/ lay more than a dozen directories: ai, agent, tui, coding-agent, protocol… He clicked one at random and found hundreds of files inside.

"Lao Z," he called out, "this map is enormous. Which directory do I start from?"

Lao Z walked over, glanced at the screen, and asked back: "What questions did Part I · Concepts leave you with?"

"Where, inside one real project, do the boundaries of the model, the loop, the session, and the terminal actually land," Xiao A recited — he had it memorized.

"Right. You are not here to 'finish reading Pi'. You are here to check those boundaries," Lao Z said. "So do not guess by directory. First fix the scale of the map, then draw the main path."

Every confirmed fact in this part is anchored to tag v1.0.0 of the upstream pi repository (github.com/earendil-works/pi, migrated in 2026-09 from badlogic/pi-mono), commit a13d35a742c6ef8462812a28fbe1d8c8b7431c32, committed 2026-10-01. This book keeps using the name pi-mono for that monorepo. The eight packages listed below all report version 1.0.0 in their package.json, while the root package.json gives the monorepo version as 0.0.3. The two must not be mixed. The pi/ directory in this book's repository is a snapshot of that tag with Chinese comments added; paths and symbols match upstream, but line numbers shift because of the comments.

That "eight" is this book's reading scope, not the total in the root workspace: packages/ holds 13 packages. The other five are chord, codemode, durable, mcp, and telemetry. chord and telemetry get named only where they come up; codemode and mcp get their own appendices (Appendix 10 and Appendix 11); durable is the subject of Part II Chapter 13. The root workspace also contains extension examples. packages/evals is a private workspace package, not a published one.

First, fix the scale of the map ​

Xiao A: "Eight packages… are they eight separate programs?"

"No," Lao Z said. "A workspace name and a published-package boundary prove a unit can be imported independently. They do not prove it runs as a separate process. Read the package metadata and the exports first, then look for evidence by following the control flow of one input."

Metaphor: the scale of a map

Set "how many kilometres one centimetre stands for" before the map can stop misleading you. The eight packages are this book's reading scale, not the whole repository, and certainly not eight separate processes.

What this book calls "the eight packages" means the eight product and infrastructure packages selected in the table below. Each package's responsibility comes from the name, description, dependencies, and exports in its package.json. A description is what the maintainer declares; it is not proof of everything the code does.

Packagenpm nameBoundary evidenceWhat this book follows it forNot asserted in this chapter
packages/ai@earendil-works/pi-airoot, api/*, providers/* and other exportsmodels, auth, stream adaptersthe service quality of any vendor
packages/agent@earendil-works/pi-agent-coredepends only on pi-ai; root export onlyAgent and the loopsession storage (no longer in this package)
packages/tui@earendil-works/pi-tuiterminal UI package with zero internal dependenciescomponents and renderingAgent decisions
packages/coding-agent@earendil-works/pi-coding-agentthe pi binary entry; depends on 9 internal packagesCLI assembly, session, compaction, tools, extensionsthe behaviour of all extensions
packages/protocol@earendil-works/pi-protocoltransport-neutral CBOR protocol package; depends on chordframes, envelope schemas, versioningnetwork reliability
packages/client@earendil-works/pi-clientdepends on chord and pi-protocolremote client connection and requestsserver-side policy
packages/server@earendil-works/pi-serverdescribed as experimental; depends on chord and pi-protocolhandshake, request routing, session attachmentproduction deployment guarantees
packages/evals@earendil-works/pi-evalsprivate evaluation workspace packageharness, controlled experiments, judgeconclusions about product quality

Xiao A's eyes stopped on the coding-agent row. "It depends on nine internal packages? And what about agent?"

"agent depends directly on AI only," Lao Z said. "That is also the easiest line in this table to skip: the generic loop is designed so it does not have to know the terminal, the remote protocol, or the session file. v1.0.0 also moved the experimental harness that used to sit in the agent package out entirely, and session and compaction landed in coding-agent. From this you may infer that the generic loop is independent of the product shell. What you may not infer from the dependency graph is that any product must persist sessions the same way."

Seven product changes in Pi 1.0 ​

Xiao A asked, "Since the source baseline is v1.0.0, what did this release add for users?"

Lao Z said, "Start with the pi-coding-agent 1.0.0 release notes. They list seven product changes under New Features. These are highlights announced at the 1.0 release; they do not mean every underlying capability first appeared in 1.0. Codemode and MCP, for example, already existed in earlier versions, and 1.0 continued to improve them."

1.0 release highlightChangeRead next
Full-screen terminal interfaceThe interactive UI uses full-screen mode by default; set tuiMode: "regular" to restore ordinary terminal scrolling.Part II Ch. 6 Terminal; terminal settings
Leaner CodemodeThe release notes report roughly 40% fewer prompt tokens under the default tool configuration and improved errors that show likely matches and repair directions for missing names. This figure is a release-note summary, not a fixed guarantee for every model and tool combination.Codemode documentation
Image generation in CodemodeScripts can call image models with models.generateImages() using the current session credentials; image() can return generated results to the model.Codemode image generation
Radius login/login can sign in to Radius and then configure the MCP servers it provides.Provider documentation
Anthropic copy-code loginWhen the browser is on another machine, copy the authorization code from the authorization page and paste it back into Pi. This supports remote or headless environments.Interactive authentication
Hardened MCP OAuthYou can specify authorization-server metadata; iss in the authorization response is checked according to RFC 9207; credentials are separated by server name and URL; extending permissions preserves granted scopes.MCP OAuth documentation
Header-only startupquietStartup: "header" keeps the version and shortcut hints while hiding the model scope and loaded-resource list.Terminal settings

"These seven changes mainly affect interaction, access to model capabilities, and authentication." Lao Z added, "One architectural change needs its own note: @earendil-works/pi-durable was first released in 1.0. In the same release, the experimental harness was removed from pi-agent-core as a breaking API change, and durable-session support moved to pi-durable. This is a package-boundary change, not one of the seven CLI features above, and it does not mean Pi stopped supporting durable sessions." (durable changelog; agent-core changelog)

Later chapters in Part II explain session, terminal, and extension boundaries in Ch. 5, Ch. 6, and Ch. 8. This section gives the version map; to verify the complete scope and each statement, return to the changelogs and documentation for the fixed v1.0.0 tag.

The eight packages in three layers: who depends on whom ​

The table still looked scattered to Xiao A. Lao Z took the pen and drew a three-layer diagram on paper. "Layer by dependency direction and the relationships read at a glance. An arrow means 'depends on'. The upper layer calls the lower one; the lower one does not know the upper one exists. The parentheses name packages this book does not open but does mention."

text
┌────────────────────────────────────────────────────────────────────────┐
│  Product layer                                                         │
│  ┌──────────────────────────────────────────┐   ┌────────────────────┐ │
│  │ pi-coding-agent                          │   │ pi-evals           │ │
│  │ (CLI product, session, tools, extensions)│◀──│ (private evals)    │ │
│  └──────────┬────────────────────┬──────────┘   └────────────────────┘ │
└─────────────┼────────────────────┼─────────────────────────────────────┘
              │                    │
┌─────────────┼────────────────────┼─────────────────────────────────────┐
│  Core layer ▼                    ▼                                     │
│  ┌──────────────────┐   ┌──────────────────┐   ┌──────────────────┐    │
│  │ pi-agent-core    │   │ pi-client        │   │ pi-server        │    │
│  │ (Agent + loop)   │   │ (remote client)  │   │ (request routing)│    │
│  └──────────┬───────┘   └────────┬─────────┘   └────────┬─────────┘    │
└─────────────┼────────────────────┼──────────────────────┼──────────────┘
              │                    └───────────────────┬──┘
┌─────────────┼────────────────────────────────────────┼─────────────────┐
│  Base layer ▼                                        ▼                 │
│  ┌──────────────────┐   ┌──────────────────┐   ┌──────────────────┐    │
│  │ pi-ai            │   │ pi-tui           │   │ pi-protocol      │    │
│  │ (model stream)   │   │ (terminal UI)    │   │ (codec, framing) │    │
│  └──────────────────┘   └──────────────────┘   └──────────────────┘    │
│  telemetry, chord, codemode, mcp, durable: named on use only           │
└────────────────────────────────────────────────────────────────────────┘

"Three points matter when reading this diagram," Lao Z said.

  • The three base-layer packages do not depend on each other: pi-ai handles model streams only, pi-tui handles the terminal only, pi-protocol handles byte encoding only. pi-ai depends on telemetry and pi-protocol depends on chord; this book names those two only where they come up.
  • The core layer sits on the base layer: pi-agent-core depends only on pi-ai; pi-client and pi-server both depend on pi-protocol and chord. In v1.0.0 pi-server no longer depends on AI or the CLI — it does handshake, routing, and attachment only.
  • The product layer assembles the parts below it: pi-coding-agent depends directly on agent, ai, tui, protocol, client, and server, plus chord, codemode, and mcp. pi-evals uses ai and coding-agent as development dependencies. The product layer is the thickest, and in v1.0.0 session and compaction live there too.

Xiao A: "So which layer do I start reading from?"

"Start from the core path. pi-ai and pi-agent-core are the spine of the whole main path. Dip into the base layer as needed — open protocol when you reach the protocol, open tui when you reach the terminal," Lao Z said. "That is the reading order of the thirteen chapters in this book's Part II · Pi in Source: Part II chapters 2 to 5 first, to get models, the loop, and the session working; then chapters 6 to 8 for the terminal and the product; then chapters 9 to 11 for protocol, remote, and evaluation; chapter 12 closes the main path; and chapter 13 opens one more engine — pi-durable, and how it answers 'what lets a session survive a crash' with atomic commits and task checkpoints."

Read the replaceable surface from the public exports ​

Xiao A: "Where is the entry? Do I just start at index.ts?"

"Yes, but first tell the root entry apart from the subpaths." Lao Z opened packages/ai/src/index.ts:

ts
// packages/ai/src/index.ts (module entry; v1.0.0, excerpt)
// Core only, side-effect free: no generated catalogs, no provider factories,
// no api-registry, no OAuth implementations, no compat. Provider factories
// live under "@earendil-works/pi-ai/providers/*", API implementations under
// "@earendil-works/pi-ai/api/*", the old global API under
// "@earendil-works/pi-ai/compat".
export * from "./api/lazy.ts";
// ……the rest are type exports and modules such as models, types

"Look at the comment at the top: the root entry holds core code only and carries no side effects. Provider factories live under providers/*, API implementations under api/*, and the old global API under compat. That is not just a directory convention — the exports field of package.json also states this subpath boundary," Lao Z said. "The code above only tells you which API the root entry can reach. It does not tell you what order one request goes through."

He then opened packages/agent/src/index.ts. "On this side v1.0.0 is down to five lines: it exports agent.ts, agent-loop.ts, proxy.ts, types.ts, and setDefaultStreamFn. Session storage, compaction, and skills are none of them here. That says the generic Agent binds to no persistence method. Treating 'Agent' as 'must write JSONL' is a false premise; the one that writes JSONL is coding-agent."

Export layerWhat a caller may rely onWhat you cannot conclude from it
pi-ai root entryModels, the event stream, types, lazy-loading utilitieswhich Providers are registered
pi-ai/providers/*one Provider factorythat auth is configured or the model is definitely available
pi-ai/api/*the request and conversion implementation of one APIthat other APIs behave the same way
pi-agent-core root entryAgent, the loop, and turn hookswhich storage or UI the host uses
pi-coding-agent binarythe product entry of the pi CLIthat remote mode or any extension is enabled

One main path, not a complete architecture diagram ​

Xiao A: "Then which line do I actually follow? I can't read every package through."

"The chapters on the main line go by control flow, not by reading filenames out of directories," Lao Z said. He drew a main path with station numbers, one station per chapter: start at the model request, pass through the loop and the session, and end by assembling the complete request. Part II Chapter 13 stands off that main line: it opens a second engine — pi-durable — and answers the crash-recovery question Part II Chapter 5 left behind.

text
  ① model request     ② streaming         ③ loop drives       ④ session
  ┌───────────────┐   ┌───────────────┐   ┌───────────────┐   ┌───────────────┐
  │ ch2          │──▶│ ch3          │──▶│ ch4          │──▶│ ch5          │
  │ pi-ai         │   │ pi-ai         │   │ pi-agent      │   │ coding-agent  │
  │ models.ts     │   │ lazy.ts       │   │ loop.ts       │   │ session       │
  └───────────────┘   └───────────────┘   └───────────────┘   └───────────────┘
                                                                      │
  ⑤ terminal          ⑥ product startup   ⑦ tool trust                ▼
  ┌───────────────┐   ┌───────────────┐   ┌───────────────┐   ┌───────────────┐
  │ ch6          │   │ ch7          │──▶│ ch8          │   │ ch12          │
  │ pi-tui        │   │ coding-agent  │   │ coding-agent  │   │ end-to-end    │
  │ main-screen   │   │ startup       │   │ tools, trust  │   │ full request  │
  └───────────────┘   └───────────────┘   └───────────────┘   └───────────────┘
                              │                   │                   ▲
  ⑧ protocol bytes    ⑨ remote parity     ⑩ eval verdict              │
  ┌───────────────┐   ┌───────────────┐   ┌───────────────┐           │
  │ ch9          │──▶│ ch10          │   │ ch11          │───────────┘
  │ protocol      │   │ server        │   │ evals         │
  │ codec.ts      │   │ router        │   │ harness       │
  └───────────────┘   └───────────────┘   └───────────────┘

"Read this diagram in groups," Lao Z said.

  • The main line is ①→②→③→④: the model request starts it, the stream passes through the adapter layer, the loop drives state forward, the session outlives the process. The first three stations stand on pi-ai and pi-agent-core. In v1.0.0 the session lives in coding-agent, so station ④ has already entered a core part of the product layer. Read these four chapters first.
  • ⑤⑥⑦ are the product layer: how the terminal refreshes, how the product starts, how tools and trust connect. They stand on the core layer. Read them as the second group.
  • ⑧⑨⑩ are remote and evaluation: how the protocol becomes bytes, how remote stays consistent, how evaluation judges. They are separate capability boundaries; read them as needed. Part II Chapter 12 then assembles every station into one complete request.

Which files of which package each chapter reads ​

Xiao A: "What about specific files? When I open ch2, which file do I actually read?"

Lao Z drew up a full lookup table. "This table is your navigation for Part II · Pi in Source. When you open any chapter, first see which package it stands on and which core files it reads."

ChapterWhich package you are readingCore files (these are enough)What this station answers
1 The mapall eight packagespackage.json × 8how the eight packages layer out, how the main path runs
2 The model requestpi-aimodels.ts, auth/resolve.tshow one request gets from auth to a Provider
3 The streaming adapterpi-aiapi/lazy.ts, api/openai-responses.tshow vendor events become uniform events
4 The looppi-agent-coreagent.ts, agent-loop.tshow model output pushes state forward
5 The sessionpi-coding-agentcore/agent-session.ts, core/session-manager.tshow a session outlives one process
6 The terminalpi-tuitui-main-screen.ts, stdin-buffer.tswhy the terminal can refresh stably
7 Startuppi-coding-agentmain.ts, core/agent-session-services.tshow the CLI product starts
8 Tool trustpi-coding-agenttools/file-mutation-queue.ts, extensions/runner.tshow tools and extensions connect safely
9 The protocolpi-protocolcodec.ts, framing.ts, protocol.tshow messages become reliable bytes
10 Remotepi-server + pi-clientserver.ts, session-router.ts, client.tshow a remote session handshakes, routes, and attaches
11 Evaluationpi-evalssrc/harness.ts, src/plan.ts, src/report.tshow evaluation judges one change
12 End-to-endacross all packages(revisit the files of Chapters 2 to 11)how one complete request runs to the end
13 Durable runtimepi-durablesession/session.ts, harness/scheduler.ts, harness/tool.ts, storage/how one commit and tool call recover after a crash

"Note this. There are two kinds of data on this line. Do not merge them into one," Lao Z said, and added another table.

DataIts shape on the main pathThe key boundary
configurationmodel, headers, auth, signal, retry optionshanded to the Provider only after ModelsImpl.applyAuth merges it
contextAgentMessage[], converted to AI Message[] before the model callconvertToLlm inside streamAssistantResponse
generationstart, delta, done / error on AssistantMessageEventStreamthe adapter produces it, the loop consumes it
side effectstool result, session append, terminal refreshan Agent event and AgentSession writing the session are not the same thing

Xiao A: "Why not just start at the CLI entry and read all the way to the network request? Isn't that more direct?"

"That line drags configuration, interactive mode, the terminal, and extensions in at the same time," Lao Z said. "Lock down the stream and loop boundaries that stay stable across packages first; otherwise you will mistake one product's assembly for the core mechanism. Part II Chapter 7: The Address on the Household Register — pi-coding-agent reconnects the CLI to this line later."

How to keep the evidence strong while reading ​

Xiao A opened his notebook, ready to start on the code. Lao Z stopped him. "Remember this first: source walkthroughs make three kinds of mistakes easily. I have made them. Don't."

Three common reading mistakes

  1. Expanding a comment or description into a runtime guarantee: the description of pi-server contains experimental, so all you may confirm is that it calls itself experimental. You may not fill that in as "unsuitable for any production scenario".
  2. Reading optional typing as a certain missing implementation: Provider.refreshModels? is an optional method, meaning a static Provider may have no refresh path. It does not mean every dynamic Provider refreshes successfully.
  3. Flattening different failure outcomes into false: an unknown Provider, unconfigured auth, an aborted stream, a failed tool, and a JSONL parse failure sit at different layers and need different recovery strategies. Later chapters compare them in one failure-semantics table.

"Read a fixed snapshot in this order: exports and types first; then the complete branches of the entry function; then follow into the interface implementation in the next package; finally use the tests, or one controlled call, to verify the three paths — normal, error, abort. When you have to reason across layers, mark it as reasoning. Do not supply the author's motives on the source's behalf."

What this split buys, and what it costs ​

"Is splitting it this way worth it?" Xiao A asked.

"Engineering opinion: organize reading around package boundaries plus the call chain. The gain is that when you replace a model adapter, a session backend, or the UI, you can look for the contract first instead of understanding all the product code first," Lao Z said. "The cost is that the reader has to travel between source files in several places, and without looking at a specific host you will not know where the default configuration comes from."

Xiao A went on: "What does this chapter deliberately leave out?"

"The complete model catalog of each Provider, the protocol fields of each API, the tool definitions, the TUI's event-subscription implementation, the Protocol's framing, Server / Client reconnection, and the evaluation cases," Lao Z said. "Those are for the matching call-chain chapters. This chapter does not open them."

Break the main path into reading stations you can stop at ​

Xiao A: "How long should a chapter take? Follow the whole chain in one go?"

"Don't. Source reading should not treat a chain as a long function you must finish in one sitting. Stop at every public type or event boundary and write down the input, the output, and the failure outcome. That catches cross-layer assumptions far better than recording only 'what this package does'." Lao Z handed over a reading-station table.

Reading stationThe smallest questionNext stationWhere to look first on failure
model selectionwhom does Model.provider point toModelsImplunknown Provider
request preparationhow credential and options mergeProvider.stream*auth, header transform
stream adaptationhow upstream events become uniform eventsrunLooperror, aborted, pending
Agent turnwhat enters the next contexttool execution / queuelength, tool error, terminate
session persistencewhich events get appendedAgentSession / SessionManagerwrite failure, bad line skipped
host displaywho subscribes to events and refreshesTUIrendering, terminal, input boundary

"For example: a network failure should not be explained by jumping straight from 'request preparation' to 'terminal display'. First check whether the Provider normalized it into an error event. Then check whether the loop wrote the final error message into the context. Only after that do you look at whether the session layer or the UI recorded or showed it," Lao Z said. "That is a reading order, not a runtime retry chain the source promises."

Xiao A: "But if a chapter reads only one function, won't I miss state that crosses files?"

"You will not read one function only. The point is that each chapter fixes one entry, one exit, and a few branches," Lao Z said. "When a function calls across files, keep following its direct contract instead of reading the whole package first. On a fixed commit, git grep can confirm a symbol exists, but existence does not replace reading from the call site to the return site, and the same type name does not mean the same semantics. For example, Context at the AI layer and an entry in the session tree sit at different levels of abstraction. This book marks that explicitly at every boundary."

Summary ​

This chapter answers the first question of Part II · Pi in Source: facing more than a dozen packages in pi-mono, where to start. The answer is not to read directory by directory. Pin three coordinates first: version, dependency direction, main path.

  • Version coordinate: the baseline is upstream tag v1.0.0 (commit a13d35a7). The eight packages this book selects are all 1.0.0 (pi-evals is a private workspace package); the root monorepo is 0.0.3. The two must not be mixed. The eight packages are the reading scope; the repository has 13 packages.
  • Dependency coordinate: the eight packages form three layers. The base-layer packages (ai, tui, protocol) do not depend on each other; the core layer (agent-core, client, server) stands on the base; the product layer (coding-agent, plus evals which uses it) does the assembly, and in v1.0.0 session and compaction live there too. The generic loop is designed so it does not have to know the terminal, the remote protocol, or the session file.
  • Path coordinate: the main path splits "input to stream, stream to loop, loop to session / UI" into boundaries you can verify one at a time. Each station is one chapter.

Remember

A package boundary is not a process boundary. A workspace name and a dependency graph prove "a unit that can be imported independently". They do not prove a separate process at runtime. When reading source, locate yourself with these three layer coordinates first, then follow the call chain, instead of reading filenames off directory by directory.

Source Walkthrough ​

  1. Clone the upstream repository and check out the tag: git clone https://github.com/earendil-works/pi && cd pi && git checkout v1.0.0, then run git rev-parse HEAD; the expected complete output is a13d35a742c6ef8462812a28fbe1d8c8b7431c32. The pi/ directory in this book's repository is the annotated snapshot of the same tag. It has no git history of its own: the paths match, the line numbers shift.
  2. Run node -p 'require("./packages/ai/package.json").version' and the same command for the agent package; confirm they report 1.0.0, then compare against the version in the root package.json so the two are not mixed up.
  3. Open the exports field of packages/ai/package.json; record the root entry, ./providers/*, ./api/*, and ./compat separately. Do not treat a subpath as a root export.
  4. Open the dependencies field of packages/agent/package.json; confirm @earendil-works/pi-ai is there and pi-tui is not, to check the direct-dependency claims in the table above.
  5. Read the opening comment and the exports of packages/ai/src/index.ts line by line; tell a runtime export * apart from an export type that only exports types.
  6. Read the five export lines of packages/agent/src/index.ts; then, under packages/coding-agent/src/core/, find session-manager.ts, compaction/, and skills.ts to confirm that session, compaction, and Skills belong to the product layer in v1.0.0.