Topic 61

Files as Working Memory

Artefacts

Large intermediate results belong in files, not in the context window. The agent writes a CSV, reads back the three numbers it needs, and the other 40,000 rows never cost a token. Once there is a filesystem this is available immediately, it requires no library and no framework feature, and it is the cheapest context-management technique in this book.

The arithmetic is blunt. Sundry's reconciliation works over 6,412 refund lines and 2,000 ledger rows: in the context that is roughly 256,000 tokens, re-sent on every remaining turn, which no budget from Chapter 5 survives. On disk it is two paths, two row counts and a column list — under 200 tokens, and the run's actual working set never enters the transcript at all.

Compute into a file, summarize the file into context, keep the file as the deliverable
Compute into a file6,412 and 2,000 rows joined
Print a summarya count · a total · five worst
Read back a slice20 rows, three columns
600 TOKENS, NOT 256,000Extract the artefactmanifest · checksum · 400 days
The same run4,000 rows written
BENEFIT GONE IN ONE TURNRead it all backabout 160,000 tokens

The Pattern

Three moves, in order. Compute into a file. Summarize the file into context. Keep the file as the artefact. The context holds a pointer and a conclusion; it does not hold the data. Everything the agent decides on the next turn is decided from the summary, and if the summary is not enough to decide with, the fix is a better summary rather than a bigger paste.

Two steps of the reconciliation, showing what crosses back into context
# step 3 — compute into a file, print a summary
out = j[j.delta_cents != 0].sort_values("delta_cents")
out.to_csv("/out/run-2026-08-10/discrepancies.csv", index=False)
print(len(out), out.delta_cents.sum(), out.head(5).to_string())

# step 4 — read back a slice, not the file
worst = pd.read_csv("/out/run-2026-08-10/discrepancies.csv", nrows=20)
print(worst[["seller_id", "delta_cents", "last_ledger_entry"]].to_string())

In words: step three writes every discrepancy row to a named file and prints only a count, a total and the five worst offenders. Step four needs more detail on the bad sellers, so it opens the same file and reads twenty rows with three columns — not the file, a slice of the file. The observation that comes back into the transcript is about 600 tokens both times. The file on disk is 23 rows now and could be 4,000 next week without changing that number by one token, which is the property that makes the pattern worth a rule rather than a habit.

Artefacts as Deliverables

The spreadsheet is the output. The agent's closing message is a summary of it — 23 sellers, $4,118.62, the three largest listed, the file attached — and finance never reads the transcript. That inversion matters more than it sounds: it means the deliverable is a thing that exists on disk with a checksum, not a paragraph whose accuracy depends on the model's account of its own work. A reviewer opens the file and checks a row. Nobody can check a paragraph.

It also sharpens what "done" means, which Chapter 7 left as a genuinely hard question. A run that produced a confident summary and no file did not finish, whatever it says about itself, and the completion check is a file-exists assertion rather than a judgement. This is the same defect Chapter 10 found in subagents that return polished descriptions of work they did not complete — and here it is trivially detectable, because the artefact is either on the mount or it is not. Sundry's completion rule is three clauses long: the named file exists, it passed verification, and the manifest records both. A run that satisfies two of the three is a failure with a good explanation attached.

Naming and Lifecycle

Paths are deterministic and chosen by your code, never by the model: /out/run-2026-08-10/discrepancies.csv, derived from the run id. A model that invents final_v2_FIXED.csv on step three has broken the pipeline in the worst available way, because step four's read fails with a file-not-found that reads like a bug in the extraction step, and the run that half-worked is the one nobody debugs correctly. Give the agent the path in the instruction and check it on write.

The manifest, written by the parent process at extraction time
{"run_id": "recon-2026-08-10", "finished_at": "2026-08-10T06:41:12Z",
 "artefacts": [
   {"path": "discrepancies.csv", "step": 3, "rows": 23,
    "sha256": "9f1c…a802", "verified": true, "retain_days": 400},
   {"path": "seller_summary.xlsx", "step": 6, "rows": 2000,
    "sha256": "3ab7…40de", "verified": true, "retain_days": 400}],
 "discarded": ["scratch/joined.parquet", "scratch/fee_lookup.csv"]}

The manifest answers three questions a week later, when finance asks where a number came from. What was produced, by which step, with how many rows and which checksum. Whether the verification from Topic 59 passed on it. How long it is kept — 400 days here, because that is the finance retention rule and not a number the agent had any say in. The discarded list matters too: it names the intermediate files that were deliberately not kept, so nobody spends an afternoon hunting for joined.parquet believing it still exists somewhere.

Reading Back Selectively

Read heads, tails, filtered queries and aggregates — never a whole generated file. This is Chapter 3's result-shaping discipline applied to the filesystem, and it fails in exactly the same way when ignored: a tool that returns whatever it found puts an unbounded amount of text into a transcript that will be re-sent on every subsequent turn. Cap the read tool at the boundary, in lines and in tokens, and mark truncation honestly so the model asks for the next slice instead of answering from a fragment.

The temptation to read the whole file arrives dressed as diligence. The agent has written 4,000 rows and wants to check them, so it reads them back — and the entire benefit of the pattern is gone in one turn, at a cost of roughly 160,000 tokens for a check that a two-line assertion does better and for free. Checking is the verification step's job, in code, against invariants. The model's job is to look at twenty rows and decide what to do next.

Which slices are worth reading is a design question, not a model one, so answer it in the tool. Sundry's read tool exposes four operations and nothing else: the first N lines, the last N lines, rows matching a column predicate, and an aggregate over a named column. Every one of them returns a bounded result with the row count of the full file attached, so the model always knows the difference between what it read and what exists. A general "read this file" tool has neither property, and the first oversized result it returns will be paid for on every remaining turn of the run.

Cross-Run Artefacts

A container dies at the end of its run and takes the mount with it. Anything that must outlive the run is copied out deliberately by the parent process before teardown — that is what "extraction" means in the manifest above — and lands in a store with a key, a retention rule and an owner. Sundry puts the reconciliation artefacts in object storage under the run id, and the finance share gets a copy of the two that a human reads.

Carrying a file forward to the next run is then a storage question, not a container question. This week's job needs last week's discrepancy file to tell a persistent disagreement from a new one, so the task-state row for the run carries the object key of the previous artefact, and the parent mounts that file in read-only alongside the fresh exports. Keeping a container alive for a week to preserve a file is the wrong answer to the same question, and it costs you every property from the previous topic.

Common Mistakes
  • Reading a whole generated file back into context to check it — 4,000 rows is roughly 160,000 tokens, the benefit of the entire pattern is gone in one turn, and an assertion would have checked it better.
  • Letting the model choose file names — step four cannot find what step three wrote, and the run fails with a file-not-found that looks like a bug somewhere else entirely.
  • Losing artefacts with the container — the deliverable evaporates on cleanup, the run is recorded as successful, and the only trace left is a summary claiming a file exists.
  • Treating files as memory across runs without a store — next Monday's job starts in an empty box and cannot tell a persistent disagreement from a new one.
Best Practices
  • Write large results to files and read back only summaries and named slices, with the read tool capped in lines and tokens at the boundary.
  • Derive every path from the run id in your own code, and emit a manifest naming each artefact, its step, its row count and its checksum.
  • Extract artefacts explicitly before the container dies, with a retention rule set by whoever owns the data rather than by the run.
  • Reference artefacts from task state by storage key when they must survive the run, instead of extending a container's life to hold them.
Comparable toolsObject storage where extracted artefacts outlive the containerNotebook outputs the same compute-then-inspect loop, with a humanFramework file toolkits read, write and list, implemented with varying careCI build artefacts the identical lifecycle problem, solved decades ago

Knowledge Check

What belongs in a file rather than in the context window?

  • The bulk data the run computes over, with only the summary and named slices crossing back
  • The task's constraints and instructions, since they are stable and can be re-read on demand
  • The conclusions the agent has reached, so the context can be reserved entirely for raw data
  • Anything containing customer identifiers, because a file is not re-sent to the model provider

The agent has written 4,000 discrepancy rows and wants to confirm the file is right. What should happen?

  • Code asserts the invariants against the file, and the agent reads at most a capped slice
  • The agent reads the file back in full, since verifying its own output is exactly the diligence wanted
  • A second model call summarizes the file so the agent can confirm the totals look plausible
  • The agent reads fifty random rows and accepts the file if none of them look wrong

Why must artefact paths be derived by your code rather than chosen by the model?

  • The next step has to find what the last one wrote, and an invented name breaks that silently
  • A model-chosen path could be written outside the sandbox's writable directory
  • Two runs executing at once would otherwise overwrite each other's output files
  • Checksums in the manifest can only be computed for files with predictable names

Next week's run needs this week's discrepancy file. What is the right mechanism?

  • Extract it to object storage, put the key in task state, and mount it read-only next week
  • Keep the container alive between runs so the output directory is still there on Monday
  • Summarize the file into the run's transcript and carry that summary into the next run's context
  • Have next week's run recompute last week's numbers from the same exports and compare

You got correct