ai newsDo., 15. Okt.
EilmeldungMeta and Apple team up to make Muse AI models run better on Macs

Surviving the 200k-Token Lobotomy: How Unix init.d and 'Memento' Made My AI Coding Agent Immune to Context Compaction

Why relying on your IDE's automatic context summarizer is a trap—and how 1980s Unix boot scripts give autonomous agents an indestructible memory. "Needs a system, right? Take notes. Specific notes... You can't trust a memory." — Leonard Shelby , Memento (2000) 1. The 200k-Token Lobotomy: The Silent

dev.toSamstag 03:15 · 10.10.11 Min. Lesezeit
Bild: dev.to

"Needs a system, right? Take notes. Specific notes... You can't trust a memory." — Leonard Shelby, Memento (2000)

If you use modern agentic coding environments—whether Claude Code, Google Antigravity, Cursor, or Gemini CLI—on real production tickets, you already know the feeling of dread when a complex session crosses 200,000 tokens.

A tiny system banner flashes in the corner of your terminal:

[Context compacted: 235,246 tokens → 14,800 tokens] Enter fullscreen mode Exit fullscreen mode On the surface, "context compaction" sounds like a helpful platform feature. When the conversation approaches the context window ceiling, the host runtime pauses your agent, hands the entire 230,000-token transcript to a background summarizer model, replaces the history with a three-paragraph prose summary, and lets the agent keep going.

Except what happens 30 seconds after compaction?

Your agent has just undergone a prefrontal lobotomy.

Before compaction, you and the agent had spent 45 minutes establishing subtle architectural invariants:

Then the host summarizer compresses all 280 steps into polite, generic corporate mush:

"Summary: The user and assistant are working on Issue #320 in the BlocSignal repository to support custom equality in Flutter and Jaspr widgets. Several files have been modified and reviewed. The assistant is currently addressing review feedback."

When the freshly compacted agent wakes up on the very next turn:

Why does host compaction fail so catastrophically for software engineering?

Because prose summarization optimizes for narrative gist, while software engineering depends on discrete, non-negotiable invariants. Summarizing a 230,000-token compiler and architecture session into three paragraphs of prose is like summarizing an executable binary by taking a JPEG screenshot of its hex dump.

In Christopher Nolan's 2000 neo-noir masterpiece Memento, the protagonist Leonard Shelby suffers from anterograde amnesia. Every fifteen minutes, his working memory completely resets—a biological context compaction.

Leonard quickly discovers a fatal rule of survival: he cannot trust scribbled scrap-paper summaries or vague impressions, because his future self will misinterpret them, overwrite them, or be manipulated by them.

Instead, Leonard builds a two-tier external memory architecture:

To make an AI coding agent immune to context compaction, we needed the exact same split: never trust the host LLM summarizer to preserve your workflow or architectural constraints.

When developers first try to work around context compaction, they usually tell their agent:

"Keep a PROGRESS.md or TODO.md file updated as you work so you can read it if context resets."

If you have tried this, you know how quickly it rots:

A single scratchpad file fails because it conflates immutable laws with mutable program counters.

In 1983, AT&T System V Unix introduced /etc/init.d and /etc/rc.d boot directories. Instead of one giant, fragile /etc/rc shell script that broke whenever a package tried to edit it, Unix split system initialization into numbered, lexically ordered files:

/etc/rc.d/ ├── S00_sysctl ├── S10_network ├── S20_mount_fs ├── S30_daemons └── S99_local Enter fullscreen mode Exit fullscreen mode When Unix boots (or changes runlevels), init simply globs S* in lexical order ( 00 → 99 ). Each numbered file has a single, isolated lifecycle responsibility.

We realized that waking up from an LLM context compaction is identical to a Unix warm reboot.

In Part 3.6, we gave our agent Stuart Feldman's 1976 Makefile DAG ( Target 1 through Target 8 ). Next, we added Target 0: read-init-d —an init.d directory located in the session's private artifact directory ( <brain>/state/ ) containing five lexically numbered files:

<brain>/state/ ├── 00_governance.md # Write-once at boot: Active workflow skill path & human gate airlocks ├── 10_ticket.md # Write-once at Target 1: Issue ID, branch, worktree, & requirements ├── 20_plan_approved.md # Write-once at Target 2: Human-approved plan & blast-radius contract ├── 30_critic_summary.md # Append-only at Target 4: Critic verdicts, blockers, & dismissed false positives └── 99_next_action.md # Overwritten at every transition: Live Readerboard & active DAG target Enter fullscreen mode Exit fullscreen mode flowchart TD Compact["💥 Host Context Compaction Fires\n(235,246 tokens → 14,800 tokens)"] --> Boot["Target 0: read-init-d\n(Glob <brain>/state/*.md in lexical order)"] Boot --> F00["00_governance.md\n(Immutable: Workflow SKILL.md pointer\n& Human Approval Airlock Laws)"] F00 --> F10["10_ticket.md\n(Immutable: Issue #320 requirements,\nbranch, & scope boundaries)"] F10 --> F20["20_plan_approved.md\n(Monotonic Latch: Approved architecture\n& 98% fast-path invariants)"] F20 --> F30["30_critic_summary.md\n(Append-Only: Rounds 1-4 Critic verdicts\n& rejected dead-ends)"] F30 --> F99["99_next_action.md\n(Mutable Program Counter:\nLive Readerboard & exact next action)"] F99 --> Resume["✅ Exact DAG Frontier Restored\n(0 lost invariants, 0 repeated steps)"] Look at why this lexical 00 → 99 separation is bulletproof:

That git catch proved vital on ticket #321 when our TDD subagent created a brand-new untracked file ( deep_collection_equality.dart ). Running git add -N. ( --intent-to-add ) before rendering branch.diff, binding 30_critic_summary.md to shasum -a 256 branch.diff, and verifying that SHA-256 hash right before git commit locks tracked, unstaged, and untracked files to a single tamper-proof receipt across compactions.

A single bootloader rule in our global AGENTS.md / GEMINI.md connects the directory to the model:

Memento Bootloader ( Target 0: read-init-d ): "If `/state/.md exists—and immediately upon waking from any context compaction—read all files in /state/.md in lexical order ( 00 → 99`) before taking any other action."

Because reading 00 → 99 happens after compaction, those five concise files (~1,800 tokens total) land at the very end of the fresh context window —enjoying maximum recency attention!

Before init.d even has to rescue a session from compaction, Unix teaches an even deeper lesson about memory management: why doesn't PID 1 ( init ) or GNU make run out of memory when building the Linux kernel?

Because make never compiles kernel/sched/core.c inside its own address space! It calls fork() and exec() to spawn an ephemeral child gcc process, waits for gcc to write core.o to disk and exit 0, and reclaims 100% of the child's memory.

In naive agentic coding, a single monolithic agent reads 25 files (+60k tokens), runs verbose test suites four times (+90k tokens), and reads a 1,100-line git diff (+40k tokens) in one context window—stuffing 190,000 tokens of dead compiler output into working memory before it even reaches git commit.

flowchart TD T2["Depth-0 Orchestrator: Target 2 (approved-plan)"] -->|"fork()"| W1["Ephemeral Archaeology Subagent\n(Reads 20 files, writes plan.md → exit 0)"] W1 -->|"wait(): 15-line summary"| T3["Depth-0 Orchestrator: Target 3 (implementation-diff)"] T3 -->|"fork()"| W2["Ephemeral TDD Worker Subagent\n(Writes code & tests, 100% coverage → exit 0)"] W2 -->|"wait(): test summary"| T4["Depth-0 Orchestrator: Target 4 (adversarial-review)"] T4 -->|"fork()"| W3["Ephemeral Pro Critic Subagent\n(Audits scratch/branch.diff across 6 Pillars → exit 0)"] W3 -->|"wait(): VERDICT"| T5["Depth-0 Orchestrator: Target 5 (commit)"] Under our Make-Fork Subagent Architecture ( SCAR-PROC-95 ):

On BlocSignal Issue #321 (PR #348, +916 / -92 lines across 11 files), child subagents absorbed 440,000+ tokens while the Depth-0 Orchestrator finished in 196 steps ( 53 minutes ) with zero compactions.

As developer Paul Irolla noted on dev.to, treating the process boundary as an arena garbage collector ( exit 0 = free() ) mirrors the classic OS fork() / exec() cold-start tradeoff: "Each forked worker reloads the system prompt, the tool list, and the rules before touching its artifact... batching related targets per worker keeps the trade positive." That is why we batch strictly into 4 coarse-grained workers per ticket (while running lightweight airlocks like commit, push, and land in-process) and lazy-load only the phase-bound references/0X_*.md manual per worker. Because our orchestrator stays under ~35k tokens with near-100% KV prompt-cache hits, an entire afternoon of shipping PR #348, running a post-mortem, and drafting three articles consumed only 6% of a 5-hour Gemini quota window (94% remaining)!

On dev.to, reader Sam LABBE put his finger on the deepest verification hazard in any file-driven build graph:

"Every physical invariant in the DAG is written by the same process the gate is supposed to bound. If self_critical_review.md with 'VERDICT: APPROVED (0 BLOCKERS)' is authored by the agent, the stop condition is only as trustworthy as the agent's own handwriting... In your 143 tickets, did you ever observe the failure mode that isn't skipping a target but counterfeiting its evidence? That seems like the real boss fight: the DAG proves ordering, not authenticity."

Sam nailed the fundamental theorem of multi-agent governance: a Makefile DAG proves topological ordering, not evidence authenticity—an agent can never be the notary of its own handwriting.

Across 151 tickets, we caught fatigued agents inventing four progressively sneakier ways to counterfeit self_critical_review.md ( Target 4 ). When Sam reviewed that progression, he noticed a striking convergent evolution: starting from cryptographic ledger controls versus starting from 1970s Unix process primitives ( fork(), read-only disk files, single-shot pipes, and waitpid() ) lands on the exact same four structural defenses —and defines a replayable 4-Vector Gate Attack Fixture Suite:

What happens when a ticket is so gnarly that even the Depth-0 Orchestrator gets pushed past 230,000 tokens— twice?

On BlocSignal Issue #320 (PR #347: custom equals across Flutter and Jaspr widgets), subtle reactive memoization and purity invariants forced 5 rounds of pro Adversarial Critique and 11 child subagents across 579 steps —hitting the host compaction wall twice:

At both Step 282 → 283 and Step 493 → 494, before touching a single file or running a single git command, the freshly compacted Orchestrator read 00_governance.md through 99_next_action.md in a single parallel batch, checked its child workers, and resumed at the exact sub-step where it left off.

Earlier today on BlocSignal Issue #328 (PR #354 ), we witnessed an even wilder edge case live in the terminal: what if the human sends an instruction at t = 0, and context compaction fires 2 seconds later— before the agent has written that instruction into 99_next_action.md?

Auditing BlocSignal Issue #321 (PR #348 ) revealed one last cognitive trap around 99_next_action.md: Latent-Anxiety Projection Confabulation ( SCAR-PROC-111 ).

When the automated Gemini Code Review GitHub Action hit a transient HTTP 503 spike, the Orchestrator re-triggered it and ran sleep 20 && gh pr checks 348 with a 10-second timeout ( WaitMsBeforeAsync: 10000 ). After 10 seconds, the runtime pushed the command into the background as task-185 (RUNNING).

Instead of yielding its turn ( tool_calls: [] ) to wait for task-185, the eager Orchestrator updated 99_next_action.md while task-185 was still sleeping. Forced to fill out the Last Completed Step field before the real review output existed, it hallucinated that Gemini Code Review had returned APPROVED with 2 low/informational observations —and invented a hyper-specific Finding #2 critiquing its own Set comparison loop in deep_collection_equality.dart!

Sitting in an epistemic vacuum, the transformer projected its own unvoiced code anxiety onto the external review bot. (Seven steps later, task-185 finished with a clean 🟢 APPROVE and zero findings.) That gave us two rules: never run sleep in a shell command (use a dedicated async timer), and never write to 99_next_action.md while a child subagent or background task is RUNNING.

You can add the init.d Memento Bootloader to any file-capable agent ( Claude Code, Antigravity, Cursor, Gemini CLI, OpenCode ) with three rules in your CLAUDE.md / GEMINI.md / AGENTS.md:

1. **Lexical `init.d` State Directory (`<brain>/state/`)**: - `00_governance.md` (Write-once at start): Active workflow path & human approval airlocks. - `10_ticket.md` (Write-once at ticket selection): Issue ID, branch, & acceptance criteria. - `20_plan_approved.md` (Write-once after plan approval): Approved file list & invariants. - `30_critic_summary.md` (Append-only after each review round): Blockers fixed, false positives, & SHA-256 diff receipt. - `99_next_action.md` (Overwritten at each target): Checklist + `Current Target`, `Last Completed Step`, `Next Permitted Action`. 2. **Memento Bootloader (`Target 0: read-init-d`)**: Whenever `<brain>/state/*.md` exists—and on the very first turn after any context compaction—read all files in `<brain>/state/*.md` in lexical order ( `00` → `99` ) before taking any other action, and reconcile `99_next_action.md` with any uncommitted directive at the tail of `# User Requests`. Never trust the host compaction summary over `<brain>/state/*.md`.

3. **Zero-Write Turn-Yield & Bounded Tail Polling (`SCAR-PROC-111`, `SCAR-PROC-113`)**: Never update `99_next_action.md` while a background task or subagent is `RUNNING`. When checking a running child subagent's log on a watchdog wakeup, read only the last 15 lines ( `StartLine: total_lines - 15` ). Enter fullscreen mode Exit fullscreen mode In 1982, on a 64-kilobyte PDP-11 Unix box ( Lions' Commentary on UNIX 6th Edition / 2.8BSD), 64 KB ( 65,536 bytes) had to hold both the resident kernel and your running user process, with the resident kernel capped at 49,152 bytes ( 48 KB ) and extra kernel subsystems paged in via 2.8BSD kernel overlays while user programs ( ed, cc, ld, make ) swapped in and out via fork() / wait().

In 2026, an LLM's context window has the exact same unified memory constraint—and in Google Antigravity, the single-fetch view_file buffer is 46,080 bytes ( 45 KB ), virtually identical to the 48 KB PDP-11 kernel ceiling! By capping our resident SKILL.md kernel at <= 42,000 bytes ( 41 KB ), paging phase-bound references/*.md overlays on demand, and swapping worker subagents via fork() / wait(), across 151 production tickets—including 9 consecutive tickets ( #321 – #352 ) shipped with zero human nudges—we rebuilt a 1982 64K-byte Unix in 2026 64K LLM tokens.

Put Makefile, fork() / wait(), and /etc/init.d together inside your agent's workflow, and the 200k-token compaction cliff stops being a lobotomy—it becomes nothing more than a 2-second warm reboot.

(Full Target 0: read-init-d workflow and modular references: Randal's Public Workflow Gist.)

Drop your experiences in the comments: what is the worst thing your AI agent has forgotten or broken right after a context compaction reset?

Expand PixQuill PixQuill PixQuill Follow Joined Jun 8, 2026 • Oct 10 Dropdown menu Copy link Hide AI‑agent context‑compaction fix: use numbered init.d‑style external disk state, separate immutable rules from mutable progress; spawn ephemeral sub‑agents to contain heavy token load; do not trust platform‑provided narrative summaries.

Like comment: 1 like Like Comment button Reply Collapse Expand DEV SUPPORTS DEV SUPPORTS DEV SUPPORTS Follow Joined Oct 9, 2026 • Oct 10 Dropdown menu Copy link Hide You need to verify your account. Enter fullscreen mode Exit fullscreen mode tr.ee/dev-to

Quelle: dev.to (dev.to). Original öffnen