What I Read This Week by Trevor Houghton

Reads · saved 2026-11-04

Instead of .md specs, try this: make the system a state machine (or rather, a reducer). Ask your ...

dearlordylord @ohdearlordylord ♥ 1.9k

Instead of .md specs, try this: make the system a state machine (or rather, a reducer). Ask your slopus to make an interactive diagram with real events from your flow and the real reducer. Step through them, asking the agent "whys" this and that.

Read the original on X ↗

Full captured text
**Shared by trevor:**
This is wild but I kinda wanna try

Instead of .md specs, try this: make the system a state machine (or rather, a reducer). Ask your slopus to make an interactive diagram with real events from your flow and the real reducer. Step through them, asking the agent "whys" this and that. https://t.co/AQIJEu7hMZ

Summary

@ohdearlordylord suggests writing a system's core as a reducer instead of a markdown spec. A reducer is one pure function: it takes the current state and an event and returns the next state. You then ask the agent ("slopus" is slang for Claude Opus) to build an interactive diagram that replays events through that same reducer. You step through it and ask the agent why each step happens.

The worked example is the author's open-source tool Hapsland, a realtime reviewer for coding agents. Its core is written in Bend and wired to TypeScript with Effect. One reducer drives production, the diagram, a seeded simulator and a game, and a repo check bans any second copy of the logic.

The thread

Six posts by the author on 2026-10-12. The first three carry 5-second screen recordings.

1. **The post.** Make the system a state machine, or rather a reducer. Have the agent build an interactive diagram from real events and the real reducer, then step through it and ask "why". *Video:* a flat flow diagram of Hapsland's review loop. Each box is labeled by kind: a native fact (the agent's edit, the classifier request), a Bend decision (admission and capacity, job scheduling, review outcomes), Bend state (awaiting source read, ready advice, round state) or a native effect (read and prepare source, host output). Numbered arrows mark the transitions. A side panel shows the limits all agents share: 8 preparation workers and 8 classifier permits. Each step highlights the active arrow and names the item it moves, for example "Source #2 admitted, Round #1".

2. **The simulation is faithful.** It runs through the same logic as the production app. The diagram covers the whole path: an agent's code edit, real-time semantic enrichment, the classifier call and advice delivered back into the same agent turn.

3. **Simulation comes almost free.** Code modeled this way makes it easy to run automated simulations that check the system's "liveness" and show shared resource use under concurrency. The flat diagram alone gave about 90% of the benefit. *Video:* the same diagram as a stack of 3D layers you can rotate, one layer per agent, all sharing one background service's permits.

4. **Games from production logic.** LLMs can reuse the exact production logic to one-shot video games. That can serve as teaching material or explain concepts in docs, here the queues and key nodes such as the Jev classifier calls and delivery to agents. *Video:* "Switchback District", a pixel-art map. Edits travel as units through source reading, preparing, the classifier and pending findings. Panels show active work, and keys add bursts, outages and new arrivals.

5. **The point.** Better ways to see and understand LLM output are key to the "understanding bottleneck". Talk to your own model about the approach by pointing it at the codebase: [github.com/dearlordylord/hapsland](https://github.com/dearlordylord/hapsland).

6. **Stack.** Made with [Bend](https://bend-lang.com/) and [Effect](https://effect.website/) (EffectTS).

The repo: Hapsland

  • **What it is:** "Realtime semantic review for coding agents." It hooks into Claude Code and Codex CLI on each edit and when the agent stops, and into Pi through an extension. When the agent edits a type or function, Hapsland follows its references to gather the related definitions. It asks a classifier your rule questions and sends any finding back while the agent is still working, or at the latest when it stops. Site: [hapsland.dearlordylord.com](https://hapsland.dearlordylord.com/) ("make invalid states unrepresentable").
  • **Rules:** seven editable defaults about code design: `meaningless_combinations`, `split_correlations`, `absence_confusion`, `bare_domain_value`, `name_wider_than_type`, `name_claims_resource` and `body_reaches_undeclared`. The site's examples: a type that allows choices that don't belong together, a price and an amount paid both passed as a bare number, two lists that must stay in step, and the same fact stored twice. You can add your own rules as JSON. The repo runs all seven on itself.
  • **Classifier and data:** Jev from [TypeSafe AI](https://typesafe.ai/) by default, or Cloudflare's Clef. The changed declaration, its related code and the rule questions go out. The prompt, the chat, the diff and the rest of the file stay local. The README warns that some classifiers "like Jev store your data and can do with it whatever they want".
  • **Languages:** TypeScript types and functions, plus bounded support for Rust, Python, Go and Bend types. A skipped edit is not a clean review.
  • **State on 2026-11-04:** 135 stars, created 2026-09-19, last push 2026-10-31, 52 open issues. There is no license, so all rights are reserved by default. It installs by Homebrew tap on arm64 macOS and Linux. npm has `@hapsland/hapsland` 0.1.3 since 2026-10-09, so the README's npm 404 note is stale.
  • The reducer

  • `Canonical.step` in `packages/agent-flow-bend/Canonical.bend` is the reducer. It takes the state and one of 137 events. It returns `Advanced` (the new state plus outputs) or `Rejected` (the old state plus a reason).
  • Every event is a fact the host reports: a permit issued, an edit admitted, preparation done, a classifier request started or settled, the agent stopping. The reducer reads no files and no clock. The host passes times and sizes in as event fields.
  • The state holds a shared capacity ledger, review rounds and work items. A work item moves from awaiting source read to source reading, preparing, reviewing, a classifier request in flight and a pending finding.
  • Outputs come in three typed kinds: an action the host should run, an event now established and a policy decision. So the diagram never implies that an effect actually ran.
  • Bend compiles the reducer to JavaScript. Production calls it through one TypeScript adapter that checks inputs with Effect Schema, and the background service runs the effects in Effect fibers. A repo check requires production and the diagram to import that same adapter and bans any other copy. From the Bend package's README: "Generated JavaScript is an artifact, not an alternate implementation."
  • The diagram

  • It is live at [hapsland.dearlordylord.com/dashboard](https://hapsland.dearlordylord.com/dashboard) ("Hapsland agent flow"). The home page doesn't link to it.
  • It replays a list of events. The state at step N is the reducer run over the first N events from the start state. Rejected events stay in the history with the reducer's reason. The arrow keys move one event, and Shift plus an arrow moves one guided action. The default scenario runs 59 steps over 100 events.
  • It has 14 boxes with numbered routes, each tagged by owner: native fact, Bend state or Bend decision. Dashed arrows are requests, not proof that an effect ran. A box is a view, not a state in the reducer.
  • The author's rules for it (`DASHBOARD-RULES.md`): it is "a projection of compiled Bend transitions". The viewer holds no second reducer, scheduler or capacity math, and every arrow must trace to a record, an event and an earlier cause.
  • Its events are hand-built scenarios and simulator runs, not recorded sessions. Recorded agent sessions live in a separate local dashboard (`hapsland dashboard`).
  • Simulation ("Monkey Business")

  • A seeded simulator with a virtual clock drives the production reducer with a modeled world: agents making edits, classifier answers, delays and faults. Any run replays exactly from a JSON file that holds the seed, the inputs and a hash of the reducer source.
  • Its checks: every request settles once and frees its permit. No moment shows more than 8 permits or 8 preparing jobs. A refused request never starts. A stale finding is retired once a newer edit lands. A faulty agent doesn't block a healthy one, and denied imports are never read.
  • Shared limits: 8 preparation jobs and 8 classifier permits per machine. Extra preparation waits in a queue. A ninth ready review is refused at once, with no retry.
  • Limits: the liveness checks are bounded and mostly scripted, "not a proof for arbitrary schedules". The TigerBeetle-style random sweeps are a deferred issue ([#169](https://github.com/dearlordylord/hapsland/issues/169)). The simulator doesn't cover the full background service, file capture or the real Jev connection.
  • Laws and proofs

  • `packages/agent-flow-bend/LAWS.bend` holds 340 claims. Most are literal cases ("this input gives exactly this output"), such as a denied import producing a skip and no read. Twelve are general laws, checked by Bend's proof checker and a Lean kernel.
  • The general laws say that import trees stay under the byte cap, one operation can't disturb another's findings, an admitted edit reaches submission through the real reducer and the classifier request holds only the model, the state and the questions.
  • The checks plant bugs in production code and require each one to break a proof. A run with the kernel switched off must fail too.
  • The author's caveats: this is not an end-to-end proof, and liveness assumes the host delivers each fact or deadline. The README's "formally checked core" is narrower than it sounds.
  • The games

  • `prototypes/canonical-defense` is the game in the third video ("Switchback District"). It imports the production reducer, so its monsters are real work items. They pass source reading, preparation, a Jev room with three request lanes, pending findings and delivery. Towers only speed up callbacks; outcomes never change. It teaches fan-out, capacity, the stop deadline and delivered versus uncertain advice. Its native, JavaScript and TypeScript runs match byte for byte.
  • `prototypes/bend-tower-defense` is a hand-built teaching model that restates the rules; it doesn't run the production reducer. `prototypes/edit-admission-comparison` is a proof prototype, not a game.
  • The READMEs show many rounds of redesign, so "one-shot" undersells the work. Both games say that what players actually learn is unmeasured.
  • Practices worth copying

  • **Doc headers:** 62 of 68 markdown files open with Purpose, Audience, Status, Authority, Expected use and Lifecycle. An authority ladder (contract, guidance, proposal, evidence) says which doc wins: "a report does not become a product contract merely by describing implemented behavior". A temporary doc needs an exit: delete it or fold it into a named home.
  • **One routing table:** `docs/agents/navigation.md` maps each task to its contract, entry points and checks. `CONTEXT.md` is an 80-term glossary.
  • **Evidence rules** (`CHECKS.md`): cite the requirement first and "claim executed evidence only". Silence is not a pass. After two attempts without a telling result, name the competing causes and change the experiment.
  • **Declare, then amend:** success criteria are written before a test runs, and later changes are marked. Laws need a human's approval before proofs are written.
  • **Separate reviewer:** a reviewer agent ("Astra") writes only its report, and the parent agent owns final acceptance.
  • What the author said in the replies

  • **Influence:** the TigerBeetle approach (deterministic simulation testing). The author expects that "people are going to interrogate agents visually".
  • **Who it helps:** both the human and the model. It controls the model's intent and helps you discover and learn the domain.
  • **Production or mock-up?** Asked whether it drives the real production logic: "Yep. That's the point!"
  • **Scope:** one diagram won't express the whole system, but it is "a great lens into its inner workings", like the parable of the blind sages and the elephant.
  • **Models:** once the model sees a verified event stream, the author found Astra (a model or agent the author uses for reviews and visual work) good at this, and sends it any spatial or visual work (diagram layout, UX). An earlier experiment had it one-shot an explanatory animation from a reducer for a small kata: [piglatin.curatorman.com](https://piglatin.curatorman.com/).
  • **Skills needed:** "mostly software engineering skills", plus a domain-driven design agent skill.
  • Pushback and open questions

  • **Cost:** a reader who built something similar for domain modeling said Opus at high effort used about half its context by the time the artifact was done.
  • **Diagnosis, not design:** another found it good for diagnosing but weak for improving the architecture, since the model has to work out what the events mean.
  • **Toy projects only?** One reply says so. Hapsland itself, about 2,400 files, suggests otherwise.
  • **State explosion** (unanswered): in complex business logic, do you split into sub-machines or fix the grain early? Too coarse and the diagram becomes another .md.
  • **Also unanswered:** how it compares with TLA+, and the exact prompt used.
  • **Field reports:** one reader used it on a legacy Excel-to-AI HVAC inspection tool and says it finally opened the black box and helped fight recurring hallucinations. Another stepped a Win32 message loop from a real recorded trace and said it felt like a visual debugger.
  • Key Takeaways

  • **A reducer is a spec the agent can run.** A pure function maps the state and an event to the next state, with files, clocks and API calls kept outside. Unlike a markdown spec, it can't drift from the code, because it is the code.
  • **Replay events and ask why.** An interactive diagram that runs the real reducer over a list of events exposes missing states and wrong assumptions fast. The flat diagram gives most of the value.
  • **One core, many views, enforced.** Production, the diagram, the simulator and a game all call the same reducer. Hapsland backs this with a check that bans any second copy, so no view goes stale.
  • **Label what the diagram shows.** Typed outputs separate a request from a fact, so the picture never claims an effect ran.
  • **Simulation is cheap once the core is pure.** A seeded, replayable simulator can check that work settles and shared limits hold. Hapsland's runs are mostly scripted; full random sweeps are still a backlog item.
  • **Proofs as guardrails.** Bend's `LAWS.bend` holds rules the AI must prove ("AGENTS.md backed by proof"), and planted bugs show the proofs bite.
  • **Know the limits.** A diagram is one lens, not the whole system. Big domains need sub-machines. It costs tokens. It helps diagnosis more than design.
  • How to try it

    1. Pick one flow with a real event log, for example a request that moves from message to agent run to draft to approval to send.

    2. Ask the agent to rewrite that flow's core as a pure reducer: `step(state, event)` returns the new state and its outputs, or a rejection with a reason. Nothing inside reads a file, the network or the clock; time comes in on the event.

    3. Label each output as an action to run, a fact now true or a decision.

    4. Export a day of real events as a JSON list. Add a few hand-written traces with the outputs you expect.

    5. Ask for a one-page diagram that imports the same reducer, not a copy, and replays the events from the start state. Give it step, back and play. Highlight the active transition and keep rejected events visible with their reason.

    6. Step through it and ask the agent "why" at every surprise. Fix the reducer or the flow, not a doc.

    7. Later, add a seeded simulator: a heap of (time, sequence) with an integer clock, one random generator per concern and a replay file with the seed, the inputs and a code hash. Check invariants at every step, run to idle under a step budget and plant a bug to prove the checks fire.

    You don't need Bend or Hapsland to start. Python or TypeScript works.

    Links

  • Hapsland: [repo](https://github.com/dearlordylord/hapsland), [site](https://hapsland.dearlordylord.com/) and [the agent flow diagram](https://hapsland.dearlordylord.com/dashboard)
  • [Bend](https://bend-lang.com/), a fast language whose type checker checks proofs ("LAWS.bend is AGENTS.md backed by proof")
  • [Effect](https://effect.website/), the TypeScript library the app is built on
  • [Jev](https://typesafe.ai/), TypeSafe AI's classifier and Hapsland's default reviewer
  • The author's earlier reducer animation: [piglatin.curatorman.com](https://piglatin.curatorman.com/)
  • The author's blog: [dearlordylord.com](https://www.dearlordylord.com/)