fluidfix
Zero-token repair decisions for mechanical single-line bugs. A machine-authored four-instruction kernel decides which repair to try, your test suite judges it, and a language model — when you use one at all — is only ever the eyes. Every output is either a repair your suite accepts — measured byte-exact in 26 of 26 accepted repairs on the benchmark — or an explicit refusal. There is no "plausible fix" branch.
pip install --upgrade fluidfix # core: zero runtime dependencies
pip install "fluidfix[llm]" # adds the Claude Opus 5 observer
# commit-and-forget: watch the suite, restore what breaks, refuse what is novel
fluidfix guard path/to/project --python path/to/venv/bin/python --interval 900 --commit
# or one-shot on a known defect file
fluidfix repair path/to/project --file pkg/module.py --python path/to/venv/bin/python
How fast will it be on your repo? Repair time is suite runs x your suite's own runtime — test count barely matters. Ask before you commit:
fluidfix estimate .
1990 passed, 25 skipped in 4.87s
suite runtime: 5.60s (+~0.5s pytest startup per run)
EXPECTED REPAIR TIME on this repo
typical in-vocabulary defect (2-10 suite runs): 12.2s - 61s
(Those bounds are real: the same repo repaired in 36s and 50s.)
from fluidfix import Oracle, build_packet, MechanicalObserver, repair
oracle = Oracle("path/to/project", python="path/to/venv/bin/python")
packet = build_packet(oracle, "pkg/module.py") # mechanical, 0 tokens
observations = MechanicalObserver().observe([packet])[0]
print(repair(oracle, "pkg/module.py", observations).summary())
▶ Full demo video (76s, real-time output) · ▶ Live session, unedited + its wall-clock-stamped terminal log (every command shown, breaks included — 3 repairs and 1 refusal in 6.5s of machine time) · Beginner quickstart · Step-by-step tested instructions — every step enforced by tests/test_demo_walkthrough.py in CI.
Watch it (each under 30 seconds, real runs)
| Live from PyPI | install + exhaustive selfcheck |
| Deploy, break, forget | guard repairs and commits in 0.7s |
| Real library | 455-test suite, byte-exact restore |
| Teach a class once | refused -> register() -> repaired |
| One hard example, whole class | one dictionary fixes 3 different files |
Measured, not promised
All numbers below are from a live benchmark on 33 injected single-line bugs in
five real PyPI libraries (humanize, inflection, natsort, parse, wcwidth), each
library's own suite as the oracle, run 2026-08-30. Per-bug data and
methodology ship with this package in docs/BENCHMARK.md;
the corpus, injector, and recorded baselines are from
fluid-router
benchmark/.
| fluidfix (Claude Opus 5 as eyes) | full Claude Opus 5 debugging | |
|---|---|---|
| in-vocabulary byte-exact | 26/27 | 22/27 (5 green-only) |
| out-of-vocabulary | 6/6 refused honestly | 5/6 exact |
| silently wrong repairs | 0 | — |
| tokens¹ | 125,402 total (3,800/bug) | 1,322,802 (40,084/bug) |
| decision cost after that | 0 tokens² | ~40k tokens each time |
- The observer named the correct defective line 33/33 from lean packets averaging ~1,060 tokens.
- The mechanical localiser (no model at all) put the true defective line in the packet for 33/33 bugs, at zero tokens.
- The kernel's decisions are invariant under all 16 renumberings of the act vocabulary: 432/432 live decisions correct; a frozen lookup table scores 27/432 on the same test.
- With no model anywhere, fluid-router's recorded blind-search kernel scores 17/27 byte-exact at zero tokens — without the localisation this package adds. fluidfix's mechanical mode is validated end-to-end but not yet corpus-scored; see docs/BENCHMARK.md.
¹ Fleet-level harness measurement, all agent context included; the two token
columns use different accounting and support the ~10× ratio, not a precise
figure. Provenance: docs/data/lean_arm_tokens.json.
² fluid-router2's C verifier measures its kernels at 1.55 ns/decision; this
package's pure-Python reference is ~0.6 µs. Either way: no tokens.
The guard: deploy, commit, forget
Most deployed software is not being actively developed — it is being kept
alive. fluidfix guard is built for exactly that. It needs no defect file:
when the suite goes red it finds the fault file mechanically (traceback
frames, else failing-test coverage ranking), repairs it, and — with
--commit — records the restoration:
$ fluidfix guard . --commit
[16:43:06] billing.py: repaired line 2 in 4 suite runs (0.7s):
- return p * (1 - rate)
+ return p * (1 + rate)
committed
Run it one-shot in CI (exit 0 green/repaired, exit 2 refused), or under cron
with --interval. Green suite: it touches nothing. Novel fault class: it
refuses, leaves the tree byte-identical, and writes
.fluidfix/last_refusal.json — the teach-me signal for register() below.
.fluidfix/ is the guard's state directory: add it to your .gitignore.
How it works
suite fails ──► localise (frames ∪ failing-test coverage ∪ AST spans; 0 tokens)
──► observe (mechanical regexes, or one batched Claude call)
──► EMIT names the fault m & (-m)
──► route() picks the act 15 & ((x>>4)+((x>>8)-x)) ◄ the brain
──► apply & run the suite green → HALT
──► ADVANCE and try the next m - (m & (-m))
──► empty mask → refuse, never guess
The routing expression was authored by a program-synthesis engine and is
vendored verbatim from fluid-router
(verdict: minimal in D∩I); the loop discipline is
fluid-router2's
EMIT/ADVANCE/HALT, exhaustively verified on all 256 mask states. Run the
proofs yourself, offline, in seconds:
fluidfix selfcheck
What should we test first?
fluidfix maintains exactly what your tests cover, so that is the question worth asking before adopting it — and your repository already knows, because every bug fix in its history names the file that broke:
fluidfix hotspots .
Measured on Box2D's own history: guarding 60% of its past defects costs testing 58 files, not 60% of the engine. Defects cluster, so coverage aimed at the cluster is worth roughly twice coverage spread evenly.
Languages
| language | command | judge | status |
|---|---|---|---|
| Python | fluidfix guard |
pytest | stable |
| C / C++ | fluidfix cguard |
your test binary, plus the compiler as a cheap first oracle | alpha |
| C# / .NET | fluidfix cguard --build-cmd "dotnet build" --test-cmd "dotnet test --no-build" |
dotnet test (xunit measured) |
alpha |
| Java | fluidfix jguard |
JUnit via Maven | alpha |
C# needed no adapter at all — cguard is generic over its build and test
commands. Supporting it cost one source extension (.cs) and one regex for
the Failed Class.Method [2 ms] shape that dotnet prints. Measured: a
cross-product sign flip in a .NET class library repaired byte-exact in 14
suite runs (20.8s), warm cycle 1.63s.
Unity is not the same as C#. The language works; Unity's own test framework generally needs the Editor in batch mode to run tests, which is a harder oracle and is untested here.
Adding a language is an adapter, not a rewrite — the kernels route
integers and edit lines of text, and never learn the language. Java took 223
lines, C took ~450. Measured on two real game repos, all byte-exact:
Box2D's b2Cross sign flip in 46 suite runs (82.8s), cglm's glm_vec3_add
in 100 runs, and a pointer-arithmetic defect in Box2D's contact_solver.c —
with no traceback frame, no discriminating literal and no name affinity — in
428 runs once the gcov tier was supplying executed-line evidence.
selfcheck re-derives five machine-authored laws with no network and no
dependencies: fluid-router (which repair), fluid-router2 (which candidate
next), the engine law (what to do when blocked — one controller that governs
four different jobs, 0 of 256 situations ruling differently), the ranking law
(which line first) and the SIGHT law (which file first — two tiers, where
pointing evidence outranks circumstantial evidence algebraically).
Safety properties
- Refuses on a green suite. Searching without a failing test has been
measured to corrupt working code while reporting success;
repair()checks first and returns "nothing to repair". - Refuses outside its vocabulary. and/or confusion, flipped booleans,
*//swaps have no act — the mask comes back empty and fluidfix says so, loudly, instead of guessing. - Restores byte-exactly on failure. Every rejected candidate is rolled back; a refused repair leaves the tree untouched.
- Bounded candidates. A candidate that will not terminate is a failed candidate, not a hung pipeline.
- The oracle is defended. Stale-bytecode, plugin-collision,
exit-first-swallows-coverage, and truncated-node-id failure classes are all
encoded in
oracle.py, each one a scar from a measured harness defect.
Teaching it new classes — the maintenance loop
The four shipped acts are a starter dictionary, not a ceiling. A fault class is teachable the moment its repair can be expressed as a mechanical transform of the defective line:
import re
from fluidfix import register
register(4, "logic-flip", 'an "and" that should be "or", or vice versa',
re.compile(r"\b(?:and|or)\b"),
lambda line, obs: (line.replace(" or ", " and ", 1) if " or " in line
else line.replace(" and ", " or ", 1)))
One registration, once — the router is never edited: it infers the new
class's act code from the same single worked example
(tests/test_regressions.py shows an and/or bug going from refused to
repaired with exactly this snippet). That is the deployment story fluidfix is
built for: ship it on a maintained codebase, let the known classes repair
themselves for free, and when an update introduces a novel fault class, hand
that class to fluidfix once and maintenance is free again.
The honest boundary: classes whose repair needs information absent from the
defective line — a wrong variable, a missing guard, a different algorithm —
are not transforms, and are refused rather than attempted. (Measured share of
real one-line fixes that are single-token substitutions: ~16%; see
fluid-router's benchmark/domain/.) The refusal is your signal to spend a
frontier model exactly once, on the class, never again on its instances.
Teach it your bugs
docs/TEACHING.md is the full guide: how to turn a refusal into a registered fault class, what makes a transform safe, and how the router infers the new act from one worked example. examples/company_rules.py is a ready-to-adapt dictionary of registrations to copy into your own deployment.
Licensing
AGPL-3.0-or-later. Section 13 (network use) applies. If AGPL does not suit your use — proprietary products, SaaS without source offer — commercial licenses are available: see COMMERCIAL.md.
Metadata
Release files for fluidfix 0.13.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fluidfix-0.13.0.tar.gz | 9.2 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fluidfix-0.13.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 9.3 MB
Release files / fluidfix-0.13.0.tar.gz
| Download URL | fluidfix-0.13.0.tar.gz |
|---|---|
| Size | 9.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5cdc15b6bb88d441155bdbc1703ef598eff53514c35d65110aa4ea34b9cd6b87
|
|
BLAKE2b-256 checksum How to use checksums |
7285edaefe92855220f89bb1bcc5b96ec89567f0aa94fcf54f65f62648cbc512
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logRelease files / fluidfix-0.13.0-py3-none-any.whl
| Download URL | fluidfix-0.13.0-py3-none-any.whl |
|---|---|
| Size | 96.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1cddf0750918001b0edd9c98b52ed925da55f17ba069249bd9e2afb72f92bb33
|
|
BLAKE2b-256 checksum How to use checksums |
56db0b8f2d53bce035e5c699f677f41e2e0922e74a32fb1ad99a7bf54c2e887c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logSecurity for fluidfix 0.13.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for fluidfix-0.13.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.