Denny Schaedig — home
← Back to Overview

MAXIM 1.3.2

Foundations

A release with no new headline result, on purpose

Design write-up By Denny Schaedig · Written October 2026. The counts here were measured at the v1.3.2 tag; its changelog is the authority wherever the two disagree. For what ships today, see pymaxim.bio.

Most software releases lead with a new trick. pymaxim 1.3.2 doesn't have one, and it makes no new claim about what Maxim's agents can do. Instead it spends a whole release on the parts nobody sees: places where Maxim's memory systems quietly reported the wrong thing, the project's biggest and most tangled file, and above all the way I work on it. You can't trust the next headline if you can't trust the foundation it stands on.

Renovating Before You Build

Picture an old house you want to add a second storey to. A sensible builder doesn't start with the new floor. They open the walls first and find the wire that runs nowhere, the pipe that has been dripping into the basement, the circuits nobody labelled. Then they fix what they found, write down what they changed, and only then build up.

1.3.2 is that inspection for Maxim, my open-source AI agent with memory systems loosely modelled on parts of the brain. Everything in it is a fix, a guard against a fix coming undone, or a change in how the work is done. It doesn't show that Maxim's agents learn anything new, and I'm not claiming it does. The release notes also carry this month's downgrade of the drowning-fear results, which a plain learner matched; Floors tells that story, so I won't repeat it here.

Memory That Tells the Truth About Itself

Maxim's parts are named after brain regions. That's a way to organise the design, not a simulation of a brain. Several of those parts had been reporting things that weren't true. None of them crashed loudly. Each one quietly bent what the agent learned or what an experiment recorded.

A failure, booked once

Maxim keeps score of which actions worked in a part named after the nucleus accumbens. When a tool failed and then succeeded, the score could come out as two successes. Some failures were booked twice. It was a till that rang up a refund as a sale. Now each failure is booked once, against the exact attempt that failed, along with how surprising it was. Robot movements got the same fix (#1200, #1207, #1209, #1221).

Learning that went in the bin

The Cerebellum, Maxim's part for predicting what a movement will do, saved its learning to one place and loaded it from another. Picture a diary written every evening and filed in a drawer nobody opens, while the morning reader checks a different one. Every session started from scratch. Now it saves where it loads (#908). Nothing acts on those predictions yet, so no behaviour changes.

Two parts that crashed when busy

The SCN, Maxim's internal clock, could crash when a background job added to it while sleep or a save was reading it, like two people editing the same list at once. The Hippocampus, which stores episodes, had the same weakness and showed it as an intermittent test failure. Both now take turns (#1217, #1135).

An engine left running

The Default Network runs background tasks while the agent is idle. In simulations it was never switched off at the end of a run, so its threads kept ticking on a finished run, like an engine left running after you park. They also drew random numbers that broke an unrelated test. The loop that starts it now stops it (#1263).

The narrator who couldn't hear

Some of Maxim's experiments run in a simulated world described by a narrator, a second AI that decides what happens next. The narrator was getting a delivery receipt instead of what the agent actually said, so it chose its next move without hearing the reply (#1261). And the narrator's own tool notes had leaked into the agent's instructions, telling the agent that its reply tool was “NOT AVAILABLE”, which cost an extra step on every reply (#1260). Picture an interviewer wearing earplugs, handing the candidate a sign that says “don't answer.” Both are fixed. Runs from before and after aren't comparable wherever the narrator depended on the agent's replies, and re-checking the affected experiments is its own follow-up.

The last fix in this group is just honesty. Some mechanisms never earned a role in behaviour: scaffolding that made it look as if pain could interrupt an action (#1179), a fear bridge whose calls never matched the part it talked to (#840), and a recall function whose “story memories” have always come back empty (#1138). They are now marked Dormant in the code, with the reason. The project's rule is dormancy over deletion: in code this tightly wired, ripping out a dead wire can break three live ones. So you label the circuit in the fuse box “not connected” and build nothing new on it. It only comes back if a new experiment earns it a place.

Taking the Loop Apart Without Breaking It

Every Maxim agent runs one central loop: perceive, think, act, learn, repeat. At 1.3.1 that loop lived in a single file of 5,543 lines. That's hard for anyone to hold in their head, and hard to change safely. In 1.3.2 it is down to 3,363, and the pieces live in nine smaller modules with one job each, six of them new in this release: setup, gates, perception, planning, the bio-system's proposals, and so on.

The danger in a move like that is changing what the code does without noticing. So before each piece moved, I wrote a characterization test: a recording of exactly what the old code did, from the outside. The moved code had to pass it unchanged. It's like photographing a room before you move the furniture, so you can check that everything ended up where it was.

Then come the ratchets. A ratchet wrench turns one way and won't slip back, and the project now has several checks that work the same way:

  • Function length. The 52 functions still over 200 lines are pinned at their current size. None may grow, and no new one may pass 200.
  • Test coverage. The share of code the tests exercise has a floor, overall, per package and per file, that only rises, and new changes must be at least 80% covered.
  • Type checking. An automated check that each piece is handed the kind of data it expects now covers the layer that wires the parts together, at 0 errors (37 before). Elsewhere, no file's error count may rise.
  • Silent errors. No new code may swallow an error without reporting it.

The decomposition isn't finished, and I've made that binding. An automated check now refuses to let any 1.4.0 release pass until the rest of the job is done: a written list of 32 items, 3 functions that must shrink, and 5 more recordings of the simulation runner. That is a promise about process, not a claim about behaviour. No new storey until the inspection list is closed.

The Front Door Was Unlocked

One fix in 1.3.2 is a security fix, and it's the one to read first if you run Maxim. Several Maxim machines can work together, with one acting as the leader that the others connect to. Before 1.3.2, a machine that hadn't been told its role became a leader by default, and a leader without a password-like key let anyone in. Remote-admin commands were switched on whenever that door was open, and through a Cloudflare tunnel, the leader's debug pages could be read by anyone who knew its web address. It's as if the renovation found that the house had been shipped with the front door unlocked and the spare key taped to it.

The fix makes Maxim fail closed: when in doubt, it refuses instead of allowing. A machine now defaults to working alone. A leader without a usable key refuses to start and says how to fix it. A request from the machine itself no longer counts as proof of who sent it, and remote admin stays off until you switch it on. Each of those guards was proven the same way as every other guard in this release, by deleting the thing it protects and watching its test fail. The problem is published as a high-severity security advisory covering pymaxim 1.3.1 and earlier.

If you run a Maxim leader

Upgrade each leader on its own machine and restart it from cold. Don't upgrade and restart it remotely: a remote restart carries the old settings into the new process, and a leader that now refuses to start can't be reached remotely to fix it. Run maxim doctor there first. The advisory and the changelog list the steps: setting the role, creating or tightening the key, opting back in to remote admin, and moving peers to the new port.

How I Work Now

The fixes above are the evidence. This is the part I'd most want another engineer to take away: the habits that found those defects and that keep them found.

1. Show the leak before you fix it.

Every bug fix starts as a test that fails for the right reason, marked as an expected failure. The fix has to make it pass. If the fix lands and the test still fails, that's not an annoyance to delete. It's the test telling you the fix didn't reach the bug.

2. Test the smoke alarm with smoke.

A guard only counts if removing the thing it protects makes it fail. Every new guard is proven by deleting its mechanism and watching it go red. A test that stays green with the mechanism gone is decoration.

3. Three different inspectors.

Every code change gets three reviewers before it merges. One asks whether it works, one whether it's the right design, and one traces every place outside the change that feeds it or reads from it, like the inspector who follows the pipes into the next room. Fixes from a review are reviewed again. The point is a different reader, not a more careful one: an audit found that eight of eight sampled breaking changes reviewed by just two readers missed a broken connection.

4. Weak evidence never counts.

A run that crashed or stopped early isn't data. It can't change a result's status or a release claim. Each result is stamped with the exact code, model and settings that produced it, and the ledger of results is machine-readable, so an automated gate checks it rather than my memory.

5. Exceptions are written down.

When I decide to bend a rule, the decision is committed as a machine-readable record, never a verbal OK. 1.3.2 ships with one result, the cross-session experiment Exp 37, marked out of date under a written exception, and its changelog says so.

6. Inspect the house as it stands today.

The slow tests run overnight. A release now refuses to go out unless every overnight run passed within the last 48 hours on the exact code being released. Last week's clean inspection doesn't cover this week's wiring.

In numbers, since 1.3.1: 189 pull requests merged; the Python files in the test suite grew from 575 to 697; and the repository's automated lint checks, each one a rule that a script enforces instead of my attention, went from 13 to 24. That last number matters most to me. A rule followed by attention is where slips land. A rule a script enforces is one I can stop worrying about.

What It Doesn't Show, and What's Next

1.3.2 claims no new behaviour. It doesn't show that Maxim learns better, faster or more than it did. Some of its fixes may even make learning look slower, because a failure that used to be counted several times now counts once. What it does show is narrower: the memory systems now report what actually happened, the loop is smaller without doing anything differently, and the rules that keep both true are enforced by scripts.

The next survival experiments need a situation that a plain learner could actually lose, as Floors explains. And 1.4 builds on the decomposed loop, which it can't ship without finishing. The source is on GitHub, and the docs and the evidence ledger are at pymaxim.bio.

A release like this is the house inspection nobody photographs for the listing. It's also the only reason to believe the listing.