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 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
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())
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.
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
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.
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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fluidfix-0.1.0.tar.gz.
File metadata
- Download URL: fluidfix-0.1.0.tar.gz
- Upload date:
- Size: 48.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dddc15d47324dda9c90473e8d8adc1cbbfeca5205501ded3256b3ffdb1ff4826
|
|
| MD5 |
17212d64d9cc8fbc21f5fdd19bfab819
|
|
| BLAKE2b-256 |
0d3849efc6f2ae997ce0b238bfffec12be5ff7c6ca2cf390b8e5b0168702c9f8
|
Provenance
The following attestation bundles were made for fluidfix-0.1.0.tar.gz:
Publisher:
publish.yml on devkancheti4-design/fluidfix
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fluidfix-0.1.0.tar.gz -
Subject digest:
dddc15d47324dda9c90473e8d8adc1cbbfeca5205501ded3256b3ffdb1ff4826 - Sigstore transparency entry: 2651003639
- Sigstore integration time:
-
Permalink:
devkancheti4-design/fluidfix@abc16a632e22cb34a42c7fff42e8d28e5d08c36c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/devkancheti4-design
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@abc16a632e22cb34a42c7fff42e8d28e5d08c36c -
Trigger Event:
push
-
Statement type:
File details
Details for the file fluidfix-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fluidfix-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f7a35b3af9a2e25eab8af39a6efa0c42ec0866d36ecce19db038e4af0e8152f
|
|
| MD5 |
86c459ec6b8164347a9a12cb2f5b2f83
|
|
| BLAKE2b-256 |
10109c3e32719289e713fd682247f4f27ff609f0a2a06b780b2effb21bde9520
|
Provenance
The following attestation bundles were made for fluidfix-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on devkancheti4-design/fluidfix
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fluidfix-0.1.0-py3-none-any.whl -
Subject digest:
8f7a35b3af9a2e25eab8af39a6efa0c42ec0866d36ecce19db038e4af0e8152f - Sigstore transparency entry: 2651003672
- Sigstore integration time:
-
Permalink:
devkancheti4-design/fluidfix@abc16a632e22cb34a42c7fff42e8d28e5d08c36c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/devkancheti4-design
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@abc16a632e22cb34a42c7fff42e8d28e5d08c36c -
Trigger Event:
push
-
Statement type: