Agent Engineering: A Field Guide
Everything in this document is sourced directly from two open-source repositories, the design paper bundled with one of them, and a blog post by one of the repositories’ own creators explaining his design decisions. #
Methodology, stated plainly #
This document draws from four sources, and only four:
earendil-works/pi— a coding-agent harness, MIT licensed, single primary maintainer (Mario Zechner). Cloned withgit clone --depth 1, read with search/grep/direct file reads. Nonpm install, no build step, no code from the repository was ever executed.deepseek-ai/deepseek-harness(dsh) — DeepSeek AI’s open-source agent harness, MIT licensed. Cloned and read the same way — read-only, no install, no execution.- The Cordis design paper, “A Programming Paradigm for Spatiotemporal Composability” (Yifan Shi, Wei Zhang, Tianyi Cui — Peking University / DeepSeek-AI), which
deepseek-harness’s own README links to directly as the design document for the plugin framework it’s built on. - A blog post by Mario Zechner, Pi’s creator, published on his personal site, explaining his motivations and design reasoning for the project. This is a first-party account of why the decisions in source (1) were made, which the source code alone can’t tell you.
Where I describe an idea from any of these four sources, I’m paraphrasing it in my own words unless a specific short phrase is set off in quotation marks with attribution — I’ve kept any direct quotation brief and sparse throughout, because the point of this document is to teach the underlying engineering, not to reproduce anyone else’s writing. Code is quoted more freely than prose, because code is the actual technical content this document exists to teach.
I have deliberately not brought in outside frameworks, unrelated blog posts, or third-party commentary as comparison points. Where either project’s own documentation, code, or its creator’s own writing references a real external tool — ripgrep, GitHub Copilot, Claude Code, OpenAI’s Codex, a sandboxing technology, a wire-format standard, tmux — that reference is grounded in one of the four sources above, and I call it out explicitly, because those are the genuine real-world integration points and comparison points these sources themselves raise.
One important note about internal consistency, flagged up front: these four sources don’t always agree with each other. Most notably, Zechner’s blog post describes Pi as deliberately having no sub-agent mechanism, arguing that automatically-spawned sub-agents (as seen in some competing tools) create an unobservable black box. The actual source code, however, contains a real, working subagent-provider registry with two distinct delegation modes. I address this directly in Part IX rather than silently picking one account over the other — it’s a genuinely useful thing to notice when reading any real engineering project: the stated philosophy and the shipped code are not always perfectly in sync, and that gap is often more informative than either account alone.
Table of contents #
Jump to any chapter
Part I — The Shape of Two Systems
- Pi's four-layer architecture
- DeepSeek Harness's plugin-first architecture
- The core loop, in both systems' own code
- Why Pi exists: the creator's stated motivations
- Two philosophies, stated in their own words
Part II — Durable State and Crash Recovery
- The problem, as Pi's own design document frames it
- Pi's specified design: entries, registers, ledger
- The effect sandwich, in full, with every worked example
- What is actually running in production instead
- Storage backend contracts, SQLite, and the conformance suite
- Versioning and migration across harness versions
- Cordis: reversible effects and reactive coeffects, the formal model
- Cordis: the theorems, and what they buy an agent harness
- Cordis: from theory to the concrete API
Part III — Context Window Management
- Pi's compaction algorithm, in depth
- DeepSeek's two-tier compaction: summarization plus deterministic pruning
- The stable-prefix discipline in both codebases
- Context handoff between model providers
- A real-world data point: long sessions without compaction
- DeepSeek's caching reality
- Pi's append-only-context invariant as a caching discipline
- Token and cost tracking limits: the cross-origin problem
- Splitting a tool result for the model versus the interface
- Pi's behavioral eval harness
- DeepSeek's benchmark posture, and its actual internal quality bar
- Informal validation: what Pi's own benchmarking commentary says
Part VI — Tools, Minimalism, and the Permission Question
- What a tool is, in both systems' type definitions
- Pi's seven built-in tools, exhaustively
- The minimalism argument, in the creator's own reasoning
- Deliberate omissions, and why each was rejected
- DeepSeek's execution pipeline: approval, sandboxing, fail-closed
- Two stated security postures
Part VII — Composition: Workflows, Chains, and Routing
- DeepSeek's workflow scripting engine
- Named patterns that exist: the Ralph loop and goal rounds
- The pattern that is explicitly, admittedly absent
- Routing as it actually exists, and the Cordis connection to it
- What Pi does and does not have here
- Pi's three-tier trust ladder
- Pi's package manager, exactly
- Supply-chain discipline
- DeepSeek's bundle/profile/patch layering
Part IX — Multi-Agent Patterns
- Pi's subagent providers, and a stated-versus-shipped tension
- DeepSeek's subagent stack, including cross-vendor delegation
- The workflow engine as orchestrator-workers
Part X — Security Posture, In Their Own Words
- Pi's project trust mechanism, exactly
- Pi's stated scope and out-of-scope list
- DeepSeek's layered, fail-closed defaults
Part XI — Sessions, Modes, and Running Systems
Part XII — Building the Human Interface
- Why an append-based terminal interface, not a fullscreen one
- Pi's differential rendering engine
- Pi's CBOR wire protocol
- The client/server architecture, and its honest incompleteness
Appendices
Part I — The Shape of Two Systems #
1. Pi’s four-layer architecture #
Pi is not one program. It’s an npm workspace of separate packages, layered so that each one only depends on the ones below it — no circular dependencies anywhere in the stack:
graph TD
CLI["pi-coding-agent<br/>the CLI: bash/read/write/edit/find/grep/ls,<br/>TUI, sessions, extensions, package manager"]
Core["pi-agent-core<br/>the harness: durable state,<br/>compaction, the agent loop"]
Client["pi-client / pi-protocol<br/>remote-session transport"]
Tui["pi-tui<br/>terminal rendering"]
Ai["pi-ai<br/>unified LLM client across many providers"]
Telemetry["pi-telemetry<br/>event schema only — no destination of its own"]
CLI --> Core
CLI --> Client
CLI --> Tui
Core --> Ai
Ai --> Telemetry
Every package in this stack currently ships at the same version number, even packages that didn’t change in a given release — a deliberate lockstep versioning choice so you never end up with an incompatible pairing between, say, pi-ai and pi-agent-core. Two more packages sit alongside this stack: pi-server (an experimental remote-session server, covered in Part XII, and genuinely incomplete — no production implementation of the interface a real agent would need to plug into it, only an in-memory test fake), and a pluggable SQLite storage backend for pi-agent-core, covered in Part II.
2. DeepSeek Harness’s plugin-first architecture #
DeepSeek Harness organizes itself completely differently. Its own architecture document states the premise directly: every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself. Composition happens in layers, from the outside in — a profile (for example web or headless) is a named stack of bundles plus a local configuration overlay; a bundle is a distributable unit of configuration rows plus the code they mount; dsh-base is the first layer of every profile (model adapters, tools, persistence, sandbox and approval policy, settings, credentials, telemetry), with surface-specific bundles adding layers on top. Layers apply in a fixed, printable order, and the harness can print the exact resolved configuration tree on demand — composition here is fully introspectable, not implicit.
graph TD
Base["dsh-base<br/>model adapters, tools, persistence,<br/>sandbox/approval policy, settings, telemetry"]
Bundle["surface-specific bundles<br/>(e.g. dsh-web-app, dsh-headless)"]
Profile["a profile (e.g. 'web')<br/>= ordered stack of bundles"]
ProfilePatch["profile-level patch"]
HomePatch["home-directory-level patch"]
CliPatch["--patch overlay (optional)"]
Resolved["fully resolved, printable config tree"]
Base --> Bundle --> Profile --> ProfilePatch --> HomePatch --> CliPatch --> Resolved
Below that boot-time layering sits a per-agent scoping primitive: every live agent gets its own child context, and anything registered through that agent’s context is visible only to that agent and automatically unwinds when the agent disposes.
This “everything is a plugin” claim is backed by real theory, covered in Part II — the plugin framework underneath it, Cordis, is the subject of an actual academic paper with proven theorems about what happens when plugins load, unload, and depend on each other while the system is running.
3. The core loop, in both systems’ own code #
Every agent harness, underneath everything else, runs the same three-step cycle: ask the model what to do, do it, show the model what happened, repeat. DeepSeek’s own core agent class is named after exactly this cycle — an explicit naming choice by DeepSeek’s own engineers.
Pi’s currently-running (not speced — genuinely shipped) agent loop breaks into a small set of cooperating functions worth knowing individually. One function streams the model’s response and pushes the resulting message onto the conversation. If a response gets cut off mid-generation and still contains tool calls, the loop deliberately refuses to execute them — it appends an error result explaining that the arguments may have been corrupted by truncation and asks the model to reissue the call, rather than guessing at what a half-formed bash command was supposed to do. Otherwise, tool calls are dispatched either sequentially or in parallel, with one wrinkle worth remembering: if even a single tool in a batch declares itself unsafe to run concurrently, that forces the entire batch to run one call at a time. The parallel path still validates and hook-checks every call in strict order before dispatching any of them, so side effects from validation stay deterministic even though the actual execution runs concurrently.
Each tool call passes through a small pipeline: look the tool up, run any argument-preparation step, validate the arguments against the tool’s schema, run an optional pre-execution hook (which can block the call outright and substitute an error result), run the tool, then run an optional post-execution hook that can patch the result’s content or error status. One specific, real inconsistency worth knowing about: if the post-execution hook itself throws, the entire result gets replaced with a fresh error — a stricter failure behavior than how the pre-execution hook’s own failures are handled, and the kind of detail you only notice by reading the actual code rather than the design description.
DeepSeek’s own loop implements the identical shape but expresses every junction point as an internally dispatched event rather than a plain function call — the model request itself passes through a chain of middleware that any plugin can rewrite before it’s sent, and the closing of a turn passes through a similar chain that lets a plugin object and steer the loop back into another round. DeepSeek’s own engineering conventions are explicit that this pluggability is deliberate but bounded: new behavior is meant to attach to a documented extension point, and changing the loop’s actual control-flow shape — as opposed to its pluggable behavior at each junction — is treated as a distinct, higher-bar kind of change.
4. Why Pi exists: the creator’s stated motivations #
Pi’s creator, in his own blog post about the project, gives a specific account of why he built it rather than using an existing coding agent. Several concrete complaints recur:
- Uncontrolled growth in an existing tool he’d used. He describes a competing product having accumulated a large amount of functionality he personally never used, and — more specifically — describes the system prompt and tool set changing on every release, which broke his own established workflows and changed model behavior underneath him without warning.
- A desire for total visibility into what actually reaches the model. He states plainly that he wants to inspect every part of his interaction with the model, and that existing harnesses generally make this difficult or impossible, because they inject additional content behind the scenes that never surfaces anywhere in the interface. He connects this directly to a broader belief that precisely controlling what enters a model’s context is one of the biggest levers on output quality available to someone building an agent.
- Wanting a session format he could process automatically, and a simple enough core that he could build alternative interfaces on top of it without fighting the harness itself.
- Frustration that self-hosted models are poorly supported by the popular unified-LLM libraries many competing agents build on, which he attributes to those libraries being designed primarily around hosted commercial providers.
His stated overall design principle, in his own words, is short and direct: if he doesn’t need a feature, it doesn’t get built — and, in his own account, he doesn’t need very many features. This single sentence is worth keeping in mind through the rest of Part VI, because it’s the explicit, first-person justification behind an entire category of deliberate omissions covered there.
5. Two philosophies, stated in their own words #
Pi’s own README states its permission stance without qualification: the system ships with no built-in mechanism for restricting filesystem, process, network, or credential access, and by default runs with the full permissions of whatever user and process launched it. The creator’s blog post gives this stance its own informal name — he describes Pi as running in what he calls “full YOLO mode,” assuming the person running it understands what they’re doing.
DeepSeek Harness’s architecture document states the opposite instinct just as plainly: there is no privileged core to patch, because you extend the system by mounting a plugin beside the existing ones, and every registration is a reversible effect that automatically unwinds when its owning plugin unloads. Safety mechanisms in DeepSeek’s world are themselves ordinary plugins, shipped on by default, engineered — as Part VI will show — to fail closed rather than fail open.
Neither position is simply correct. Pi’s approach is legible: you always know exactly how much protection exists, and the responsibility for anything more sits entirely with whoever embeds it. DeepSeek’s approach gives real defense-in-depth by default, at the cost of a much larger, more architecturally committed codebase to get there. Watching the same problems solved twice from these different starting points is the organizing structure for the rest of this document.
Part II — Durable State and Crash Recovery #
6. The problem, as Pi’s own design document frames it #
Pi ships an internal design document, roughly 2,900 lines long, describing a crash-safe state machine for a long-running agent session in real detail, with worked examples and formal invariants.
One correction has to be stated up front, because it changes how to read everything in this part. This document describes a system that is specified, not one that is shipped. The actual class implementing it in Pi’s codebase is roughly 500 lines, and nearly every state-mutating method on it — sending a prompt, compacting, resuming, aborting, steering, navigating the session tree — is implemented as a call to a helper that simply rejects with a “not implemented” error. The design document itself is explicit that this is intentional and temporary: it names, in its own build-order section, the current implementation directory as slated for wholesale deletion once the new design ships, stating there’s no obligation to adapt anything in the code being replaced.
What this gives a reader is something more useful than either piece alone: a real, live “before and after” of an architecture rewrite, with the old, working system still sitting in the same repository as the new system’s full specification and the stated reasons for replacing it.
7. Pi’s specified design: entries, registers, ledger #
The design’s foundational claim is that a session’s entire state lives in exactly three places:
- The entry tree — an append-only, immutable log of everything that’s happened: messages, tool results, compaction summaries. You can append to it; you can never edit or delete from it.
- Registers — small, named, mutable key-value cells. This is the only mutable state in the entire design. Overwriting a register replaces its value outright; deleting a register removes the key, with no history kept of what it used to hold.
- The usage ledger — an append-only record of token and cost accounting. Every settled provider attempt writes one row here, successful or failed, including attempts whose surrounding operation later aborts, so billing survives everything that can happen to the orchestration state around it.
The document states the whole premise in one line: every payload lives in an entry, a register, or the ledger, and there is no fourth place for state to hide.
The durable program counter. After every step, the design overwrites one specific register — the operation’s complete current state, not a diff — so that recovering from a crash means reading that one register and switching on it, rather than replaying a log through some reconstruction logic. Recovery, in the document’s own framing, is a read, not a computation.
Lanes. A lane is a named cursor into the shared entry tree. Every session always has a default lane, and each lane owns its own position, its own model configuration, and at most one in-flight operation at a time — the mechanism that lets multiple concurrent threads of work share one history without stepping on each other, because each only ever mutates its own lane’s registers.
8. The effect sandwich, in full, with every worked example #
This is the single most transferable idea in the entire document. Every risky action — a model API call, a real tool call — is wrapped in three commits: an intent commit stating what’s about to happen and which output IDs it will use, the uncertain action itself, and a settlement commit recording the actual output, its usage, and the next state.
The document names precisely the one genuinely uncertain window this creates: an intent has been durably recorded, but the matching settlement never arrived. Three separate policies cover that window, one per kind of interrupted step. For an interrupted model generation, a fresh, later-numbered attempt is only started if the retry policy captured at the time of the original request still allows it; once that budget is exhausted, a synthetic error response is inserted under the already-reserved output ID rather than leaving it permanently unresolved. For an interrupted tool call, the tool’s own declared replay policy governs: the default policy is to not re-run the effect, instead appending a synthetic “interrupted” error result under the reserved ID and moving on; a tool may instead declare itself safe to replay, in which case the effect genuinely is re-run with the exact persisted arguments — but only if both the persisted declaration and the currently-loaded tool’s declaration agree it’s safe, a deliberate guard against a tool quietly being reclassified across a code upgrade. For an interrupted deferred write, the design waits for an explicit resume if the surrounding operation was still running, or synthesizes an aborted outcome if cancellation had already become durable before the crash.
graph TD
A["Commit intent:<br/>'about to call tool X, output reserved as ID R'"] --> B["Perform the effect<br/>(the one uncertain step)"]
B --> C{"Process crashes before<br/>settlement commits?"}
C -- "No" --> D["Commit settlement:<br/>output + usage + next state"]
C -- "Yes" --> E{"Tool's declared<br/>replay policy?"}
E -- "never (default)" --> F["Synthesize an 'interrupted'<br/>error under reserved ID R —<br/>never re-run the effect"]
E -- "safe" --> G["Re-run the effect with the<br/>exact persisted arguments"]
A worked example given directly in the document, at the level of detail it deserves: a model returns two tool calls in one turn. The harness records the batch plan, then records that the first call is about to execute with specific arguments and declares itself unsafe to replay. The tool begins deleting files. The process is killed mid-deletion. On restart, the harness reads exactly one register, finds the call marked as pending with an unsafe-to-replay declaration, and does not re-run the deletion — it appends a synthetic interrupted-error result under the ID that was reserved before the effect ever began, marks that call complete, and proceeds to the next one. The document’s own summary of this: the conversation stays coherent, because every tool call ends up with a result, and nothing runs twice. Had the tool instead declared itself safe to replay, the harness would have re-executed it with the exact persisted arguments instead of synthesizing an error.
A second worked example, for context-overflow recovery: a tool result sits at the end of the tree awaiting an assistant turn, and the resulting request simply doesn’t fit the model’s context window. The failed response is committed durably, alongside a marker that compaction is now needed specifically because of this overflow. Compaction then runs using the ordinary rules from Part III — the just-committed error response is excluded from both the summary and the retained tail, on the general principle that error responses aren’t real conversational content worth summarizing. If the retried request overflows a second time, a durable flag set on the first overflow prevents an infinite compact-and-retry loop, and the run instead moves into an explicit failure state.
On the race-condition side, the document gives a full table of every possible race between two concurrent operations on one lane — a prompt racing another prompt, an abort racing a response settling, a manual compaction reservation racing an ordinary write — and states, as a design principle, that every such race has exactly two possible durable outcomes, never more, because every state-dependent mutation on a lane serializes through a single linearizing point before the next mutation can begin.
9. What is actually running in production instead #
The currently-shipped implementation is a completely different, and completely conventional, architecture: event sourcing. Durable records describing every operation, step, tool call, and queue action are appended forever, and a pure reducer function replays the entire record log, in order, on every single recovery to reconstruct the current state.
This comes with the cost every event-sourcing system pays: roughly 80 lines of hand-written validation logic checking for corrupted logs — a non-consecutive attempt number, a queue operation appearing after an already-recorded abort, a duplicate tool invocation, a mismatch between a provisioned entry and what actually exists. These are exactly the class of failure the register-based design above is built to make structurally impossible, because there’s no log to replay and no reducer left to have a bug in.
This is worth sitting with as a general lesson: a specification document and the shipped code, in the same repository, can describe two entirely different architectures, and the only way to tell which one you’re actually looking at is to read the code, not just the docs.
10. Storage backend contracts, SQLite, and the conformance suite #
The design specifies a single storage interface — commit a transaction, read entries, read or list registers, scan a branch, scan usage rows, get aggregate stats, close — with three backends (in-memory, JSONL, SQLite) all meant to pass one shared conformance suite, so swapping backends never changes observable behavior.
The SQLite backend’s concurrency approach is worth understanding on its own. Every transaction opens with an immediate write-lock acquisition rather than a deferred one, because a deferred transaction that reads before it writes takes a read snapshot that can fail to upgrade later if another writer commits in between — and no amount of waiting can rescue that failure, since waiting can’t refresh a stale snapshot; the only recovery is a full retry. On top of this, a lease table enforces a hard single-writer-per-session rule across processes, because the underlying database engine’s own write-ahead-log mode would otherwise happily let two separate processes alternate writes to the same file — exactly the interleaving this design forbids. The lease is time-bounded and fenced: opening a session claims it, ongoing activity renews it, and closing only releases the exact claim that was granted, so a stale, already-superseded owner can never accidentally release a lease belonging to whoever replaced it.
11. Versioning and migration across harness versions #
The design’s schema-evolution approach rests on one hard, explicitly stated constraint: migrations must be total. If a future version of the state machine removes a phase that used to exist, an old, in-progress operation sitting in that removed phase has no natural equivalent — the rule is that whoever makes the change must write an explicit mapping for every reachable old state into a well-defined new one, in the same change, reviewed and tested alongside it. A state with no natural successor maps to an explicit fallback choice, typically the nearest safe point from which ordinary crash recovery can proceed. This is made tractable by a second constraint: migration only runs at session-open time, under the exclusive write lease, so it only ever sees a fully quiescent set of registers — nothing mid-flight — which turns the whole operation into a pure function over a small, fully enumerable, typed set of values.
12. Cordis: reversible effects and reactive coeffects, the formal model #
DeepSeek Harness’s plugin framework, Cordis, is the subject of a real design paper — an actual paper with theorems and proofs, not marketing copy — titled “A Programming Paradigm for Spatiotemporal Composability.” Its target problem is dynamic composition: software that loads, unloads, and reconfigures components at runtime, as opposed to the ordinary static composition resolved once at compile time.
The paper’s central move is noticing that two existing pieces of programming-language theory already describe exactly what dynamic composition needs, just in a static, compile-time-only form: an effect system formalizes how code modifies its environment, and a coeffect system formalizes what code requires from its environment. The paper’s contribution is lifting both into mechanisms a running system can use, so the safety guarantees these ideas normally give only at compile time become guarantees a live, constantly-changing system can maintain while running.
This splits into two matching halves. Temporal composability models an effect as a function producing both the new state and an explicit inverse, with the runtime automatically composing these inverses as effects accumulate, so a single accumulated “undo everything this component did” operation always correctly recovers the prior state — and the paper proves that when two effects are provably independent, they can even be reverted in any order. This is the direct backing for Cordis’s actual API: one primitive is the single channel every context mutation flows through, which is exactly why tearing down a plugin automatically and completely unwinds everything it registered, with no hand-written cleanup required. Spatial composability has a component declare the set of keys it needs from the shared context, with the system reactively tracking whether that set is currently satisfied and activating or deactivating the component the instant satisfaction changes — structural, runtime-enforced dependency safety rather than a convention plugin authors have to get right by hand.
The paper motivates this with a concrete empirical observation: it reports that a majority of a sample of popular editor extensions it examined contain code that forces a full host restart on removal, because the host’s own deactivation hook only fires at whole-process shutdown, which decouples when an effect was created from when it’s supposed to be cleaned up and makes completeness of that cleanup fundamentally unverifiable from outside. Cordis’s answer is making that cleanup automatic and structurally guaranteed.
13. Cordis: the theorems, and what they buy an agent harness #
The paper proves several properties, and the headline one is Confluence: any sequence whatsoever of runtime component insertions, removals, or replacements reaches the same final state, up to renaming, that loading the final configuration from scratch would have reached. This is the exact guarantee that licenses reasoning about a live, constantly-mutated agent harness as if it had been assembled once, statically — precisely the property wanted when a harness is swapping tool sets, sandbox backends, or subagent providers underneath a session that’s still running. Two supporting theorems make Confluence meaningful: Preservation (every registry produced stays well-formed after any sequence of operations) and Progress (the system never deadlocks, reaching a stable configuration in a bounded number of steps proportional to how much actually changed).
The paper is careful about the limits of its own claims: its stated production validation is a different, pre-existing chatbot framework with thousands of third-party plugins, and it names agent harnesses whose components continuously modify themselves with little human oversight as a future validation target for the same theoretical machinery — not a claim that this has already been demonstrated. DeepSeek Harness is the concrete next system being built on the same foundation.
14. Cordis: from theory to the concrete API #
The paper includes a table mapping its formal model onto Cordis’s actual, usable API — the unified context becomes the ordinary context object every plugin receives; the single effect primitive becomes a method returning a disposer; getting or setting a coeffect becomes simple get/set calls; a formal component becomes a fiber — a live instantiation carrying declared dependencies, provisions, and an effect function; registering a component at runtime becomes a single method call.
DeepSeek’s own primer document restates this plainly: a plugin implements a service shape, a context is a repository of services, a service dependency is declared explicitly, and registrations are reversible effects installed so that both a manual reload and an automatic teardown unwind them predictably. On top of this core sits a declarative component loader — configuration entries with an ID, a source, an isolation scope, and an enabled/disabled flag — reconciled incrementally rather than by tearing the whole tree down, with the soundness of that incremental reconciliation following directly from the Confluence theorem above. The same layer implements hot module replacement: a source-file change is classified via a fixed-point walk over the import graph, and reload is fully transactional — if any module fails to re-import, the entire affected set rolls back to its pre-reload state, with no developer-annotated “this file is safe to hot-reload” boundaries required.
Part III — Context Window Management #
15. Pi’s compaction algorithm, in depth #
Unlike the crash-recovery machinery in Part II, Pi’s compaction algorithm itself is real, working code today, even while the state-machine driver meant to call it automatically is still a stub. One function handles the “deciding” step: it finds the most recent prior compaction, if any, so a second compaction can build on the first summary rather than re-summarizing already-summarized content; estimates the total token count of the context under consideration; and walks backward from the end of the conversation, accumulating estimated tokens per message until a configured budget is exceeded, then snapping the cut point to the nearest clean boundary — never mid-tool-result, only at a clean message or prior-summary boundary.
A specific tricky case the algorithm handles explicitly is the “split turn.” Sometimes the chosen cut point falls in the middle of an in-progress assistant turn rather than cleanly before a fresh user message. When this happens, the part of that turn occurring before the cut is summarized separately, with its own shorter prompt and a smaller output-token cap, and the two summaries are concatenated rather than forcing one prompt to handle both a clean historical range and a still-open turn simultaneously.
By default, compaction reserves roughly 16,000 tokens of headroom and aims to keep at least 20,000 tokens of the most recent conversation completely uncompressed. Every summary gets a footer tracking which files were read and modified across the compacted range, so the agent retains that knowledge even after the underlying messages are gone from its view.
Which of the three trigger types actually work matters in practice. Manual compaction is fully implemented. Threshold-based compaction exists only as a callable comparison — is current usage past the reserved budget — with nothing in the shipped code actually calling it automatically at a checkpoint. Overflow-triggered compaction, recovering automatically from a request that simply didn’t fit, has no implementation at all in the code examined; only the type definitions for it exist. The design document itself is careful to label overflow detection explicitly as a heuristic rather than a guarantee wherever it discusses it — a good habit worth copying even in places where the logic is working, since mistaking a best-effort heuristic for a guaranteed detector is exactly how a harness quietly breaks in production.
16. DeepSeek’s two-tier compaction: summarization plus deterministic pruning #
DeepSeek Harness’s approach to the same problem is fully implemented and deliberately split into two independent, composable mechanisms — arguably the more directly copyable design of the two.
The first tier is a model-free tool-result pruner, doing deterministic head/middle/tail character truncation of oversized tool output with no LLM call involved at all. Each replacement is preceded by a small bookkeeping record noting exactly how much content and how many tokens were shadowed, so a downstream consumer can account for the removed cost without needing to retain any of the pruned content itself.
The second tier is LLM-based summarization, triggered either proactively — when context usage crosses roughly 80% of the window by default — or reactively, when an actual overflow error came back from the provider. It measures pressure via a token meter, selects a range to summarize while retaining roughly the most recent 16% of the window verbatim by default, and replaces that range in the model-visible surface without deleting it from the durable underlying log, recording the replacement as a distinct shadowing operation so a full audit trail survives even though the model no longer sees the raw messages.
The two compose rather than compete, and the order matters: pruning always gets the first, cheap attempt on an overflow before the more expensive summarization step is even considered. This is worth generalizing past this one codebase: not all context bloat needs a model’s judgment to fix, and treating “shrink the context” as one monolithic operation misses free, essentially-zero-cost wins that a simple character-count truncation already captures.
One further specific detail worth copying: when DeepSeek’s harness makes its own internal call to actually generate a summary, it deliberately uses a fresh, isolated session identity for that call rather than reusing the main conversation’s own identity, on the stated reasoning that this isolates routing and avoids writing to a cache slot that couldn’t be reused anyway — a housekeeping operation kept from silently polluting the real conversation’s cache.
17. The stable-prefix discipline in both codebases #
The single most transferable idea across this part of the document: treat “don’t disturb the stable prefix of your context” as a running design constraint, not an afterthought bolted onto caching later.
Pi’s design states the rule directly: across the requests of one lane, provider context only ever grows at the tail. Inserting anything before the previous request’s tail invalidates whatever cache the provider was keeping and multiplies cost. This is exactly why mid-run writes never splice into an in-flight request; they queue and only apply at the next checkpoint, where they can be appended cleanly at the tail.
DeepSeek’s version of the same idea is a concrete, directly copyable mechanism. Volatile per-turn facts — the current time, the active sandbox mode, the working directory — are not re-rendered inline into the system prompt on every request. Instead they’re projected into one trailing message, and a new message is only appended when the rendered text actually differs from the previous turn. A plugin author’s own code comment states the motivation plainly: routing the complete current value after retained history means switching a setting doesn’t rewrite the stable system-prompt prefix a cache is keyed on.
18. Context handoff between model providers #
Pi’s creator describes cross-provider context handoff as a deliberate design goal of the unified LLM layer from the very start of the project, on the reasoning that a session should be able to switch which model provider it’s talking to mid-conversation without losing the ability to continue coherently. Because different providers represent tool calls and internal reasoning traces in incompatible native formats, this can only ever be a best-effort translation rather than a lossless one. One concrete example he gives: if a session started against one provider and switches to a different one mid-conversation, that first provider’s own internal reasoning traces get converted into plain text content blocks, wrapped in an explicit marker tag, rather than being silently dropped or causing an error.
This is a genuinely distinct engineering problem from anything covered in Part I’s tour of the unified LLM layer — it’s not just “can we call multiple providers,” it’s “can a single ongoing conversation survive being handed from one provider’s native format to a different one’s without losing the thread,” and it’s worth noting as a real, specific design goal rather than an incidental side effect of supporting many providers.
19. A real-world data point: long sessions without compaction #
Pi’s creator offers a direct, first-person data point relevant to everything covered in this part: in his own account of daily use, he describes being able to run sessions of hundreds of exchanges without needing compaction at all — something he states he was not able to do in a comparable competing tool without that tool’s own compaction kicking in. He states plainly that the absence of automatically-triggered compaction (consistent with the finding in Chapter 15 that threshold and overflow triggers aren’t actually wired up yet) has not been a problem for him in practice.
This is worth reading alongside Chapter 15’s finding rather than as a contradiction of it: a mechanism can be incompletely automated in the code and still not matter much for a specific, real workload, if that workload’s actual context growth stays under whatever a given model’s context window happens to be. It’s a useful reminder that “this automatic trigger isn’t implemented yet” and “this is currently a problem in practice” are two separate claims, and conflating them would overstate the urgency of a gap that its own creator reports not having personally hit.
Part IV — Caching and Cost #
20. DeepSeek’s caching reality #
DeepSeek Harness does not implement any manual cache-breakpoint placement logic — there is no component deciding where, within a request, to insert a cache boundary. What exists instead is threefold. First, usage accounting: the token-usage type carries explicitly disjoint fields, uncached input tokens counted separately from cache-read and cache-write tokens, and DeepSeek’s own model adapter maps the underlying wire format’s cache-hit counter back into this disjoint shape — confirming that DeepSeek’s own API performs automatic, prefix-keyed context caching with no client-side annotation required at all; the harness’s job is simply surfacing the resulting hit/miss counts for cost accounting. Second, an explicitly unresolved design question left as a code comment rather than papered over: the type describing a conversation call’s configuration states directly that provider routing, model choice, reasoning effort, and sampling values can all affect whether a provider’s cache gets reused, and flags exactly which fields should count as “cache-affecting” as an open, unresolved internal question. Third, a pass-through retention knob on one alternate model adapter, letting a deployment choose how long the provider should retain what it’s already caching — a preference, not a placement decision.
The overall conclusion: DeepSeek’s caching story is “lean on whatever the provider does automatically,” combined with the architectural discipline from Chapter 17 that maximizes how often that automatic cache actually gets hit.
21. Pi’s append-only-context invariant as a caching discipline #
Pi’s design doesn’t describe a separate caching feature either — it folds the whole concern into the append-only-context invariant already covered in Chapter 17, with compaction named explicitly as the one deliberate, understood exception: the one place the design intentionally throws the existing cache away, in exchange for a smaller context to build a fresh one against going forward.
The rule both systems converge on: caching is not a feature to bolt on separately. It’s a direct, mechanical consequence of how disciplined your context-assembly code already is.
22. Token and cost tracking limits: the cross-origin problem #
Pi’s creator describes a specific, concrete obstacle to accurate cost tracking across providers. Some providers support the kind of cross-origin request that lets a client-side library observe token usage directly; he names Anthropic and xAI as providers that make this comparatively easy. Even where usage figures are observable this way, he notes there’s no way to attach a unique identifier a developer could later use to correlate a specific request with that provider’s own separate billing records. His stated conclusion is that Pi’s own token and cost tracking is necessarily best-effort — adequate for a single person’s own usage, but not something he’d rely on for accurate billing if a service were charging its own end users based on these numbers.
This is worth including as its own point because it’s a specific, first-party admission of a limitation that wouldn’t be visible from reading the code alone — the code can show you that usage is tracked, but only the creator’s own account explains why that tracking can’t be made fully precise across every provider.
23. Splitting a tool result for the model versus the interface #
Pi’s creator describes an abstraction in the unified LLM layer that he states he hasn’t seen in any comparable library: a tool’s result can be split into two separate parts — one portion of content handed to the model itself, and a second, separate portion of content intended purely for how the result gets displayed in a user interface. This lets a tool implementation return, for instance, a concise textual summary for the model to reason over while separately returning a richer, more detailed rendering (a diff, a table, a live preview) for a human watching the session, without needing the model-facing content and the display content to be the same thing, or without needing the interface layer to parse the model’s own content back out to figure out how to render it.
This is a small, specific, and genuinely useful design idea worth calling out on its own: the content a model needs to reason well and the content a human needs to understand what happened are not always the same content, and building a tool result format that treats these as two separate channels from the start avoids a whole category of later hacks where a UI layer has to reverse-engineer a human-readable view out of whatever text happened to be sent to the model.
Part V — Evaluation #
24. Pi’s behavioral eval harness #
Pi’s evals package is explicitly described, in its own documentation, as behavioral, model-backed checks for how Pi itself behaves — not a generic benchmark suite for arbitrary language models, and not a plain unit-test package (ordinary unit tests for Pi’s own code live separately). It adapts a genuinely real, running agent session into a third-party test-running library, executes it inside isolated temporary directories, and attaches native session transcripts as artifacts alongside the results.
Its own simplest example eval is instructive precisely because of how minimal it is: send a trivial factual prompt with every tool disabled, and assert that the trimmed output matches exactly, that no errors occurred, and that the reported token usage matches the configured provider and model with a nonzero total. This is a deliberate smoke test of the harness’s own wiring — a fully deterministic round trip with zero tool use — not an attempt to measure the model’s actual capability. Beyond individual eval files, the package includes purpose-built comparative tooling for running a baseline configuration against a candidate configuration across repeated trials and computing the resulting pass-rate difference, alongside paired token, latency, and cost deltas between the two — treating “did this change help” as a comparative question with a confidence interval, not a single pass/fail signal from one run.
25. DeepSeek’s benchmark posture, and its actual internal quality bar #
This is one of the more counter-intuitive findings behind this document, precisely because it runs against what you’d expect. DeepSeek Harness’s top-level benchmark document is three lines long, and it is not a benchmark suite of its own — it’s a pointer directing you to install the project’s Python SDK and use the harness itself as the agent under test, embedded inside someone else’s benchmark runner, with the explicit instruction to give each independent task its own isolated workspace and session identity. The recommended configuration for exactly this use case is deliberately stripped down — two tools, compaction turned off, the most permissive sandbox setting, no persona or skills loaded — on the evident reasoning that a benchmark harness wants the smallest, most predictable agent surface, not a fully-featured product configuration.
The actual internal quality bar for the project lives in a separate testing document, not the benchmark file. Two tiers matter: a snapshot-testing tier that boots a genuinely real example agent, replays a recorded session, and diffs the normalized output against a checked-in expected transcript; and a real-API end-to-end tier that runs against live provider APIs and self-skips only if no credential is configured, under an explicit stated house policy against rationing real-API tests to save cost, because only a run against an actual model proves the agent genuinely works.
The single best, most generalizable finding from this entire section is a stated house rule inside that testing document: end-to-end tests are required to verify the world, not the agent’s own self-report — after the agent claims to have made an edit or run a command, the test independently re-reads the file or re-runs the command from outside the agent’s own output, because a check that merely matches keywords in the agent’s own claimed summary would let an agent that’s simply wrong pass by asserting success without having actually achieved it. This deserves to be applied far past this one test suite: never grade an agent by asking it whether it succeeded, because an agent’s self-report is produced by exactly the process whose reliability you’re trying to measure.
26. Informal validation: what Pi’s own benchmarking commentary says #
Pi’s creator, discussing informal benchmark comparisons in his blog post, is upfront that such comparisons don’t fully represent real-world performance, offering them mainly as evidence that his broader claims about a minimal design holding up aren’t unfounded. He specifically points to a minimal, comparably-scoped external coding-agent benchmark entrant as evidence that a stripped-down tool set can hold its own against agents shipping far more elaborate tooling, across a range of different underlying models — treating this as supporting evidence for the same minimalism argument covered in the next part, rather than a rigorous, controlled study.
Part VI — Tools, Minimalism, and the Permission Question #
27. What a tool is, in both systems’ type definitions #
Stripped to essentials, a tool in either system is a name, a description the model reads to decide when to call it, a parameter schema, and an execute function. Both harnesses use the same runtime schema-validation library, TypeBox, for that schema — a specific, shared technology choice worth noting since it means both projects validate tool arguments the same structural way even though the codebases are otherwise unrelated.
DeepSeek Harness’s tool interface is meaningfully richer than the bare minimum: alongside input parameters, a tool must also declare a validated output schema, whether it’s safe to run concurrently with sibling calls, a cooperative execution timeout, and explicit render-intent methods so the presentation layer never needs tool-specific special-casing. One further, unusual detail: DeepSeek Harness supports switching an entire session between sending the model every tool’s schema directly, or instead sending it exactly one code-execution tool plus a generated set of type stubs, where every other capability becomes callable only from inside a program the model writes and submits — switchable per session, so one running process can have some agents in the direct mode and others writing code simultaneously.
28. Pi’s seven built-in tools, exhaustively #
Every one of Pi’s built-in tools is a plain object built by a factory function, and the single most important structural fact about all seven is that none contains any confirmation, approval, or permission-check logic whatsoever — each validates its own arguments, does the actual filesystem or process work, and returns a result or throws an error, nothing more.
The bash tool’s schema is exactly two fields — a required command string and an optional timeout in seconds, with no default timeout at all if the model omits one, meaning a command can run indefinitely unless something external aborts it. Output truncates at 2,000 lines or 50 kilobytes, whichever comes first, truncated from the tail on the reasoning that a command’s final output matters more than its beginning; on abort or timeout, the entire process tree is killed, not just the immediate child, since a shell command can spawn further children that would otherwise survive.
The read tool supports both text and images, sending images back as attachments rather than text, using the same line/byte truncation as bash for text, with an offset/limit pair for paging through large files; its own system-prompt guideline nudges the model toward using it rather than shelling out to a text-dumping command.
The write tool creates a file if it doesn’t exist and unconditionally overwrites it if it does, creating missing parent directories along the way, with no size limit, no diff shown, and no check of any kind on whether the file was previously known to the model — structurally the single most destructive of the seven tools, with no built-in guardrail beyond a per-file mutation queue that only prevents two concurrent calls from racing on the same file.
The edit tool takes exact-text replacement pairs that must be unique and non-overlapping within a call, and includes a compatibility shim for models that send malformed input — a JSON-encoded string instead of a real array, or an older single-edit calling convention with fields at the top level rather than nested — a small, real reminder that tool schemas have to defend against models that don’t call them exactly as specified.
The find tool shells out to the real fd binary rather than reimplementing glob matching in-process, with logic specifically detecting whether the search is happening inside a git repository, since that changes how ignore-file rules should be interpreted relative to nested repositories.
The grep tool shells out to the real ripgrep binary, parsing its structured output rather than its plain text output, with an optional context-lines parameter matching conventional grep behavior.
The ls tool is the simplest: it reads a directory, sorts entries, and silently skips any entry that fails to be examined rather than erroring the whole call out.
All seven tools share the same truncation constants and the same underlying error-handling pattern: no internal exception handling for ordinary failure modes, relying instead on a shared filesystem abstraction that converts errors into thrown exceptions at the tool boundary, plus repeated cancellation checks bracketing every mutating step so an abort that lands mid-write never gets silently reported as success.
29. The minimalism argument, in the creator’s own reasoning #
Pi’s creator makes a specific, direct argument for why exactly these four core tools — bash, read, write, edit — are sufficient, with read-only variants like grep and find as convenience additions. His reasoning is that current frontier models have been trained extensively enough that they already understand what a coding agent is and how to use a shell, and that they’ve specifically been trained on read, write, and edit as tool shapes, so a large system prompt explaining coding-agent behavior in general isn’t needed the way it might have been with earlier, less capable models. He states that Pi’s entire system prompt and tool descriptions together come in well under a thousand tokens, in contrast to some competing tools’ orders of magnitude larger prompts, and that the one piece of context always injected is whatever project-level instructions file exists in the working directory.
The transferable argument here is narrower than “always use fewer tools” — it’s specifically that a chunk of prompt engineering that made sense for earlier models may be pure overhead for current ones, and that it’s worth periodically re-testing whether scaffolding you added for an older, less capable model is still earning its token cost against whatever model you’re actually running today.
30. Deliberate omissions, and why each was rejected #
Pi’s creator documents a specific list of features he considered and explicitly chose not to build, each with its own stated reasoning, and each is worth knowing as a real, specific engineering argument rather than a vague preference for simplicity.
No built-in to-do or task list. His stated reasoning is that a to-do list is itself a piece of state the model then has to track and keep updated, which is an added opportunity for the model to get something wrong, rather than a pure benefit — and that anyone who genuinely needs task tracking across a session can get it more reliably by having the agent write it to an external file, which persists independently of the model’s own attention.
No dedicated planning mode. He argues that simply asking the agent to think through a problem conversationally, without modifying anything, is generally sufficient, and that a plan meant to persist across multiple separate sessions is better served by writing it to a file than by a mode that only exists transiently within one session — a file-based plan, unlike an ephemeral one, can be picked back up in a later session.
No support for the Model Context Protocol. He argues MCP servers are overkill for most use cases and carry a real, measurable context cost, citing two well-known real MCP servers by name as examples whose full tool descriptions consume a meaningful single-digit percentage of a typical context window before any actual work begins. His preferred alternative is building an ordinary command-line tool with its own README file, so the agent only pays the token cost of reading that documentation when it actually decides the tool is relevant to the task at hand — a form of the same “load detail only when needed” idea that shows up under different names throughout this document.
No built-in background-process management. He argues that properly supporting long-running background processes (tracking them, buffering their output, cleaning them up, sending them further input) adds real complexity for a capability that an existing, well-known terminal multiplexer already provides. His recommended alternative is simply running Pi alongside a persistent terminal multiplexer session, letting the agent and the human share the same long-running process directly rather than the harness reimplementing process supervision itself.
No automatically-spawned sub-agents. He argues that when a competing tool delegates part of a task to an automatically-spawned sub-agent, the result is effectively a black box nested inside another black box, with the human left unable to see what actually happened during that delegated work. He frames using a sub-agent mid-session purely to go gather more context as a symptom of insufficient upfront planning — his suggested fix is to do that context-gathering work explicitly, in its own separate session, before starting the real task, rather than delegating it invisibly partway through.
This last point is the one genuinely at odds with the shipped code, and it’s worth stating plainly rather than smoothing over: Part IX describes a real, working subagent-provider registry in Pi’s own source, with two distinct delegation modes. It’s possible this reflects the stated philosophy being about automatic, opaque sub-agent invocation specifically — as opposed to an explicit, visible, opt-in delegation primitive that a user or extension author deliberately chooses to invoke — but that reconciliation isn’t something either the blog post or the source code states directly, so it’s presented here as an open, honestly-unresolved tension between stated design philosophy and shipped functionality, rather than a puzzle this document claims to have solved.
31. DeepSeek’s execution pipeline: approval, sandboxing, fail-closed #
DeepSeek Harness’s tool-execution path is an explicit, ordered pipeline: a pre-execute stage that can allow, deny, or require approval; a chain of guards, each able to deny a call, with a deliberately stated invariant that no guard can force-allow a call another guard already denied — denial is monotonic, and approval never overrides a prior denial. After the guard chain, the tool body runs wrapped in timeout, retry, and metrics middleware, followed by a post-execute stage that can accept or block the result, and finally an observation-only result stage.
Two genuinely independent layers of defense compose on top of this. Approval defaults to requiring a decision from whatever human or interface answerer is composed into the session, and if no answerer is actually wired up to answer that question, the missing answer is treated as a denial — fail-closed by construction. A stricter policy exists for unattended, headless deployments, automatically rejecting every approval-requiring call with no human in the loop at all. Sandboxing offers three graduated modes — read-only, workspace-write, and a fully permissive setting — enforced through real, well-known operating-system mechanisms depending on platform: a Linux container-style sandboxing tool followed by a kernel access-control feature on Linux, a macOS application-sandboxing technology on macOS, a restricted access-control-list token on Windows. The load-bearing rule stated in the code: if the platform-appropriate confinement mechanism is missing or can’t be verified as actually working, the system fails closed rather than silently running the command unconfined.
32. Two stated security postures #
Pi’s own documentation states its position consistently, across more than one document: no built-in sandbox, deliberately, on the reasoning that a partial in-process safety mechanism is worse than an honestly-absent one, because it’s easy to mistake for a real security boundary when it isn’t one. Its creator’s own blog post gives the underlying reasoning for this in stronger, more direct terms: once an agent has the ability to write and execute code, he argues, meaningfully restricting what it can do becomes extremely difficult without also cutting off network access entirely, and he frames the combination of reading private data, executing arbitrary code, and reaching the network as a set of capabilities that can’t be safely separated from each other through partial measures — concluding that, in his view, effectively every user of every comparable tool is already operating in an equivalent unrestricted mode in order to get real work done, whether or not the tool advertises a permission system.
DeepSeek Harness’s engineering conventions describe the opposite instinct as a load-bearing practice rather than only a policy statement: safety and reliability claims are expected to be wired into an executed, mechanically-checkable gate, with an explicit requirement that every changed acceptance path be proven to reject an invalid case as part of the same change. The same fail-closed instinct extends to the project’s own development tooling — if a required build or test command fails specifically because the contributor’s own development sandbox is blocking credentials or network access, the stated guidance is to retry with the narrowest possible escalation before concluding the underlying code itself is broken, specifically to prevent a contributor from mis-attributing a sandbox limitation to an actual bug.
Part VII — Composition: Workflows, Chains, and Routing #
33. DeepSeek’s workflow scripting engine #
DeepSeek Harness ships a genuine scripting seam for composing multiple agent calls together, exposed as a tool the model itself can invoke: the model writes a JavaScript orchestration script, executed off the main thread inside an isolated worker with no filesystem, network, or timer access, given three callback primitives to compose with — run one subagent to completion with an optional schema-validated result; run each item in a list through the same sequence of stages with no barrier between stages; and run a set of independent operations concurrently and await them all together.
This means the actual shape of a fan-out is a decision the model makes per task, while the surrounding deployment still enforces hard caps on total concurrency and total spawned-agent count that the model’s own script cannot override. A slot-based limiter bounds how many calls can be in flight simultaneously, and per-run configuration can route every child spawned during a given orchestration to a specific provider without the orchestrating script itself choosing, or even being aware of, which provider that is.
34. Named patterns that exist: the Ralph loop and goal rounds #
Two more constrained, purpose-built composition patterns exist alongside the general scripting engine above, and both are worth knowing by their actual names because the codebase itself names them.
The Ralph loop repeatedly spawns one fresh, fully context-isolated child agent per round, handing that child nothing from the parent conversation except a small, schema-validated handoff report from the previous round — a status field, a summary, supporting evidence, next steps. The workspace’s own filesystem, not any conversation transcript, is the durable record of progress across rounds; each fresh child is told explicitly that it has no parent conversation and that the current state of the working tree is the actual record of what’s been done. The loop stops on an explicit complete or blocked status, or a hard round-count cap, and it deliberately requires a genuinely fresh-context subagent provider to run at all, refusing to operate against a provider that would instead inherit the parent’s conversation, because the whole pattern’s correctness depends on that freshness holding.
Goal rounds are a related but distinct mechanism: sequential rounds within the same ongoing session, rather than fresh isolated agents, each gated by a verification step checking the agent’s claimed progress record both before and after the round runs, with the session’s durable state explicitly saved before each round is admitted.
35. The pattern that is explicitly, admittedly absent #
Neither system implements a “generate, then have a second call critique or score the result, then iterate” loop anywhere — and this is worth treating as a genuine, honest finding, because DeepSeek Harness’s own documentation says so about itself, in exactly the two subsystems where this pattern would be the natural next step. The goal-round driver’s own documentation states plainly that there is no independent evaluator — the model itself decides when its own evidence is sufficient to call a task complete — and names evaluator-backed certification as a deferred, not-yet-built capability. The Ralph loop’s documentation says essentially the same thing about task completion: it is worker self-declaration, with no independent verifier, and names evaluator-driven continuation as deferred as well.
This is a useful data point about why this particular pattern is harder to build well than the others in this part: chaining, parallelizing, and delegating to workers all just require more calls. A trustworthy critique-and-iterate loop needs a second opinion that’s actually more trustworthy than the first call’s own account of itself — and Chapter 25’s principle, verify the world rather than the self-report, is exactly why that’s hard: if the “evaluator” is just another model reading the same self-report, nothing independent has been added.
36. Routing as it actually exists, and the Cordis connection to it #
It’s worth being precise about what “routing” actually means here, since only some senses of the word show up in the code. What’s real: a specific sub-task, such as DeepSeek’s own compaction summarization call, can be configured to run against a different, presumably cheaper model than the main conversation, as a deployment-time choice rather than a runtime decision; individual worker calls spawned by the workflow engine can specify their own provider and model per call, though that choice is made by whatever wrote the orchestrating script rather than an automatic classifier; and a whole session’s entire tool/prompt/model composition can be selected as a single unit at session start through a Cordis preset, cleanly isolated from any other concurrently-running session’s own preset.
What’s not present anywhere in the code examined: an automatic classifier reading an incoming request at runtime and deciding on its own whether to route it to a cheap model or a more capable one.
The one genuinely interesting structural connection worth calling out: a preset’s enabled/disabled state is evaluated dynamically against live context, and flipping it is exactly what causes an entire capability composition to activate or deactivate — meaning “switch to a different composition of tools and services” is not a hand-written conditional branch at all, but a reactive transition the Cordis runtime itself drives, carrying the same Confluence and Preservation guarantees from Part II. That’s a genuinely stronger correctness property than an ordinary conditional gives for free; what it doesn’t give is the decision logic itself, which is still ordinary code sitting on top.
37. What Pi does and does not have here #
Based on everything examined, Pi does not appear to have anything resembling DeepSeek’s general-purpose workflow scripting engine — and this is directly consistent with its creator’s own stated position from Chapter 30 against automatically-orchestrated, invisible multi-agent composition. Pi’s multi-call composition surface is narrower and lives mostly in its subagent-delegation mechanism (Part IX) and whatever an extension author chooses to build using its hook system. This is a plain, observed contrast worth stating rather than glossing over: DeepSeek Harness has built a genuine, model-authorable orchestration layer as first-class infrastructure; Pi’s equivalent, where it exists at all, is assembled from lower-level primitives by whoever builds on top of it, consistent with the minimalism philosophy running through Part VI.
Part VIII — Extensibility #
38. Pi’s three-tier trust ladder #
Pi’s extensibility model draws a clean, three-way distinction, and the tiers look superficially similar from a distance but differ enormously in what they can actually do.
Extensions are plain TypeScript files, executed directly with a runtime TypeScript loader, running with the full privileges of the host process — unrestricted filesystem, network, and process access, with no capability boundary of any kind separating extension code from Pi itself. Pi’s own documentation states this without hedging, advising that extensions should only be installed from trusted sources. An extension can subscribe to an extensive, precisely enumerated lifecycle — session start and shutdown, every point around a model request, every point around a tool call (including a point where it can block the call outright), turn and message boundaries, compaction start and completion — and can register entirely new tools, replace the input editor, or even re-register one of the seven built-in tools under its own name to intercept it.
Skills are a different kind of thing: a directory containing a Markdown file, following a standard skills specification, read by the model on demand rather than imported as code. A malicious skill can’t silently execute anything by itself — it can only instruct the model to attempt something, which routes through the same ungated tool-execution path described in Part VI. Skills sit at a genuinely lower trust tier in one practical sense, since their plain-text instructions are directly readable, but the eventual ceiling of what a malicious skill can cause is identical to what an extension can cause, because both ultimately reach the same unguarded tools.
Prompt templates are the lowest tier of all: static Markdown text expanded into the conversation on request, with no code execution and no tool registration involved.
39. Pi’s package manager, exactly #
A Pi package bundles any combination of extensions, skills, prompt templates, and themes, installable from a package registry, a git URL, or a local path. Installing a registry-sourced package resolves to a real, literal shelled-out install command with peer-dependency resolution disabled — a specific accommodation for how Pi’s own internal packages get resolved inside an installed extension. Installing a git-sourced package clones the repository, checks out the requested reference if one was given, and, if the cloned repository has its own dependency manifest, resolves its production dependencies.
There is no signature verification, no checksum validation, and no registry-provenance check anywhere in this install path. The only integrity-adjacent mechanism found nearby is a path-traversal guard ensuring a maliciously-crafted package source can’t resolve to a filesystem location outside its designated install root — a containment measure protecting the host filesystem’s layout, not a content-integrity measure protecting against a malicious package’s actual contents.
Resource discovery inside an installed package follows either an explicit manifest listing which files count as which resource type, or, absent a manifest, a set of convention directories. Where the same resource is defined in more than one place, a fixed precedence order resolves the conflict, from highest to lowest: an explicit project-level settings entry, a resource auto-discovered at the project level, an explicit user-level settings entry, a resource auto-discovered at the user level, and finally anything contributed by an installed package.
40. Supply-chain discipline: where it’s rigorous, where it isn’t #
Pi’s own build practices real, unusual rigor: its package-manager configuration refuses to pull in any release less than two days old, a specific defense against a compromised-maintainer-account attack getting adopted within minutes of publishing; it maintains an explicit, enumerated allowlist of exactly which of its own transitive dependencies are even permitted to run an install-time script, with its own build tooling failing outright if any other dependency with such a script shows up unreviewed; and its own contributor and continuous-integration workflows consistently disable install-time scripts entirely.
None of that discipline extends to installing a third-party package through the package manager itself — the exact shelled commands for both registry-sourced and git-sourced installs leave install-time scripts fully enabled, meaning a malicious package’s own install script, or one belonging to any of its transitive dependencies, executes automatically the moment it’s installed, with none of the age-gating, allowlisting, or script-disabling review applied to Pi’s own dependency tree.
The lesson generalizes past this one repository: a project’s supply-chain discipline is not one number, it’s at least two separate commitments, and a team can excel at one while leaving the other essentially unaddressed. It’s worth asking about both, separately, when evaluating any extensible tool’s actual security posture.
41. DeepSeek’s bundle/profile/patch layering as its extensibility model #
DeepSeek Harness’s own extensibility story, covered already in Chapter 2, is worth restating specifically as an extensibility mechanism: because every capability is a plugin, extending the system is structurally the same operation whether it’s DeepSeek’s own team shipping a new bundle or a third party mounting a plugin beside the existing ones. This is a genuine contrast with Pi’s explicit three-tier ladder — where Pi draws a hard, visible line between arbitrary code and declarative instructions, DeepSeek’s model treats every capability the same way at the framework level, with the practical trust gradient instead coming from how much imperative code any given plugin’s own activation logic happens to contain.
Part IX — Multi-Agent Patterns #
42. Pi’s subagent providers, and a stated-versus-shipped tension #
When one agent delegates work to another, there is exactly one architecturally load-bearing question every such system has to answer: does the child inherit the parent’s conversation, or does it start with nothing? Pi’s subagent registry makes this an explicit, named choice between two shipped, in-process providers — a spawn-style provider giving a child that never sees the parent conversation at all, and a fork-style provider giving the child the full prefix of the parent’s session log up to the last closed turn. Pi’s own model-facing tool description for delegation changes its wording depending on which style is configured, telling the model either that the delegate is self-contained and cannot see this conversation, or that it’s a child seeded with every completed turn so far and can build on them freely — a small, effective example of surfacing an architectural fact directly into the prompt so the model’s behavior calibrates to what’s actually true about the agent it’s delegating to.
As covered in Chapter 30, this sits in genuine, unresolved tension with the creator’s own stated philosophy against automatically-spawned, opaque sub-agents. The most charitable available reading — not something either the blog or the code states directly, so offered here as a plausible interpretation rather than a confirmed fact — is that the objection is specifically to automatic and invisible delegation happening mid-task without a human choosing it, and less to an explicit, opt-in primitive that a user or an extension author deliberately invokes and can fully see the results of. Whether or not that reading is the intended one, the tradeoff between the two provider styles is itself a real and useful thing to understand regardless of how it fits the stated philosophy: a fresh child is cheap to reason about and forces a genuinely complete task description, at the cost of losing any already-established shared context; a forked child gets that shared context for free, at the cost of reintroducing Part III’s entire context-management problem into every child spawned that way.
43. DeepSeek’s subagent stack, including cross-vendor delegation #
DeepSeek Harness’s subagent system is a named-provider registry where multiple delegation backends coexist, each registered under its own name and selected by whoever is delegating. Two providers mirror Pi’s spawn/fork distinction exactly, but three more are notable because they delegate not to another instance of DeepSeek’s own harness, but to entirely different, real, external agent products over each product’s own official integration surface: one provider invokes Anthropic’s Claude Code through the official Anthropic Agent SDK; another invokes OpenAI’s Codex over its official protocol; and separate bridge packages translate Claude Code’s and Codex’s own hooks configuration formats so hooks written for those products can drive DeepSeek Harness’s own interception points without being rewritten from scratch.
This is worth calling out on its own as a genuinely uncommon design decision: an agent harness that treats a competitor’s whole agent product as just another interchangeable delegation target, selected the same way any other named provider would be. The transferable lesson for anyone designing their own subagent registry is architectural, not competitive: make the delegation interface generic enough that “the worker happens to be a completely different vendor’s whole product” is not a special case requiring its own bespoke code path.
Two lifecycle shapes exist alongside the provider choice: one-shot delegation, where the caller holds and must explicitly dispose of the run, and continuable delegation, where a durable child session survives beyond the initial call, can receive later follow-up turns, and can asynchronously report status back to its parent whenever it eventually settles. Recursion is bounded by a maximum-depth setting, defaulting to three levels, with zero meaning delegation is forbidden entirely, enforced at every delegation call so a misconfigured deployment can’t allow runaway recursive delegation.
44. The workflow engine as orchestrator-workers #
Tying back to Chapter 33: the model-authored scripting engine covered there is, functionally, an orchestrator-workers pattern where the orchestrating logic is itself written by the model at task time rather than fixed in advance by the harness’s own code — a genuinely different, more flexible take on the delegation problem than either spawn, fork, or the fixed round-based Ralph loop.
Part X — Security Posture, In Their Own Words #
45. Pi’s project trust mechanism, exactly #
Project trust is Pi’s one user-facing gate, and it’s worth understanding precisely what it does and doesn’t cover, since the name alone invites over-reading it. Trust is only even asked about if a project directory contains resources that specifically require it — a local settings file, local extensions, skills, prompts, or themes, or certain system-prompt override files. A bare directory with none of these is trusted by definition, trivially, because there’s nothing there needing protection.
Where trust-requiring resources exist, the decision resolves in a fixed priority order: an explicit command-line override wins outright; otherwise, if any extension is already loaded, the first one to return a yes-or-no answer to a trust-decision event owns the decision; otherwise a previously-saved decision for this exact directory, or the nearest ancestor with a saved decision, applies; otherwise a global default setting governs; and if no interactive interface is available at all, the system falls back to not trusting rather than ever showing a prompt with nobody there to answer it. Saved decisions live in a plain, human-readable JSON file keyed by the canonical absolute path of the directory in question, and a decision saved on any ancestor directory implicitly covers everything beneath it unless a more specific decision overrides it.
What trusting a project actually unlocks: loading that project’s local settings, extensions, skills, prompt templates, and themes; installing any project-configured packages that are missing; running project-local extensions. What trust explicitly does not touch, confirmed against the actual tool-execution code and not just the documentation’s claim about it: nothing about trust changes what the seven built-in tools are permitted to do once a session is already running. The check fires exactly once, at session start, to decide what to load — never again afterward.
46. Pi’s stated scope and out-of-scope list #
Pi’s repository-level security policy states its scope with unusual directness. Declared explicitly out of scope for vulnerability reports: the intentional absence of a built-in sandbox; the behavior of user-installed extensions or skills; risks from working inside untrusted repositories; risks from installing untrusted packages; and prompt injection specifically — the policy states directly that content like a project instructions file, or instructions embedded in ordinary code comments, can trivially manipulate the agent, and describes this as something that cannot be reliably protected against. The stated bar for what does count as a genuine vulnerability is a demonstrated, reproducible bypass of an actual privilege boundary, not a demonstration of behavior the project has already documented as expected.
47. DeepSeek’s layered, fail-closed defaults #
DeepSeek Harness’s equivalent posture, covered already in Part VI, is worth restating here as a security-specific summary: where Pi states plainly that no default protection exists, DeepSeek ships two independent layers, approval and sandboxing, both on by default, both engineered to deny or refuse whenever their own supporting infrastructure is unavailable or unverifiable, rather than silently proceeding. The same fail-closed instinct extends into the project’s own engineering culture, not just its shipped defaults, per the testing and self-debugging conventions already described.
Part XI — Sessions, Modes, and Running Systems #
48. Pi’s session identity and storage #
Pi uses two entirely distinct identifier schemes for two entirely distinct things. A session — one whole conversation file — gets a time-ordered identifier, meaning session IDs naturally sort chronologically by creation time even treated as opaque strings. An entry inside a session’s tree — one message or event node, used for branching and forking — gets a short, collision-checked identifier instead, unrelated to session identity.
Sessions are stored under a per-project subdirectory, not in one flat pool — a project at a given path gets its own dedicated directory, derived deterministically from that path. Each session file’s name embeds both a creation timestamp and the session’s own ID, so filenames sort chronologically and double as a human-readable creation time. Every session file follows a simple line-delimited format: a header line describing the session and its working directory, followed by one entry per line thereafter.
Forking preserves provenance deliberately: a forked session’s header records the original source session’s resolved path, even though the new session gets a brand-new ID, a brand-new file, and — critically — the target project’s own working directory rather than the source’s, which is exactly what makes it possible to fork a session found in one project into a completely different one.
49. Pi’s four operating modes #
Pi resolves which of four modes to run in from a simple, fixed set of rules: an explicit mode flag wins outright; otherwise, an explicit print flag, or either input or output not being a real interactive terminal, forces a non-interactive mode even without that flag; only a genuine interactive terminal on both ends defaults to the full interactive experience.
Interactive mode is the full terminal experience most people mean when they describe using Pi: streaming text, live tool-call rendering, slash commands, session-tree navigation. Print mode is a single-shot mode built for shell scripting — send one prompt, print only the final answer, the natural mode for a pipeline or a script where nobody is watching a live terminal. JSON mode is the same single-shot idea, but streams every event as one JSON object per line instead of only the final answer — useful for a programmatic consumer that wants the full structured stream without committing to a full bidirectional protocol. RPC mode is the most capable of the four: a genuine, bidirectional, line-delimited JSON protocol over standard input and output, explicitly built for embedding Pi as a subprocess inside another application, with an extensive command surface covering prompting, steering, aborting, model switching, and the entire session-management surface exposed programmatically. Because RPC mode has no terminal UI to fall back on, it re-implements the extension interface entirely over the wire — a request to show a confirmation dialog becomes a message sent to the embedding host, which is expected to answer it the way a human would in the interactive experience.
50. DeepSeek’s monorepo, package by package #
DeepSeek Harness’s own package layout is itself a useful lesson in how to organize a large agent-engineering codebase, because the grouping directly mirrors the subsystem boundaries this document has been organized around. A non-exhaustive tour, grouped by directory: a core group containing the agent interface and its event registry, the concrete loop driver, and the tool registry and execution pipeline; an LLM group containing the provider-neutral model interface and its adapters; a compaction group containing the two-tier mechanism from Part III; a context group containing workspace-instruction loaders and cross-session reference snapshots; subagent and workflow groups containing the entire multi-agent stack from Part IX; a sandbox group split into a provider-neutral policy seam and separate per-platform enforcement backends; an interaction group containing the approval service and bundled permission presets; shell, subprocess, and terminal groups containing the actual process-execution machinery; a filesystem group again split into a provider-neutral seam and separate backends; a genuinely notable proof-of-concept group swapping the filesystem and subprocess seams onto a real, independent, third-party remote-sandbox service — a concrete demonstration of the claim, made in DeepSeek’s own architecture document, that swapping one capability provider moves the whole surface of related tools with it; a session group containing persistence backends, durability checkpoints, and full-text search over history; a skills group mirroring Pi’s own skills tier; an MCP group bridging tools from any server implementing the real, independent, published Model Context Protocol onto DeepSeek’s own tool registry; a hooks group containing the Claude Code and Codex bridges already mentioned; groups implementing the real, published Agent Client Protocol and DeepSeek’s own SDK protocol; boot/bundle/preset groups implementing the profile layering from Chapter 2 and the Cordis-preset-based session composition from Part VII; a self-modification group letting the agent itself inspect and mount or dispose of plugins in its own live runtime; and a client group, the largest single group by package count, applying the identical plugin model to the browser-based web front end, confirming the architecture is used end to end rather than only server-side.
Part XII — Building the Human Interface #
51. Why an append-based terminal interface, not a fullscreen one #
Pi’s creator distinguishes two broad approaches other coding agents take to their terminal interface: a fullscreen approach, which takes over the whole terminal viewport, versus an append-based approach, which behaves more like an ordinary chat log printed line by line into the terminal’s normal scroll history. He argues that a coding agent’s interaction naturally has the shape of a linear chat, and that an append-based interface can lean on functionality the terminal emulator itself already provides for free — ordinary scrolling, and searching within the terminal’s own scrollback buffer — rather than the harness needing to reimplement that functionality itself inside a fullscreen viewport. This is the stated reasoning behind Pi choosing the append-based style, and it’s a specific, concrete design tradeoff worth knowing about independent of which style any particular tool happens to use, since it trades a small amount of layout control for free use of infrastructure the terminal already has.
52. Pi’s differential rendering engine #
Pi’s terminal UI is not a virtual-DOM framework in the style of a web UI library — there’s no tree-reconciliation step, no keyed-child diffing. Its creator describes the approach as a simple retained-mode design: a component is just an object with one method that returns an array of strings for a given width. Components are expected to cache their own output — his own example is an assistant message that’s already finished streaming, which doesn’t need to re-parse its markdown or regenerate its terminal color codes every single frame just because something else on screen changed.
The renderer diffs the new, complete array of lines against the array from the previous frame, purely as a line-by-line string comparison — this is concretely what differential rendering means here. On an ordinary update, only the range from the first changed line to the last changed line gets repainted, not the whole screen, specifically to reduce flicker when something as small as a single animated character changes. Every repaint is wrapped in a real terminal synchronization feature that makes the update atomic from the viewer’s perspective, so a partially-redrawn frame never flashes into view. Full-screen clears are reserved specifically for width or height changes, since those change how text wraps and nothing short of a full redraw is correct there, and because a full clear also wipes the terminal’s own scrollback history, which the renderer otherwise goes out of its way to preserve.
Pi’s creator also reports that the practical result of this approach varies meaningfully by which actual terminal emulator is running it — he describes it working essentially flawlessly, with no visible flicker at all, in capable terminal emulators, while noting that some less capable terminal implementations, including the terminal built into at least one popular code editor, still show some flicker despite the same underlying mechanism. This is a useful, concrete reminder that a rendering technique’s correctness on paper and its actual visible behavior can diverge depending entirely on how faithfully the terminal it’s running inside implements the escape sequences it depends on.
53. Pi’s CBOR wire protocol #
Pi’s remote-session protocol defines a binary wire format built on CBOR, a real, published binary-serialization standard, deliberately narrowed to a specific, strict subset the package itself defines. Every message on the wire is exactly a four-byte, big-endian length prefix followed by one complete encoded item.
The specific subset supported is worth knowing because of what it deliberately allows that plain JSON doesn’t: alongside ordinary JSON-shaped values, the format’s native byte-string type lets the protocol carry raw binary data directly, without inflating it through a text-safe encoding first — a real, structural advantage plain JSON doesn’t offer, and the protocol’s own JSON-value schema explicitly excludes this byte-string capability to keep it distinct from the ordinary JSON-shaped fields.
The message vocabulary is compact: from a client, a handshake and a small, fixed set of commands — list sessions, create one, attach or detach, send a prompt, steer an in-flight one, abort, change the model or thinking level. From a server, a handshake in return carrying the full current state of every session, and a stream of events — either an incremental progress update, not itself authoritative, or a full, authoritative snapshot of a session’s or the server’s current state.
54. The client/server architecture, and its honest incompleteness #
This is worth stating plainly, because it’s a real, interesting finding rather than a critique: the client-side half of Pi’s remote-session story — the wire protocol above, and a transport-neutral client library built on it — is genuinely complete and working. The server-side half is explicitly labeled experimental in its own documentation, and on close inspection genuinely is incomplete in a specific, checkable way: the actual interface a real running agent would need to implement to be exposed over this protocol exists only as a type definition, with the only implementation anywhere in the repository being an in-memory test fake used purely for the protocol package’s own conformance tests, faking every response with canned text rather than running a real agent loop. What does exist and genuinely work on the server side is the session-multiplexing logic and one concrete transport — a Unix domain socket, secured only by ordinary filesystem permissions, with no protocol-level authentication of its own, since authentication is expected to already be handled by whatever established the underlying connection before any protocol bytes are exchanged.
The generalizable lesson here is the same one from Part II, applied to a different subsystem: a document describing an architecture, and the actual code implementing it, can be at very different stages of completeness, and the only way to know which is true of any given subsystem is to check whether the interface the design describes has a real implementation behind it, or only a type signature and a test fake.
Part XIII — Synthesis #
55. Cross-cutting lessons, observed only in these sources #
A small number of ideas recur across otherwise unrelated subsystems in this research, worth naming as general lessons precisely because they showed up more than once, independently.
The gap between what’s specified and what’s shipped is real, and worth actively checking for rather than assuming away — it showed up in Pi’s crash-recovery design and again in Pi’s remote-server architecture, two unrelated subsystems in the same repository, both cases where a detailed design document describes something a look at the actual code reveals isn’t built yet. Stated design philosophy and shipped code can likewise diverge — Pi’s stated position against automatic sub-agents sits alongside a genuinely working subagent registry, and it’s worth learning to notice this kind of gap rather than assuming a project’s own description of itself is always perfectly synchronized with what it actually does.
Cheap-then-expensive is a genuinely underused pattern for costly operations — DeepSeek’s compaction pipeline runs a free, deterministic pruning pass before ever considering an LLM summarization call, a shape worth applying anywhere else a system reaches immediately for its most expensive tool as a first resort.
Fail-closed is a stated, deliberate engineering choice in DeepSeek Harness, repeated across at least three unrelated subsystems — the tool-approval gate, the sandbox-confinement layer, and the guard chain’s monotonic-denial invariant — not something that happened to be true in one place, but a consistent stance applied everywhere the codebase has to decide what happens when something it depends on is unavailable.
Explicit, written-down documentation of a system’s own limits is itself valuable engineering, not just honesty for its own sake — Pi’s security documentation states exactly what is and isn’t protected, consistently, across more than one document, and that precision is directly what let this document describe Pi’s permission posture accurately rather than having to guess at it from behavior alone.
Naming an absent feature explicitly, rather than staying silent about it, is worth more than it might seem — DeepSeek’s own documentation states, in its own words, that no independent evaluator exists yet for two different iterative-agent loops, and that small act of writing it down made this document’s discussion of that absence far more precise than if the gap had gone unmentioned and had to be inferred.
Real-world usage reports are a different kind of evidence than either a specification or a test suite, and worth weighing as such — the creator’s own account of running hundreds of exchanges without needing compaction doesn’t resolve whether the automatic triggers are actually implemented, but it does tell you something a spec document alone can’t: whether the gap has actually mattered in practice.
56. A practitioner’s checklist #
For each subsystem this document covered, here is the question worth asking about your own project, grounded in what these sources’ choices concretely illustrate.
On state: if your process crashes mid-tool-call, what happens on restart? Pi’s specified effect-sandwich model and DeepSeek/Cordis’s proven reversible-effects model are two different, real answers — know clearly which one, if either, you’ve actually implemented versus merely designed.
On context: is your context bloat mostly conversational, needing real judgment to compress well, or mostly noisy tool output a cheap, deterministic truncation already handles for free? DeepSeek’s two-tier split is directly copyable.
On caching: are you accidentally invalidating your own provider’s cache by interpolating something volatile directly into your system prompt? Both systems converge on the same fix — push volatile facts to a trailing, change-gated message instead.
On cost tracking: if you’re supporting multiple providers, do you actually know which of them let you observe token usage precisely enough for billing, versus which only give you a best-effort estimate? Pi’s creator’s own account of this limitation is worth taking seriously before promising precise cross-provider cost accounting to anyone else.
On evals: do you have any way to check an agent’s claimed success against reality that doesn’t route back through the agent’s own self-report? If the honest answer is no, that’s the first eval infrastructure worth building, ahead of everything else on this list.
On tools and permissions: can you state, precisely and in writing, what your default posture actually protects against? Pi’s explicit “there is no protection, here’s exactly what that means” and DeepSeek’s explicit “here’s our layered, fail-closed defense” are both legitimate answers — an unstated posture is the only illegitimate one.
On minimalism: before adding a feature, have you actually re-tested whether the model you’re targeting today still needs the scaffolding a feature like it would have needed on an older, less capable model? Pi’s own argument for a sub-1,000-token system prompt is a specific, concrete instance of this question worth revisiting periodically rather than answering once and forgetting.
On composition: which of chaining, parallelizing, delegating to workers, or critiquing-and-iterating does your actual task need? Build the first three before the fourth — a trustworthy critique loop needs a real answer to the evals question above, and building it before that just gives you a second unreliable opinion, not a more reliable one.
On extensibility: for every tier of extension you offer, what’s the actual blast radius if something loaded through it turns out to be malicious? If the honest answer is unlimited, identical to the host process, say so as plainly as Pi does.
On multi-agent design: for every child agent you spawn, is it starting fresh or inheriting the parent’s context, and does your delegation prompt actually tell the model which one it’s getting?
Appendix A: Glossary #
- Agent loop: the ask-do-observe cycle every agent harness runs at its core; DeepSeek’s own agent class is named after this shape directly.
- Compaction: replacing a range of old conversation history with a generated summary while retaining a verbatim recent tail.
- Coeffect: a formal description of what a piece of code requires from its environment; the theoretical basis for Cordis’s dependency-satisfaction model.
- Confluence (as a proven property, in the Cordis paper): any sequence of runtime component changes converges to the same end state that a from-scratch load of the final configuration would reach.
- Effect sandwich: Pi’s specified crash-safety pattern — commit intent, perform the uncertain effect, commit settlement.
- Fiber (Cordis): a live, running instantiation of a component, carrying its own lifecycle state.
- Lane (Pi): a named, independently-progressing cursor over shared conversation history.
- Orchestrator-workers: a coordinating call dynamically delegating subtasks to worker calls at runtime, realized in DeepSeek Harness as its model-authorable workflow scripting engine.
- Ralph loop: DeepSeek Harness’s named pattern of spawning fresh, context-isolated child agents per round, using durable workspace state rather than conversation history as cross-round memory.
- Register (Pi): a small, named, mutable key-value cell — the only mutable state primitive in Pi’s specified crash-recovery design.
- Spawn vs. fork (subagents): whether a delegated child agent starts with no parent context or the full inherited conversation prefix.
- YOLO mode: Pi creator’s own informal term for running with no permission checks at all.
Appendix B: Every numeric constant and default found, in one table #
| Constant | Value | System |
|---|---|---|
| Tool output truncation (lines) | 2,000 | Pi — shared across all seven built-in tools |
| Tool output truncation (bytes) | 50 KB | Pi — shared across all seven built-in tools |
| Maximum bash timeout | roughly 24.8 days | Pi — the largest value representable by the underlying timer |
| Compaction reserve tokens | roughly 16,000 | Pi |
| Compaction keep-recent tokens | roughly 20,000 | Pi |
| Compaction pressure threshold | 80% of context window | DeepSeek |
| Compaction retained-tail ratio | roughly 16% of context window | DeepSeek |
| Default subagent recursion depth | 3 (0 forbids delegation) | DeepSeek |
| Minimum release age accepted for new dependencies | 2 days | Pi |
| Allowlisted install-scripted dependencies | 1 (reviewed and annotated) | Pi |
| Pi’s own system prompt + tool descriptions | under 1,000 tokens | Pi, per its creator |
Appendix C: Real-world tools and standards referenced by these sources #
Referenced by Pi: ripgrep, the actual search binary Pi’s grep tool shells out to; fd, the actual file-finder binary Pi’s find tool shells out to; CBOR, the binary serialization standard Pi’s remote-session protocol is built on; a real terminal graphics protocol and a distinct terminal image protocol, with an explicit fallback for the one lacking in-place image deletion; GitHub Copilot, one of the LLM providers Pi’s model layer supports; tmux, recommended by Pi’s creator as the substitute for a background-process feature he chose not to build.
Referenced by DeepSeek Harness: Cordis, the plugin framework, and its accompanying academic design paper; a real, independent, third-party remote-sandbox service DeepSeek Harness has a proof-of-concept integration for; the Model Context Protocol, a real, published, independent standard bridged into DeepSeek’s own tool registry; the Agent Client Protocol, another real, published protocol implemented as a server; Anthropic’s Claude Code, invoked through the official Anthropic Agent SDK as one of DeepSeek Harness’s own subagent delegation backends; OpenAI’s Codex, invoked over its official protocol as another delegation backend; real operating-system sandboxing mechanisms on Linux, macOS, and Windows underlying the platform-specific sandbox backends; SQLite, used by both projects for durable session storage.
Appendix D: A stated feature comparison, from Pi’s own creator #
Pi’s creator draws a small number of specific contrasts with named competing tools in his own blog post, worth reproducing as a direct comparison since they’re his own stated observations rather than this document’s independent analysis:
| Point of comparison | Pi’s creator’s stated position |
|---|---|
| Sub-agent visibility | Argues a competing tool’s automatically-spawned sub-agents are invisible to the user — a black box nested inside another black box |
| System prompt size | States his own system prompt and tool descriptions together stay under 1,000 tokens, in contrast to what he describes as an order of magnitude larger prompt in a competing tool |
| MCP tool-description overhead | Cites two specific, well-known real MCP servers whose full tool descriptions he states consume a meaningful single-digit percentage of a typical context window before any work begins |
| Plan-mode usability | States that a competing tool’s plan mode is difficult to use in practice without approving a large number of command invocations along the way |
| Earlier personal preference | States he preferred a competing tool for most of his own work back when that tool was in an earlier, more basic form, which he says fit his workflow well at the time |
Appendix E: Source map #
Every path below links straight to the file or directory on GitHub — earendil-works/pi (branch main) and deepseek-ai/deepseek-harness (branch master) — so you can go verify any claim in this guide yourself.
- Pi’s harness design specification:
packages/agent/docs/harness.md - Pi’s currently-shipped (pre-redesign) harness implementation:
packages/agent/src/harness/agent-harness.ts,reducer.ts,session/types.ts - Pi’s shipped agent loop:
packages/agent/src/agent-loop.ts - Pi’s built-in tools:
packages/agent/src/harness/tools/*.ts(lower-level),packages/coding-agent/src/core/tools/*.ts(CLI-level) - Pi’s security documentation:
packages/coding-agent/docs/security.md, repository-rootSECURITY.md - Pi’s extension/skill/package system:
packages/coding-agent/docs/extensions.md,docs/skills.md,docs/packages.md,packages/coding-agent/src/core/package-manager.ts - Pi’s settings and project-trust logic:
packages/coding-agent/src/core/settings-manager.ts,project-trust.ts,trust-manager.ts - Pi’s evals:
packages/evals/ - Pi’s terminal UI and remote-session protocol:
packages/tui/,packages/protocol/,packages/client/,packages/server/ - Pi’s session management:
packages/coding-agent/src/core/session-manager.ts - Pi’s four operating modes:
packages/coding-agent/src/main.ts,src/modes/* - Pi’s creator’s blog post: “Pi Coding Agent,” Mario Zechner, published on his personal site, 2025-11-30
- DeepSeek Harness’s architecture documentation:
docs/architecture.md,docs/development.md,AGENTS.md,docs/cordis-primer.md - DeepSeek Harness’s agent loop:
packages/core/agent-loop/src/agent.ts - DeepSeek Harness’s compaction system:
packages/compaction/compaction-basic/,packages/compaction/compaction-tool-result-pruner/ - DeepSeek Harness’s tool execution, sandboxing, and approval:
packages/core/tools/,packages/sandbox/,packages/interaction/user-approval/ - DeepSeek Harness’s subagent and workflow systems:
packages/subagent/,packages/workflow/ - DeepSeek Harness’s benchmark and testing posture: repository-root
BENCHMARK.md,docs/testing.md,docs/user/guide/python-sdk.md - The Cordis design paper: “A Programming Paradigm for Spatiotemporal Composability,” bundled in the
cordiverse/paperrepository linked directly from DeepSeek Harness’s own README