Summary

EntropiaOrme v0.1.0 ran as two processes: a native shell, and a bundled Python backend the shell spoke to over local HTTP. The backend was ported to Rust by AI agents (Fable 5 and Opus 4.8), one service at a time behind an equivalence gate: recorded and scripted play sessions were replayed through both implementations, and a ported service landed only by reproducing the Python backend’s outputs byte for byte. Since v0.2.0 the app is one Rust binary; the installer is about 70% smaller (181 MB to 54 MB, per the releases page) and live data appears in about 0.8 seconds instead of 3.5.

Problem statement

In the first release, the analytics backend was written in Python and ran, together with a bundled Python runtime, as a second process beside the native shell. That process had three costs: the runtime dominated the installer, live data waited on a second program starting up, and the socket between the halves added failure modes of its own. Therefore, the backend was moved into the shell’s own language.

v0.1.0 · two processes
Native shellUI, screen capture
Python backendbundled runtime
v0.2.0 · one binary
Rust shell + backendin-process calls

The equivalence gate

The risk in the port was output slightly different from the Python backend’s, so the current behaviour was pinned down in a checkable form before any of it changed: play sessions are replayed through the full pipeline in the game’s own chat.log format, and everything observable at the far end is captured into committed reference files that a ported service has to reproduce. Where the reference files did not reach (some database tables had none), the gap was recorded rather than assumed covered, and those surfaces were watched through a period of real play before the old backend was removed.

Play sessions17 scripted · 1 recorded hunt
Python backendthe reference
Rust portthe candidate
Normaliseidentifiers, timestamps
Compare byte for byteevents · database · API responses
Testing equivalence gate used to guide migration.

Porting with agents

With the gate in place, the porting was orchestrated with AI agents (Fable 5 and Opus 4.8), one service at a time. The replay harness is what made the orchestration workable: an agent could replay the sessions, compare its port’s output against the reference files, and keep correcting itself until they matched, so the work could run in long uninterrupted spans; the longest single run had Fable 5 working for over 32 hours.

The reference files did not cover everything. Two defects were caught by manual testing, both on uncovered surfaces: a settings file with two writers, and a keyboard listener that had collapsed two independent hooks into one. Each was diagnosed against candidate causes by independent agents and settled by a manual reproduction. When the last service was ported, the socket was removed.

The pure-Rust OCR experiment

One native dependency remained after the migration: the ONNX runtime that executes the OCR model. A reimplementation in candle, a Rust machine-learning framework, was proven faithful (across the 594-image test set from the OCR benchmark, the two implementations agree on every cell), but it measured about four times slower on CPU, has no GPU route matching the DirectML one the app uses, and pulls in a C library transitively. It is parked, with its equivalence proof, on a public branch.

Results

The two architectures are compared below, measured once the port had settled.1

Python backend (v0.1.0)Rust backend (v0.2.0)
Release files
Installer181 MB54 MB
Portable package181 MB52 MB
Cold start, from process start
App window visible372 ms392 ms
Backend ready3,054 ms794 ms
Live data painted3,535 ms802 ms
Idle memory, by component
Native shell32.6 MiB137.2 MiB
Python backend (2 processes)~192 MiBnone
WebView2 renderers~550 MiB~547 MiB
Whole app775 MiB684 MiB
CPU usage while tracking a hunt
Mean0.2%0.0%
95th percentile0.8%0.1%
Peak1.5%0.3%
Cold start in warm-run medians; both versions load the same frontend, so the app window itself paints at parity. CPU usage is the share of a 12-core machine over a recorded hunt.

Conclusion

EntropiaOrme has been one Rust binary since v0.2.0, and v0.2.1 retired the Python implementation entirely; the behaviour it defined remains in the test suite as byte-for-byte assertions. The porting itself, run behind the gate, took about two weeks; the gate and its recorded sessions were built over the weeks before.

Footnotes

  1. Installer and portable sizes are computed from the published release files; the remaining figures are instrumented rebuilds measured on Windows 11 (12 logical cores) under light background load: cold start over six runs, idle memory as the median of five samples after settling, and the tracking measurement a recorded 150-line hunt replayed at real cadence (about 229 seconds). The figures compare the two architectures rebuilt with current dependencies, not the historic v0.1.0 binary as released. OCR per-scan latency and the game’s frame rate were not measured.