Bouzécode — how the context is built

The agent that forgets on purpose

In a normal AI coding agent, everything read and said piles up, and every single API call resends the whole pile. Bouzécode does the opposite: a tool result is destroyed at the end of the turn, unless the agent explicitly copied out what mattered. What survives is a notebook the agent writes for itself — plus the very last tool result. That is the entire context.

The lab notebook. You borrow a 400-page file from the archive, you copy the 20 lines that matter into your own notebook, you give the file back. Next week you still have the 20 lines — and you never paid to carry 400 pages around.

One rule about that notebook: you only ever write at the end of it. You never go back and rewrite page 3 — your colleagues already photocopied pages 1–40 and those photocopies are cheap to reuse. Edit page 3 and everyone has to photocopy everything again.

That last paragraph is the part people get wrong, so it is stated here up front: the notebook is append-only. The model adds a block when it has something worth noting; it never edits or rewrites an earlier block. Section 5 explains why that is not a style preference but the whole economic argument.

2. What normally happens

Fix one bug: the agent reads main.py (400 lines), edits it, runs the tests. One instruction from you, four calls to the model. Here is what each call carries — the width of a bar is the size of what is transmitted.

call 1
systemyou
call 2
systemyoumain.py — 400 lines
call 3
systemyoumain.py againedit
call 4
systemyoumain.py againeditpytest output

The 400 lines of main.py are transmitted on calls 2, 3 and 4. The agent needed one function out of that file, and it carried the whole thing to the end of the session. Multiply by every file read, every grep, every test run — that is the bill.

3. What Bouzécode does instead

Every tool result arrives with this line stapled to the front of it — verbatim, from the source:

[SYSTEM] This tool_result will be destroyed at the next user turn unless you snippet it or stash a note with Methodology.

minimal_payload.py:23 — _DESTRUCTION_BANNER

It is not a threat, it is a description. When the next call is assembled, the wire is rebuilt from almost nothing:

Survives

  • Your latest message
  • The tool results of the live batch only (the ones just produced)
  • Write/Edit results from earlier turns, squeezed to a one-line ack
  • The notebook — as a cached system block

Destroyed

  • Every earlier tool result
  • Every assistant sentence ever written
  • Every record of which tools were called

build_messages_for_api / build_minimal_payload — minimal_payload.py:335, :187

Because the assistant's own message is gone, a surviving result would lose all trace of what produced it. So each one is re-labelled with a one-line recall of its own call: [↩ Read: {"file_path": "/repo/main.py"}] (_tool_call_recall — minimal_payload.py:92).

Two ways to save something

Methodology — the notebook

One tool call, one appended block: what was found, what was decided and why, what is next. Some blocks are appended automatically with no action from the model: your messages (## User), the plan (## Plan), questions and answers (## Q&A).

Snippet — the 20 copied lines

Any result of 50 lines or more is wrapped in markers and renumbered 1..N, so the model can name exactly the region to keep. Snippet(file_path=, symbol=) stores the symbol's name, not its line numbers, and re-resolves it every turn — so it survives later edits that shift lines. discard=true says "seen it, keeping nothing".

snippet_wire.py:18 (SNIPPET_MIN_LINES = 50) · methodology.py:196, :238 · snippet_resolve.py:46

Snippets are appended into the same notebook — there is no second store.

4. Watch it happen, byte by byte

One bug, four API calls. Below is the entire payload sent on each call — there is nothing else in the model's world — then what the model sends back, then the state of the notebook once the turn closes. Every marker, banner and header below is the literal string the code emits.

API call panels ①②
① Sent to the model
② The model answers
③ The notebook, after the turn
Append-only. Purple = the block just appended, a cache write. Grey = bytes already in the note, re-sent as a cache read and never rewritten.
cache read — unchanged bytes, ~0.1× cache write — new bytes entering the cache, ~1.25× fresh input — never cached, 1× every call

Round token counts, chosen to be realistic rather than measured — the point is the shape. Cached tokens are counted at one tenth of fresh ones, the right order of magnitude for prompt caching.

Read the crossover, it is the honest part. For the first two calls Bouzécode puts more on the wire, not less: it pays up front for the notebook and for a reminder that is deliberately never cached. It crosses over on call 3 and keeps pulling away. The 400 lines of main.py crossed the wire exactly once; on the keep-everything side they cross it three times, and would cross it again on every remaining call of the session.

On price, at four calls with a warm cache, the two are roughly a wash — the second figure in the counter says so. Prompt caching makes keeping everything cheap for as long as the cache holds. The volume advantage turns into a price advantage precisely when it stops holding: a longer session, a second and third file to read, or a five-minute pause. Then everyone re-buys their prefix at full price, and Bouzécode's prefix is a fraction of the size.

5. Why the notebook may only grow

A small context that gets rewritten every turn is worse than the disease. Here is why.

Model providers cache the beginning of a prompt: if the first N bytes you send are byte-for-byte identical to last time, they are billed at roughly a tenth of the normal price. The cache is a prefix match — it holds only up to the first byte that changed.

Rewrite one line in the middle of the notebook and everything from that line on is new bytes. You would be sending a small context that is 100% freshly billed, every single turn. Cheaper-looking, more expensive.

So Bouzécode never rewrites. Old bytes are dropped from the wire, never edited in place — the design comment says so explicitly:

Dropping prior wire bytes (rather than stripping/rewriting them) is
load-bearing for the prompt cache: any post-hoc rewrite of an earlier
byte invalidates the cache from that point on.

minimal_payload.py:15-18

The same rule governs the notebook itself. It is rendered verbatim and split in two: the part that was already cached last turn, and the delta added since — that is the grey/purple split in panel ③ above. Only the delta is new. When a snippet's source file is edited, the stored copy is not refreshed in place — a ## snippet-stale: marker is appended below it instead, so the cached bytes above stay untouched.

build_methodology_system_blocks / split_methodology_for_cache — methodology.py:38, :31

The cached prefix also does not live forever: five minutes by default, one hour on the official Anthropic API. An expiry means re-paying the entire prefix at full price — so a session that pauses while a human reads a diff pays for its own memory all over again. That is also when the design pays off most: the smaller the thing you have to re-buy, the cheaper the pause.

_resolve_cache_control — dispatch.py:154-161

And there is exactly one operation that deliberately breaks the cache on purpose: structural compaction. Past 20 000 tokens the notebook is cleaned — duplicate snippets, snippets whose file no longer exists, snippets flagged stale. No model call is involved, it is pure text surgery. It also resets the cache snapshot, meaning the next turn re-pays the whole prefix. That is precisely why the threshold is set high enough for it to be rare.

compact_methodology.py:16 (threshold), :184 (snapshot invalidation)