Fux — a portable, agent-aware knowledge engine: rules bound to code, read by agents before they touch anything, checked deterministically.
Project description
Fux
Your documents already know the answer. Fux lets you ask them — offline, deterministic,
$0, cited.
Fux is a portable, agent-aware knowledge engine. fux ingest turns the folders you
point it at into a git-versioned Markdown corpus with provenance; fux ask answers
natural-language questions over it with ranked, file:line-cited passages — no
network, no API keys, no external model, the same answer every time.
Pronounced "fox." · Python ≥ 3.11 · stdlib only · MIT
The story
You move into an old house. Down in the basement, the previous owner painted one pipe bright red. There is a note explaining why — it's in a binder, in a box, in one of forty folders the last owner left behind. You'll find it about a week after the basement floods.
That's most project knowledge. The answer to "why did we do it this way?" is written down — in a decision doc, a runbook, a PDF someone exported, a page twelve levels deep in a wiki. Being written down isn't the problem. Being findable at the moment of confusion is — and grep only works if you already know the magic word. (Hand the folders to an AI assistant and it has the same problem, faster: it guesses instead of digging.)
Fux is the index to every note in the house. Point it at your folders once; ask in plain English; get back the actual passages — quoted verbatim, scored, cited to the exact file and line — so you (or your agent) verify instead of trusting. And because the corpus lives in git, what you knew and when you knew it has history, like everything else that matters.
See it
$ fux ask "why did we pick a composite index for trades?"
notes/anton/decisions/db-indexing.md:12 (score 7.412)
## 2026-05 — Indexing the trades table
We chose a composite index on (symbol, ts) over per-column indexes because
every hot query filters by symbol then range-scans time. Rejected a covering
index — write amplification on the tick ingest path was too high.
notes/anton/schema/trades.md:5 (score 3.121)
trades(symbol, ts, price, qty, status) — composite PK on (symbol, ts).
2 passages · corpus 50 docs · 12ms
The evidence, not a summary — with the file:line to jump to. Want it stitched
into prose? fux answer builds one from the source's own sentences, every clause
cited, nothing generated:
$ fux answer "why did we pick a composite index for trades?"
We chose a composite index on (symbol, ts) over per-column indexes because every
hot query filters by symbol then range-scans time. [1] Rejected a covering index —
write amplification on the tick ingest path was too high. [2]
Sources:
[1] notes/anton/decisions/db-indexing.md:12
[2] notes/anton/decisions/db-indexing.md:14
Quickstart
pip install fux-engine # zero runtime deps; ~7 MB wheel incl. the model
cd your-project
fux setup # wizard → fux.toml (every prompt has a flag; -y for defaults)
fux ingest # folders → .fux/ corpus + fux.lock + index
fux ask "why did we pick X?" # ranked, cited passages
fux find "deploy runbook" # which files
fux answer "how do rollbacks work?" # extractive, cited answer
fux explain docs/adr/0007.md # one doc deep: outline, edges, key passages
fux path docs/adr/0007.md docs/runbooks/failover.md # how two docs connect
Optional Office/PDF converters (never on the query path):
pip install 'fux-engine[ingest]'. Ten-minute real-project walkthrough:
DOGFOOD.md · worked input/output for every command:
docs/example/CLI.md.
Explain it like I'm five
Your notes are a giant pile of paper. Somewhere in the pile is the page that answers your question — you just can't find it, so you ask the smart kid instead, and the smart kid makes something up. Fux reads the whole pile once, remembers where everything is, and when you ask, it holds up the actual page and points at the actual sentence. It never makes anything up, it works with no internet, and it answers the same way every single time.
Why it's different
Properties, not features:
- Deterministic. Sorted walks, stable serialization, no wall-clock output, no model in the maintenance path. Same sources → byte-identical corpus and index; same question → same answer. Proven by golden-file tests on every commit.
- Cited or it didn't happen. Every passage carries
file:line;answeris extractive — verbatim source sentences, ordered and cited — never generative, so it cannot hallucinate. - Hybrid retrieval, still offline. BM25F field-weighted lexical search fused
(RRF) with a bundled 7.9 MB static-embedding model inferred in pure stdlib —
semantic recall for paraphrased questions with zero downloads, zero services.
--lexical-onlypreserves the pure-BM25F path byte-for-byte. An eval harness gates every retrieval change. $0and zero-dependency. Stdlib-only runtime — the frontmatter parser, the WebSocket client, and the embedding inference are hand-rolled on purpose. Auditable line by line, portable as a tarball, runs air-gapped.- Agent-native.
--jsoneverywhere,--explainshows why every result ranked (per-term field hits, dense rank, RRF contribution), andfux setup --agents --skills --hooksteaches Claude Code, Copilot, and Kiro to query the corpus before guessing — via AGENTS.md, the open SKILL.md standard, and fail-open hooks. - A corpus, not a disposable index.
fux.toml+fux.lock+.fux/state/are committed: knowledge changes become reviewable diffs, and "what did we know in March?" is agit checkoutaway. - A clone is queryable before you ingest. The committed state plane costs ~240 bytes per document — small enough for git, complete enough to answer with the same rankings and scores a full index gives, by re-deriving candidate text and reading exact corpus statistics from the committed df sidecar.
How it works
sources (fux.toml) ──ingest──▶ fux.lock per-source sha/date ledger ← commit this
.fux/state/ codes + signatures + exact df ← commit this
.fux/cache/ OKF Markdown corpus + provenance ← rebuilt on clone
.fux/index/ fux.db: chunks, postings, vectors ← derived; gitignored
every verb ◀── one retrieve() ── BM25F ⊕ dense ⊕ FuxVec global ⊕ graph → RRF
Git carries the recipe and the state, never the warehouse. fux.toml says
what to ingest, fux.lock records exactly what was ingested and when, and
.fux/state/ carries enough to answer immediately after a clone. The heavy
runtime plane is one SQLite file, gitignored and rebuildable — and every rebuild
is verified against the lock, so a sha match proves it is provably the same
corpus.
Ingest is two-tier by design: the fast inferred pass handles everything by
default (markdown/txt/code natively, JSON flattened, YAML fenced, images as
metadata stubs, Office/PDF via the extra); the advanced pass —
fux ingest --advanced report.pdf — re-converts exactly the files that deserve it
with Docling layout extraction or Tesseract OCR, and records the upgrade in each
file's fidelity frontmatter so readers (human or agent) know what they're
looking at.
The web is a source too, behind an explicit fence: fux ingest --web crawls
[sources.web] (robots.txt obeyed, depth/budget/domain caps, attachments
converted, full url/parent/depth provenance) — and render = "cdp" drives
your own headless Chrome over a hand-rolled RFC 6455 WebSocket client for
JS-rendered pages. Network never touches the query path — an import-fence test
enforces it.
The full command surface
fux setup # wizard → fux.toml; every prompt has a flag; -y
fux setup --agents --skills --hooks # AGENTS.md + pointers, skills, agent hooks
fux ingest # convert + chunk + index (incremental by sha)
fux ingest --check [--strict] # drift report (sha mismatch/new/missing); --strict exits 2
fux ingest --list-inferred # upgrade candidates (inferred fidelity)
fux ingest --list-skipped # what didn't ingest, and why
fux ingest --advanced <file> # one file → Docling/Tesseract → fidelity: advanced
fux ingest --web # fenced crawl of [sources.web] (+ CDP rendering)
fux ask "<question>" # ranked cited passages (--json --explain --top -C)
fux find "<topic>" # ranked files
fux answer "<question>" # extractive cited answer (--answer-max)
fux ask … --lexical-only # pure BM25F, byte-identical to v1
fux explain <doc-id> # outline + edges + key passages for one document
fux graph "<topic>" # the nodes and edges around a topic
fux path <doc-id> <doc-id> # how two documents connect (or that they don't)
fux cat <doc-id> [--out FILE] # print one document, wherever it is stored
fux db pull <url> # fetch a CI-built index, sha-verified vs fux.lock
fux doctor [--json] # whole-install/corpus health, 7 groups, fix commands
fux why "<query>" --doc <path> # why a document did or didn't rank — one verdict line
fux hook prompt-submit|session-end # fail-open agent-hook entrypoints
The $0 guarantee
No maintenance or query path ever calls a model or the network. The bundled
semantic model is a static token→vector table shipped inside the wheel — looked
up, mean-pooled, and dot-producted in pure stdlib (int8, exact). The only network
code in the product lives inside the explicit fux ingest --web fence, and the
only model-adjacent tooling (distillation) runs at development time in
tools/distill/, never at runtime.
Honest limits. Fux retrieves and quotes; it does not write prose or reason
across documents — answer selects the source's own sentences, which is the
point, but means no synthesis beyond what's written. The bundled model is
English-biased (other languages degrade gracefully toward lexical). And retrieval
quality is measured, not promised: the committed eval harness gates changes, and
the current hybrid ships on a tie-with-rescues over lexical — the honest numbers
live in ADR 0006.
The name
Named after Johann Joseph Fux, author of Gradus ad Parnassum (1725) — the counterpoint treatise every composer learned the rules from. A tool built so the reasons survive the people, named for the man who wrote the rulebook. The long-term Fux vision — version-controlled rules bound to code, checked deterministically — is on hold, deliberately, until this query engine has earned its keep in daily use; the design of record is docs/PLAN.md.
What's new
Latest — v0.24.0 (2026-07-22): debug & observability. Every stage is now
inspectable without a debugger: [debug] in fux.toml (level/categories/
output/timing/redact, --debug=trace/FUX_DEBUG), a stdout-safe emitter
instrumenting the whole pipeline, fux doctor (seven-group whole-install
diagnosis — every failing check names the exact fix command), fux why
(explains why a document did or didn't rank for a query, ending in one
verdict sentence), and a third skill, fux-debug, so an agent can
self-diagnose. See docs/example/DEBUG.md.
v0.23.1 (2026-07-22): docs & examples. Documentation-only patch (no
engine change). The docs bundle was reorganized — core trackers promoted to
ALL-CAPS entry-point files — and a new docs/example/ bundle
landed: worked, verified examples for the CLI, config, setup + hook installation,
skill usage, and the Python API.
v0.23.0 (2026-07-22): the knowledge substrate. One SQLite runtime
plane; committed fux.lock + lean state (a fresh clone answers with the same
rankings and scores as a full index, ~230 B/doc); FuxVec from-scratch binary
dense search (hit@5 → 1.000 on the eval set, ADR 0006's named miss rescued); one
retrieval kernel behind every verb, with explain/graph/path/cat/db pull
new; lean/full profiles measured at 23 MB per 100k docs.
Full release history → CHANGELOG.md.
Status
v0.24.x — debug & observability is shipped: v1 query CLI, v1.1 web/CDP/
advanced ingest, v2 bundled-model hybrid, v3 substrate (SQLite store, committed
fux.lock + state plane, one retrieval kernel, the FuxVec dense engine, graph
verbs, lean/full profiles), v4 debug ([debug] + emitter, fux doctor,
fux why, fux-debug skill) — 417 unit tests, 100 e2e, eval gate beaten.
Retrieval quality across the staged engines, on the committed 21-pair eval set:
| engine | hit@1 | hit@5 | MRR |
|---|---|---|---|
| v1 lexical (BM25F) | 0.762 | 0.952 | 0.833 |
| v2 hybrid (+ bundled model) | 0.762 | 0.952 | 0.833 |
| v3 + FuxVec dense-global | 0.810 | 1.000 | 0.873 |
v2's dense pass could only re-score what BM25F already found, so a document
sharing no vocabulary with the question stayed unreachable — the miss
ADR 0006 recorded and could not fix. FuxVec
scans every document's 32-byte binary code (~27 M comparisons/sec, pure stdlib)
and closes it. Decisions live in docs/compare/ and
docs/adr/; the docs are an OKF v0.1 bundle rooted at
docs/index.md; the old build is archived under
archive/. Now dogfooding (DOGFOOD.md).
If the binder-in-a-box problem is real in your project, try Fux on one folder —
pip install fux-engine.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
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 fux_engine-0.24.0.tar.gz.
File metadata
- Download URL: fux_engine-0.24.0.tar.gz
- Upload date:
- Size: 7.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ec256e9e43d34635f56e2efde12b621e582121f9afdb7f3a061cd1550282767
|
|
| MD5 |
71506801714878de7a2b65180f2d8742
|
|
| BLAKE2b-256 |
61d4c9847ab91adf9fd7af9dc30d58d0bf758f50c2a8d31ca676a552dc804e7b
|
Provenance
The following attestation bundles were made for fux_engine-0.24.0.tar.gz:
Publisher:
publish.yml on arpitarya/fux
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fux_engine-0.24.0.tar.gz -
Subject digest:
6ec256e9e43d34635f56e2efde12b621e582121f9afdb7f3a061cd1550282767 - Sigstore transparency entry: 2219428829
- Sigstore integration time:
-
Permalink:
arpitarya/fux@cd9550687a15ffa157515882d3f188f31a7049cb -
Branch / Tag:
refs/tags/v0.24.0 - Owner: https://github.com/arpitarya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cd9550687a15ffa157515882d3f188f31a7049cb -
Trigger Event:
release
-
Statement type:
File details
Details for the file fux_engine-0.24.0-py3-none-any.whl.
File metadata
- Download URL: fux_engine-0.24.0-py3-none-any.whl
- Upload date:
- Size: 7.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ccccf427b4b34b577f054ed5cbd97b5dd1e385d5d9baa84ebce22b93e894182
|
|
| MD5 |
bb1f65e7b301cc52c50feda6303915b5
|
|
| BLAKE2b-256 |
d9db94ea5c88f2e262026222442377c546e5405cbb512297beef30ba120c9e42
|
Provenance
The following attestation bundles were made for fux_engine-0.24.0-py3-none-any.whl:
Publisher:
publish.yml on arpitarya/fux
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fux_engine-0.24.0-py3-none-any.whl -
Subject digest:
8ccccf427b4b34b577f054ed5cbd97b5dd1e385d5d9baa84ebce22b93e894182 - Sigstore transparency entry: 2219429079
- Sigstore integration time:
-
Permalink:
arpitarya/fux@cd9550687a15ffa157515882d3f188f31a7049cb -
Branch / Tag:
refs/tags/v0.24.0 - Owner: https://github.com/arpitarya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cd9550687a15ffa157515882d3f188f31a7049cb -
Trigger Event:
release
-
Statement type: