How Much Should an Agent's Prompt Carry? — Pi vs Claude Code on Where Harness Complexity Lives
How Much Should an Agent’s Prompt Carry? — Pi vs Claude Code on Where Harness Complexity Lives
I wrote about Pi before, calling it a “bare-bones apartment”: few tools, few rules, lots of capabilities not included by default.
But after writing that, a question kept nagging at me: a bare-bones apartment looks clean, but when it’s time to actually get work done — what does it rely on?
Pi’s answer is written entirely in its own System Prompt — 154 lines. That’s the complete “about me” manual, the only luggage it carries into every task.
I decided to read through that Prompt line by line, to see how an agent with so few words actually gets things done. And as I read, I couldn’t help pulling up Claude Code’s Prompt too.
Side by side, the gap was bigger than I expected.
This isn’t just about whose Prompt is longer. The real question is: how much should an agent bake into its context window?
How Pi Introduces Itself
Pi’s Prompt starts by establishing its identity:
You are an expert coding assistant operating inside pi, a coding agent harness.
It tells the model two things at once: who it is, and where it works — not a chat window, but a harness that can read files, run commands, and edit code.
The next sentence states the scope:
You help users by reading files, executing commands, editing code, and writing new files.
Then four basic tools:
read: read filesbash: run commandsedit: make precise editswrite: create or overwrite files
That’s Pi’s entire inventory. No permission modes, no memory directories, no skill invocation instructions. Four tools, countable on one hand.
So the question stands: with just this, can it actually get work done?
A Simple Rename Task
I picked the most ordinary task: renaming a function.
First, the model reads the file instead of guessing:
{
"tool": "read",
"arguments": {
"path": "src/utils.ts"
}
}
Suppose it reads:
export function formatDate(date: Date): string {
return format(date, 'yyyy-MM-dd')
}
Then it submits an edit:
{
"tool": "edit",
"arguments": {
"path": "src/utils.ts",
"edits": [
{
"oldText": "export function formatDate(date: Date): string {",
"newText": "export function formatDateTime(date: Date): string {"
}
]
}
}
At this point, “rename a function” looks like a simple string replacement.
sequenceDiagram
participant M as Model
participant H as Harness
participant F as Filesystem
M->>H: read("src/utils.ts")
H->>F: Read file
F-->>H: File content
H-->>M: Return content
M->>H: edit(oldText, newText)
H->>F: Exact match oldText
F-->>H: Match result
H-->>M: Success/Failure
The interesting part starts here.
When oldText Doesn’t Match, No Guessing
Pi has several specific rules for edit.
First, oldText must match exactly.
If the file was modified by someone else, or the model misremembered the original text, edit must not guess at a “close enough” location. Per this contract, if it doesn’t match, it returns failure — putting the decision back on the model.
The model can re-read the file, re-locate, and re-edit. It’s not forbidden to edit — it just has to edit based on what’s actually in the file.
Second, multiple oldText values in a single call are all matched against the original file — not against each other’s results.
Third, edits must not overlap or nest within each other.
Fourth, snippets should be as small as possible, but must be unique in the file.
These four rules together say the same thing: the model decides what to change, but the boundaries of the change must be verifiable by the execution layer.
Let’s Look at Claude Code Too
I originally only planned to read Pi, but curiosity got the better of me, and I opened Claude Code’s Prompt too.
Side by side, the difference is immediately visible:
Pi 0.84.2
- System Prompt: 154 lines
- Tools recorded by Phistory: 4
- Default tools:
read,bash,edit,write
Claude Code 2.1.234
- System Prompt: 1627 lines
- Tools recorded by Phistory: 24
- Beyond tool definitions, the Prompt includes permission modes, irreversible operation confirmations, memory and context management rules
The line counts and tool counts come from Phistory version snapshots — they count default Prompts and tool definitions, not product capability scores.
If you only look at the numbers, it’s easy to conclude “Pi is minimal, Claude Code is bloated.” But don’t pick sides too quickly.
Claude Code Does the Same Thing, Just a Different Contract
Pull up Claude Code’s Edit tool and you’ll see something similar, but subtly different:
{
"file_path": "src/utils.ts",
"old_string": "export function formatDate(date: Date): string {",
"new_string": "export function formatDateTime(date: Date): string {"
}
It also requires:
- Must
Readbefore editing; old_stringmust match exactly, including indentation;- Target text must be unique;
- To replace all occurrences, explicitly pass
replace_all: true.
So it’s not “one side is rigorous, the other is sloppy.” Both set an evidence bar for the model.
The difference is in the shape of the tool contract:
Pi’s edit is more like a small batch patch: one call can submit multiple non-overlapping edits, all matched against the original file.
Claude Code’s Edit is more like a controlled replacement: read the file first, then submit a single unique old_string; use replace_all explicitly when needed.
Same task, two design philosophies: Pi keeps tools generic, Claude Code bakes more operational rules into the tool definitions themselves.
154 Lines vs 1627 Lines: Complexity Just Moves
With that context, the two numbers start to make sense.
Pi’s 154 lines cover: identity, four tools, tool usage, and a documentation entry point.
Claude Code’s 1627 lines cover: coding tools, permission modes, confirmation rules for dangerous operations, where memory lives, how context is managed, how skills are invoked, plus detailed specs for 24 tools.
This isn’t just “writing a longer manual.” These rules shape what the model carries in its head before every action, what it considers first, which operations need confirmation, and how to recover from tool errors.
Roughly, the trade-off is:
- Pi: short contract. It states the minimum boundaries and leaves more judgment to the model and project environment.
- Claude Code: operations manual. It pre-loads more operational rules and capability boundaries into the context, so the model has to guess less.
This is why you can’t just copy the “154 lines” number.
When there are many tools, fine-grained permissions, and irreversible operations, a short Prompt might just be shifting the burden onto the model. Conversely, when the model is capable enough, the environment is trustworthy, and task boundaries are clear, a long Prompt becomes dead weight the model carries every round.
flowchart LR
subgraph Pi["Pi (short contract)"]
direction TB
A["154-line Prompt<br/>4 tools"]
B["States boundaries<br/>Judgment to model & environment"]
end
subgraph CC["Claude Code (ops manual)"]
direction TB
C["1627-line Prompt<br/>24 tools"]
D["Rules in context<br/>Less guessing, heavier luggage"]
end
Neither made complexity disappear — they just moved it somewhere else.
Pi Puts Low-Frequency Knowledge on the Shelf
There’s an easy-to-miss rule in the second half of Pi’s Prompt:
Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI)
SDK docs, extensions, themes, skills, TUI — none of these are crammed into the context. The Prompt only tells the model where the docs are and when to look them up.
It’s like keeping thick reference books on a shelf instead of leaving them open on the desk every day.
Claude Code’s approach is to carry more tools and rules on its person. The upside is the model takes fewer detours — when it encounters permission, memory, or tool questions, the answers are right there. The downside is heavier luggage on every trip.
This isn’t about which is smarter — it’s about where each chooses to place the complexity.
Of course, line counts reflect design intent, not runtime evidence. A well-written Prompt doesn’t guarantee the execution layer actually follows through — what happens when matching fails, when concurrent edits collide, or when permissions are enforced? You have to read the source code. Don’t treat the Prompt as a load-bearing wall.
Back to That Rename Task
A simple function rename ended up revealing three layers:
First, the model must read the real file, not edit from memory.
Second, a tool contract can turn “please be careful” into a verifiable matching rule.
Third, neither Pi nor Claude Code piles complexity in one place: Pi leaves more judgment to the model and environment; Claude Code writes more rules into the Prompt and tools.
So 154 lines vs 1627 lines isn’t a simple victory of “minimalist” over “maximalist.”
What they’re really comparing is: who carries the complexity for whom.
If you’re building your own agent harness, don’t start by agonizing over whether to write 100 lines or 1600 lines. First, figure out who — your model, your tools, or your environment — is better suited to carry that complexity.
Get that question right, and the line count is just a number.
References
| Source | Used for |
|---|---|
| Pi 0.84.2 System Prompt | Pi’s identity, four tools, edit contract, and documentation-on-demand rules |
| Claude Code 2.1.234 System Prompt | Claude Code’s Prompt size, tool count, Edit contract, permission and context rules |
| Pi 0.84.1 → 0.84.2 System Prompt diff | Pi version changes and Prompt analysis baseline |
| Pi author Mario Zechner | Pi’s design background |
| Pi source repository | Project entry point; this article does not claim unexpanded source capabilities as Prompt conclusions |