Peter Niu
Projects / AI Agent Infrastructure

Agent Legion

A local-first 2D colony monitor inspired by RimWorld — and a worked example of making parallel AI coding agents, context rot, and worktree collisions visible at a glance.

active
Updated November 3, 2026
v0.1.0
10 min read

When four or five CLI coding agents run in parallel across local terminals, coordination failures stay invisible until two agents overwrite the same git worktree or a 260,000-token session quietly forgets its instructions. Agent Legion turns live session transcripts, OS processes, git worktrees, and tool connectors into an inspectable 2D workshop map — and pairs it with a bounded choice classifier for high-volume background screening.

TL;DR

  • Why I shut down my cloud observability dashboard and replaced it with a local-first 2D workshop map
  • How four invisible multi-agent failure modes become physical mechanics you can spot in half a second: Worktree Contention (Two Chefs, One Wok), Context Rot (scroll stacks and walking speed), Blocked Sessions, and Orphaned Processes
  • How a four-seam architecture — privacy-stripping sensors, a pure deterministic world reducer, decoupled room coordinates, and a zero-build-step 2D Canvas renderer — keeps the simulation fast and testable
  • How a bounded choice classifier handles repetitive background tagging with crash-safe job markers and mandatory human review gates

Why I built this (and why it replaced my cloud dashboard)

Earlier in the year, I built a hosted observability dashboard on Railway and Postgres to monitor my cloud functions, weekly maintenance jobs, and API spend. In October, I shut it down. The cloud services were quiet and predictable; checking a web dashboard for green uptime bars wasn’t solving an actual failure mode.

The real operational failures were happening locally on my workstation whenever I ran four or five coding agents (Claude Code, Codex, Gemini, Mistral, DeepSeek) in parallel:

  1. Silent worktree collisions: Two agents in separate terminal tabs would start editing the same repository at the same time, tangling unstaged hunks before either ran tests.
  2. Unnoticed context rot: A long debugging session would drift past 250,000 tokens of context, losing track of earlier constraints while still sounding confident.
  3. Forgotten approval prompts: A subagent in a background tab would pause on a clarifying question and sit idle for forty minutes.
  4. Orphaned background processes: Finished sessions would leave behind detached dev servers, browser automation bridges, or hung child processes.

A table of process IDs and log files forces you to read rows to spot a collision. Video games solved parallel autonomous status decades ago: in RimWorld, you can tell in half a second whether two colonists are fighting over the same workbench, who is carrying too much weight to walk fast, and which generator is sparking.

I built Agent Legion as a local-first 2D workshop colony where every project repository is a workshop room, every running CLI agent is a colonist pawn, and every coordination failure has an unmistakable physical signature.


Four invisible problems made visible

1. Worktree contention (“Two Chefs, One Wok”)

Each project room contains one Anvil (the room’s single write station — the “wok” in the kitchen analogy), representing exclusive write ownership of that git worktree. Reading files and delegating research happen at the Research Bench; running shell commands and tests happens at the Terminal.

When an agent invokes a file-editing tool, the state reducer claims a 10-minute write reservation on that room’s write station for the root session — automatically rolling child subagent edits up to the parent session that dispatched them. If a second root session edits the same worktree while that reservation is active, both colonists crowd the same station, red sparks fly between them, and a top-priority WorktreeContested alert fires on the HUD.

Agent Legion workshop room showing Two Chefs, One Wok worktree contention alert with two colonists colliding at the same write station
Two root sessions editing the same repository ("Two Chefs, One Wok") trigger a top-priority contention alert and red collision sparks at the room's write station.

2. Context Rot (scroll stacks, walk speed, and the handoff relay)

One epistemic rule carried directly over from my retired cloud dashboard is that unknown is a value, not a zero. A large transcript file on disk does not prove how full the live context window is (for example, after context compaction), and a harness that does not report token telemetry should never be rendered as having 0 tokens used — instead surfacing an explicit ContextUnknown state.

Agent Legion extracts verified per-turn context fill from each vendor’s native telemetry and evaluates it against a 250,000-token clean-handoff goal:

StageToken BandPhysical & Visual Effect on Colonist
Nimble0 – 125kGreen bar, 1–2 scrolls on back, 100% walking speed
Loaded125k – 200kWarm amber bar, 3–4 scrolls on back, 80% walking speed
Handoff Zone200k – 250kOrange bar, 6-scroll tower + sweat droplets, 60% walking speed, handoff warning
Closeout Grace250k – 285kActive while committing or writing a session handoff: 5 scrolls and a 110% closeout sprint
Context Rot> 250k (> 285k w/ grace)Red bar, 8-scroll boulder shedding loose papers, 30% walking speed, high-priority rot alert
Unknown / EstimatedUnverifiedStriated neutral bar — never faked as green

When a heavily loaded agent writes a clean session handoff (HANDOFF.md) before crossing the 250,000-token threshold, the colonist walks to the room’s Bookshelf, shelves a gold-trimmed volume, and increments the colony’s Clean Handoff Streak Monument. When the next session starts in that repository and reads the handoff file within its first 10 minutes, a cyan relay arc connects the bookshelf to the incoming colonist.

Agent Legion showing scroll encumbrance stages, clean handoff bookshelf volumes, and the handoff relay arc
As context fills toward 250k tokens, paper scrolls stack on the colonist's back and walking speed drops; filing a clean handoff shelves a gold-trimmed volume on the room's Bookshelf.

3. Blocked sessions and specialist summons

A tail state machine inspects the last 15 transcript records of each session to distinguish an agent that is actively thinking from one waiting on human input. Blocked colonists walk to the room’s Lectern, raise a pulsing ? speech bubble, and trigger an AgentAwaitingInput alert so a paused tab never goes unnoticed.

When a parent session dispatches a specialist subagent, a smaller Specialist Pawn spawns inside the parent’s workshop room with a tether line to its summoner and a visual archetype matching its role:

  • Inquisitor (Adversarial Bias Auditor): carries a magnifying lens and audits plans at the Easel.
  • Engineer (Architecture Reviewer): carries a cyan blueprint roll at the Research Bench.
  • Owl Scout (Discovery & Literature Search): carries a lantern and inspects sources at the Bookshelf.
  • Classifier Mechanoid: metallic worker pawn rendered with a live progress bar during batch classification runs.

4. Orphaned daemons and degraded connectors (“Lights Left On”)

Below the project workshops sits the Comms & Power Bay. Every configured MCP server renders as a Comms Console and every long-running local background process renders as a Generator.

Process sensors walk OS process ancestry. If a child process outlives its parent terminal session, it is flagged as a suspected orphan. Rather than offering a blind “kill” button, the Inspector enforces a two-step reviewed cleanup flow:

  1. Dry-run inspection verifies the process is still orphaned, checks listening sockets and child processes, and issues a single-use review token valid for 60 seconds.
  2. Confirmed termination re-verifies both the process ID and its exact OS creation timestamp (preventing PID-reuse accidents) and refuses to terminate any process that belongs to an active session or holds a listening server socket.

Architecture: four primitives, zero framework bloat

Agent Legion runs as a lightweight Python server paired with a vanilla ES module HTML5 Canvas client — zero frontend build step, zero bundler, and zero UI framework dependencies. It separates concerns across four strict seams:

1. Read-Only Sensors Transcript tail reader OS process tree scanner Worktree & MCP probes Batch worker telemetry Strips prompts, diffs, args & env secrets 2. Pure World Reducer (prev_state, obs, now) • Colonists & Capacities • 10-min Write Leases • Priority Alerts (P0–P4) • Edge-Triggered Letters Deterministic & replayable 3. Plot Layout Persistent room grid Room coordinates live outside the world state reducer Zero-overlap placement 4. 2D Canvas Client 9-Step Procedural Map 16×16 Section Cache 8-Way A* Pathfinding Perimeter HUD Zero frontend build step

Sensors strip sensitive content at the boundary; the pure reducer computes world state deterministically; layout coordinates stay decoupled from state; and the 2D Canvas caches static terrain in 16×16 tile sections.

Three non-obvious design decisions

  1. Strict privacy boundary at the sensor edge: Because Agent Legion inspects live transcripts across every project on the machine, the sensor layer strips all user prompts, assistant prose, code diffs, shell command arguments, and environment variables before creating observation records. Only structural metadata — tool category, target filename, and token counts — ever enters world state.
  2. Colony weather reflects machine strain, never backlog guilt: The renderer supports five atmospheric states (Clear, Gentle Snow when the colony is dormant, Rain, Thunderstorm, and Fog when telemetry is stale). Early on, I considered tying weather to overdue issue-tracker tickets. I rejected that immediately: an operational monitor should tell the truth about machine state right now. If you have a hundred backlog tickets but zero contested worktrees, healthy MCP connectors, and nimble context windows, colony weather is Clear. Thunderstorm is reserved for active local emergencies (contested worktrees, severe context rot, or a downed connector).
  3. Section-cached procedural map generation: The frontend builds the colony terrain through a seeded 9-step procedural pipeline (elevation noise, terrain, room plots, prefabs, corridors, doors, roofs, props, and lighting) over a flat typed-array grid, then caches static layers into 16×16 offscreen canvas sections with dirty-bit invalidation. Per-frame rendering only blits visible sections and draws moving colonists, sparks, and weather particles on top.

Bounded choice classification: when not to use a chat model

Packaged alongside the colony monitor is my shared classification worker, built on TypeSafe’s constrained choice primitive (system_one). Unlike a general LLM chat completion, a choice primitive returns only discrete category probabilities — zero thinking tokens and zero free-text explanations — at roughly $0.04 per million input tokens.

Fast classifiers fail silently unless you pair them with calibration gates. Frontier reasoning tokens are too slow and expensive to spend on repetitive tagging, but a small non-thinking classifier gives you no chain-of-thought to audit when a rubric is ambiguous.

To keep high-volume classification trustworthy, the worker enforces three guardrails:

  • Versioned rubric contracts: Every classification task declares explicit output categories, hard inclusion/exclusion criteria, and calibration examples.
  • Crash-safe in_flight job markers: Before each paid API call (with automatic retries disabled), the job store writes an atomic in_flight (outcome_unknown) durability marker to disk so an interrupted batch never silently double-bills or duplicates work.
  • Mandatory human review until validated: New rubrics default to review_policy: all, routing every prediction into a human inspection state until the rubric has been validated against a gold-labeled benchmark.

The stack, annotated

LayerTechnologyWhy it is here
Sensors & Local ServerPython 3.11+, psutilReads multi-vendor session transcripts, OS process trees, git worktrees, and connector health with strict content redaction
World SimulationPure Python state reducerDeterministic (prev_state, observations, now) -> WorldState engine with 10-minute write-station leases and capacity state machines
2D Colony ClientVanilla ES Modules + HTML5 Canvas 2DSeeded 9-step procedural terrain pipeline, 16×16 offscreen section cache, 8-connected A* pathfinding, and Perimeter HUD
Choice ClassifierTypeSafe SDK (system_one primitive)High-throughput discrete classification with crash-safe job manifests and review_policy: all calibration gates
Test Suitepytest (254 Python tests) + Node test runner (78 JS tests)Covers sensor privacy redaction, reducer edge transitions, cold-start notification seeding, and deterministic map generation