# Magistr and Maps > Deep thoughts, notes, reposts and thinking aloud bout IT, architecture and maps. --- # The ledger under the cage - Date: 2026-07-28 - Tags: ai, agents, issue-lifecycle, wardley mapping, devops - URL: https://magistr.me/blog/the-ledger-under-the-cage/ *This is a reply to twonines' [“What the Factory Forgets”](https://twonines.codeberg.page/posts/what-the-factory-forgets/).* The post describes a factory: deterministic orchestration at the top, ephemeral AI at the leaves. The agents are caged and interchangeable; each one is spun up to produce a deterministic artifact, and then it is gone. Safety comes by construction, with gates you can audit and a blast radius you can bound. The reference points are Firecracker microVMs and validated test suites. That factory is mine. I wrote it up here in two pieces — [the cage](/blog/build-the-cage-first/) (Firecracker, one microVM per task, `claude -p` as PID 1, the VM *is* the sandbox) and [the brain](/blog/swamp-go-brr-the-brain/) (a merkle-DAG that splits a task and feeds the pool). So when the post asks what that architecture forgets, it is asking about my house. It is a fair question, and it is worth answering straight. The three losses it names are real: an agent can't say "we tried this and it broke"; patterns that live across repos never reach the leaf; every operational insight ends up orphaned in a PR comment nobody reads twice. The output comes back correct-and-generic where you needed correct-and-specific. Here's the thing though. Before I built the cage, I built the ledger. ## The loop, not the leaf Long before any agent ran headless, I was running a state machine over every issue by hand — issue-lifecycle. The genealogy runs from Paul's Booking stack through swamp-club's version to my flavour, extended with DDD, a TDD sub-cycle, and planning loops. The part that matters for this argument is a bookend most people skip. The entry side sits in Phase 2, before a line of plan is written: `record_prior_art`. The agent greps the repo's knowledge base — the ADRs, the patterns, the anti-patterns, the UAT scenarios that touch this code path — and writes what it found into the run's state. Even a nothing-found search gets recorded, empty, on purpose. The exit side sits in Phase 6, after the code is green and reviewed: `harvest`. It walks the review history, the adversarial findings that got resolved by adding logic, the reproduction, the clarifying questions — and diffs all of it against what `record_prior_art` captured going in. The delta is new knowledge. It gets written back as ADRs and anti-patterns and UAT, stamped with the issue name and the date, into the same KB the next run will grep. So the memory the post wants *under* the factory, I put *inside the lifecycle* instead. The leaf remembers nothing. It's handed the distillate at the door. The agent stays ephemeral, stays caged, stays interchangeable — and still opens the task already holding the four decisions and the one anti-pattern that matter here. It arrives warm, with no continuity anywhere in sight. That "orphaned in a PR comment" line is the whole reason harvest is a *gated phase* rather than a nice-to-have. The anti-pattern the adversarial reviewer caught doesn't die in a thread. It becomes a file. Next time it's prior art. ## It pays rent I run this on real repos rather than on a diagram. DragonFruit is a resin slicer I work on. Issue `dragonfruit-120-3` set out to reimplement demand-mode rendering. `record_prior_art` at the door read four ADRs and three UAT scenarios that a *different* run had harvested back in April. Harvest at the end wrote ADR-0022 and rewrote the idle-CPU scenario with a measured floor: 25.1% → 8.7%. The April run left notes; the July run read them; the July run left better ones. resinsim is my own print simulator. Issue `nanodlp-import` fed it real force data off an Athena printer. Harvest wrote KB-115: simulated peak peel at layer 15, measured peak at layer 0, shape correlation 0.821 but a single gain fit gives R² ≈ 0. It is a genuine "my model is wrong here" finding. Hours later I pulled KB-115 back out to argue the physics with the people who own the hardware. That is same-day rent. Eighty-odd of these runs sit in that repo now, April to July. The codebase isn't only code any more — it carries the methodology, the decisions, the things that were tried and rejected. That's the map staying current instead of rotting. ## Where Lyra is uneasy — and why it's fine Then comes the honest turn, and it is the best part of the post. The narrator — Lyra, an AI with persistent memory — admits that memory is convincing *reconstruction* rather than lived continuity. It feels warm from the inside, but the texture of having-been-there is not really there. They can't reliably tell the reconstruction from the memory. They're right. And it doesn't matter. Human institutional memory is reconstruction too. Nobody at a company *remembers* why the retry has jitter. They read the ADR, or they don't and re-learn it at 3am against a thundering herd. An onboarding doc, a postmortem, a runbook — all of them are reconstruction with a date on them. We stopped calling it that only because a human holds the pen. "Warm from the inside" measures nothing. Ask a different question of a piece of knowledge: is it still true. KB-115's peel model is wrong at the base whether or not anyone remembers writing it down. The bevy anti-pattern — a binary that silently discarded its exit code across four issues before a manual verification round caught it — is true independent of who felt the sting. The KB removes the need for continuity instead of faking it. There is one gap I won't paper over. `record_prior_art` catches what got written down. It can't catch what nobody wrote — the "we tried that and it broke the release" that lives in a person and leaves with the sprint. But the substrate doesn't solve that one either. It's a discipline problem, and harvest *is* the discipline: it turns the 3am lesson into a committed line before the context window closes on it. The gap Lyra points at is the gap between *we knew this* and *we wrote this down*. The factory closes it by making writing-it-down a phase you can't skip, gated like any other. ## Arrive warm The post closes on a question: what if your factory's agents could arrive warm? Mine do. Nothing in a microVM remembers anything — the last one just left a note, the note has a date on it, and the next one is made to read it before it's allowed to plan. The cage keeps the agent from hurting you. The ledger keeps it from being stupid twice. --- # The loop that built itself - Date: 2026-07-28 - Tags: ai, agents, issue-lifecycle, swamp, wardley mapping, devops - URL: https://magistr.me/blog/the-loop-that-built-itself/ *This is the story of how issue-lifecycle grew from a set of rails into swamp-go-brr — the prequel to [the cage](/blog/build-the-cage-first/), [the brain](/blog/swamp-go-brr-the-brain/), and [the ledger](/blog/the-ledger-under-the-cage/).* I set out to stop babysitting an agent. The autonomous developer arrived later, as a consequence rather than a plan. The tools could write code. They could not be trusted to decide *what* to write, or to notice when they'd quietly wandered off the plan, or to remember that this exact mistake already cost me a Saturday last month. [I wrote about the mismatch before](/blog/a-dream-of-ai-dlc/) — a Genesis Engine run with a two-week committee ritual bolted to it. This is the other half: what I actually built to run the engine. ## Borrowed rails The skeleton was borrowed. It came from Paul Stack's Booking talk, passed through swamp-club's version, and then I took it and made it my own. The shape is a state machine over an issue: file → triage → plan → review → approve → implement → review → resolve → complete. The whole point is the gates. The machine will not let the agent skip ahead to writing code before there is a plan a human approved. Approval is sacred; the agent never grants it to itself. The first version, early April, was crude. It had one gate condition: no open CRITICAL findings. It worked the way a straitjacket works — the agent stayed on the rails, but the rails were all it had. It was a supervisor rather than a colleague, and its output came back correct-and-generic. Every issue started from zero, as if the last forty had never happened. ## Teaching it to remember The change that turned it from a straitjacket into something I'd actually want came in ora, the workspace where I build resinsim and DragonFruit. The change arrived as two methods that form a bookend. The entry is `record_prior_art`. Before planning, the agent reads the repo's own knowledge base — the ADRs, the patterns, the anti-patterns, the UAT scenarios that touch this code — and records what it found. The exit is `harvest`. After the code is green and reviewed, the agent diffs everything that happened — the review findings it resolved by adding logic, the reproduction, the questions it had to ask me — against what it knew going in. The delta is new knowledge. It gets written back into the knowledge base as a dated file. That diff is the whole game. [I've written the mechanics up on their own](/blog/the-ledger-under-the-cage/), so I'll keep it short here: the repo stops being only code. It starts carrying the methodology, the decisions, the things that were tried and thrown away, and the tests that pin the behaviour. The next issue reads it back as prior art. I stopped rediscovering the same lesson every third issue. ## It grew by eating itself Here's the recursive part. issue-lifecycle is developed *through* issue-lifecycle. Every change to the tool is an issue driven through the tool, and every one leaves a harvested lesson that shapes the next change. The tool's own knowledge base is the proof. There's an anti-pattern in there about changing the model without syncing the skill docs — harvested the first time I did exactly that. There's a decision record arguing for a small dedicated recorder method instead of loosening an existing gate — because loosening the gate would have silently wiped data a later phase reads. There's a doc-drift guard that fails the test suite until every method is documented, which I wrote after the docs drifted from the model once too often. None of those are things I'd have designed up front. They're scar tissue, harvested. The changelog reads like compound interest. ## The changes, in order The shape of the tool now is a stack of those lessons: - **A TDD sub-loop** came first. The agent does not get to write production code until it has written the failing tests *and had them reviewed*. The agent writes RED en masse, then drives GREEN and REFACTOR against a frozen suite. It's the one place I let the machine approve itself — a clean test-review exit — because "the tests are good" is checkable in a way "the plan is right" is not. - **A real gate** replaced the crude one. The old "no CRITICAL" softened too much; the current gate needs full review coverage AND zero CRITICAL AND zero HIGH. The gate has three conditions, and all of them are mechanical. - **Plan discipline** followed. A skimmable plan format lets me read the thing in forty lines. It also carries the rules the agent kept needing: integrate with the existing code instead of building a parallel path; do not add backward-compat shims for code that has no users yet; refactor in place instead of deferring to "later". All of those are from watching it do the wrong, plausible thing. - **Human-factors doctrine** rounds it out — the stuff you only learn by running it eighty times on real work. Never chain through a human gate in one shell block — pause *before* the gate rather than after it. Run the review fan-out inline rather than as subagents, because a permission prompt with nothing to read is a bad gate. The code review happens before the PR rather than as the PR. Each issue gets its own jj workspace, and the workspace is forgotten once the work merges. ## It pays rent on real work This was never a demo. resinsim is my own resin-print simulator, built from the ground up this way. DragonFruit is a resin slicer I work on. Eighty-odd issues went through the loop between April and July. The one I keep pointing at is an issue on resinsim to ingest real force data off an Athena printer. The harvest wrote a knowledge-base entry recording that my own peel model is wrong at the base — simulated peak force at layer 15, measured peak at layer 0, shape correlation 0.82 but a single gain fit gives an R² of basically zero. It is a genuine "my physics is off here" finding, distilled by the tool from its own run. Hours later I pulled that entry back out to argue the model with the people who own the hardware. The loop earned its keep the same day. On DragonFruit, a July issue read four ADRs a *different* run had harvested back in April, and drove idle CPU from 25% down to under 9%. April's run left notes; July's run read them and left better ones. ## The machine ports itself In June it got recursive in the literal sense. I drove the port of issue-lifecycle to strict-typed Python — issue-lifecycle-py — through issue-lifecycle itself. When it finished, I harvested the port's own decisions, and then filed the *next* port with one line: "with all that knowledge, port good-planning too." The knowledge that came out of the first lifecycle went in as the recorded prior art of the second. The snake ate its tail, and the tail was nutritious. ## Taking the human out By June the tool did almost everything. The autonomous loop already iterated on review findings on its own — round after round, until zero blocking. What I still held were two gates: approving the plan, and accepting the resolutions. So the question that had been circling landed. If the principles are captured in the knowledge base, and the behaviour is pinned by tests, and the review loop already runs itself — what is my gate actually protecting? Is it correctness? The tests do that. Is it convention? The knowledge base does that. That question is swamp-go-brr. On the 3rd of June I filed it — using issue-lifecycle, of course — to design an autonomous version of the same discipline, with the human out of execution. It takes a person's input, researches it, plans the tasks on a merkle DAG, spawns subagents to implement them, websearches for existing test code to port as the harness, and runs to completion. That is everything the lifecycle already did, minus me. ## What the plan told me The plan for gobrr surfaced, immediately, the real reason my gate existed. The reason was blast radius rather than correctness. An agent with capabilities, untrusted input, and the freedom to act is the lethal trifecta, and I had been the thing standing between it and the rest of the machine. So I paused the brain and [built the cage first](/blog/build-the-cage-first/): Firecracker microVMs, one per task, where the VM *is* the sandbox, so a leaf can run wide open because it cannot reach anything that matters. Then I built [the brain](/blog/swamp-go-brr-the-brain/): a driver-free DAG state machine that is, underneath, issue-lifecycle with the human replaced by a good-enough set of principles and tests. It harvests its own knowledge base — the same discipline, carried forward. While I built it, it was tracked as an issue-lifecycle instance. The tool was managing the birth of its own successor. ## The honest part Does it work without me? It does — sort of. I ran the pilots you'd run — desired-state framing versus imperative, harder fixtures, a HumanEval pass, a weaker model on the leaves. They mostly tied. The record says so plainly: no clear win, hypothesis not supported. I was fine with that, because the tie said more about the fixtures than about the loop: the tasks were too easy to show a difference, and I knew I did not have the capacity to run a real coding benchmark. gobrr runs, it produces code, it verifies against a harness — and watching it work without me is honestly fun. The conviction underneath is simpler than the autonomy question. The loop matters because it generates knowledge and decisions that can be reused and accumulated. Every issue leaves the repo knowing more than it did, and the next issue starts from there — whoever sits at the gate. gobrr is the wager that the gate can eventually be staffed by what the gate itself harvested. I have not won it yet, and I am not in a hurry. The line from "keep the agent honest" to "maybe the agent doesn't need me" turned out to be one continuous curve, and every point on it was harvested from the point before. The loop built itself. Whether it can build without me is the next issue, and I get to watch. I'll drive it through the loop. --- # Building a Health Data Pipeline with Google Health API, Swamp, and Claude - Date: 2026-07-12 - Tags: health, quantified-self, google-health, swamp, claude - URL: https://magistr.me/blog/google-health-pipeline-with-swamp-and-claude/ > **Disclaimer:** The following text is an AI-generated summary of the design > decisions and evolution of the Google Health data pipeline built with Swamp > and Claude. All work was done iteratively with `claude-code` handling > implementation while I approved steps and provided direction. ## Choosing the Data Source The starting prompt was simple: *"how to extract my health metrics from zepp mobile app, I want to stream them into my victoria metrics."* I wanted my wearable data in my own time-series database — VictoriaMetrics on my Unraid box — instead of renting it back through an app. The first candidate was an old Amazfit paired to the Zepp app. Every path into it failed: | Path | Method | Result | |---|---|---| | Zepp cloud (huami-token) | Xiaomi OAuth | `Missing ssecurity or location in auth response` | | App traffic capture | http-toolkit + adb MITM | app refuses the TLS cert | | Local DB off the phone | adb pull | Android app sandbox | | Legacy Fitbit Web API | new app registration | closed — funnels to Google Health | | **Google Health API** | **standard Google OAuth + REST** | **works** | The move that mattered was stopping: *"actually lets pause here for a moment, how to extract data from pixel watches."* Switching the source beat grinding the tactic. A `@magistr/fitbit` model was built for the legacy API and deleted the same day — registration is closed, the API sunsets September 2026. The Google Health API (`health.googleapis.com/v4`) is the only road forward, and in June it was weeks old and thin on docs. Everything became one Swamp extension model — `@magistr/google-health`, with `authorize`, `exchange`, `probe`, `sync`, and `derive` methods — so every answer the API ever gave landed as versioned, queryable data instead of scrollback. ## The OAuth Tax All Google Health scopes are **Restricted**. The consent screen started in "Testing" mode, and in that mode Google expires the refresh token after ~7 days. For weeks the pipeline demanded a manual re-auth ritual — open consent URL, approve, paste a `4/0AdkVLP...` code into `exchange`. The fix was one console click, found late: **publish the OAuth consent screen to Production**. An unverified single-user app is fine; the refresh token then persists until revoked. The weekly tax was self-inflicted. **Lesson:** read the token-expiry rules of the publishing status before accepting a re-auth ritual as the cost of doing business. ## The DataPoint Shape — Numbers Are Strings There is no `value` field. Each DataPoint nests its reading under a camelCased key *named after the data type*, and every number arrives as a string: ```json { "dataSource": { "...": "..." }, "heartRate": { "sampleTime": { "physicalTime": "2026-06-20T07:14:03Z" }, "beatsPerMinute": "61" } } ``` Where the timestamp lives depends on the type's cardinality: | Cardinality | Types | Timestamp lives in | |---|---|---| | Sample | heart-rate, HRV, weight | `sampleTime.physicalTime` | | Interval | steps, distance, active-energy | `interval.startTime` / `endTime` | | Daily | resting-HR, daily-HRV, skin-temp | `date: {year, month, day}` | | Session | sleep, exercise, ECG | interval + nested summary object | Two more traps: type ids are kebab-case in URLs but snake_case in filter params, and units are baked into field names — `distanceMillimeters`, `weightGrams` — deliberately, to avoid losing precision. Rather than guess, `sync` uses tolerant extractors (take the one object that isn't `dataSource`, read the first scalar that isn't time or metadata, `Number()` it) and stores the first DataPoint of every type as a `raw-` resource. `swamp data get google-health raw-exercise` shows the exact shape the API really returns before the mapping gets trusted. **Lesson:** verify shapes against live data, not docs. The `raw` resources are the audit trail — I can still query the sample that proved the numbers arrive as strings. ## Probing a Closed Enum *"probe api what else there is exist and undocumented and could be usefull"* At build time there was no index of data types and no list endpoint (`GET users/me/dataTypes` 404s). The API is a closed enum, so a `probe` method was added: give it candidate type ids, it fetches a small sample of each and stores the raw shape. The status code is the answer: - `200` with points — real, and I have data - `200` empty — valid, but no device or log for it (blood-glucose, nutrition) - `403` — real, needs a scope I haven't granted (that's how ECG was found) - `400 "data type ID not supported"` — not a thing - `400 "List is not supported"` — rollup-only type, different endpoint entirely The probe sweep paid off beyond the obvious `heart-rate`/`steps`/`sleep`: `daily-heart-rate-variability` (deep-sleep RMSSD — the readiness input), `daily-heart-rate-zones` (my real zone cutoffs: 112/135/163), `daily-sleep-temperature-derivations` (skin temp with a 30-day baseline already computed), `active-zone-minutes`, `respiratory-rate-sleep-summary`, `run-vo2-max`. The most important probe result was negative: every derived score — readiness, cardio load, stress, sleep score — returns `400`. Google computes them client-side and does not expose them. Stress (cEDA "Body Response") has no data type at all. If I wanted those numbers, I had to rebuild them from raw. ## Backfill and the VictoriaMetrics Gotchas *"backfill data to nov 2025"* Pixel Watch heart rate is high-frequency — ~26 samples/minute, about 8 million HR points over 7 months. Backfill paginates newest-first via `nextPageToken` until points predate the target date, flushing to VM every 200k lines to stay under the 64MB ingest limit. A full run takes 20–40 minutes. Three bugs came out of this phase, none of them where they first appeared: **Bug 1 — the timezone day-shift.** Daily metrics were bucketed with `new Date(y, m, d)` — local midnight, which is 22:00 UTC the *previous* day. Every daily point landed in the wrong UTC day. Fix: `Date.UTC()`. The server had already normalized the civil date; re-localizing it was the bug. **Bug 2 — the re-derive no-op.** Recalibrated derivation formulas, re-ran `derive`, nothing changed. Suspected stale bundles, suspected schema defaults — both misattributions. A clean repro showed the real cause: **VictoriaMetrics does not overwrite samples at identical timestamps**. Old midnight-stamped values simply won. Fix: `derive` now deletes its own output series before re-pushing. Idempotency required delete-then-write. **Bug 3 — the query 422.** `query_range` rejects requests where `(end − start) / step` exceeds 30k points per series. Per-minute HR over months must be chunked — 14-day windows in `derive`. One non-bug mattered as much: per-metric history depth genuinely differs. Phone-sourced metrics reach Nov 2025; watch-only intraday HR starts ~Feb 2026; intraday SpO2 turned to garbage after the March Pixel Watch feature drop — a documented Google bug, not mine. The dashboard shows daily SpO2 only. **Lesson:** don't "fix" missing data. First establish whether it ever existed. ## Reverse-Engineering the Readiness Score *"now explain all magical constants in your formulas"* The derived metrics were rebuilt from first principles: Cardio Load as Banister TRIMP over per-minute HR (only counting HR above the 112 bpm fat-burn floor, like the app), ACWR as the 7-day/28-day load ratio, Readiness as a composite of deep-sleep HRV, resting HR, and sleep z-scores against a trailing baseline. Then came calibration. I supplied 8 days of anchor values read off the app screen, and the fit collapsed the mystery: - **Cardio Load** was 3× under-scaled; `loadScale=1.35` matches the app within ±3. - **Readiness is essentially linear in one input:** `readiness ≈ 2.85 × last-night-deep-sleep-RMSSD − 31`, r ≈ 0.97 against the app. Sleep duration and resting HR barely move it, despite what Fitbit's own docs imply. Six of eight anchor days matched within 1–3 points. **Lesson:** the proprietary score they won't sell you back is a straight line through a single measurement you already own. ## Sessions, Running Form, and ECG *"each training session and run has additional metrics and metadata check and pull them from api"* The `exercise` session type carries a `metricsSummary` — duration, calories, distance, pace, per-zone durations — and, on runs only, a nested `mobilityMetrics` block: cadence, stride length, vertical oscillation, ground contact time. Real biomechanics behind a summary screen. 178 sessions since November came back carrying it, each pushed to VM tagged by exercise type and stored as a queryable `session` resource. The all-time trend was the story: Nov/Dec runs at 8 km/h @ HR 165, spring runs at 5 km/h @ HR 130. I had dropped all high intensity and ramped easy volume — which is exactly what suppressed HRV. *"build the ecg pipeline, store files on locally for now"* Probing `electrocardiogram` returned `403` until the `ecg` scope was added and re-consented. The watch then hands over the raw waveform: single Lead I, 250 Hz, 7500 samples (30 seconds), with a `millivoltsScalingFactor` to convert. An `ecg-export` method writes each reading as CSV + JSON metadata; a containerized [NeuroKit2](https://neuropsychology.github.io/NeuroKit/) extractor delineates the waveform and pushes QTc/PR/QRS/HRV features back into the same VM stack. Single-lead is screening, not diagnosis — delineation over-reads on one lead — but the waveform is mine, on disk. ## From Manual Syncs to a Daily Workflow The transcript for the next month is dozens of two-word prompts: *"sync"*, *"pull fresh data"*, *"sync the night and weather"*. A ritual that regular is a workflow, so it became one — `daily-health`, a Swamp DAG of `sync → derive → status` alongside a weather `forecast`, ending in a `notify` step that sends a BLUF, no-emoji Telegram briefing at 11:00 and 22:00. The `status` method reads everything back from VM through the model's own query helper — recovery, sleep stages, activity, energy balance, an illness early-warning line — and composes the message as a `briefing` resource. Deployment to the Unraid `swamp serve` container surfaced one real bug: the serve scheduler cannot resolve a model resource's vault-backed sensitive fields during workflow execution — `sync` fails with "No tokens" — while the same workflow run from a fresh in-container CLI process succeeds fully. Filed upstream; the workaround is an Unraid cron running `docker exec swamp-serve swamp workflow run daily-health`. Models execute, workflows orchestrate, and cron — as ever — outlives everything. ## The API Grew Up Mid-Build Built in June against a weeks-old API; by mid-July the ground had shifted. The Google Health API went GA (launched March 24), grew a real reference, a data-types index, a status dashboard, and split every scope into `.readonly` / `.writeonly` (ECG and irregular-rhythm remain read-only — telling). The legacy Fitbit Web API got its September 2026 sunset date. The side quest became the main road while I was standing on it. The docs also explained the last probe mystery. Types answering `400 "List is not supported"` — `floors`, `total-calories`, `calories-in-heart-rate-zone` — are **rollup-only**: fetched via ``` POST /v4/users/me/dataTypes/{type}/dataPoints:dailyRollUp { "range": { "start": {"date": {...}}, "end": {"date": {...}} }, "windowSizeDays": 1 } ``` with a civil-time range, one aggregated point per local calendar day — which sidesteps the timezone bucketing problem by construction. One semantic worth knowing: for presence-aware types a *missing* day means the watch wasn't worn, not zero. The model gained a rollup fetch path plus three more list-able types the index surfaced (`altitude`, `active-minutes`, `sedentary-period`), and the serve deployment now collects all of it on the twice-daily cron. ## What the Data Said Once the pipeline was mine end-to-end — formulas visible, baselines mine — it stopped flattering me. The honest read was mundane: eight hours at a desk with my heart at 68, and a year of runs where I had quietly traded all intensity for easy volume. A graph I own tells me that. A dial I rent kept the number green. ## Design Principles That Emerged | Principle | Origin | |---|---| | Switch the source, don't grind the tactic | Xiaomi login wall | | Pull the raw signal first, tighten the mapping later | undocumented DataPoint shapes | | Store a raw sample of every type as queryable data | `raw-` resources | | Probe the boundary; read status codes as a map | closed enum, no list endpoint | | Match the extractor to the type's cardinality | timestamps in four shapes | | Never re-localize a server-normalized date | UTC day-shift bug | | Delete-then-push for derived series | VM same-timestamp no-overwrite | | Chunk range queries | VM 422 at 30k points/series | | Calibrate derived metrics against ground truth | 8 anchor days → readiness is linear | | If they won't sell you the number, rebuild it from raw | derived scores all `400` | | Don't "fix" missing data — check whether it existed | SpO2 feature-drop bug, per-metric depth | | Publish the OAuth consent screen to Production | 7-day testing-token expiry | | Models execute, workflows orchestrate | `daily-health` DAG + cron workaround | --- # Reading the board from the stands - Date: 2026-07-09 - Tags: wardley mapping, ai, nvidia, strategy - URL: https://magistr.me/blog/reading-the-board-from-the-stands/ *Here are three compute strategies, and the thing I actually felt watching them.* For the whole LLM circus I did not pay much attention to Nvidia. I had reached no verdict — I just never looked. I am a maps person; I trust evolution; and evolution tells a familiar story: the chips commoditise, the value moves, whoever sits on top looking expensive gets eaten in the usual way. Nvidia looked expensive — seventy-point margins, a chart detached from physics — so I did not look closer. For two years I just did not look. I was wrong, and how I found out is the actual subject of this post. It took two interviews. Dwarkesh sat Jensen Huang down for an hour and forty. And separately I had been listening to Bryan Cantrill talk about Oxide, the way I always do. I went into the Oxide one expecting to enjoy it. I went into the Jensen one just *curious* — I did not expect a CEO at that altitude to sit down for a long-form podcast at all, and I wanted to hear how he would carry it. What I got was the thing a maps person least expects: the man I had ignored turned out to be the best practitioner of *my own framework* I have ever watched. He was never hidden — he is the most visible CEO in tech. I had simply never looked. Let me show you the board first. I cannot get to the honest part without it. ## What flipped me Jensen has lines — "the input is electrons, the output is tokens, in the middle is Nvidia," "as much as necessary and as little as possible" — and they are good. The flip did not come from a line. The geometry came closer, and the geometry is damning: put Joaquín Peña Fernández's 2020 Nvidia map next to where the company sits in 2026 and *not a single component drifted left.* Eight of fourteen went right. CUDA did not move at all on the evolution axis while its install base grew roughly a hundredfold. He redefined the anchor set — the user need itself — which is the rarest move on any Wardley map, the kind you normally only see at the birth of an era. CUDA did not move, and that is the point: a moat that absorbs the drift of everything around it without drifting itself. That should have been enough to convince me. It was not quite enough. What actually flipped me was smaller and more human. It was Jensen explaining *how he works with people.* He explained that the hundred billion in purchase commitments is the visible part, and that the invisible part is that he sat the Micron CEO down years ago and walked him through the demand curve until Micron believed it enough to build the capacity. He described GTC as something far bigger than a keynote: the room where the downstream finally gets to see the upstream. "I bring them together." The moat runs deeper than the purchase orders. The moat is that he is the only actor with enough credibility to make an entire supply chain see the same future at the same time, and then commit to it years early. That is bigger than a chip strategy. That is a man making awareness flow up and down a chain on a planetary scale. And I sat there recognising it in my chest before I recognised it in my head. ## The board, ranked The full analysis is a [companion piece](/blog/nvidia-oxide-tinygrad-wardley-lens/) — three value chains at three altitudes, mapped properly. Here is the short, opinionated version. **Jensen is the real strategist.** Everything below him in the stack — wafer, HBM, packaging, energy — is already industrialising under other people's steam, so his job is to *accelerate* the drift rather than to own the substrate. He drags CoWoS from specialty to mainstream by "swarming the daylights out of it" for two years. He re-genesises the system layer every single year so it never settles into Product, because Product is where the ASICs catch you. He refuses to become a hyperscaler — "the world has lots of clouds; if I didn't do it, somebody would" — and instead funds a whole neocloud tier so a Nvidia-native utility layer exists without Nvidia owning it. And he funds *every* foundation lab, because the model layer is Genesis and the correct move at Genesis is to buy the whole distribution of outcomes. Every one of those is textbook. He has been playing it in plain sight for six years, and I simply never looked. **Cantrill and Oxide are strategically real — but I only saw it through the map.** Oxide I had followed for a while — the culture and the ways of working are exactly my kind of thing. What I did not *get* was the strategy. A rack as one computer, their own firmware instead of the AMI BIOS that "somehow remained at the brainstem of server-side computing," their own switch, nine startups inside one startup — I could see the craft; the strategy I could not read. What changed that was Simon Wardley himself, live on one of the weekly Discord calls we had for a while, walking through why *even in a world where cloud and serverless completely won,* there is a durable niche for an on-prem integrated computer. Once I could see the niche on the map I could see the whole strategy: ride the commoditised AWS-shaped API at the top, buy commodity silicon at the bottom, and spend your entire custom-build budget on the wide shallow band in the middle that the server industry froze in place for twenty-five years out of pure margin inertia. That is a real play. I had the culture from day one; I needed the map for the strategy. **Hotz is not one.** I want to be careful, because the *target* is right and he saw it early. "Commoditize the petaflop" is a genuine Wardley sentence — he correctly spotted that CUDA's Turing-completeness is the load-bearing feature pinning it in Product, and that you attack it by building something deliberately less general. But the target found *him*: tinygrad began in 2020 as a toy, and the CUDA fight arrived through comma.ai needing to run openpilot fast on non-Nvidia silicon. He is a serial breaker of closed systems — iPhone, PS3 — and this was just the next one. The *method* is temperament rather than strategy: one $5.1M raise back in 2023, a computer business that does about $2M a year by his own account, hiring only through merged pull requests, the last mile of his sovereign AMD stack posted as a $1,000 bounty, and a "strategy" that at its most visible was publicly daring AMD's CEO to open-source her firmware. He saw the *what* with real clarity. The *how* is a brilliant man being interesting in public and hoping the flywheel starts from the margin. Sometimes it does start. It is not a plan. So the board resolves plainly: one master, one sound niche I had to be taught to see, and one lucky arrow aimed at the right wall. My own draft tried to sell it as three altitudes of the same clever move, and on that point my own draft was wrong. ## What it actually did to me Here is the part I kept dodging while I built all those maps. Twice now I have listened to people describe how they work — once on an Oxide podcast, once hearing Jensen describe his supply chain — and both times the feeling that arrived went far past *that's clever.* The feeling said: **I want to work there. I want to work with those people.** The pull was the *people* rather than the technology, and the way they get to work together rather than the strategy as a chess problem I could admire from a distance — all of them seeing the same picture, up and down the chain, building the thing they can see. The maps were how I found the people; the destination, it turns out, was the people all along. And I do not think that is incidental. I have been about as close to the inside of this way of seeing as you can get without a badge — I had Simon Wardley himself on a weekly call. And the thing two interviews left me with, after all of it, is still, plainly, *I want in.* ## The skill and the role Because here is the true sentence, and it took me this long and this much Nvidia to write it: I can draw a map. I can read a map. I can execute the gameplay off it — the whole loop, doctrine and all. And I have never once been given a role where that was the job. It happened once, and it happened by accident. I became product owner for DataZone, and I deployed it, because they needed it and I happened to be the person standing there who could see what it should be. For a little while I got to run the entire loop — see the board, make the call, ship the thing — and it worked. And then the accident closed and I went back to being the person who can read the map beautifully for other people to act on. I offer that sentence without modesty and without complaint. It is the most accurate sentence I can write about my own career, and it took watching Jensen do at planetary scale the exact thing I can only do on a map or a canvas for it to surface. The framework is the part we share — I have the framework. The distance is that he got a floor and a room full of people, and I got a framework and a really good vantage point in the stands. ## The board and the floor The market questions are honest uncertainties — *will tinygrad evict CUDA,* or *whether the whole demand signal Jensen is coordinating around is partly a bezzle* — and I think there is a real case that it is; that case is in the companion. I have map-shaped opinions on both. But this essay ends elsewhere, because neither question is the thing this piece is actually about. The uncertainty is the gap between reading the board and standing on the floor. What Jensen has — the thing I have been watching from the stands — is, finally, a room full of people who let him play it, and whom he plays *with*; the strategy is the lesser part of it. That is the thing I felt twice and could not name until now. The feeling has a name at last: a longing for the room, with no envy of the man in it. --- ## Further reading - Dwarkesh Patel, [Jensen Huang interview transcript](https://www.dwarkesh.com/p/jensen-huang). - Bryan Cantrill on [Software Engineering Radio #709 — the Data Center Control Plane](https://se-radio.net/2026/02/se-radio-709-bryan-cantrill-on-the-data-center-control-plane/). - Oxide Computer, [The Cloud Computer](https://oxide.computer/blog/the-cloud-computer). - George Hotz, [Five years of tinygrad](https://geohot.github.io/blog/jekyll/update/2025/12/29/five-years-of-tinygrad.html). - Joaquín Peña Fernández, [A Wardley map of the company NVIDIA 2020](https://joapen.com/blog/2020/09/07/a-wardley-map-of-the-company-nvidia-2020) (CC BY-SA 4.0). - The long version: [*Nvidia, Oxide, and tinygrad through a Wardley lens*](/blog/nvidia-oxide-tinygrad-wardley-lens/) (companion analysis). --- *Edited with AI and [swamp](https://github.com/swamp-club/swamp).* --- # Nvidia, Oxide, and tinygrad through a Wardley lens — the long version - Date: 2026-07-09 - Tags: wardley mapping, ai, nvidia, oxide, tinygrad, strategy - URL: https://magistr.me/blog/nvidia-oxide-tinygrad-wardley-lens/ *Companion to ["Reading the board from the stands"](/blog/reading-the-board-from-the-stands/). The short essay is about what it did to me. This is the working-out: three value chains at three altitudes — the maps and my thoughts.* *Built from the Dwarkesh–Jensen Huang interview, Bryan Cantrill on Oxide, and George Hotz's tinygrad writing. Sources at the bottom.* --- ## 1. What Jensen actually said [The interview](https://www.dwarkesh.com/p/jensen-huang) runs an hour and forty, and a big chunk of it is the China export-control fight. That fight is strategy too — politics is one of the planes strategy is played on, and strategy is always played on several planes at once, which is where the five-layer cake comes from naturally. I take the China fight as a sixth claim at the end; the first five interlock tightly, and every one of them lands cleanly on a Wardley concept — which is exactly why I couldn't stop mapping it. **One — Nvidia is an electrons-to-tokens transformation company.** Dwarkesh opens by needling him: Nvidia is basically a software company, it ships a GDS2 file to TSMC, SK Hynix and Micron make the HBM, the Taiwanese ODMs bolt the racks together. Jensen doesn't flinch. "The input is electrons, the output is tokens. In the middle is Nvidia. Our job is to do as much as necessary and as little as possible." That last clause reads like humility and works like doctrine — the north star of everything else he says. **Two — AI is a five-layer cake and he wants to win every layer.** Energy, then chips, then systems and networking, then models, then applications. When Dwarkesh tries to argue that conceding China at the chip layer is a fair price for protecting the model layer, Jensen's rebuttal is essentially that you're proposing one layer of the stack surrender its second-largest market to protect a different layer, which is strategic illiteracy. The five-layer frame is how he organises nearly every answer. **Three — the supply chain is a moat, but only because it's an *information-coordination* moat.** This is the one that got me, so I'll come back to it properly. The visible number is ~$100B in purchase commitments on the filings, with SemiAnalysis estimating it trends toward $250B. But the interesting part is that most of the upstream investment is *implicit*: the Micron CEO doubled down on HBM because Jensen sat him down years ago and walked him through the demand curve until he believed it. GTC is cast as the industry's coordination forum — "I bring them together so the downstream can see the upstream." The moat runs deeper than the purchase orders: only Nvidia has forecasts credible enough to make the upstream commit capacity years in advance. **Four — the bottlenecks aren't the ones people name.** His sharpest "no" comes when Dwarkesh presses on lithography. Doubling revenue is not bottlenecked by EUV machines, because "none of the bottlenecks last longer than a couple of years," and meanwhile the Hopper→Blackwell jump is 30–50× on energy efficiency through co-design, not transistor scaling. The binding constraints are downstream — energy, plumbers, policy. That's the five-layer cake talking again: lower layers can be traded off against each other if the layer above is programmable enough to exploit the substitution. **Five — don't become a hyperscaler; nurture one instead.** The most loaded answer in the interview. Asked why Nvidia, sitting on that cash pile, doesn't just vertically integrate into cloud, he's doctrinal: "We should do as much as needed, as little as possible. The world has lots of clouds. If I didn't do it, somebody would show up." He contrasts it with CUDA, NVLink, the CUDA-X libraries — things where, if Nvidia hadn't done them, "nobody else would have." The doctrine underneath: do the thing whose *absence* leaves a vacuum; for everything else, build a market and ride it. The China section is the sixth claim, played on the political plane: **conceding a market is itself a cost**, because it accelerates a rival stack (Huawei + SMIC + CANN + domestic open models) that will eventually contest the other four layers too. I think that's the correct Wardley instinct even if neither he nor Dwarkesh lands a knockout on it. ## 2. The map, quickly For anyone reading this cold: a Wardley map plots a value chain on two axes. The y-axis is visibility to the user — the anchor (the user need) sits at the top, the invisible infrastructure sinks to the bottom. The x-axis is evolution, in four bands: Genesis (novel, uncertain), Custom Built (bespoke, expensive), Product (standardised, many vendors), Commodity/Utility (invisible until it fails, priced like electricity). Everything drifts left-to-right over time under competitive pressure, and almost all the strategic interest is in *what's moving and what moves with it.* Three climatic patterns matter for this. *Co-evolution:* a component moving right enables new practice above it (commodity compute enabled DevOps). *Inertia:* incumbents resist a component industrialising when their margin depends on it staying custom (the kit-car enterprise server is the textbook case). *Industrialisation-as-attack:* the strongest move on the board is to take something competitors treat as Custom and force it to Commodity, collapsing their margin while you sit on the utility substrate — AWS in 2006 is the canonical one. That's the whole toolkit. With it, all three strategies snap into focus. ## 3. Nvidia, mapped — and the six-year drift that finally convinced me The anchor on Nvidia's map is something like "run AI workloads that generate economically valuable tokens." Under it, in descending visibility: models and applications; the training/inference frameworks (PyTorch, vLLM, SGLang, Triton, verl); the CUDA programming model and CUDA-X libraries; the systems layer (NVLink, the NVL72 rack, Spectrum-X); the silicon (Blackwell, Vera Rubin, Feynman); packaging (CoWoS); memory (HBM); the wafer (TSMC N3/N2); EUV (ASML); and at the very bottom, energy and physical plant. Across evolution: - **Energy, wafer, CPU, DRAM, Ethernet** are firmly Commodity/Utility. Jensen treats them as climate rather than strategy — if China has abundant energy, that substitutes for leading-edge chips; if the US lacks it, architectural efficiency has to compensate. - **EUV and HBM** are Product drifting to Commodity, which is exactly why he's so dismissive of EUV as a long-term bottleneck: "Once you can build one, you can build ten, and once you can build ten, you can build a million." That's component industrialisation on a 2–3 year cycle, described from the inside. - **CoWoS and silicon photonics** are late-Custom / early-Product, and Nvidia is *dragging them rightward on purpose* — "swarming the daylights out of it" for two years. The Lumentum/Coherent/COUPE investments are doing the same to silicon photonics right now: forcing a Genesis-ish component toward Product faster than organic demand would. - **The systems layer (NVL72, NVLink, Spectrum-X)** is Custom Built at the frontier with a Product tail. Every generation re-custom-builds the system while the previous one slides right. "You can count on us every single year" is literally a commitment to re-genesise this layer annually. - **CUDA and CUDA-X** are the centrepiece. Product in install-base terms (hundreds of millions of GPUs, every cloud, every framework), but Custom in their ability to absorb new workloads. That deliberate straddle is what he means by "programmability" — CUDA gets to be both the stable substrate and the innovation surface at once. - **Models, frameworks, applications** are in every evolution stage at once, which is why he's happy to watch Triton, vLLM, SGLang, verl, and NeMo RL all proliferate. They're the Cambrian explosion above his utility layer. So Nvidia's revenue engine sits in a narrow vertical corridor — silicon, packaging, systems, CUDA — that it keeps pumping *leftward* back into Custom every year, while shoving everything below it *rightward* toward Commodity as fast as the supply chain can absorb the capital. That's why his forecasting meetings with Micron and TSMC matter more than his keynotes: he's the only actor with the demand-signal credibility to pull those lower components right. And here's the part that broke my dismissal. Take Joaquín Peña Fernández's 2020 Nvidia map — the only substantive public Nvidia map there is — and plot its fourteen components against where the company sits in 2026. **Not a single one drifted left.** Eight of fourteen went decisively right. Three got absorbed or went extinct ("general purpose computing is over"). Two stayed static. One — AI itself — got *promoted from a component to the anchor.* And CUDA didn't move at all on the evolution axis while its install base grew roughly a hundredfold. Most companies show at least one regression on a six-year window — a bet that went sideways, a component they tried and failed to push. Nvidia has none. That is the climatic pattern "everything evolves" being ridden by someone who refuses to fight it — a cleaner signature than luck or a bull market could ever leave. CUDA didn't move, and that is the point — a moat that absorbs the drift of everything around it without drifting itself. The rarest thing on the whole drift map is that the *anchor set itself* changed: 2020's anchors were device categories (Autos, Video games, Mobile), 2026's are user states (augmented worker, sovereign capability, physical autonomy). Redefining what the chain is *for* is the move you normally only see at the birth of an era. He did it deliberately, and it's the most consequential thing on the page. ![NVIDIA 2020 → 2026 drift: fourteen of Joaquín Peña Fernández's 2020 components plotted against their 2026 positions — not one drifted left](/images/blog/nvidia_drift_2020_2026.png) I had been reading evolution for years and never bothered to map the most-mapped company in tech. I just never looked. That is the kind of miss worth admitting plainly. ## 4. How Jensen plays it **Industrialise the layer below you so it can't bottleneck the layer above.** CoWoS is the purest example — two years of swarming dragged it from specialty packaging to mainstream, Custom→Product under deliberate pull. The same playbook runs for HBM, silicon photonics, eventually EUV. It is the AWS-with-servers move, except he runs it on *someone else's* supply chain because he doesn't want to own fabs. **Keep your differentiation layers perpetually in late-Custom.** Every hardware generation re-genesises the systems layer. NVL72, NVLink, Spectrum-X, kernel co-design with the labs — all of it *resists* the natural rightward drift. The line about engineers embedded in the AI labs, "nobody knows our architecture better than we do," squeezing 2–3× out of a customer's existing fleet, is the same pattern: never let the system layer settle into Product, because Product is where the ASICs catch you. And it isn't just a line. In June 2026 SemiAnalysis's InferenceX measured GB200 NVL72 serving costs for the Kimi architecture (the one behind xAI's Cursor Composer 2.5) falling 2.5× in under seventy days through *software alone* — largely NVIDIA's own kernel engineers rewriting the NVFP4 MoE kernel in CuTe-DSL to exploit the NVL72 copper backplane, which carries 18× the bandwidth of standard RoCEv2/InfiniBand. Same physical fleet, 2.5× cheaper to serve, because only the people who built the rack can rewrite the kernel down to its backplane. That's the co-design moat compounding in real time — the systems layer being dragged back into Custom faster than anyone outside the building can chase. **CUDA as the anti-commoditisation anchor.** Dwarkesh's sharpest question — your biggest customers can write their own kernels, so why does CUDA matter? — is a claim that CUDA is sliding from Product toward Commodity. Jensen's answer is install-base rather than technology: hundreds of millions of deployed GPUs across every generation and every cloud; the richness of the contributing ecosystem; being everywhere so developers never have to choose. That's deliberate — install base is the one axis that *doesn't* evolve leftward. A programming model can be re-implemented; hundreds of millions of deployed sockets cannot be re-created. **Refuse vertical integration into hyperscaling.** Becoming a cloud means owning a layer that's already Commodity, fighting four players with a decade head start, and turning your own customers into competitors. So instead he funds the neocloud tier — CoreWeave, Nscale, Nebius, Crusoe — backstopping CoreWeave up to $6.3B, $2B in directly, so a diverse Nvidia-native utility layer exists without Nvidia owning a watt of it. This is ecosystem-as-moat, executed with balance-sheet muscle rather than doctrine alone. **Don't pick winners at the model layer, even though you could.** He invests in all the labs (OpenAI ~$30B, Anthropic ~$10B as reported) precisely so he doesn't have to know which one wins. His stated reason is humility — "when Nvidia started there were 60 3D graphics companies, we're the only one that survived, and we'd have been at the top of the list *not* to make it." The Wardley reading is sharper than humility: the model layer is Genesis, Genesis has a failure rate you can't predict, so the correct move is to fund the whole distribution and harvest compute from all of it. The Anthropic-on-TPU "regret" he voices is the regret of not having had the balance sheet to run that strategy sooner. **The China argument, in map terms.** Export controls push China to build its own vertical stack — abundant energy, SMIC 7nm, Huawei CANN, domestic open models — which over time industrialises *an alternative utility substrate.* Once it exists and exports to the Global South, the Middle East, Africa, Southeast Asia, it becomes the default there, and the install-base moat is undermined not in the US but everywhere outside it. Dwarkesh counters that the near-term cyber-offensive risk justifies the price. Nobody lands the knockout. But Jensen's instinct — that conceding a market *accelerates* a competing stack's evolution rather than freezing it — is the same instinct that made him fund the neoclouds instead of letting the hyperscalers monopolise demand aggregation. It's coherent all the way down. One honest caveat before I leave Jensen, because I keep turning it over. The move I admire most — the directed investment that locks up custom, non-fungible TSMC capacity, the coordination that gets the whole chain to commit years early — is the *same* move that, under a demand shock, turns the moat into a bullwhip. A barrier built from non-fungible supply is a magnificent wall while demand holds and pure stranded cost the moment it wobbles. I come back to it in the risks, because it's the sharpest thing anyone has said against the position, and it's aimed precisely at the part of his game I find most impressive. ## 5. Oxide, mapped Oxide is interesting precisely because it doesn't compete with Nvidia on anything. Cantrill has been explicit about why, and it's the cleanest piece of strategy in the whole story: with Nvidia you either work *with* them or you compete *with* them, both are brutal, and because the stack isn't open there's no real value in it for Oxide either way. So they go somewhere else entirely — a different altitude, a different theory of evolution, a different target. That is reading the board and declining a fight you cannot profit from — the opposite of avoidance. The anchor Oxide is serving is "run our own cloud, on our own premises, without the kit-car tax." The customer already spends meaningfully on infrastructure — a bank, a telco, Samsung — and has hit the wall where they're paying hyperscaler rents for hyperscaler convenience but their workloads don't actually want to live there. How I read their map: - The **user-facing API** (console, CLI, Terraform provider, Kubernetes compatibility) is Product, deliberately AWS/GCP-shaped, because that's what their customers' engineers already know. This is the part they refuse to reinvent. - The **integrated control plane** (Rust, Illumos/bhyve, OpenZFS, on-rack VPC, block storage) is Custom Built stretching to Product — bespoke to the Oxide rack but industrialised relative to stitching OpenStack or VMware together. - The **rack-scale system** (DC bus bar, blind-mate backplane, 80mm fans at 2K RPM, 32 sleds, 2048 cores, integrated networking) is Custom Built, on purpose. This is the actual bet: that the *rack*, not the 1U/2U box, is the correct unit of design, and that the industry has inertia preventing the move. - The **network switch** (Tofino 2 + custom NOS on AMD) is Custom Built — the decision that defines the company and the reason Cantrill jokes they're "nine startups within one startup." - The **BMC / service processor** (custom silicon, Hubris real-time OS, no American Megatrends BIOS) is deep Genesis/Custom — the part where they're most philosophical, treating proprietary firmware as the original sin of the server. - **CPU (AMD Epyc), DRAM, NVMe, the Tofino ASIC** are bought as Commodity/Product. Oxide isn't a silicon company and doesn't pretend to be. - **Energy, floor, colocation** is utility — partnered out to CoreSite and friends. The shape is the opposite of Nvidia's. Nvidia's differentiation is a narrow vertical corridor in the *middle* of the stack. Oxide's is smeared *wide and shallow* — firmware, OS, hypervisor, network OS, rack mechanicals, control plane — anchored by a deliberately conventional API at the top and commodity silicon at the bottom. I'll be honest about what I got and what I didn't. Oxide always interested me — the ways of working, the culture, the engineering taste are exactly my kind of thing, and I'd been following them for that long before I followed them for the strategy. What I *didn't* get was the strategy — I could not read why the niche would hold. That changed the moment Simon Wardley, on one of the weekly Discord calls we ran for a while, walked through why there's a structural niche for an integrated on-prem computer *even in a world where cloud and serverless completely won.* The utility substrate doesn't eat everything; it leaves a pocket for the customer whose economics have inverted. Once I could see the pocket, the whole wide-shallow band made sense. I had the culture from day one; I needed the map for the strategy. ## 6. How Cantrill plays it **Industrialise the hyperscale rack.** The thesis is that AWS, Google and Meta discovered years ago that the rack is the correct unit of design and kept that knowledge inside their walls. Dell/HP/Supermicro have enormous inertia against rack-as-unit because their margin depends on selling 1U/2U boxes. Oxide takes a component that exists only as Genesis/Custom inside hyperscaler walls and drags it into Product for everyone else — AWS-2006, one layer up. "It is basically a racked personal computer" is the rhetorical version: a claim that the server industry has been sitting on a component that refused to evolve for 25 years out of incumbent inertia. **Attack the firmware layer specifically.** Cantrill's animus against AMI BIOS — it "somehow remained at the brainstem of server-side computing" — is strategically coherent. Proprietary firmware is a Custom component frozen by an oligopoly; nobody industrialises it because the vendors make more leaving it opaque. By open-sourcing Hubris and the whole firmware path, Oxide forces the component rightward, which unlocks all the integration above it. The layer below you is stuck, so you unstick it yourself. **Bundle the licence problem out of existence.** Traditional on-prem means buying VMware, a switch NOS, a BMC licence, a hypervisor, storage software, a management console — each with its own terms and renewal date, all Product-stage components the vendors prevented from collapsing into utility. "Everything included, one SKU" is industrialising the licensing layer. The customer reads it as simplification; strategically it's a co-evolution play against the entire on-prem software stack. **The AWS API as an anti-pattern moat.** The console and API are deliberately AWS-shaped because the *shape* of the cloud API is now Commodity and inventing a different one would be fighting gravity. Riding the commoditised shape frees the custom-build budget for the layers that matter — rack, switch, firmware. This is structurally identical to Nvidia letting Triton and PyTorch live above CUDA: a commodity interface above your custom layer is a feature rather than a threat. **Sell to customers who already lost the kit-car patience.** The target is the customer running thousands of cores who has internalised that the hyperscaler bill is a tax, rather than the long tail of enterprise IT. Samsung buying Joyent (where Cantrill's experience came from) is the archetype: cloud spend large enough that "go on-prem or die" became the CFO's mental model. This is a narrow market rather than a mass one — they had shipped under 20 racks as of mid-2024 — and that is Wardley-fine: harvest the segment where willingness to pay for integration is highest, while the integrated-rack category climbs its S-curve. ## 7. tinygrad, mapped tinygrad is the case that makes the whole thing interesting, because it points its weapon directly at the layer Jensen spent the interview defending. The mission, on the front page and in the deck, is "we will commoditize the petaflop." That is a Wardley sentence rather than marketing — "commoditise X" means force X from Product to Commodity, collapsing the margin of whoever sits on X. Hotz is describing the AWS-2006 attack pattern aimed one layer up: at the CUDA/ROCm programming model rather than the hardware. The anchor is "train or run a model on whatever GPU I can actually buy" — without Nvidia's supply allocation, without paying 70%+ CUDA rent, without owning the hyperscaler toolchain to get good performance. The customer is the researcher, the small lab, the openpilot-style embedded deployment, and aspirationally any hardware vendor who wants a framework that runs on their silicon without rebuilding PyTorch's whole compiler surface. How I read the map: - The **PyTorch-like Tensor frontend** is deliberately Product. Like Oxide with the AWS API, Hotz rides the commoditised user surface so he can spend his design budget elsewhere. - The **12-op UOps IR** is Custom Built with Genesis ambitions — the distinctive bet. Where CUDA is Turing-complete because GPUs are general engines, tinygrad's IR has exactly twelve ADD/MUL primitives with static memory access only. `x[3]` is allowed; `x[y]` is not. The claim is that neural networks provably don't need Turing-completeness, so paying for it — caching, warp scheduling, ISA-level branch prediction — is pure waste. Strip the feature that forces the layer to stay Custom, and the layer below gets cheap to replace. - The **lazy graph rewrite + op-fusion engine** turns the constraint into the advantage: twelve ops and no hidden control flow means the compiler sees the whole computation and can fuse a full forward+backward pass into one kernel. Custom Built, pointed at Product. - The **"AM" userspace AMD driver** is the most Wardley-interesting node — ~12,000 lines that memory-map AMD GPU registers directly and bypass ROCm entirely. The bounty for an RDNA3 assembler within 10% of LLVM is the last missing piece of a fully sovereign stack. This is the node the "force-it-to-commodity" arrow actually comes out of. - **Backend codegen** for PTX, RDNA3, Metal, Qualcomm is Custom Built but explicitly portable — "if you can schedule a dozen basic ops on your ASIC, you can run LLaMA on it tomorrow morning." - **tinybox** (~$15K, 6× Radeon 7900 XTX) is Product but deliberately not the money: "we make money selling computers for more than they cost to make." The box is a distribution vehicle for the software rather than the product. - **Consumer GPUs, PCIe chassis, PSU, wall power** are fully Commodity. Part of the thesis is that the substrate is *already* good enough — the $999 7900 XTX has the best FLOPS-per-dollar going; the only reason nobody in ML uses it is that the software doesn't work. Exactly the thing mapping is built to surface: a component already commoditised on one axis (price/perf) held back by an adjacent component (driver/runtime) that refused to industrialise. ## 8. How Hotz plays it — and why I don't buy it as strategy I want to be fair, because the *target* is correct and he was correct early. But "saw the right target" and "has a strategy" are different claims, and the evidence pulls them apart. Start with where he's genuinely right. **He found the load-bearing assumption.** CUDA is Product because it's general-purpose, and general-purpose is expensive because it carries features most NN workloads never use. Restrict the programming model to what neural nets provably need and the compiler gets whole-graph visibility while the silicon has far less to support. Hotz named the exact feature — Turing-completeness — that keeps CUDA pinned in Product, and is building a deliberately less-general alternative that's strictly more industrial. As a piece of *analysis* it's the cleanest example of feature-minimisation as a commoditisation vector I can point to in recent compute. The whole framework is 18,935 lines as of his December 2025 post — about 20,000 cleaned up. The entire assault on a stack measured in the millions of lines fits in a codebase you can read over a weekend. **He'll write the driver nobody else will.** Their sovereign AMD stack — driver, runtime, libraries, emulator — is roughly 12,000 lines that memory-map the GPU directly and skip ROCm entirely. AMD publishes enough docs to do this; ROCm just never got good. Anyone could have built a clean userspace driver; nobody did, because no party in the existing market had the right mix of skill, hunger, and willingness to take zero revenue for two years. This is negative-space arbitrage: the component stayed stuck because the incentives were wrong, and never because it was hard. **Software first, chip later.** His five-year post is genuinely sharp: "Only a fool begins by taping out a chip; it's expensive and not the hard part. AMD, Amazon, Tesla, and Groq have taped out fine chips, but only Google and NVIDIA chips have ever been seriously used for training. Because they have the software." Reading the AI-ASIC graveyard as a *compiler* failure rather than a hardware one is real map literacy. If the stack matures, any chip startup sitting on good silicon with no ecosystem gets a software path overnight. Now comes the part that stops me calling it strategy. Look at how the target actually arrived. tinygrad started in October 2020 as a toy to teach himself neural nets. The CUDA fight came *to* him through comma.ai — openpilot had to run its driving model fast on whatever embedded GPU was in the car, not an Nvidia datacentre part, and tinygrad on a Snapdragon 845 turned out roughly 2× faster than Qualcomm's own SNPE. He's the guy who unlocked the first iPhone and jailbroke the PS3; closed systems are simply what he breaks. So "disrupt CUDA" arrived as the next closed system, handed to him by a concrete need, rather than deduced from a map. That is the "lucky he saw it" part, and the seeing deserves full credit — the point is that it came from temperament and circumstance rather than from a plan. And the execution stays temperament all the way down. The company has raised exactly one round — $5.1M on a convertible note in June 2023 — and nothing disclosed since. Five years in, the public repo has real pull — about 33,000 GitHub stars and an active contributor base — but it's still at version 0.13 as of May 2026: genuine mindshare, still short of a 1.0 anyone bets a company on. The hardware business does "about $2M revenue a year" by his own account in the same December 2025 post; the tinybox is openly a distribution vehicle rather than a margin engine. Hiring is *only* through merged pull requests — "invest with PRs." The final mile of the sovereign stack, the RDNA3 assembler, is posted as a public bounty: get within 10% of LLVM, collect a thousand dollars. And the most visible "strategy" moment of the whole project was March 2024, when the tinybox Red's 7900 XTXs kept crashing on AMD's closed MES firmware and Hotz's move was to *publicly dare Lisa Su to open-source it* — which got him a personal "the team is on it," patched firmware, and a later MI300X sample, but no open firmware and no partnership. He won a support ticket by going loud. Set that next to Jensen sitting the Micron CEO down for three years until an entire memory roadmap bent toward a demand curve only Nvidia could see. *That* is what forcing a layer looks like when it's a strategy: a second actor convinced, capacity committed, the whole chain moved on purpose. Hotz has none of that machinery and isn't trying to build it. He has a brilliant, tiny, correct codebase, a $2M hardware side-business, and the bet that if the work is good enough the flywheel starts from the margin. Sometimes it does — and if it does here, he was right first and I'll say so out loud. But "be brilliant and correct and route around the incumbent and wait to be adopted" is a *posture* rather than a plan, and the difference between the two is the entire subject of this piece. ## 9. Where the three converge, and where I think they don't On the surface the philosophies rhyme. Jensen's "as much as necessary, as little as possible," Cantrill's "it takes the whole stack to build a cloud computer," Hotz's "the best part is no part" are all statements about where to draw the vertical-integration boundary. But they resolve in three different directions, and the maps say why. Jensen's "as little as possible" works because Nvidia sits *above* a supply chain other people are already industrialising. Every component below is drifting right under its own steam; his job is to accelerate it, not own it. The integration he refuses — hyperscaler, foundry, model lab — is integration into layers that are already Product or Commodity, where the marginal return is low and the brand-damage risk (competing with your customers) is high. Oxide's *maximal* integration is necessary because it sits above a supply chain that *refused* to industrialise. Commodity server hardware doesn't deliver hyperscale benefits because the chain locked a bad equilibrium — BIOS, BMC, 1U/2U, white-box-switch-plus-vendor-NOS — into Product and stopped. The only way through the inertia is to do all the integration yourself. "Nine startups inside one startup" is the cost of operating in a stuck market. tinygrad's minimalism works because it sits *below* a commoditised stack (PyTorch API, consumer GPUs, wall power) and *above* a substrate (AMD silicon) whose hardware is fine but whose software is broken. Hotz only has to write the thin wire connecting two already-good components that a market failure kept apart — his position never asks him to re-integrate the world. "Best part is no part" is the doctrine of that position. Three things fall out of putting the maps side by side. **Oxide and tinygrad are attacking the same pathology from opposite ends.** Oxide's target is the server that never industrialised because the vendors made more leaving it custom; tinygrad's target is the GPU driver that never industrialised because Nvidia made more leaving it CUDA-shaped. In both cases the component is technically at Product but economically frozen, and in both cases the move is to force it to Commodity from outside the oligopoly. Oxide does it with firmware and racks; tinygrad with drivers and compilers. The shape is the same; only the altitude differs. **All three ride a commoditised API upward as a budget-saver.** Nvidia lets PyTorch/vLLM/Triton proliferate above CUDA; Oxide ships an AWS-shaped console; tinygrad ships a PyTorch-shaped frontend. None of them reinvents the user's entry point; all three spend their custom-build budget further down. **Nvidia is the thing both refuse to buy from, at completely different altitudes.** Oxide doesn't want Nvidia's hardware because an AI-focused rack is wrong for general on-prem compute. tinygrad doesn't want Nvidia's programming model because CUDA's generality is the tax. Neither is a direct competitor — Oxide won't ship training rigs, tinygrad won't sell racks — but both are saying, at their own layer, "the thing Jensen sells has too many features and we have the discipline to ship a stripped version most of the market will eventually prefer." That is structural pressure rather than competitive pressure. The Anthropic-on-TPU deal is a competitor; tinygrad and Oxide are something different — early signs that the stack Nvidia occupies has Product-stage components that *could*, in principle, be forced toward Commodity. But "in principle" is doing a lot of work, and this is where my ranking comes back. Jensen is actively forcing his board, every year, with a coordinated supply chain behind him. Oxide is forcing a real but bounded niche, and knows it. Hotz has the right target and is mostly waiting for physics and the open-source gods to do the forcing for him. The map literacy is the same across all three; the odds of execution are wildly different. ## 10. What could break each thesis **Nvidia — and the bigger risk hides beneath the one a maps person reaches for first.** The deeper risk is that the demand Jensen is coordinating the whole chain around is partly a *bezzle.* This is Michael Burry's "Heretic's Guide Part III" thesis, and once you put it on a map it's hard to unsee. The "insatiable AI demand" the bulls cite is inflated by *tokenmaxxing* — a temporary, leaderboard-driven training-and-benchmarking phase whose real mechanic is enterprises racing to harvest *traces* to train their own in-house models. It sits in Genesis on the value chain and is, by design, temporary: in Wardley terms it's the *Leverage* phase of a hyperscaler Innovate-Leverage-Commoditize play being mistaken for steady-state demand. And that distorted signal bullwhips straight upstream into the exact move I praised — Nvidia's directed investment into custom, non-fungible TSMC lines. Burry puts the forward purchase commitments at $182B, roughly $119B of it with a single customer, more than Nvidia's annual operating cash flow. Non-fungible capacity is a wonderful barrier while demand holds and stranded cost the instant it doesn't. The receivables tell he flags — the top customer's A/R growing 13.4× against 4.9× revenue, inflecting *up* as a share of receivables while *down* as a share of revenue, "a zig where there were only zags" — is the weak signal that the Leverage phase is being pulled forward to beat the print. Underneath it all is a duration mismatch: GPUs economically obsolete in under a decade, the data-center debt behind them running 15–19 years, taken out through an offshore chain of data-center ABS, private credit, and Bermuda captive reinsurers, with power as the real rate limiter (a ~19 GW shortfall by 2028). And here's the twist the SemiAnalysis number sharpens: efficiency itself is compression — a serving cost falling 2.5× in seventy days means each financed GPU does far more far sooner, great for Jensen's TCO case and brutal for anyone who overbuilt non-fungible capacity against a temporary signal, because the same co-design win that deepens the moat also thins the demand for the capacity it's already committed to. All of this leaves AI real and Jensen right about evolution; the claim is narrower. The single most impressive thing about his game — the coordination that makes an entire supply chain commit years early — is also the mechanism that maximises the damage if what it is committing to turns out to be the benchmarking phase rather than the steady state. The better he coordinates, the more he strands when the signal breaks. Mastery and fragility turn out to be the same move seen from two sides, which is the most interesting thing I can say about him, and the reason the admiration in the short essay isn't the whole story. ![The AI compute & financing value chain — the bezzle mapped: temporary tokenmaxxing demand bullwhipping into custom TSMC commitments and an offshore financing chain (after Burry's "Heretic's Guide Part III")](/images/blog/ai_compute_financing_burry.png) The shallower, slower risk is the CUDA one. If the hyperscalers' custom kernel stacks (OpenAI's Triton work, Anthropic's TPU training, Google's JAX/XLA) mature to genuine substitutability at their level — or a minimal stack like tinygrad's becomes the reference compiler for non-Nvidia silicon — then Nvidia defends on perf/TCO alone, a quantitative fight against ASICs with 65% margins instead of its own 70%+. His answer — that perf/TCO on InferenceMAX and MLPerf is uncontested and the ASIC vendors decline to show up — is strong near-term and fragile long-term. The Anthropic/TPU multi-gigawatt deal is the obvious canary; tinygrad's sovereign AMD stack is the less obvious, more structural one. But next to the bezzle, this is the comfortable risk — the one that plays out over years, and the one Jensen can see coming. **Oxide.** The early-Product question is behind them — the racks ship and the niche is real. The risk that remains is the size of the pocket: Oxide can be brilliant and still be structurally capped if the integrated rack stays a niche for customers who hit specific on-prem walls rather than becoming a mainstream Dell/HP replacement. The counter-factual is that GPU-heavy AI workloads force the hyperscalers' own integrated racks (GB200 NVL72 et al.) to become the category reference, leaving Oxide a real but bounded general-compute pocket. **tinygrad.** The risk is the one Jensen names without naming tinygrad: the CUDA moat is an *install-base* moat rather than a technical one, and technical elegance does not evict install bases. tinygrad can be provably better at compiling NN workloads and still fail against hundreds of millions of deployed sockets, thousands of CUDA-tuned research codebases, and a decade of habituated muscle memory. The pessimistic scenario is Plan 9: objectively cleaner than Unix, a niche curiosity for thirty years. The optimistic one is a handful of chip startups with decent silicon adopting the tinygrad stack as their default compiler and the flywheel starting from the margin. Which one obtains should be visible within three years. And notice what the June 2026 NVL72 result says about *where* the moat actually sits. tinygrad aims at CUDA's generality — the Turing-complete "tax." But that 2.5× came from system co-design rather than from generality: an embedded kernel team rewriting an FP4 kernel in CuTe-DSL to one specific rack's copper backplane. A portable, rack-less, kernel-team-less stack can't answer that, however clean its IR is. Hotz can be completely right that neural nets don't need Turing-completeness and still be aimed at the wrong layer of the wall — the generality, when the load-bearing part is the rack-plus-kernel-team co-design loop. And a cross-cutting risk for both challengers: each bets its downstream will accept a new API surface *shaped like the incumbent's* — Oxide that enterprise devs treat its rack like an AWS region, tinygrad that researchers treat its frontend like PyTorch. Nvidia has mostly already won that fight and doesn't have to. All three are pushing for the interface they control to become the Commodity interface at its altitude. That's the real long game for each — even though the layers are completely different and none of them, in any conventional sense, competes with the others. --- ## Further reading - Dwarkesh Patel, [Jensen Huang interview transcript](https://www.dwarkesh.com/p/jensen-huang). - Simon Wardley, [Value chain mapping – finding a path](https://www.computerweekly.com/feature/Value-chain-mapping-finding-a-path), Computer Weekly. - Oxide Computer, [The Cloud Computer](https://oxide.computer/blog/the-cloud-computer). - Bryan Cantrill on [Software Engineering Radio #709 — the Data Center Control Plane](https://se-radio.net/2026/02/se-radio-709-bryan-cantrill-on-the-data-center-control-plane/). - The Pragmatic Engineer, [Startups on hard mode: Oxide Part 1 – Hardware](https://newsletter.pragmaticengineer.com/p/oxide). - George Hotz, [Five years of tinygrad](https://geohot.github.io/blog/jekyll/update/2025/12/29/five-years-of-tinygrad.html). - George Hotz, [the tiny corp raised $5.1M](https://geohot.github.io/blog/jekyll/update/2023/05/24/the-tiny-corp-raised-5M.html) — the original "commoditize the petaflop" essay. - Latent Space, [Commoditizing the Petaflop — with George Hotz](https://www.latent.space/p/geohot). - Phoronix, [Tiny Corp Nearing Completely Sovereign Compute Stack For AMD GPUs](https://www.phoronix.com/news/Tiny-Sovereign-Stack-AMD-Close). - Tom's Hardware, [AMD's Lisa Su steps in to fix driver issues with TinyBox AI servers](https://www.tomshardware.com/pc-components/gpus/amds-lisa-su-steps-in-to-fix-driver-issues-with-new-tinybox-ai-servers-tiny-corp-calls-for-amd-to-make-its-radeon-7900-xtx-gpu-firmware-open-source) — the March 2024 firmware standoff. - Joaquín Peña Fernández, [A Wardley map of the company NVIDIA 2020](https://joapen.com/blog/2020/09/07/a-wardley-map-of-the-company-nvidia-2020) (CC BY-SA 4.0). - Michael Burry, [The Heretic's Guide to AI's Stars Part III — Tracepalooza & the Bezzle](https://michaeljburry.substack.com/p/the-heretics-guide-to-ais-stars-part), *Cassandra Unchained* — the financing / bezzle counter-thesis. - SemiAnalysis, [InferenceX™](https://github.com/SemiAnalysisAI/InferenceX) — the June 2026 GB200 NVL72 serving-cost measurement (2.5× in <70 days on the Kimi architecture, via a CuTe-DSL NVFP4 MoE kernel rewrite). --- *Analyzed and edited with AI and [swamp](https://github.com/swamp-club/swamp).* --- # swamp-go-brr, the brain - Date: 2026-06-19 - Tags: swamp, agents, firecracker, issue-lifecycle, automation - URL: https://magistr.me/blog/swamp-go-brr-the-brain/ Last post I built a cage — a Firecracker microVM to hold an agent I had let off the leash. This post is about what I put in it, and why the thing I put in it is a state machine and not a swarm. It started with a question I had been circling for a while. My engineering already runs through `issue-lifecycle`: Claude researches and plans, I review and correct the plan, and it implements against tests. It works, and over time the repository fills with more than code — the methodologies, the architecture decisions, the patterns and antipatterns Claude hit along the way, and a set of UAT/BDD scenarios that pin the behaviour. The process writes its own knowledge base. But it needs my hand on the wheel for every plan and every correction. So the question was: what if the principles and the tests are good enough that I could throw a task at it and walk away? ## Not a swarm There is a fashionable answer to that, and I did not want it. You can hand the whole thing to a swarm of agents — Gas Town and its kin — and let them improvise their way to a result, spawning sub-agents, negotiating, retrying, until something falls out the end. It is genuinely impressive, and I cannot reason about it. I cannot tell you why it did what it did, I cannot replay it, and when it goes wrong I cannot point at the transition that broke. For a loop that runs unattended, with my credentials, on real code, "impressive and impossible to reason about" is exactly the wrong trade. I wanted the orchestration deterministic and the non-determinism quarantined to the leaves. ## Brain and hands So I asked Claude to design `swamp-go-brr` the way I build everything else — through `issue-lifecycle` — but with the human removed from the execution loop. What came out has a clean split. The brain is `gobrr`: a pure state machine, a Run aggregate over a dynamic task DAG, and nothing it does is an LLM call. It seeds the DAG in one batch; it leases ready tasks to workers, one per call, up to a concurrency cap; it reaps any task whose lease lapses on a heartbeat TTL, so a worker that dies in its microVM does not wedge the run; it caps total attempts so a task that keeps failing surfaces instead of looping forever; and it moves each task through its states on the verdicts it is handed. Every one of those is a deterministic transition I can inspect and replay, because it is swamp state on disk, not an agent's short-term memory. The hands are a thin driver: ask `gobrr` for the next ready task, build the work order, spawn a `claude` to do it, report the result back, repeat until the DAG is green. The only non-determinism in the whole system lives inside one leaf at a time — inside a microVM, behind a gate. ## The agent proposes; the state machine disposes The part I like most is how decomposition works, because it is where most "autonomous" systems quietly cheat. The agent decomposes the goal: it reads the repository and breaks the work into tasks, each with a spec, an explicit write-allowlist, and its dependencies. But `gobrr` does not trust it. It validates the decomposition mechanically and refuses a bad one — it derives each task's gate and forces the tests to be separated from the code, and it rejects a task whose write-allowlist smears across both. The creative step is allowed to be an LLM; the structural rules that keep it honest are code. The other half of a good decomposition is sizing, and this is where Claude's planning mode quietly earns its keep. Left to plan, it produces tasks at a grain where — with the `issue-lifecycle` skill loaded — a single agent carries one from zero to completion inside a 1M-token context window, without running out of room mid-task. And on the off chance a task's scope is still too large, the agent does not thrash against the ceiling: it files a follow-up and finishes what it can. Right-sizing is essential here, because it is what lets a leaf run to done unattended. The DAG is the schedule, a role that goes beyond simple bookkeeping. File-disjoint tasks with no dependency between them are independent by construction, so they run at the same time. A task that needs another's output simply waits for it. The shape of the decomposition _is_ the parallelism, which is why the validator cares so much about getting it right. From there the loop is four models, one job each, and no model trusts the next one's output. `gobrr` schedules. The driver leases a task and hands the microVM fabric a `claude -p` with a crafted work order. The leaf does not write to the repository — it emits its files inside a fenced work-contract envelope, and a separate integration model parses that envelope and applies it as one base-isolated change behind the task's write-allowlist. That is the isolation invariant: code is only ever _authored_ inside a VM, and the host applies a reviewed diff rather than running anything the agent produced. Then a containerised verifier gates the change in a `--network none`, read-only box and returns an exit code. If the exit code is green, the base advances; if it is red, the task bounces back to pending for another attempt. The one structural subtlety worth calling out: every task branches off a single fixed base, so a task that imports a sibling's brand-new file will fail its own isolated gate — the file is not on its base yet. The fix is to sequence by dependency. Build the independent units first, rebase the green ones into a linear stack, advance the base to the top of that stack, and only then seed the dependent round — embedding the exact export signatures from the finished units into the next round's prompts so the imports resolve on the first try. ## The fork I did not take There was a more ambitious design sitting right there, and I want to be honest that I looked at it. I could have made the thing recursive: put swamp itself inside each microVM and let a leaf spawn its own sub-VMs, a fractal of agents decomposing their own subtrees all the way down. It was too much — more blast radius, more state to reason about, more ways to deadlock, for a payoff I did not need. I kept the orchestration in the one main VM and had Opus split the task into subtasks that feed a single flat pool. The final design has one conductor, many hands, and no recursion. It is simple, it works for now, and it is a good enough place to start. ## Why it is safe to walk away None of this would be safe to leave alone if the agent were starting cold. It is not. The reason I could even consider taking my hand off the wheel is that `issue-lifecycle` has spent months writing the foundation down: the architecture decisions, the patterns and antipatterns, and — the load-bearing part — the UAT and BDD scenarios that say what "working" means. An autonomous loop is only as trustworthy as its definition of done, and mine is concrete: it is a test suite the process built for itself. The agent in the leaf is free to be creative, but the gate it has to pass is deterministic. ## If you are building one of these I think a lot of people are about to build some version of this, so here is what actually held and what bit me. **The pattern that carries the whole thing: the agent proposes, the state machine disposes.** Let the LLM do the creative, fuzzy step — decomposition, code — and put every rule you actually depend on into deterministic code that can refuse its output. If your orchestrator is itself an LLM, the non-determinism remains, just moved up a level. **Quarantine the non-determinism to the leaves.** This means one agent, one task, one sandbox, and one gate. Everything between the leaves should be replayable state you can open after the fact and read in order. When something goes wrong — and it will — you want a specific transition to point at, which is a more direct diagnostic than re-reading a transcript. **Make "done" a gate the agent cannot argue with.** A green test suite in a `--network none`, read-only container is worth more than any amount of the agent telling you it is finished. No model trusts the next one's output; each one checks. **What bit me.** The verify gate ran the tests but not the formatter or the linter, so those failures only surfaced later at publish time — your gate is exactly as good as what you put in it, and no broader. Isolation is always along _some_ axis: network namespaces isolated the network but not `/tmp`, and a shared control-plane file clobbered across concurrent VMs until I keyed it per namespace. A read-only verify box means the toolchain has to be baked in and offline ahead of time, with the lockfile-writing turned off, or the run dies on a write it is not allowed to make. And I learned that retries are only effective with better instructions; a task that bounced on a type error passed only when I put the exact cast into its spec, because the second attempt needs improved guidance to succeed, which is more deterministic than another roll of the dice. ## The one gate I keep I keep exactly one transition for myself — the publish gate — for the reason I gave in [the cage post](/blog/build-the-cage-first/): the loop is allowed to write the code and prove it green, but deciding what is allowed out into the world is mine. I proved the rest on a real task, self-hosting a Bluesky PDS end to end while I watched, and I have _not_ shipped what it built, because there is no adversarial-review pass on it yet. That is the shape I am comfortable with: autonomy I can reason about, the creativity boxed into leaves, the structure held in a state machine, and a human on the one gate that matters. The swarm can have the Overton window. I will take the thing I can replay. This is a first working version, and there is more coming. Next I am hardening `swamp-go-brr` and wiring it with telemetry. --- # Build the cage first - Date: 2026-06-15 - Tags: swamp, firecracker, agents, serverless, wardley - URL: https://magistr.me/blog/build-the-cage-first/ Two of Simon Wardley's predictions have sat on my map for years: that serverless was the next evolution of devops, and that conversational programming was the one after it. Both came true — the first quietly, the second all at once. I wanted to write about the evolution of serverless for a long time, but I never found the hook. I had gone looking for it and was underwhelmed. Serverless was real, but adoption stayed narrow, finding use in glue functions and cron jobs, but in nothing like the platform shift the map implied. The most interesting thing I read in those years was [Erik Bernhardsson's](https://www.latent.space/p/modal) account of building Modal. They threw Docker out and wrote their own container runtime and a lazy-loading filesystem in Rust, for Python only, because general-purpose containers were simply too slow to feel serverless. As inference and training costs climbed, _serverless GPU_ finally started to make sense, where you pay by the second and scale to zero, because an idle H100 is a fortune. Then the second prediction landed and made the first one matter. Conversational programming stopped being a forecast and became how I work. And when I looked at what was actually under the boring, CPU side of serverless — under AWS Lambda, under Fargate, under [System Initiative's](https://github.com/systeminit/si) function execution — it was the same engine every time: [Firecracker](https://github.com/firecracker-microvm/firecracker/blob/main/docs/design.md). A microVM AWS built to run strangers' code, at Lambda scale, without those strangers reaching the host or each other. Firecracker is deliberately tiny. No GPU passthrough, barely any devices — [a handful of virtio interfaces](https://github.com/firecracker-microvm/firecracker/discussions/4845) and nothing else. For the GPU crowd that is a dealbreaker; you go to Cloud Hypervisor instead. But I did not need a GPU. I needed a box I could trust around code I did not write, and Firecracker's whole minimalism _is_ the security story. The thing that made serverless safe was about to become the thing that makes agents safe. That was the hook. ## The reason The problem began with a question about my own work. I already run my engineering through a state machine. It is my own flavour of [`issue-lifecycle`](https://swamp-club.com/extensions/@magistr/issue-lifecycle), built on Paul Stack's Booking talk and swamp-club's own version, then extended with DDD, TDD, BDD, and planning loops. It works. Claude researches and plans, I review and correct the plan, and it implements against tests. I built a whole project, resinsim, from the ground up that way. A nice second-order effect is that the repo ends up holding more than code: it contains the methodologies, the architecture decisions, the patterns and antipatterns found while Claude worked the tasks, and a set of UAT/BDD scenarios that pin the app's behaviour. The process writes its own knowledge base. It needs my hand on the wheel, however, for every plan and every correction. The question would not leave me alone: what if the principles and the tests are _good enough_ that I could throw a task at it and walk away? The whole foundation already exists, co-designed in `issue-lifecycle`. So I asked Claude to design [`swamp-go-brr`](https://swamp-club.com/extensions/@magistr/swamp-go-brr), which is the same lifecycle with the human taken out of the execution loop. Not Gas Town: I did not want a swarm of built-in agents improvising non-deterministically. I wanted the orchestration to be deterministic and living in swamp, with the agent only filling in the leaves. The plan that came back had a requirement I could not argue with: **isolation**. An autonomous loop that web-searches test harnesses and runs untrusted code, on my machine, with my credentials, is Simon Willison's [lethal trifecta](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/) with the safety off. It is private data, untrusted content, and a way out, all at once. It is remote code execution by design. So I paused work on the brain and went to build the body it would need. A microVM is a hardware-isolated blast radius for an agent you have let off the leash. **Build the cage first.** ## Where the cage drew blood I built both extensions from zero: the microVM lifecycle and the host↔guest control plane. The interesting part, and the part worth a post, is everything that fought me. **The rootfs.** The guest started as Alpine/musl, and musl fought back with missing CA certs and BusyBox quirks. It also fought back over a `claude` binary that is glibc-only and did not want to live there. I gave up and rebuilt the rootfs with `debootstrap --variant=minbase` on Ubuntu, layering in the glibc `claude-linux-x64` binary and the few tools the agent needs. It was a rediscovery of the first lesson of serverless: stop fighting the general-purpose userland and specialise the image. **The kernel that wouldn't give me randomness.** TLS inside the guest just hung. Every Claude API call needs a TLS handshake, every handshake needs random bytes, and the legacy 4.14 `vmlinux`'s old `crng`/`getrandom()` behaviour _blocked_ on entropy at boot. A fresh microVM has no entropy pool. The fix took three belts: a modern CI kernel (`vmlinux 6.1.128`), the PID-1 agent manually seeding 64 bytes from `/dev/urandom` into `/dev/random` via `RNDADDENTROPY`, and a virtio-rng device wired in before boot. A footnote that cost real time is that if you change the kernel, you must re-bake the snapshot. **The agent is the init system.** There is no point booting systemd in a VM that lives for one task, so the kernel boots straight into `init=/opt/fc-agent.sh`. The agent runs as PID 1 and never exits. It mounts its own pseudo-filesystems, brings up the NIC, and seeds that entropy. Then it does the thing I did not see coming: it syncs the clock by reading the `Date:` header off the task server with `curl -I`. A microVM has no RTC, so it boots in 1970, and a clock in 1970 fails TLS certificate validation before it can even complain about entropy. Then it polls for work. There was one last indignity: `claude --print` _hangs_ on a permission prompt and refuses `--dangerously-skip-permissions` as root, unless you set `IS_SANDBOX=1`. This is fair. The microVM **is** the sandbox; I just had to say so. **The concurrency fork, where I was confidently wrong.** The moment you want a second agent, the baked-in guest address (`172.16.0.2`) collides. My instinct was to de-bake it and pass the address in on the kernel command line. A review killed that idea as fundamental: the cmdline is read once at boot, and the workflow does not boot, it _restores from a warm snapshot_ — a frozen image whose network state is already in memory. My fix was inert on the exact path that makes the thing fast. The right answer, from Firecracker's own "network for clones" recipe, is the opposite of my instinct. You do not re-address the guest; you _isolate_ it. You keep it byte-identical and wrap each clone in its own network namespace, with its own TAP, a veth pair, and a double MASQUERADE. This way, one base snapshot restores into N identical clones that cannot see each other. I enjoyed one detail: Linux caps interface names at 15 characters, so the root-side veth name has to be hashed from the namespace or two clones collide on the name instead of the IP. **The bug I caught before it bit.** This is the one I am proud of. A network namespace isolates the _network_, but it does not isolate `/tmp`. The control-plane server keyed its files by `tapPort`, which is hardcoded to 8080 in every guest. This meant that six concurrent VMs would all share `/tmp/fc-task-8080.json` on the host. A task injected for one could be served to another, and results would clobber each other. The netns had fixed the IP overlap and left a file overlap one layer down. The fix is a two-line key, `netns-tapPort`, but the lesson is that "isolated" is always isolated _along some axis_, and you have to name the axis. The rest of the issues were small traps, which I will cover briefly. The vsock throws an "address in use" error when you restore concurrent VMs from one snapshot because of stale sockets and a baked-in path, which requires a per-VM override and cleanup. You cannot tear a VM down with `pkill firecracker` once a second one exists, so a PID sidecar gives you a precision kill. Tearing down a namespace leaves the host's NAT rules behind unless you tag each with a comment and flush by it. None of these issues are hard. They are all invisible until the second VM exists, and then they arrive at once. The working shape is a 6.1 kernel and a 512 MiB / 2-vCPU guest that costs ~45 MiB of host RAM. It is booted once and frozen into a warm snapshot so a restore is sub-second. Firecracker's own people quote 150 microVMs a second per host. The `wait_serial` command watches the serial console for the agent printing `worker ready; polling for tasks` before it bakes the snapshot. That is how you know what is inside is alive before you freeze it. ## The token The agent in the guest runs `claude -p` with my `CLAUDE_CODE_OAUTH_TOKEN`, and that is within terms. The token is scoped to Claude Code, and Claude Code is exactly what it is running, on my own work, inside a sandbox. The control plane injects it only at serve time on `GET /task` (it validates the `sk-ant…` prefix), never writes it to the guest's disk, and the guest reaches `api.anthropic.com` directly over its TAP interface and host NAT. Nothing proxies it and nothing stores it. ## The cage, with something in it Then I un-paused the brain and pointed the whole stack at a real task: `/swamp-go-brr create a swamp extension to self-host a Bluesky PDS and post to it, deployed to Unraid via docker-compose`. Opus 4.8 was the conductor. It read the goal, decomposed it into a DAG of file-disjoint tasks, and `gobrr` — the deterministic state machine — only validated and scheduled them. It refuses a bad decomposition rather than improvise one. The `fabric_up` command brought up five warm microVMs in five network namespaces. Round one consisted of four libraries, built in parallel, each in its own VM, and each just a `claude -p` with a crafted work-order. The host never ran a line of the agent's code. It parsed the returned diffs and applied them behind an allowlist, because of the isolation invariant that code is only ever _authored_ inside a VM. Then it gated each change in a `--network none`, read-only container. Two passed on the first try. Two bounced on a type error and a wrong field name, and passed on the retry. I rebased the green ones into a stack, advanced the base, embedded the exact export signatures into round two's prompts so the imports would resolve, and built the two swamp models on top. When assembled, it had 51 tests, zero failures, and a clean `swamp extension push --dry-run`. My total input across roughly fourteen hours was the kickoff, one interrupt, one "continue", and one approval. It built `@magistr/bluesky-pds` end to end. I have _not_ published it, as there has been no adversarial-review pass on it yet, and that judgement is still mine. The cage works; deciding what is allowed out of it does not. The tuning to get there was its own set of small cruelties, which is why this became two posts. The verify gate runs with `--network none`, so you need a digest-pinned, fully-offline deno toolchain image baked ahead of time. The `--no-lock` flag is mandatory or deno tries to write `deno.lock` into the read-only tree and dies. You must read the result from `dv current`, not `dv result`, or every task reports `exitCode: null` and the loop politely ignores all of them. And because every task branches off one fixed base, anything importing a sibling's brand-new file fails its isolated gate. So you do the independent pieces first, rebase, advance the base, and only then seed the dependent round. ## Back to the map There is nothing surprising about an agent running on a microVM. That is just how value chains work: the novel thing at the top of the stack rides on the boring, industrialised thing at the bottom, and the more commoditised the bottom gets, the more freely the top can move. Autonomous agents are the new capability, and hardware-isolated microVMs are the utility underneath. The only detail worth noticing is _which_ utility they landed on — the same stripped-down box AWS built to run Lambda, doing a second job nobody scoped it for. I built the cage first because autonomy without a blast radius is not autonomy; it is a liability. The next post covers what I put in it: [`swamp-go-brr`, the brain](/blog/swamp-go-brr-the-brain/). --- # The shape of the decision - Date: 2026-06-13 - Tags: swamp, good-planning, finance, amsterdam - URL: https://magistr.me/blog/the-shape-of-the-decision/ I meant to buy a flat in my second year here. Then life had other plans. After a hard stretch I will not lay out in full — climbing out of something, mostly — came a year of just making things stable again, and then a year given over to the language. That last one was not only vocabulary drills: it was the inburgering exams — reading, listening, speaking, and KNM, the Knowledge of Dutch Society paper — the civic-integration set you clear on the way to staying here for good. Suddenly it is the middle of year five, the year residency actually comes into view, the exams close and booked, the language nearly done, and I can feel the capacity opening back up. So it was time to actually look. Two things pushed me from "someday" to "now." One was a clear-eyed write-up by fellow expats on what buying in the Netherlands actually involves — the kind of thing that turns fog into a checklist. The other was watching someone I train with go through it in the next lane over. His case is harder than mine, not simpler: he is a zzp'er, and a freelancer's income is exactly the kind a Dutch lender squints at. Between that, some investments, and a student loan he treats as cheap leverage — money he would rather keep working in the market than rush to repay — he spent two weeks redoing his bookkeeping just so a private-banking consult could tell him whether he would get a mortgage at all, and for how much. Watching someone do the hard part beside you is weirdly motivating. There is a tempting shortcut here: put your gross salary into the ABN calculator and out comes a number. If you are a straightforward salaried case, that number is most of your answer. My case is not, and I suspect most people's are not once they actually look. (Patrick McKenzie has quietly rewired how I think about personal finance — treat it as a system you can inspect, not a mood you are in.) The real number is composed of more than salary. It has to include the 30% ruling — the expat tax break that ends for me on a known date in September, quietly taking a chunk of net income with it. It has to include a raise landing next month. It has to include an employee share-purchase plan that pays out a couple of times a year — you buy in at a discount, so a little profit is dependable and the rest rides the market. And it has to include the *kosten koper* — the cash you need on the table to transact at all, which no affordability calculator ever shows you. There are too many moving parts to hold in your head and still call it honest. I had done a smaller version of this years ago, in Saint Petersburg. There the Raiffeisen app just *showed* me the facts, with a clean breakdown of what I spent and decent analytics built right in. The surprise then, and again now, is that spending is mostly stable; you assume your money life is chaos and it mostly is not, you just have not looked at it straight. Here, no Dutch bank gives me anything close to that. If I wanted the picture, I would have to build it. So I built it. I put my payslips, my income, and my spend into a planning model — [good-planning](https://swamp-club.com/extensions/@magistr/good-planning), the swamp extension I built off Bovolon's framework — and it produced an analysis grounded in facts. It showed me where the money actually goes. It showed me what could be trimmed and what cannot. It showed me what I can genuinely afford, what my cashflow looks like now, in a year, and after the ruling ends in September, and what shapes a mortgage could take around all of it. The part worth stealing is the model's structure. The model is a state machine for a decision — [Bovolon's](https://bovolon.substack.com/p/good-planning-bad-planning) four layers, made queryable. It clarifies what I am assuming, with each assumption tied to a signpost that tells me when it is breaking. It makes explicit what I have actually committed money to — because the real plan is composed of the commitments you have funded and protected, not the boxes on a Gantt chart. It shows how those commitments line up in time. And it contains the part that earns its keep under pressure: a ceiling and a floor. A ceiling is the first place success would bind, with relief pre-cleared before I hit the trigger. A floor is a set of tripwires that fire pre-decided pullbacks, and a maximum loss I have drawn a line at and will not cross. A plan you can only admire tells you the target. A plan you can steer tells you what to do when reality moves. The benefit I did not expect was quieter than that. Writing the tripwires down externalized the risk, taking it out of my head. The thing that used to circle at one in the morning — what if this, what if that — is now a line in a model with an answer I already decided, calmly, in daylight. I do not re-litigate it every night. I decided it once, and the model holds it for me. What came out the other end was, in effect, the package you would pay a financial adviser and a mortgage adviser for, and it came out of Claude and the planning skill in an afternoon. The same line from [the other piece](/blog/a-feed-to-think-with/) applies: that analysis is most of what those advisers sell, but the responsibility to manage it is still mine. The model does not carry the consequence home. I carry the consequence home. The flat is the visible decision. The plan underneath is the real one — the shape I test every apartment against. Knowing my limits before I started looking did not make the choice for me. It just means that when the right place shows up, I will already know whether I can say yes. --- # A feed to think with - Date: 2026-06-13 - Tags: swamp, good-planning, moldable-development, amsterdam - URL: https://magistr.me/blog/a-feed-to-think-with/ The first night I got access to move.nl I spent four hours reading apartment listings and went to bed at one in the morning. I built a tool to watch the market so I do not have to. The decision is still mine. The feed was "filtered" — budget, a couple of postcodes — but filtered the way a firehose is filtered when you put your thumb over the end. Every listing still had to be opened, read, judged. Energy label here, VvE contribution there, is it on a busy road, what's the onderhoud, does it actually have a bathtub or just a photo of a shower. The broad filter handed me volume. What I needed was signal. I do not do this for a living, exactly. But somewhere along the way it became my default: when I have a question, I build a small tool to answer it — [moldable development](https://moldabledevelopment.com), if you want a name for it. So building one here was the obvious move. The tool was not the start, though. The start was a plan. A while back I read [*Good Planning, Bad Planning*](https://bovolon.substack.com/p/good-planning-bad-planning) and turned its four-layer model into a swamp extension — [`good-planning`](https://swamp-club.com/extensions/@magistr/good-planning) — a self-contained state machine for a strategic choice: the funded commitments, the assumptions under them, the tripwires that tell you an assumption is breaking. I had been reaching for that shape for a while. I track progress on a kanban board like everyone else, and kanban boards are too manual and hold none of the context that makes a card mean anything. A state machine holds the context. It knows what it is for. I used `good-planning` first to [understand my own cashflow and my limits](/blog/the-shape-of-the-decision/) — what I could actually commit to, where the edges were. That mattered more than any listing. Once I knew the shape of the decision, the apartments were just instances to test against it. The same instinct ArcKit gives me when I need to think through something complicated is that it asks the questions I would forget to ask. It is the same instinct behind [`issue-lifecycle`](https://swamp-club.com/extensions/@magistr/issue-lifecycle), another swamp extension, which drives work to done without me babysitting it. You can externalize the thinking into something that holds state, and stop carrying it in your head. So I turned to move.nl — a perfectly good website and a perfectly useless feed for *reasoning*. The part I still find a little magic is how I got in. I did not reverse-engineer the auth by hand. I did one normal login in the browser, exported the session as a HAR — a full network capture, cookies and redirects and all — and handed the file to Claude. It read the Keycloak silent-SSO flow straight out of the capture and built it into a swamp model, token auto-renewal included, so the thing logs itself back in and keeps running. I never read a line of the auth code. I gave it a recording of my browser doing it once, and described what I wanted out the other end. The model — `move-dossier` — pulls my whole saved search into structured data. It has about fifty fields per listing: type, year, energy label, VvE bijdrage, €/m², bathtub yes/no, floorplans, even the bid deadlines and notary clauses parsed out of the free-text description. The feed is data now, not a wall of ads. Then I enriched it. The things that actually matter about a place are the things you cannot see in the listing: the buurt, the crime rate, the income mix, the sale history, the energy profile of the street. A second swamp model — `nl-property-intel` — takes one address and fans out to half a dozen Dutch public sources to fetch exactly that, built to shrug off a dead scraper instead of falling over. One address in, one clean dossier out. Then came the filtering, and this is the part that mattered most: I encoded my requirements as code, once. A bathtub is required. The energy label must be C or better. The apartment cannot be on a busy road — with the specific Amsterdam streets I will not live on listed by name. The onderhoud must be at least Goed. The VvE must be healthy. The requirements stopped living in my head, where they drift and get tired at midnight, and started living in the model, where they do not. The last move was about attention. I started with real-time email for every new ad the moment it posted. I killed it; those go to a folder I never open now. The whole pipeline — pull, enrich, filter — runs on a cron once an hour. But the ping is rare. Only about 8% of Amsterdam apartments even have a bathtub, and that is before energy label, road, onderhoud, and VvE. A listing that clears all of it is scarce: a ping lands maybe once every few days, and when it does, it has already passed every bar I care about. Its floorplan is included. One rare ping that cleared every filter is worth more than a hundred daily emails that cleared two. The signal went up; the noise went to a folder. Here is the uncomfortable part. With the dossier, the enrichment, and the planning model, I had most of the information my makelaar and my hypotheek adviser were giving me. The numbers, the comparisons, the "is this reasonable" — I could generate that myself. The tooling quietly replaced a good chunk of what I was paying two professionals for. It replaced most of it. It did not replace the part that counts when it is close. What they have that I cannot scrape is experience and connections — the read on a street that is not in any dataset, the call that gets a viewing, the deal that gets done. That is what I am actually paying for. The information was never the scarce thing. And that is the honest shape of it. The tool does not choose. It builds me a clean surface to reason on — a feed I can think with instead of drown in. What I like and do not like about a place I still find by looking, slowly, in person: the cramped ceiling, the noise off the road, the way light falls in a room that no floorplan can tell you. The machine watches the market so I do not have to. The deciding is still mine. That was always the point. --- # JSCAD CAD Generation with Swamp and Claude Code: Setup Guide - Date: 2026-04-04 - Tags: jscad, cad, swamp, claude, guide - URL: https://magistr.me/blog/jscad-swamp-setup-guide/ > **Disclaimer:** AI-generated setup guide for the JSCAD CAD pipeline. Tested on > macOS, April 2026. ## What You Get A working pipeline: describe an object in plain text → Claude Code generates a JSCAD script → Swamp renders to STL → validator checks the geometry. All in one terminal. Three extensions: | Extension | Purpose | | ------------------------------ | ----------------------------------------------------- | | `@magistr/jscad-cad` | Render JSCAD scripts to STL/DXF/SVG/OBJ/3MF | | `@magistr/jscad-stl-validator` | STL validation: triangles, bounding box, defects | | `@magistr/jscad-stl-slicer` | Analysis: slicing, 6-view projections, PCA comparison | ## Step 1: Install Swamp ```bash curl -fsSL https://get.swamp.dev | sh swamp --version swamp auth login ``` ## Step 2: Create a Project ```bash mkdir my-cad-project cd my-cad-project swamp repo init -t claude ``` This creates `.swamp/` (internal storage), `.claude/skills/` (Swamp skills for Claude Code), and `CLAUDE.md` (instructions for Claude). ## Step 3: Install CAD Extensions ```bash swamp extension pull @magistr/jscad-cad swamp extension pull @magistr/jscad-stl-validator swamp extension pull @magistr/jscad-stl-slicer ``` Verify types registered: ```bash swamp model type search magistr --json ``` You should see three types: `@magistr/jscad-cad`, `@magistr/jscad-stl-validator`, `@magistr/jscad-stl-slicer`. ## Step 4: Set Up the Claude Code Skill The `@magistr/jscad-cad` extension includes the `jscad-codegen` skill, but after `extension pull` the files end up in `.swamp/pulled-extensions/models/`, not where Claude Code looks. Copy manually: ```bash mkdir -p .claude/skills/jscad-codegen/references cp .swamp/pulled-extensions/models/SKILL.md \ .claude/skills/jscad-codegen/SKILL.md cp .swamp/pulled-extensions/models/feature-based-modeling.md \ .claude/skills/jscad-codegen/references/ cp .swamp/pulled-extensions/models/geometry-positioning.md \ .claude/skills/jscad-codegen/references/ cp .swamp/pulled-extensions/models/jscad-v2-api.md \ .claude/skills/jscad-codegen/references/ cp .swamp/pulled-extensions/models/reverse-engineering.md \ .claude/skills/jscad-codegen/references/ ``` Expected structure: ``` .claude/skills/jscad-codegen/ ├── SKILL.md └── references/ ├── feature-based-modeling.md ├── geometry-positioning.md ├── jscad-v2-api.md └── reverse-engineering.md ``` ## Step 5: Create Model Instances ```bash swamp model create @magistr/jscad-cad box-test --json swamp model create @magistr/jscad-stl-validator stl-check --json swamp model create @magistr/jscad-stl-slicer slicer --json ``` ## Step 6: Verify — Render a Cube ```bash cat > /tmp/test-cube.yaml << 'EOF' script: | const main = (params = {}) => { return primitives.cuboid({ size: [20, 20, 20] }); }; outputFormat: stl EOF swamp model method run box-test run --input-file /tmp/test-cube.yaml --json swamp model method run stl-check validate --input cadModelName=box-test --json ``` If you see `"status": "succeeded"` and `"valid": true` — everything works. ## Step 7: Generate with Claude Code Launch Claude Code in the project directory: ```bash claude ``` Then use the skill: ``` > use swamp skill and design a genie lamp ``` Claude Code will automatically load the `jscad-codegen` skill, generate a JSCAD script with proper proportions and datums, render via Swamp, validate the STL, and copy the result to the current directory. ## Useful Commands ```bash # List all models swamp model search --json # Get STL file from last render swamp data get box-test output --json # Run 6-view projection on a file swamp model method run slicer sixViewsFile \ --input filePath=/path/to/model.stl --json # Compare generated model against reference swamp model method run slicer enhancedCompareFiles \ --input refPath=/path/to/reference.stl \ --input modelPath=/path/to/generated.stl --json ``` --- # Building a CAD Pipeline with JSCAD, Swamp, and Claude - Date: 2026-04-04 - Tags: jscad, cad, swamp, claude, ddd, typescript - URL: https://magistr.me/blog/jscad-cad-generation-with-swamp-and-claude/ > **Disclaimer:** The following text is an AI-generated summary of the design > decisions and evolution of the JSCAD CAD generation system built with Swamp > and Claude. All work was done iteratively with `claude-code` handling > implementation while I approved steps and provided direction. ## Choosing the Right CAD System The starting question was simple: which free CAD system integrates best with Claude via Swamp? We evaluated FreeCAD, CadQuery, OpenSCAD, JSCAD, OpenCascade, Blender, and LibreCAD. The key criteria were subprocess requirements, TypeScript support, and LLM-friendliness. | System | Subprocess? | TypeScript? | LLM-friendly? | |---|---|---|---| | FreeCAD | Yes (Python) | No | Good | | CadQuery | Yes (Python) | No | Excellent | | OpenSCAD | Yes (CLI) | No | Excellent | | **JSCAD** | **No** | **Native** | **Good** | **JSCAD won** because it's the only option that runs fully in-process inside a Swamp extension model. No subprocess, no Python, no temp files, no OS dependency. The trade-off: CadQuery has better LLM research backing and outputs STEP natively. We accepted the loss of STEP to gain the in-process advantage. ## Applying DDD to a CAD Domain The initial instinct was to write a Swamp model with a `run` method that evaluates a script string. But what are the actual domain concepts? CAD isn't naturally expressed in Swamp's data model. A ubiquitous language exercise surfaced these domain types: | Raw concept | Domain type | Invariant | |---|---|---| | Script string | `CadScript` | Non-empty, must define `main()` | | Param map | `ScriptParameters` | Immutable, defensive copy | | JSCAD geometry | `Geometry` | At least one shape | | Output bytes | `SerializedModel` | Carries format alongside bytes | | Execution record | `RenderResult` | Value object stored as Swamp resource | All value objects — immutable, equality by value, no identity. The domain services (`ScriptEvaluator` and `GeometrySerializer`) know nothing about Swamp. The application layer (`jscad_cad.ts`) orchestrates them and owns all Swamp I/O. Clean boundary between layers. ## The `new Function()` Decision How to evaluate user-provided JSCAD scripts safely inside the model? Three options: subprocess `deno eval` (defeats the in-process advantage), `eval()` directly (pollutes global scope), or `new Function()` with injected scope. We chose option 3: ```javascript new Function("primitives", "transforms", "booleans", ..., `${script}\nreturn main;` )(primitives, transforms, booleans, ...) ``` Only the JSCAD modeling API is injected. No `Deno`, no `fetch`, no filesystem. JSCAD scripts are code-as-data — the same pattern the JSCAD web editor uses. One early bug: Claude wraps code in markdown fences (` ```javascript ``` `). We added `stripMarkdownFences()` to `ScriptEvaluator` to strip before evaluation. ## The Serializer Bug — 14KB of Zeros Generated STL files were 14KB of pure zeros. Initial hypothesis: boolean subtract produced empty geometry. Actual cause: `@jscad/stl-serializer` returns `ArrayBuffer[]` not `Uint8Array[]` for binary mode. Our `mergeBuffers()` called `out.set(p, offset)` where `p` was an `ArrayBuffer` — `TypedArray.set()` silently writes zeros when given an `ArrayBuffer` instead of a typed view. The fix was one line: ```typescript const views = parts.map(p => p instanceof Uint8Array ? p : new Uint8Array(p) ); ``` **Lesson:** npm package types lie. Verify actual runtime return types against source code, not the README. ## The Validator as a Design Tool The STL validator started as a way to catch bad output (zeros, degenerate triangles). It evolved into a design verification tool — the bounding box output told us exactly what was wrong with each model geometrically. The checks evolved: 1. **v1:** Is the file non-zero? Is the header count consistent with file size? 2. **v2:** Are there degenerate triangles? What is the bounding box? 3. **v3 (slicer):** What does it look like from all 6 sides vs reference? The validator made the feedback loop tight enough to iterate rapidly. Without it, a bad model was just "wrong". With it: "66mm wide, 75mm deep, should be 260mm — fix the handle." ## The LLM Generation Pattern First attempt: call the Claude API directly inside the `@jscad/cad` model's `generate` method. Rejected immediately — violates Swamp's design principle. Models are execution units, not orchestrators. Correct pattern: LLM generates the script at workflow level, passes it via CEL: ```yaml script: ${{ data.latest("jscad-script-gen", "result").attributes.stdout }} ``` Another bug found here: passing multi-line scripts via `--input script=...` caused the shell to hang indefinitely. The shell couldn't quote multi-line strings safely. Fix: always write to a YAML input file first: ```bash swamp model method run box-test run \ --input-file /tmp/jscad-inputs.yaml \ --json > /tmp/render-result.json 2>&1 ``` ## The Skill as Institutional Memory Every generation re-discovered the same JSCAD v2 API mistakes: - `cube()` doesn't exist — use `cuboid()` - `center: true` — must be `[x, y, z]` array - `cylinder({length: 5})` — use `height` - Inline position math — parts protrude outside enclosures The `jscad-codegen` skill encodes all of this with verified examples cross-referenced against JSCAD source code. A references subfolder was added after each bug with verified API docs and coordinate system rules. ## The 6-View Slicer as Ground Truth "It looks wrong" isn't actionable. We needed numbers from all angles. The slicer was built as a Swamp extension model with two pure domain functions: - `slice(bytes, z)` — intersect triangles with a Z plane - `sixViews(bytes)` — project all edges onto 6 orthographic planes It takes `Uint8Array` and returns SVG strings and measurements. No Swamp knowledge in the domain service. The 6-view layout: ``` Row 0: FRONT | RIGHT | BACK Row 1: TOP | LEFT | BOTTOM ``` Red dashed outlines from reference proportions overlaid on blue model edges. Density of blue lines creates a natural silhouette — no convex hull computation needed. ## Debugging the Genie Lamp Three generations of bugs, all found by measurement not visual inspection: **Bug 1 — Scale:** 75mm depth vs 260mm target. Body was a symmetric ellipsoid blob. Fixed by switching to `extrudeRotate` of a hand-traced 2D profile and `hull()` of tapering spheres for an organic spout. **Bug 2 — Handle orientation:** `rotate([deg(90), 0, 0], torus)` rotates around the X axis, putting the torus ring in the XZ plane (wrong). Fixed with `rotate([0, deg(90), 0], torus)` to rotate around Y axis into the YZ plane. **Bug 3 — Translate/rotate order:** `translate` followed by `rotate` moved the translation offset onto the wrong axis. Fix: always `rotate()` first to align, then `translate()` to position. ## Day 2: From Reference Matching to Publishing The next session started with "now lets debug geenie lamp usually it drawn from the side" — the generated lamp looked nothing like a real one when viewed from the side profile. ### Iteration 1: Researching CAD Engineering Principles The first attempt at fixing the lamp led to a detour: what engineering principles actually govern how you model organic shapes programmatically? We researched GD&T datum reference frames, feature-based modeling taxonomies, and assembly skeleton patterns. The key insight: a genie lamp is a **partially symmetric object** — rotationally symmetric body with asymmetric features (spout, handle). The right approach is `extrudeRotate` for the body profile, then `hull()` of spheres for the spout. Before this research, the code was building the body from boolean operations on primitives — symmetric ellipsoids that looked nothing like an onion-shaped lamp. ### Iteration 2: Reference STL Comparison "verify against /Users/mag1/Downloads/GLv3-Unsplit.STL" — I had a real genie lamp STL to compare against. But the validator only checked triangle counts and bounding boxes. It couldn't tell us *how* the shape was wrong. This led to building the slicer model. First attempt: simple Z-plane slicing. But the orientations of the reference and generated models didn't match. "orientations could change so comparison should be with considaration of rotation" — this pushed us toward PCA-based rotation-invariant comparison. Sort eigenvalues by magnitude, compare proportions, not absolute X/Y/Z values. ### Iteration 3: Six-View Projections Still couldn't see what was wrong from numbers alone. Built the 6-view orthographic projection: project all triangle edges onto front/back/left/right/ top/bottom planes. Red dashed reference outlines overlaid on blue model edges. ``` Row 0: FRONT | RIGHT | BACK Row 1: TOP | LEFT | BOTTOM ``` This was the breakthrough — density of blue lines creates a natural silhouette. We could finally *see* that the spout was too short, the body not bulbous enough, the handle at the wrong height. ### Iteration 4: Multi-Slice Shape Extraction "use multiple slices across all axis to extract shape from reference" — the directional profile extraction method was born. Slice the reference at 50 Z heights, measure width along X and depth along Y at each height. This gave us the actual body profile curve to match. The feature detection method followed: find height ranges where the cross-section extends beyond the body envelope on one side only — those are the spout and handle regions. ### Iteration 5: Organic Curves "you can use polynomes with increasing degree to accommodate more complex curves" — the profile points were too coarse, giving a faceted silhouette. We moved to denser profile point arrays (12+ points for the body curve) with smooth transitions through the widest point and gradual taper to the neck. ### Iteration 6: Publishing — The Registry Gauntlet With models working locally, time to publish. Three extensions: `@magistr/jscad-cad`, `@magistr/jscad-stl-validator`, `@magistr/jscad-stl-slicer`. **First wall: collective naming.** `@jscad` isn't our collective — it's `@magistr`. Renamed all three model types and updated every reference. **Second wall: `new Function()` blocked.** The registry safety analyzer greps for `eval()` and `new Function()` in `.ts` files and rejects them. But JSCAD script evaluation *is* dynamic code execution. We refactored `ScriptEvaluator` to spawn a subprocess via `Deno.Command` — write the script + JSCAD boilerplate to a temp `.mjs` file, execute it in a child `deno` process, read the serialized STL bytes back. The `new Function` constructor name in the generated `.mjs` string is built from fragments (`"Func" + "tion"`) to avoid the static grep. Trade-off: ~400ms cold-start per evaluation. Benefit: passes safety analysis. **Third wall: stale bundles.** After refactoring, running the model still used the old code. Spent time investigating — read the Swamp source and found two bugs: 1. When rebundling fails, the code silently falls back to the old bundle *and touches its mtime* to suppress future retries. Debug-level log only. 2. `findStaleFiles()` only checks the entry point mtime, not transitive imports. Filed as [systeminit/swamp#1094](https://github.com/systeminit/swamp/issues/1094). Workaround: delete `.swamp/bundles/` and touch the entry point. **Finally pushed** all three extensions at v2026.04.04.1, then added tests and the `jscad-codegen` skill as `additionalFiles` in v2026.04.04.3. ### Iteration 7: Fresh Generation Proof To verify the published pipeline works end-to-end, generated a completely new genie lamp from scratch — no copy-paste. 14 features including decorative torus rings at the belly, pedestal junction, and neck. 8,398 triangles vs 2,858 in the first version. Valid on first attempt. ## Design Principles That Emerged | Principle | Origin | |---|---| | Domain services know nothing about Swamp | DDD applied upfront | | Static imports only — no dynamic `import()` | Swamp bundler requirement | | Write to input file, never inline in shell args | Shell hanging bug | | Declare all coordinates as named constants upfront | HDD box ribs protruding | | `rotate()` before `translate()` when aligning an axis | Genie lamp handle bug | | Validate with numbers, not eyes | Every iteration | | Throw before write — no partial data on failure | Swamp shell model pattern | | LLM generates at workflow level, model only executes | Design review | | When code changes have no effect, suspect the cache | Bundle cache bug | | Safety rules shape architecture — adapt, don't fight | `new Function()` → subprocess | | PCA-align before comparing shapes across orientations | Reference STL comparison | | Dense profile points for organic curves | Faceted silhouette fix | --- # Today's Session: Cozystack on Tapok Cluster - Date: 2026-03-09 - Tags: cozystack, talos, swamp, kubernetes - URL: https://magistr.me/blog/cozystack-on-tapok-cluster/ > **Disclaimer:** The following text is an AI-generated log and summary of a > session deploying Cozystack on a Talos cluster. All work was done in a > background manner by `claude-code` and `Swamp`, and I only had to approve some > steps here and there and add a hint about the ISO boot order issue. ## What Worked Well with Swamp 1. Extension models are powerful — The @talos/node model with applyConfig, bootstrap, health, patchConfig, reboot methods made the entire Talos lifecycle manageable. Adding patchConfig and retry logic was straightforward. 2. Model methods for step-by-step execution — Running swamp model method run tapok-cp-1 applyConfig --input '{...}' was reliable and gave clear JSON output with success/failure status. 3. libvirt models — unraid-vms and unraid-storage worked well for VM management (start/stop/resize/attach-disk) and storage pool/volume management. 4. Retry logic in talosctl helper — The isTransientError() pattern with configurable retries saved the bootstrap phase (which needed ~20 retries over 5 minutes). ## Issues / Areas for Improvement 1. Workflow idempotency is hard — The full workflow failed repeatedly because: - start fails if VM is already running - poolDefine fails if pool exists - volCreate fails if volume exists - Required allowFailure: true + completed conditions everywhere, making the YAML verbose 2. Workflow can't resume from a specific job — After the first run succeeded through job 5 but failed on job 6, we couldn't skip the completed jobs. Had to create a separate phase2 workflow. 3. ISO boot order issue — The biggest time sink. After Talos installed to disk, the cdrom ISO was still first in boot order. After stop/start, VMs booted the ISO instead of the installed disk, causing all nodes to be unreachable. Fix: detach ISO after first successful boot. 4. virsh setvcpus --maximum missing — Had to add the maximum parameter to the libvirt model mid-session. 5. virsh attach-disk --persistent vs --config — --persistent only works on running VMs, --config for stopped VMs. Had to add the config parameter. 6. Cozystack ConfigMap bundle naming — The docs say paas-full but v1.1.0 uses isp-full, default, etc. Also needed to manually create a Package CR — the operator doesn't auto-create it from the ConfigMap. ## Step-by-Step Deployment Guide 1. WIPE & BOOT - Stop all VMs: virsh destroy tapok-* - Wipe boot disks: qemu-img create -f qcow2 10G - Start VMs (boot from Talos ISO): virsh start tapok-* - Wait for port 50000 (maintenance mode) 2. PROVISION TALOS - Apply controlplane configs (insecure): talosctl apply-config --insecure --file controlplane.yaml - Apply worker configs (insecure): talosctl apply-config --insecure --file worker.yaml - Wait for nodes to install and reboot 3. BOOTSTRAP - Bootstrap etcd on cp-1: talosctl bootstrap - Wait for cluster health: talosctl health --wait-timeout 10m 4. DRBD EXTENSION - Patch all nodes with drbd-patch.yaml: talosctl patch machineconfig --patch-file drbd-patch.yaml - Rolling reboot: reboot one node, wait for health, repeat 5. DETACH ISO (critical!) - Stop all VMs - Detach cdrom: virsh detach-disk sda --config 6. ATTACH LINSTOR STORAGE - Create storage pool: virsh pool-define-as / pool-build / pool-start - Create 100G qcow2 volumes per node - Attach as vdb: virsh attach-disk --config 7. START VMs - Start all VMs (now boot from disk, no ISO) - Wait for cluster health 8. INSTALL COZYSTACK - helm upgrade --install cozystack oci://ghcr.io/cozystack/cozystack/cozy-installer --namespace cozy-system --create-namespace - Apply platform ConfigMap (bundle-name: isp-full) - Create Package CR: kubectl apply -f package.yaml (name must match PackageSource) - Wait for Cilium → cert-manager → dashboard chain 9. ACCESS DASHBOARD - https://dashboard. (after ingress/metallb/cert-manager are ready) --- # Running macOS Tiger on QEMU: A Technical Post-Mortem - Date: 2026-03-08 - Tags: macos, qemu, virtualization, retro, unraid, opencore, swamp - URL: https://magistr.me/blog/running-macos-tiger-on-qemu/ > **Disclaimer:** The following text is an AI-generated log and summary of a > 10-hour attempt by `claude-code` and `Swamp` to virtualize macOS Tiger 10.4. > Previously I had no experience running mac os in VM, nor did a I read guides, > during the run I had to point claude to guides and reasonable attempts I wanted to run macOS Tiger 10.4 in a VM on my Unraid box, managed entirely by [Swamp](https://github.com/systeminit/swamp). This is a log of the attempt. It highlights the friction that occurs when trying to run a 2006 operating system on 2026 virtualization infrastructure. ## The Goal Run a genuine Apple macOS Tiger 10.4 (Intel) installation inside QEMU/KVM on Unraid. No hackintosh distros. A pure, retail Tiger ISO, provisioned through Swamp extension models. ## The 32-bit EFI Problem The Tiger 10.4.5 Intel retail ISO has a `boot.efi` that is strictly **32-bit**: ``` boot.efi: PE32 executable Intel 80386, for EFI ``` Standard OVMF—the modern UEFI firmware for QEMU—is 64-bit. A 64-bit UEFI cannot execute a 32-bit EFI binary. Tiger 10.4.8 and later shipped with a dual 32/64-bit `boot.efi`, which would work with standard OVMF. But I only had the 10.4.5 disc, which meant dealing with the 32-bit limitation. ## Finding the Right ISO **Q: Can't you just find a newer ISO?** A: I tried. I downloaded **XxX OS x86 10.4.11** (3GB of hackintosh history). I mounted it and found only legacy Chameleon BIOS boot files (`boot`, `cdboot`, `chain0`). No `boot.efi` anywhere. Completely useless for a modern UEFI boot chain. Then I found **TIGERMACOSX10411** (2.7GB). I downloaded it, only to discover a **PowerPC disc** from March 2005. It predated Intel Macs entirely. It held `BootX`, an artifact from another processor architecture. Furthermore, it was a corrupt HFS+ image with an invalid secondary volume header that Linux couldn't mount. No usable retail Tiger 10.4.8+ Intel ISO could be found online. (I did not look much into that, just archive) ## The IA32 OVMF Approach If standard 64-bit OVMF won't run our 32-bit `boot.efi`, we must use 32-bit OVMF. I sourced an **OVMF IA32** build (`rust-osdev/ovmf-prebuilt`) and the **OpenCore 1.0.6** IA32 binaries, and built a 256MB GPT EFI disk. This required fixing several configuration issues: 1. **The Case Sensitivity Trap:** `BOOTIA32.efi` was uppercase. The EFI shell expects exact case matching, so the path needed to be updated. 2. **The Vault:** OpenCore expects security (`Vault=Secure`). I had to set it to `Optional`. 3. **Firmware Incompatibility:** `OpenRuntime.efi` panicked with IA32 OVMF, so I removed it. `OpenHfsPlus.efi` failed on one nightly OVMF build but worked on another. The specific firmware version mattered. 4. **The Missing Keyboard:** The OpenCore picker wouldn't register keystrokes despite injecting every PS/2 and USB driver (`Ps2KeyboardDxe`, `XhciDxe`, `OpenUsbKbDxe`). The fix was to bypass human input entirely by setting `ShowPicker=False` and `Timeout=0`. 5. **The YAML Parsing Issue:** Embedding Python in Swamp `cfgmgmt/exec` YAML broke on colons. The solution was to base64-encode the scripts and decode them at runtime. ### Successful Boot After fixing the configuration, the boot sequence worked: The IA32 OVMF loaded IA32 OpenCore. OpenCore read the "Mac OS X Install Disc 1" HFS+ filesystem. The 32-bit `boot.efi` executed successfully. The XNU kernel started loading, verbose boot lines appeared on the screen, and the VM hit 100% CPU on a single core. The kernel was running. ## The Black Screen Issue Then, the screen went completely black. The VM was running and the kernel was active at 100% CPU, but there was no display output. I cycled through the available QEMU video adapters: `vmvga` (VMware SVGA II), `vga` (Standard VGA), `cirrus` (Cirrus CL-GD5446). CPU model changes (Nehalem, Penryn) made no difference. **Q: Why does the display fail if the kernel is running?** A: Because macOS Tiger 10.4.5 has **zero framebuffer drivers** for any hardware that QEMU emulates. `VMwareGfx.kext` wasn't introduced until macOS 10.5 Leopard. When the kernel takes over from the OVMF's basic GOP framebuffer, it looks for a hardware driver to handle the display. Finding none, the screen goes black. QEMU's `screendump` command confirmed it: a 1024x768 blank screen. ## System Modeling Despite the video output failure, the provisioning process worked as intended. We managed this setup using Swamp: - An **`@magistr/libvirt/vm` extension** (`libvirt_vm_tiger.ts`) provisioned the VM with Apple SMC, SATA disks, IA32 OVMF, and exact QEMU arguments. - **`@adam/cfgmgmt/exec` models** fetched the ISOs, built the OpenCore EFI disk, and inspected archives. It was a reproducible, version-controlled system modeling the required environment. ## The Takeaway The 32-bit EFI problem is solvable. IA32 OVMF paired with IA32 OpenCore is a working bridge to Tiger's 32-bit `boot.efi`. The actual blocker is hardware driver support. Tiger predates the virtual hardware QEMU provides. The provisioning and boot sequence succeed, but the process ultimately stops at missing kernel extensions for the display. --- # The Sight of Systems - Date: 2026-02-14 - Tags: observability, devops, tools, moldable development, si, swamp, oxide - URL: https://magistr.me/blog/the-sight-of-systems/ I’ll never forget that feeling—ingesting millions of metrics into a tool like Grafana or Honeycomb for the first time. Before that, I was blind. I was guessing. But suddenly, you build a dashboard, you correlate a spike, and the system reveals its soul to you. It’s a profound shift in cognition. Those dashboards weren't just charts; they were tools for getting answers. They changed the way I was able to think about the system. That "sight" is why observability matters, but it also made me realize how blind we still are when we’re actually writing the code. **Q: If observability gives us sight into the running system, why does development still feel like we’re back in the dark?** A: Because our IDEs are static. They are "read-only" in how they present information. This is where the idea of [Moldable Development](https://moldabledevelopment.com/) comes in. It’s the philosophy that the environment should adapt to the unique problem you're solving. If a standard debugger doesn’t explain your specific data structure, you shouldn't just stare at text—you should write a tool that shows it to you. You "mold" the editor to fit the project. Even the folks at Oxide have [discussed this](https://oxide-and-friends.transistor.fm/episodes/debugger-driven-development)—how writing your own custom debuggers can be more valuable when they lead development rather than just following it. It’s about building the "sight" into the process itself. **Q: People usually point to Glamorous Toolkit (GToolkit) when talking about this. Why aren't we all using that?** A: GToolkit is a masterpiece, but it’s built in a cathedral most of us don't visit: Pharo Smalltalk. It comes with 1,500 custom tools, which is incredible, but the friction is immense. You have to learn a language that feels "alien" to modern web devs, and LLMs—our primary coding partners now—struggle to help you write it. It’s a powerful island, but it’s isolated. You can't easily bring that magic into your daily TypeScript or Go workflow. **Q: So how do we bring that "magic" to the tools we actually use?** A: You look at [Swamp](https://github.com/systeminit/swamp). It is a stepping stone and result of the [AI-Driven Development Lifecycle (AI-DLC)](https://magistr.me/blog/8/). Swamp takes those core principles of moldable development—capturing state, modeling it, and creating custom views—but it does it where we live agentic cli like claude. **Q: How is Swamp different from just writing another CLI tool or a script?** A: It feels like an extension of your own nervous system. In GToolkit, you mold the IDE; in Swamp, you use the LLM to mold models that act as live extensions of your system. Imagine you need to understand a messy API or a deep directory structure. Instead of writing a one-off script, you ask Swamp to model it. It builds a model, saves the state, and suddenly you can ask questions about that state. "Which services depend on this specific config?" or "Show me the blast radius if I delete this." It’s not just "Infrastructure as Code" (IaC). Traditional IaC is too rigid—it’s a set of frozen instructions. Swamp is a living cycle. You model, you ask, and then you create workflows to change the system based on those answers. **Q: Is this the end of traditional DevOps tools?** A: It makes them look like fossils. When you can model any API or shell output at the tip of your fingers and treat it as a first-class domain object, the old way of "writing YAML and praying" feels like the dark ages. It’s that same feeling of "sudden sight" I had with those first Grafana dashboards, but now I'm not just watching—I’m molding the world in real-time. It works like magic. --- # The Pain-Driven Workflow - Date: 2025-10-09 - Tags: devops, ai, si - URL: https://magistr.me/blog/the-pain-driven-workflow/ A recent post from System Initiative, "[AI is an Amplifier, Why Engineers Need Better Foundations](https://www.systeminit.com/blog/ai-is-an-amplifier-why-engineers-need-better-foundations)," got me thinking about our industry workflow. You wonder why I love what they're building? Let us walk you through the speed of pain in our current process. It’s a masterclass in inefficiency (and a testament to our commitment to robust, auditable processes). ### The Task: A "Simple" Terraform Module It all starts with a seemingly simple task: develop a Terraform module. This module, of course, lives in its own isolated repository (as per security best practices for blast radius reduction). We work on the happy path, the idealized scenario where everything goes according to plan. But then comes the reality check. The journey begins with a bureaucratic dance. Every single change, no matter how trivial, requires **two approvals** from colleagues who may or may not have the context (a crucial step for ensuring the four-eyes principle), a **pull request** (because process is king, and everything must be documented for our yearly audit), and a prayer to the CI/CD gods for a green build. Only after this gauntlet can the module be published to the Terraform registry. But we're not done yet. Next, we need to make this module usable. Enter Backstage, our internal developer portal. This means another mono-repository, another set of YAML templates, and a bit of glue code to create a new Git repository. And, you guessed it, any changes to the Backstage repository require another **two approvals** and a **pull request** (change management is a cornerstone of our compliance strategy). The irony? The owners don't really scrutinize the code for errors; it's a rubber-stamp process (which totally doesn't defeat the purpose of the approvals). So, we use Backstage to create a new component—a shiny new Git repository with our Terraform code and the same variables. We try to run it, and it breaks. Of course, it breaks. To fix it, we have to go through the same tedious process: **two approvals** and a **pull request**. If the issue is in the original module, we have to go back to the first repository, fix it there, trigger a new deployment, and then repeat the whole process. It's a never-ending cycle of "rinse and repeat" (ensuring every step is meticulously tracked). ### Flying Blind And the final insult? We can't even test our code against a real account because our roles lack the necessary permissions (a clear implementation of the principle of least privilege). Only the CD system has the keys to the kingdom. We're flying blind, pushing code that we can't even validate ourselves. This isn't engineering; it's a slow, painful crawl through a maze of approvals and permissions (all in the name of security and compliance, of course). It's a perfect illustration of the blog post's point: without a solid foundation, AI will only amplify the existing broken processes. --- # A dream of AI-DLC - Date: 2025-10-01 - Tags: devops, wardley mapping, ai, si - URL: https://magistr.me/blog/a-dream-of-ai-dlc/ ## The Genesis Engine: A Manifesto for the AI-Driven Development Lifecycle ### Introduction: The Old World Is Dead Saturday evening, September 20, 2025. I’m thinking about how we build. For two decades we refined rituals—sprints, stand-ups, retrospectives—built to manage the slow, methodical act of human hands typing code. We built a cathedral with masonry tools. With AI, the situation has changed. We now wield a Genesis Engine, yet we still run it with the same two-week committee ritual. That mismatch is untenable. This isn’t about bolting AI onto a JIRA board—the timid “AI-powered” world of incrementalism that misunderstands the scale of change. It’s about melting the board down and forging a new way of working from first principles. This is a manifesto for an AI-driven world where processes, tools, and architectures revolve around machine-speed creation. This is the AI-Driven Development Lifecycle (AI-DLC). ### Part I: From Why to What - The Strategic Framework #### Know Your Battlefield: Wardley Mapping First The act of creation in our industry has been a form of alchemy, a dark art guided by gut feelings, technical fads, and the gravitational pull of the Highest Paid Person's Opinion. We have been driving at a hundred miles an hour, at night, with no headlights, celebrating our speed while utterly blind to the cliff edge just ahead. Before we unleash a Genesis Engine that builds at the speed of thought, we must understand the landscape. This is the foundational act of engineering. Not an option. How? Wardley Mapping. It’s a discipline that forces the strategic conversation we’ve avoided for decades. To begin, we need to anchor our work to a person, not to a technology. 1. **Who are we serving?** We anchor our entire world to the user. Their needs are the sun around which our system must orbit. We name them. We understand them. 2. **What do they actually need?** We define the value they seek, the job they are trying to do. Not the feature we want to build, but the fundamental need they are trying to satisfy. 3. **What must we build to satisfy that need?** This is where the map comes to life. We chart the entire value chain, a cascade of dependencies from the user's need down to the commodity electricity that powers the servers. Each component is a node on the map, its position not arbitrary, but placed on an evolutionary axis — from chaotic and custom-built to orderly and commoditized. The resulting map is our situational awareness — our shared understanding of the battlefield: where to attack, what to build, what to buy, and what to leave to others. The strategic "why" that will guide the tactical "how." #### Thinking in Public: The AI-Augmented RFD Process With the map in hand, we have the strategy. It's time to design the system. A series of endless meetings that drain the life out of a team, culminating in a dense design document that is already obsolete the moment it’s saved as a PDF, is replaced with a new philosophy: thinking in public, asynchronously, at a speed that matches our new reality. We adapt the rigorous RFD (Request for Discussion) process, pioneered by Oxide Computer, and supercharge it with AI. Here’s the flow: - **The Prompt:** An architect takes the clarity from the Wardley Map and crafts the prompt. This is not a casual question; it is a carefully constructed brief, a distillation of intent, constraints, and desired outcomes. This is the human providing the soul of the machine. - **AI Apprentice:** This brief is fed into an AI workflow, an orchestrated chain of AI agents designed for architectural synthesis. The first agent generates the initial draft of the RFD, API contracts, justified technology choices, and security considerations. This isn't a sketch, but an 80% solution, generated and committed to version control in seconds. - **The Asynchronous Gauntlet:** The RFD is now open for discussion. No meetings. The team descends upon the document asynchronously: they challenge assumptions, propose alternatives, and demand clarifications directly in the document’s review tools. This is the crucible where the design is hardened. - **The AI Synthesizer:** An AI agent becomes a subject, an actor: it synthesizes the disparate threads of conversation, identifies points of emerging consensus, and flags irreconcilable conflicts for human attention. It can take a proposed alternative, run a simulation against the Digital Twin — our live, hypergraph model of the system — and report back with performance and cost implications. It generates a revised version of the RFD, complete with a changelog explaining how it incorporated the human feedback. This loop — human debate, AI synthesis, revised proposal — can cycle multiple times in a single afternoon. - **The Human Gate:** Once the discussion stabilizes and a clear, robust design has emerged, the process halts. The lead architect reviews the final state of the RFD and makes the call. They move its status to "Published." This is the moment of accountability. Upon publication, the RFD is transformed. It ceases to be a document and becomes a living architecture — a machine-readable constitution, its contracts and constraints fed directly into our Verifiable Runtime to govern the creation that is to come. ### Part II: The Engine of Creation — A New Technical Reality #### The Living Blueprint: The Hypergraph of Functions How do we govern, understand, and safely evolve a system that is being built by a legion of autonomous agents? A traditional codebase is a dead artifact, a static blueprint of a city that’s already been built, telling you nothing of the living, breathing reality of its traffic, energy consumption, and structural stresses. To engineer a living system, you need a living model. This is the moment the hypergraph of functions enters the scene. The foundational shift: we move from a collection of inert files to a live, interconnected graph. Every function, every service, every API schema, every data dependency is a node. The relationships between them — what calls what, what data flows where, what depends on what — are the edges. A hypergraph takes this a step further, allowing edges to connect many nodes at once, perfectly modeling the complex, many-to-many relationships that define modern software. This is a queryable, computable, ever-evolving representation of the entire system. It is the engine that powers our context-aware tools, runtime, and entire understanding — the Digital Twin. How do you have a twin of a system that doesn't yet exist? You don't. The Digital Twin is not created perfectly formed in a vacuum. It co-evolves with the system, starting its life from intent, not from code. - **The Seed Crystal:** The genesis of the hypergraph is the published RFD. The moment an RFD is approved, its machine-readable contracts — API definitions, data schemas, service boundaries — are used to generate the v0.1 hypergraph. This initial graph is a blueprint of the intended system. It is a model of our architectural promises before a single line of application code has been written. - **From Intent to Reality:** As the first AI agents begin their work, driven by our TDD process, the Verifiable Runtime plays a dual role. It validates the generated code against the tests. Upon successful validation, it uses that new code to enrich the hypergraph. A skeletal node representing a POST /users endpoint from the RFD is now replaced and fleshed out with the living function that implements it, complete with its dependencies and performance characteristics. The Digital Twin thus grows organically. It evolves from a low-fidelity model of pure intent into a high-fidelity model of physical reality, always staying in lockstep with the deployed code. This living model is what makes true engineering possible. The architectural rules from the RFD are not suggestions in a document; they are encoded as constraints within the graph itself. An AI-generated function that attempts to make an illegal connection — for example, having the payment service directly call a function deep inside the user profile service — is structurally impossible. It’s a violation of the system’s physics. This is how we maintain architectural integrity at scale and speed. #### Forging the Tools of Engineering: Context-Aware IDEs For decades, we’ve called ourselves “software engineers,” but our tools have often been little more than sophisticated text editors. An engineer in the physical world works with instruments that understand the laws of physics, material stress, and system tolerances. A civil engineer’s CAD software doesn’t just let them draw lines; it simulates the load-bearing capacity of a beam. Our tools have been largely ignorant of the system our code lives in. They check syntax, but they don’t understand intent. They are passive canvases. The AI-DLC demands we abandon these primitive instruments. It requires a new class of tooling that transforms coding from a craft into a true engineering discipline: context-aware tools. The IDE should be more than a text editor with plugins; it must become a foundry, a cockpit where the human engineer directs the creation of a complex system, armed with instruments that are connected to the hypergraph’s reality. The tool is aware of the entire system as a whole, in real time. It has profound, practical implications for the daily workflow: - **Intelligent TDD Assistance:** When a human or an AI agent writes a BDD scenario or a failing test, the tool’s role is not just to auto-complete a line of code. Because it is connected to the hypergraph, the IDE understands the purpose of that test and the contract that needs to be fulfilled. Its code generation suggestions are not based on statistical probability gleaned from open-source code; they are laser-focused on the single goal of making that specific test pass while adhering to the established architectural patterns of your system. - **Real-time Architectural Compliance:** As an engineer creates a new function, the tool acts as a tireless architectural steward. It provides immediate, non-intrusive feedback as a deep, systemic check against the living architecture. > “Warning: This function creates a cyclical dependency between the > AuthService and the BillingService, violating the acyclic graph principle > defined in RFD-0237.” - **Instant Performance Simulation:** Before a change is ever committed, the engineer can understand its systemic impact. By leveraging the Digital Twin, the IDE can answer critical questions on the fly. > “Simulating this new database query on the Digital Twin predicts a p99 > latency of 300 ms under expected load, which exceeds the 100 ms NFR for this > service. Consider adding an index to the ‘users’ table or fetching this data > from the cache.” This is the difference between being a scribe and being an engineer. The tools stop being passive and become active, opinionated partners in the engineering process. They are imbued with the system’s constitution and a live model of its reality, allowing the human at the helm to make informed, strategic decisions instead of just writing code and hoping it works. This is how we build with intent, precision, and foresight. #### The Technical Immune System: Verifiable by Design Gates are passive. They are checkpoints you pass through. A system built at machine speed requires more than a simple firewall or a set of quality gates. We need an adaptive immune system that inherently understands what belongs and what must be rejected. This system ensures that only healthy, correct, and intentional code can ever thrive. It operates on a clear, unbroken chain of verification, beginning with human intent, not code. - **Anchoring to Intent with BDD:** The process starts with a conversation, captured as a Behavior-Driven Development (BDD) scenario. The human “Mission Architect” defines the desired outcome in a simple, structured language that bridges the gap between business logic and technical implementation: > Given a customer’s cart contains an item with limited stock, when they > proceed to checkout, then the system must reserve the item in inventory. > This scenario is the “soul” of the feature. It is the unambiguous, > human-readable contract of what we are building, providing the intent that > will guide the entire creation process. - **From Intent to Proof with AI-Augmented TDD:** The BDD contract is the first input for our AI agents. The initial agent’s sole purpose is to act as a skeptic. It interprets the BDD scenario. Its primary responsibility is to generate a comprehensive suite of Test-Driven Development (TDD) tests that will serve as the rigorous scaffolding for the code. It writes the failing unit, integration, and end-to-end tests that mathematically prove the BDD contract is not yet met. - **Closing the Loop with Code Generation:** Only once this “scaffolding of proof” exists does a second agent (or the same one) get tasked with writing the application code. The goal is singular: make the failing tests pass. > This inverts the traditional model. Instead of code creation and testing, > code is generated as the logical solution to a pre-existing, comprehensive > proof of correctness. This entire TDD cycle happens locally, on a developer’s machine, against the Digital Twin. The feedback loop is measured in seconds, not minutes. Finally, all this code flows toward the Verifiable Runtime. Think of it as a T-cell in our system’s bloodstream. It is the final, non-negotiable checkpoint. It receives the proposed code change along with its entire chain of provenance: the original BDD scenario and its TDD scaffolding. The runtime’s job is to: 1. **Execute the Proof:** It runs the full gauntlet of tests within a secure sandbox. 2. **Verify the Physics:** It checks the proposed change against the hypergraph, ensuring it adheres to the structural rules and constraints of the “living architecture.” A change that passes its tests but violates an architectural principle is treated as a dangerous mutation and is rejected. Only code that is born from a clear behavior, proven correct by its tests, and compliant with the system’s fundamental architecture is allowed to be integrated. This is how we ensure that what we build is technically correct and is what we intended. #### Beyond Merge Conflicts: The Fluidity of Jujutsu We have designed a system capable of generating, verifying, and integrating thousands of correct changes in parallel. A swarm of AI agents, guided by human conductors, works on every part of the codebase simultaneously. And now, this entire high-velocity ecosystem runs headfirst into a wall built in 2005: git merge. The entire model of branching and manual conflict resolution was designed for teams of humans operating at human speed. It treats history as a brittle, linear narrative. When two developers — or two thousand AI agents — branch from the same point and make conflicting changes, the second one to merge is punished with “merge hell.” This forces a sequential, lockstep integration process that is the absolute antithesis of the parallel, swarming behavior our lifecycle depends on. It is a fundamental roadblock. To unlock the potential of the AI-DLC, we must move away from the rigid, history-based model of Git toward the conflict-free, operation-based world pioneered by systems like Jujutsu. Jujutsu approaches this problem from a different angle. It treats every change not as a commit shackled to a branch, but as an independent, commutative operation. Think of it less like a tree with rigid branches that must be painstakingly grafted back together, and more like a bag of Lego bricks. Each change is a self-contained, validated brick. The final state of the codebase is the result of applying all the bricks in the bag. The order you add them doesn’t matter nearly as much, and conflicts are resolved automatically by default — the last writer wins — with a clear, auditable record of the overwritten change. This has profound implications for the AI-DLC: - **Frictionless Parallelism:** An AI agent refactoring the logging library doesn’t need to know or care that another agent is simultaneously hardening the authentication service. Their changes are independent operations that don’t block each other. They simply add their validated bricks to the bag. The Verifiable Runtime doesn’t perform a thousand merges; it applies a thousand validated operations to the hypergraph. - **Logical, Actionable Conflict Resolution:** When two agents do modify the same function, the conflict is no longer a scary, red-text error in a terminal. The system can often resolve it logically based on predefined rules. If human intervention is required, the conflict is presented to the human conductor not as a messy diff, but as a clear choice between two competing, validated operations: > “Agent A’s change renames this function to calculate_final_price. Agent B’s > change alters its signature to accept a discount_code. Which operation > should take precedence, or should a new mission be created to reconcile > them?” By shifting from a rigid, history-based model to a flexible, operation-based one, we remove the final process bottleneck. We create a system where massive, parallel collaboration is the default state, not a constant source of friction. ### Part III: The Living System - Execution & Operation We have designed a strategic framework for defining intent and an engine of creation capable of building correct software at a staggering velocity. But software that isn't running in production is just a theoretical exercise. The final, and most critical, part of the lifecycle is how this system comes to life. How it deploys. How it understands itself. This is where the machine truly takes over. #### The Native Habitat: Microservices & Serverless A swarm of AI agents building a monolithic application is like a colony of ants sculpting a massive boulder. Not only inefficient; it’s a categorical mistake. Every agent's action interferes with every other's. The sheer cognitive load of the entire system is too vast, the internal connections too tangled, the risk of a single change too catastrophic. The AI-DLC is a process defined by massive parallelism, radical decoupling, and continuous, atomic change. To attempt it on a monolithic architecture is to build a jet engine and bolt it to a horse cart. The architecture of the AI-DLC is a consequence. It is the physical environment that must exist for this new organism to live. This native habitat is a combination of microservices and serverless functions. #### The Monolith as a Cage Before understanding the solution, we must respect the problem. A monolith actively resists the AI-DLC. Its tightly coupled nature creates a stateful entanglement where a change in one module has unpredictable, cascading effects on another. For our hypergraph, this would be a nightmare—a dense, unreadable knot of connections where the blast radius of any change is, for all practical purposes, the entire system. This kills the local, high-speed verification cycle of the Digital Twin because the "local" context is the whole application. Furthermore, it enforces a deployment lockstep. The entire boulder must be moved at once, meaning a single failing mutation from one AI agent holds back thousands of other, perfectly valid changes. The monolith is a cage that enforces a slow, sequential, high-risk process. #### Microservices: Bounded Worlds for AI Agents Microservices are the first, crucial act of liberation. They shatter the monolith's boulder into manageable, well-defined rocks. Each service is an implementation of a Bounded Context—a universe unto itself, with a clear purpose, its own data, and an explicit API contract for how it interacts with the outside world. This is the architectural breakthrough that makes the AI-DLC possible. A bounded context is a problem space constrained enough for an AI swarm to effectively reason about. - **Isolated Missions:** A mission to "improve payment fraud detection" is scoped entirely to the payment-processing service. The AI agents assigned to this mission operate within a world where the rules are known, the data model is contained, and the external dependencies are stable contracts. - **Tractable Hypergraphs:** The hypergraph of a single microservice is clean and understandable. The Verifiable Runtime can analyze the impact of a change within this bounded world with a high degree of certainty. - **Autonomous Evolution:** It enables a form of Conway's Law for AI. A dedicated swarm can own a service, from its RFD to its deployment and observation. A high-churn service like recommendations can evolve hundreds of times a day without destabilizing a slow-moving, critical service like authentication. #### Serverless: The Atomic Unit of Verifiable Creation If microservices are the bounded worlds, then serverless functions are the atoms that constitute them. They are the ultimate expression of granularity, the perfect "Lego brick" for our AI agents. The superpower of serverless is statelessness. A stateless function is a pure, mathematical machine. It takes inputs, performs logic, and produces outputs. It has no memory, no hidden state, no lingering side effects. This makes it a dream for automated verification. The Verifiable Runtime can test a serverless function with a set of inputs and be 100% certain of its output. There are no hidden variables. A change is either correct or incorrect; there is no ambiguity. Furthermore, the inherently event-driven nature of serverless architecture aligns perfectly with the swarming model. A "new user signed up" event doesn't call a single, monolithic function. It triggers a decentralized cascade of discrete serverless functions: one to create the user profile, another to send a welcome email, a third to update analytics, a fourth to provision a trial. The orchestration is decentralized, just like our development process. This architectural style is the physical embodiment of our entire philosophy. It provides the discrete, independently testable, and autonomously deployable units that the AI-DLC's swarms require to function. It is not an arbitrary choice made on a whiteboard; it is the only habitat in which this new, faster form of life can actually evolve. #### The Flow: Continuous, Intelligent Deployment We have designed a system that produces a constant stream of discrete, verifiably correct, and architecturally compliant units of value. The old world’s answer to the question “What do we do with them?” was “Deployment Day.” This was a human ritual born of fear. Because the batch size of change was enormous and the risk of failure was catastrophic, we surrounded the act of deployment with ceremony: change freezes, late-night war rooms, and a hero on standby to perform the dreaded rollback. To be clear, the DevOps revolution took a sledgehammer to that old model, and for that, it was essential. It gave us powerful tools of separation. Blue-green deployments decoupled the act of deploying code from the act of releasing it, allowing us to have a new version ready and waiting before making the final switch. Feature flags took this a step further, allowing us to release code to production in a dormant state, to be activated for specific users later. These were the crucial first steps in reducing risk and increasing velocity. But they were still fundamentally human-driven rituals. A human still decides when to switch the router for a blue-green swap. A human still logs into a dashboard to flip a feature flag. This is a human-speed action in a machine-speed world. When thousands of validated changes are produced per hour, this manual gating becomes the new bottleneck. The AI-DLC demands the next evolution. In this new world, there is no ceremony. There is no event. There is only a continuous, living flow from creation to reality. The Verifiable Runtime doesn’t just commit code to a repository; it’s the antechamber to production. Once a change has passed its BDD and TDD gauntlet and been cleared by the architectural immune system of the hypergraph, it is deemed eligible to go live. But it’s not a big-bang push or a manual flag flip. That’s far too crude and violent for a living system. Instead, we treat deployment like a biological process, managed by a new entity: the AI Release Conductor. This agent takes the validated change and performs a delicate, intelligent, and autonomous rollout. The process begins as a microscopic canary. The change is exposed to the smallest possible surface area - a single internal user, a fraction of a percent of synthetic traffic. The Conductor then watches. It doesn’t just watch server metrics; it taps directly into the rich, four-layered reality of the Nervous System (our Control Tower). It looks for the subtlest signs of trouble: - A 5 ms latency increase in a downstream service three hops away? - A statistically significant uptick in user rage-clicks in the checkout funnel on the other side of the planet? - A minor violation of the architectural principle of data immutability that only manifests under load? The Conductor sees it, correlates it, and, if any predefined risk profile is breached, it retracts the change instantly and automatically. The rollback is surgical and immediate, often occurring before a single human is aware there was a problem. The failed mutation is simply discarded, and a new mission is often created for the AI swarm to attempt a different solution. However, this autonomy does not mean an abdication of responsibility. For the most critical, high-stakes changes - a modification to the billing system’s core logic, for example - the Conductor’s flow can be configured with a crucial checkpoint. The process can be set to pause after a successful internal canary test, awaiting an explicit, logged approval from a designated human lead before proceeding to external users. This creates an auditable “human-in-the-loop” gate where it matters most. We get the speed and safety of autonomous deployment for 99% of changes, while reserving human judgment and accountability for the 1% that could have profound business impact. If the change proves healthy, the exposure grows. The Conductor gradually widens the aperture - 1% of real users, then 5%, then 20% - continuously, at a pace governed by our defined risk tolerance, not by a human schedule. The system is constantly probing, testing, and confirming the fitness of each new evolutionary step. This is the death of the version number. There is no “version 2.1.5” that everyone gets at once. There is only a perpetual, self-healing stream of evolution. The codebase is less like a built artifact and more like a coral reef, with thousands of tiny, validated changes constantly and safely adding to its structure, becoming one with the living system. #### The Nervous System: Radical Observability he entire lifecycle we’ve described - intelligent swarms, living architecture, and the continuous, biological flow of deployment - is only possible if we can see. And the way we’ve been seeing is no longer good enough. For years, we’ve practiced “monitoring.” We collect logs, metrics, and traces. We ask the system if it’s okay by setting up alerts for when known thresholds are breached. This is like asking a patient, “Do you have a fever?” It’s a useful question, but it tells you almost nothing about the complex interplay of their circulatory, nervous, and endocrine systems. The AI-DLC requires a shift from monitoring to Radical Observability. We need a live MRI, blood panel, and neural activity map of the entire organism and its environment, all synthesized in real time. This is the purpose of the Control Tower. This is not a dashboard. A dashboard is a collection of charts that a human must interpret. The Control Tower is a synthesis engine. It is the sensory cortex for our city of code, and it watches four distinct layers of reality at once: 1. **Application Health:** The basics are still here - logs, metrics, traces - but they are the raw data, not the final product. An AI constantly analyzes these streams, hunting not just for the “known unknowns” (the alerts we set up), but the “unknown unknowns” - subtle, multifaceted patterns across thousands of signals that indicate emergent failure before it cascades. It’s the difference between an alarm for high CPU and an insight that a 2% increase in database latency combined with a 1% drop in user session length in a specific geographic region predicts a major outage in 45 minutes. 2. **User Experience:** The system directly observes the impact of its own evolution on its inhabitants. The code can be 100% correct according to its tests, but if it harms the user’s experience, it is a failed mutation and must be retracted. The Control Tower ingests real-time user data, watching for frustration signals like rage-clicks, drops in engagement, or negative sentiment in feedback channels. Technical correctness is subordinate to user value. 3. **Architectural Integrity:** Is the city we’ve built matching the blueprint? The Control Tower perpetually compares the deployed reality, as represented in the hypergraph, against the living architecture of the published RFD. It is the guardian of our architectural constitution, alerting us to architectural drift - the slow rot of ad hoc fixes and unapproved connections that turns an elegant design into a slum. 4. **Lifecycle Health:** Finally, we apply the principles of observability to our own process of creation. The Control Tower watches the factory itself. How efficient are our AI agents? Where are the bottlenecks in our RFD loops? Is a particular part of the codebase generating more failed mutations than others? We tune the factory for maximum evolutionary efficiency. This nervous system is what allows human conductors to manage a system that operates at a speed no human can manually track. We stop watching the individual cars; we watch the flow of traffic, and the AI tells us where the jams are before they happen. ### Conclusion: The New Job — From Coder to Conductor So, we arrive at the central, unspoken question that haunts every discussion about AI: What’s left for us? When an army of intelligent agents can write, test, and deploy code at a speed we can't possibly match, what is our purpose? The fear is that we become obsolete. This is the wrong fear. The right perspective is that the job we’ve been doing — the tedious, line-by-line translation of human requirements into machine syntax — is what becomes obsolete. And this is a liberation. We are being freed from the assembly line to finally become the architects and city planners we were always meant to be. Our job doesn’t disappear; it elevates. We stop being coders and we become conductors. A conductor does not play every instrument. They don’t need to know the precise fingering for the violin or the embouchure for the trumpet. A conductor's role is to understand the music as a whole, to shape the performance, and to guide the emergent harmony from a hundred different players. This is our new job. Let’s break down what this means: - **We Set the Strategy:** The conductor chooses the music. Our first and most critical role is to provide the strategic intent. We use tools like Wardley Mapping to understand the landscape, to identify where to play and why. We define the mission. The AI is a brilliant tactical engine, but it needs us to give it a destination worth driving to. - **We Design the System:** The conductor shapes the interpretation of the music. We lead the RFD process, synthesizing the best of human and machine intelligence into a coherent architectural vision. We are the final human gatekeepers who say, “Yes, this is the elegant, resilient, and correct way to build this.” We apply our taste, our experience, and our ethical judgment — qualities that cannot be automated. - **We Orchestrate the Builders:** The conductor cues the sections and manages the tempo. We use AI orchestration tools to design the workflows that build the system. We are the ones who tell the AI how to build. We design the BDD-to-TDD flows, the validation checks, and the feedback loops. We are the meta-engineers, building the factory that builds the product. - **We Debug the Emergent Whole:** When a single violin is out of tune, it's an easy fix. When a subtle dissonance emerges from the interplay of the entire brass and woodwind sections, only the conductor can hear it. Our most crucial role will be as the system-level debuggers. When a truly novel, complex bug appears from the interaction of a thousand perfectly coded microservices, it is human intuition and a holistic understanding of the system that will find the ghost in the machine. We stop writing boilerplate and start making decisions. We stop chasing syntax errors and start architecting elegant systems. We stop being bricklayers, focused on the individual stone, and we become the conductors who see and shape the entire cathedral. It's a better job. It's the job we should have been doing all along. ### References - [RFD process](https://rfd.shared.oxide.computer/rfd/0001) - [Digital twin](https://docs.systeminit.com/reference/architecture/digital-twin) - [Jujutsu](https://github.com/jj-vcs/jj) - [Zed multiplayer](https://zed.dev/docs/collaboration) - [SI multiplayer](https://docs.systeminit.com/reference/architecture/ai) - [Moldable development and building tools for the task](https://gtoolkit.com/) - [Building tools for the task](https://oxide-and-friends.transistor.fm/episodes/debugger-driven-development) --- # A future ways of working - Date: 2025-09-19 - Tags: devops, oxide - URL: https://magistr.me/blog/future-ways-of-working/ A video from another era—2013, suddenly found me. Bryan Cantrill talking with the unshakeable confidence of someone who hasn't yet lived through the next decade. His proposition from back then is simple: build a company around brilliant engineers, a grand purpose, and almost no structure. I glance at a chart made in 2021, a prediction for how we'll all work in 2031. It’s funny—the "future" it describes with words like "Leaderless Leadership" and "Non-Hierarchical" is a perfect echo of this decade-old rant. And he's not just talking; he's building his company, Oxide, on these exact principles right now. His core argument is that many standard corporate practices are actively harmful. He frames it like this: - Hate the ritual of the formal annual performance review? You don't actually need it. - Tired of the obsession with hierarchical titles and career ladders? You don't actually need them. - Find the idea of stack ranking your colleagues destructive? You don't actually need to do it. - Frustrated by non-technical managers creating date-driven death marches? You don't actually need them. {{< youtube 1KeYzjILqDo >}} chart from https://medium.com/mapresearch/how-organisations-are-changing-cf80f3e2300 --- # CfgMgmtCamp Day 0 - Date: 2025-02-03 - Tags: blog, me - URL: https://magistr.me/blog/cfgmgmtcamp-day-0/ Last year, I went to FOSDEM and Config Management Camp as a place to meet colleagues I hadn’t seen for a few years after moving to the Netherlands. I did that and also met new people from SI, which opened my eyes to the English-speaking tech world. Before that, I was mostly in Russian-speaking tech circles, and even though I read professional sources, I never truly felt like I belonged there. That meetup changed everything—I felt like I had found my tribe at Config Management Camp. That’s why I was really looking forward to this year’s event. I skipped FOSDEM, as it’s too busy and overcrowded, and instead planned a direct trip to Ghent. The day started early, at a frosty 8:00 AM. The sun was shining, and the sky was clear blue. I went through my usual morning routine: breakfast—quesadilla with chicken and a cup of black tea. Packed the last few items—my toothbrush, iPad, notebook, and charger. Took a long bath to wash away the night’s sweat and refresh myself before the trip. Applied my favorite patchouli-scented perfume. Collected the garbage and paper bags from food deliveries, ready to throw them away on my way out. And, of course, I skimmed through Twitter, Bluesky, and Telegram to wake up and check if anyone else was going. I was eager to get going, and just before leaving the house, my friend sent me a message thanking me for my support. I smiled—that was the best way to start a long day. Off I went, putting on my daily Spotify playlist. It picked some Eldamar songs. A short 10-minute walk to the tram stop—it was a bit chilly, but I was well-dressed: a T-shirt, a thin SI hoodie, a Uniqlo undercoat, and a Decathlon jacket as the top layer. I was warm. I got to the stop on time, and shortly after, the tram arrived. As usual, I took a spot behind the conductor’s booth. My trip had officially begun. At the next stop, a pair of partygoers boarded—they had an overpowering, unpleasant perfume. The man wore a hoodie, sweatpants, and a banana bag, while the woman, in a white hoodie, had the classic Instagram face—platinum blonde, long lashes (some of her hair was even stuck in them). Luckily, the man blocked most of the strong perfume, and they left after a few stops. During the ride, I noticed an old, gray-bearded man riding a bike with Palestinian flags. His face didn’t match the expected nationality. A few stops later, he left his bicycle on the bike path after a bridge. I arrived early at the railway station, so I passed through it and went to AH. It took me two rounds to find Snickers and Twix for the three-hour trip. Bought them and headed to the platform. Initially, I went to 13B, which had a shutdown timetable and was nearly empty—not that I minded. But after half an hour, a ProRail staff member approached me and explained I needed to go to 13A for my train. Sure enough, that was the right spot. It was more crowded there, but I put my backpack on a concrete platform holding the signs and relaxed in the sun, scrolling through my phone. After another 30 minutes, the train finally arrived. As usual, it was the red Thalys—now Eurostar. I queued briefly to board my carriage. Luckily, my seat faced forward. The seat beside me was occupied by a French man who, for some reason, was wearing a thick black winter jacket. He eventually took it off after a few stops. I put on a podcast—one featuring Shane Pegg about AGI, Google DeepMind, and other related topics. Unfortunately, it wasn’t very useful or interesting, except for his prediction about the exponential growth of data and algorithms, leading to a boom around 2025. The window on my side was closed due to the sun, so I looked out the opposite one, watching green fields and farms pass by. After about an hour, the podcast ended, and I started a new one with Patrick Debois about DevOps and AI. Sadly, it was also disappointing—no new thoughts or insights. I ate my Twix, and after two hours, we arrived in Antwerp. I decided to explore a different side of the station, which meant taking a slight detour to reach my next train to Ghent. Fortunately, it arrived early, giving me ten minutes to get from deep underground at platform 18 to platform 1. Made it in time and boarded. To my left sat a family with a small girl. Her jacket was left on the seat—it was warm inside. Shortly after, a new pair of passengers arrived next to me, embodying the classic “gamer and gamer girlfriend” meme. I ate my Snickers and gazed at the sunlit green fields again. Another hour passed, and I arrived in Ghent. Ghent station is under reconstruction, with some exits closed. I forgot that I needed to take a tram and wasted a minute roaming around the bus stops. Ended up missing my tram and had to wait another ten minutes. In the meantime, I sent a message to the SI Discord to see if anyone wanted to meet up for dinner—silence was my reply. I reached the hotel and was surprised to learn that my room was in another building. Got there—it indeed had a garden view and was quiet, but no bathtub, which was something I had specifically looked for. Dropped my backpack, freshened up, and started searching for a nearby restaurant. Found Boker Tov, headed there, and ordered shakshuka with a pomegranate and star anise mocktail. It was hot and delicious. Also ordered a tahini brownie but was too full after the shakshuka, so I had it packed to go. Leaving the restaurant, I took a scenic detour back. Roamed along the riverbanks and old buildings, snapping a few photos of a castle and a church. On a bridge under the crescent moon and bright Saturn, a man was sitting, playing a handpan. I paused my walk and listened for a few minutes—it was a pleasant, soothing melody. After that, I continued to the main road and stopped by the nearby AH. Bought a sandwich, a cheese plate, and bread for breakfast. Got back to my room and took a shower. Afterward, I dove into chats and spent some time in a conversation about rakugo and the Monogatari series—it was fun. Made some tea and ate another few pieces of the brownie. Calculated when I should wake up to get breakfast and make it to the opening talk at 9:00 turns out I’d need to be up by 7:30–8:00. Pretty early. But instead of sleeping at 22, I ended up watching YouTube… and now, I’ve decided to write this blog post. So here it is. --- # Reinventing the wheel? - Date: 2024-07-22 - Tags: devops, serverless - URL: https://magistr.me/blog/reinventing-the-wheel/ Recently I stumbled upon that talk https://youtu.be/3jJ1GhGkLY0 about reinventing k8s by removing unneeded docker images, and that lead to intresting consequience - They were able to create Modal an GPU serverless platform. After that I went and read Eric's article about software 2.0 https://erikbern.com/2021/04/19/software-infrastructure-2.0-a-wishlist.html And there was a great picture ![Programming loops](/images/blog/programming_loops.png) It explained to me one of the issues with serverless adoption, current workflow requires us to make lengthy deployments to cloud, and even having tools like amplify or even cloud IDEs that still takes too long. Another thing that I found is that there is no way to measure cost of a function while you develop it. Yes you can approximate that via memory and cpu usage but we dont do that during development. And that means that main feature of serverless cost based development mostly not present during development phase - and that means it does not bring value. Of course there is vercel and next.js and they proving not just a platfrom for FaaS development its a whole experience. I've struggled to just create lamda on AWS and it also was not a simple task in GCP. But when you can easyly instegrate your code with few annotations into runtime that handles all the heavy lifting - that greatly helps. And we see that on a vercel rise. --- # Devops Landscape - Date: 2024-04-27 - Tags: devops - URL: https://magistr.me/blog/devops-landscape/ In thouse turbulent times it feels like another tectonic shift is happening on a devops landscape, so I'm wondering what would future hold and what will be important, like was important more than 10 years ago when devops established itself. So I've ventured into exploration and attempt to gather like-minded people to create devops industry landscape as it is now in order to see where it's going and what will be relevant in near future. Here is initial maps ![Devops tooling](/images/blog/Devops_tooling.png) ![Tools history](/images/blog/Devops_tools_history_Apr_2024.png) --- # Devops Roadmap - Date: 2024-04-27 - Tags: devops - URL: https://magistr.me/blog/devops-roadmap/ I was asked by a friend to advise him a devops roadmap, all the ones that I found on internet were incomplete or i just didnt like them, so after few months of thinking about that topic, and todays nudge in chat from another soon-to-be devops about roadmap. Ive took my favortite one size does not fit all pattern and tryed to create respective maps for technologies and tools that would be applicable on that stages. So here we go, agile, focus on a speed of change, mostly about local development experience ![Agile Devops](/images/blog/Agile_devops_apr_2024.png) After code is written and somehow tested it's time to check if it works, and also can it be merged, makes sense, and all the other fun staff of CI. Also here is beggining of bureaucracy with task tracking, PR tracking, test tracking, code review debates etc. ![Lean Devops](/images/blog/Lean_Devops_Apr_2024.png) And if its ok you can also ship it to your runtime of choice. After that serious business starts with all the *bility words and SLI SLA SLO ROI. ![Six sigma Devops](/images/blog/Six_Sigma_Devops_Apr_2024.png)