Patrick Jackson · blog

ReduxKotlin for Coding Agents

1,382 words7 min read#kotlin#kotlin-multiplatform#redux#reduxkotlin#ai#agents

Here’s the loop I kept watching, in my own projects, with every agent I tried:

guess → edit → run → read the log → guess again

And the one I wanted:

write → run → rk devtools diff --last 10 → targeted fix

The difference isn’t intelligence. It’s whether the thing doing the work can see the result of the work. An agent that can’t tell whether its change worked will loop, and it will loop confidently, and it will spend your tokens doing it. The hard problem in agent-assisted development isn’t generating code. It’s verification.

Part 1 covered why Redux’s shape suits a machine: one mutation point, actions as data, serializable state, pure reducers. That part was free. It’s been true since 2015. This post is about the part that wasn’t free.

Agent knowledge is code, and it rots exactly like code

Start with the failure, because it’s the one nobody warns you about.

The obvious way to make a library agent-friendly is to write an AGENTS.md. Maybe a skill. Maybe some guides. You write them once, carefully, and they’re excellent.

Six weeks later the code has moved and all three are lying to your agent with total confidence.

That’s strictly worse than having written nothing. An agent trusts its knowledge files, so stale guidance doesn’t produce an error. It produces plausible, wrong code, built on an API that changed. And you can’t see it happening. Nothing fails. Nothing warns you. The docs just quietly stop being true.

We built enormous machinery to stop source from rotting: types, tests, CI, code review. Agent knowledge has had none of it, and it decays faster, because nothing breaks when it goes stale.

So in this repo the knowledge is treated as code:

  • Authored once, assembled. The per-concern references are the single source. AGENTS.md and the Claude skill are built from shared fragments, and CI fails the build if they drift out of sync. There is no second copy to forget to update.
  • Provenance headers. Every reference file names the exact source symbols it derives from, and the commit it was last verified against. When you read one, you can check whether it’s still true.
  • An API tripwire. The committed .api dumps declare every module’s public surface. Any change to one blocks the PR until a human looks at it. The dumps can’t silently drift from the code, which is what makes them safe for an agent to read instead of the source.
  • A drift bot. A check reads each PR’s diff against the provenance-headed knowledge and comments on which references probably need updating. It’s advisory and never fails a build, because a check that blocks you is a check you learn to work around.

None of this is exotic. It’s just taking seriously that a file an agent reads to make decisions has the same maintenance obligations as a file the compiler reads.

The verify loop

The second half is feedback. A codebase an agent can read is not the same as a codebase an agent can finish work in.

Four channels ship in 1.0, and the important thing about all four is that they emit text. None of them require anyone to look at a screen:

  • Reducer tests. Pure logic, no device, milliseconds. This one was always there.
  • --semantics (Part 8), a text dump of what the rendered screen actually says. Assert that the title is Ship v1 and the column has two cards, without rendering an image into a context window.
  • Golden pixel diffs (Part 8), a pass/fail line. The PNG only gets opened when something drifted and the drift needs a judgment call.
  • rk devtools diff (Part 7), what actually happened at runtime, as JSON lines, filtered to the actions you care about.

Cheapest first. Most iterations never need to look at a picture at all, and that’s the point: looking at a picture is the expensive operation, so it should be the last resort rather than the first instinct.

Rules that fail loudly

The other thing an agent needs is for wrong code to break, not to quietly work. Scattered through this series:

  • Dispatching inside a reducer now throws (Part 3) instead of silently corrupting state.
  • Granular subscriptions delete the hand-rolled diff, which was a bug class (Part 4).
  • “Bind the narrowest slice” is enforced by a recomposition-counting test, not by a style guide (Part 5). An agent has no intuition for Compose performance, but it can read a failing assertion.
  • “Restoration replays no events” (Part 6) is stated as a rule, because it’s exactly the bug that passes every cold-launch test and fails only on a real phone.

What you actually install

AGENTS.md at your repo root. Any agent that reads AGENTS.md (Claude Code, Cursor, Copilot, Codex) picks it up. It carries the rules card and the module map, and it’s deliberately small, because it’s always in context.

A Claude Code skill at .claude/skills/redux-kotlin/. It’s a decision-routing table: adding a feature, read this; wiring the store, read this; binding Compose state, read this; debugging a running app, read this. Eleven per-concern references behind one small router, so the agent loads the guide the task needs instead of the whole manual.

Installing it today means copying it into your project’s .claude/skills/, and I’ll be straight that this isn’t good enough: the skill’s links point up into the repo’s docs/agent/ directory, so copying only the skill folder leaves you with dangling references. Packaging it as a proper plugin is on the list.

The token argument, and its asterisk

Several decisions in this series were made with token cost in mind. The DevTools CLI’s three nested output tiers mean an agent pulls four fields per action to scan a timeline rather than an entire state tree, and escalates only when it needs to. The .api dumps mean it reads one flat file instead of grepping twelve source files and inferring the API from call sites. The knowledge is tiered so the small file is always loaded and the big ones aren’t.

Now the asterisk.

I haven’t measured any of it. I wrote down the metrics I care about (tokens to a correct feature slice, write-verify cycles to green, cold agent versus knowledge-equipped agent) and I have not run the baseline. There are no numbers in the repo and there are none in this post, because I’m not going to invent them.

The structural claims I’ll defend: four fields is fewer than a state tree, one .api file is fewer tokens than twelve source files, and a text assertion costs less than an image. The magnitude is a bet I haven’t cashed.

I’ve published hand-wavy performance numbers before, in 2020, and they turned out to be the symptom of a design problem I then didn’t chase for six years. Once was enough.

Where it nets out

ReduxKotlin isn’t an AI library and I’m not going to pretend it became one. It’s a state management library that happens to be made of the ingredients an agent needs, plus a set of verification channels that emit text instead of requiring eyes, plus a knowledge layer that is prevented from lying.

That combination lets an agent close its own loop. It can write a reducer, test it, seed a store, render the screen, assert what the screen says, and check what actually happened at runtime, without a human in the middle of any of those steps. Whether that makes it faster by some specific factor, I can’t tell you yet. That it makes unattended iteration possible, I’ve watched happen repeatedly in my own work.

Start here: reduxkotlin.org/ai-agents/building-with-ai-agents.

That’s the series. Nine posts, one store, and considerably more tooling than I expected to write when I started. Questions or comments, post below, find me on Threads, or follow the community links at ReduxKotlin.org.

Happy AI loop engineering!


Sources of truth: reduxkotlin.org · github.com/reduxkotlin/redux-kotlin · the TaskFlow sample

Part 9 of ReduxKotlin 1.0.