Nestor
Meaning infrastructure. In medio, fides — in the middle, trust.
Nestor answers one question about a machine-generated answer: has a human checked this?
Not as a confidence score — as a structural fact you can audit. Every answer Nestor serves is in exactly one of three states, and the state is never a guess:
| State | What it means | |
|---|---|---|
| ✓ | sealed | A human verified this, and the seal still verifies. Served verbatim, instantly, forever. |
| ~ | draft | A machine produced it. Queued for review, never served as verified. |
| ! | pending | Nothing to offer. Said plainly rather than improvised. |
Read the first row precisely: and the seal still verifies. A row that merely
says sealed in the database is not served — a seal is bound to a key the
store does not hold, and one that does not verify is surfaced to a curator
instead of answering anyone (seal signatures,
the curator). A human
seals an answer once and can reject one just as durably, so a wrong match
is never served again. Both decisions are signed, both are appended to a hash-chained ledger.
In concrete terms it is a zero-dependency Python library, a nestor command
line, and a stdlib browser UI, all over one SQLite-backed store —
Quick start has the whole loop, machine draft to human seal to
served answer, in five commands.
This page — The mechanic · The category · Install · Quick start · Project layout · Going further · Development
Frequently asked, honestly answered — including the "not yet"s:
QUESTIONS.md. The story behind the name — the nest, Homer,
and Asimov's forged-seal-in-1947 — is docs/the-name.md.
The mechanic
One loop, and it knows nothing about language:
normalize an input → fuzzy-match it against a memory of sealed (verified) pairs → serve the match above a threshold, else queue it for a human seal → append every step to a hash-chained ledger.
That loop is the product. What it compares — sentences, aliases, figures, dates,
column headers — is decided by a Matcher, a two-method seam holding the only
domain-specific code in the system. Everything the value depends on is on the
other side of it: what counts as verified, who verified it, what gets served,
what gets queued, and what the audit trail records.
| Recipe | Matcher | "source → target" means | Module |
|---|---|---|---|
| Translation | StringMatcher |
phrase → translation | nestor.memory + nestor.cascade |
| Entity resolution | StringMatcher |
alias/surface → canonical entity | nestor.entity |
| Numeric reconciliation | NumericMatcher |
figure → labelled baseline | nestor.reconcile |
| yours | yours | whatever you can normalize and score | — |
Translation is where Nestor was extracted from, and the examples below use it most because it needs no setup to read. It is the origin story, not the boundary — a date matcher and a CSV-header-to-schema mapper have both been built against the shipped package without modifying it. Nestor has no upward dependency on any host: persistence, the matcher, the draft engine and the governance forwarder are all injected.
The category — verification, not translation memory
Translation memory is where Nestor was extracted from. It is not what Nestor is for, and reading it as a TM gets the economics backwards. A translation memory is a cache: its value is the work it skips. Nestor's three states are not a cache tier — they answer a different question, one being put to anyone shipping model output into a regulated process:
Which model outputs did a human actually check?
Each verification is permanent capital. The curve runs the opposite way to inference: cost per answer falls as the proportion of verified answers rises, and it never un-falls, because a seal does not expire and costs nothing to serve again. Spending review time buys down a recurring cost rather than renting a result. Verified once, served forever.
Where it wins: high-value, low-volume decisions where somebody is already reading the output — contract clauses, clinical notes, regulatory filings, anything with a named reviewer and a retention requirement. The review was happening anyway; Nestor is the difference between it happening and it being provable. Where it loses, stated plainly: high-volume serving. Lookup is linear in corpus size and about 97% of that time is Python-side scoring, so this is not a chat backend — see Accuracy. The design target is decisions worth a person's attention, not throughput.
Install
Python 3.10+, no runtime dependencies. The published package is
nestor-meaning (the shorter nestor is unclaimed on PyPI; import nestor
is unaffected either way). The blessed one-liner is
pipx, which isolates the nestor console
script in its own environment:
pipx install nestor-meaning # or: pip install nestor-meaning
From a checkout instead of the index, same tool: pipx install . (or
pip install .). All four paths were run clean into empty environments before
this was written; the transcripts, and the nestor init → nestor demo →
nestor ui first run, are in docs/install.md. What this does
not solve: no Homebrew tap, no curl | sh — pipx/pip is the whole install
story for now.
Optional extras add capability without moving the core:
pip install "nestor-meaning[keys]" # ed25519 per-verifier signing
pip install "nestor-meaning[cloud]" # the Anthropic draft engine
pip install "nestor-meaning[semantic]" # embedding matcher (fastembed)
pip install "nestor-meaning[browser]" # Playwright browser lane (see docs/local-fleet.md)
pip install "nestor-meaning[gate]" # the willow-gate seam
Quick start
The core loop fits in one script. Save this as demo.py and run it, in the
translation recipe:
from nestor import cascade, memory, storage
from nestor.sqlite_store import SqliteStore
storage.set_store(SqliteStore(":memory:"))
# 1. Nothing is known yet. Nestor says so rather than improvising.
p = cascade.translate_segment("Good evening.", "en", "es")
print(p.mark, p.state, repr(p.target))
# 2. A human verifies it — once.
memory.add_pair("Good evening.", "Buenas noches.", "en", "es",
status="sealed", verifier="rudi")
# 3. Forever after, including when it is retyped differently.
p = cascade.translate_segment("good evening", "en", "es")
print(p.mark, p.state, repr(p.target), p.confidence, p.meta["verifier"])
! pending ''
✓ sealed 'Buenas noches.' 1.0 rudi
One human verification, and the answer is free, instant and attributed from then
on — both steps recorded in a tamper-evident ledger. That ledger is a file even
when the store is not: the run appends to ./data/ledger.jsonl. (The run also
prints a RuntimeWarning about NESTOR_SEAL_KEY — Nestor telling you seals are
trusted on stored status alone; see Seal signatures before
using it for anything real.)
The product is three separate surfaces over one store — a machine drafts, a human seals, a model or a terminal serves — and the seal is a person sitting down, not a function call. Here is that loop across all three, file-backed:
# 1. A machine draft enters the review queue (tier 2). Nobody has checked it yet.
python - <<'EOF'
from nestor import cascade, storage
from nestor.sqlite_store import SqliteStore
storage.set_store(SqliteStore("data/nestor.db")) # the CLI's default store
cascade.translate_text("Good evening.", "es", source_lang="en") # drafts, queues
EOF
nestor ask "Good evening." # 2. ! pending — a draft is not verified
python -m nestor.ui --db data/nestor.db # 3. a human seals it under their own name
nestor ask "Good evening." # 4. ✓ sealed Buenas noches. (verified by you)
nestor ledger verify # 5. ✓ intact
Step 3 is the point, not an inconvenience. There is no nestor seal subcommand
and no way to seal from a script, because --verifier "$USER" in a cron job is
not a human checking anything. A model can draft (nestor serve), the terminal
can serve, but only a person at nestor.ui turns a draft into a sealed answer.
The whole argument in sixty seconds, against a scratch store it deletes afterwards — eight beats, each asserting its own claim (the script exits non-zero rather than narrate something that did not happen, and a test runs it):
python demo/sixty_seconds.py # --fast to skip the pauses
python demo/record_demo.py # capture it as an asciicast under demo/recordings/
From source, for development:
git clone https://github.com/Die-Namic-Systems/Nestor.git && cd Nestor
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # + pytest, ruff, bandit
bash scripts/ci-test.sh core # fast, deterministic, no live services
The bundled SqliteStore owns every table Nestor needs, so the whole cascade
runs end-to-end with no host application. It uses WAL mode, so a plain cp
of nestor.db is not a backup of a running server — use nestor export, SQLite
VACUUM INTO, or stop nestor.ui (which checkpoints on exit).
Project layout
nestor/ the package — cascade, memory, matchers, curator, ui, cli, serve, ledger, signing
bench/ measuring where the seal threshold stops holding (bench/README.md)
demo/ scripted, self-asserting demos — a claim that fails the build when it stops being true
recipes/ the seam's "yours" row, built against the shipped package
tests/ no outbound network (one test binds a loopback socket), no fixtures on disk
docs/ design memos, operating rules, and the moved-out reference material
AGENTS.md · IDEAS.md · TODO.md · QUESTIONS.md · CHANGELOG.md
The full annotated manifest — every module, bench, demo and doc with a line on
what each is for — is docs/project-layout.md.
Going further
The front door stops here. Everything past it — each surface in detail, the three shipped recipes, and the parts of the mechanic that only matter once you are building on it — is the manual.
| If you want to | Read |
|---|---|
| Write a matcher for your own domain | The Matcher seam → in depth |
| See translation, entity resolution and reconciliation worked through | The recipes |
| Understand what a reviewer's "no" does | Rejection · The curator |
| Sit a human in front of the queue | The UI |
| Drive it from a terminal | The CLI |
| Move a memory between instances | Export and import |
| Let a model read it — and know what it cannot do | Serving a model |
| Audit what was verified, and by whom | The ledger |
| Put it over Postgres or your own schema | Injected storage → the protocol |
| Measure the accuracy of your own corpus | Accuracy → why the numbers are published |
| Deploy it where the network is the problem | Sovereign deployment · Policy brief |
Frequently asked and honestly answered, including the "not yet"s and the two "never"s: QUESTIONS.md.
And how it was built. This repository carries more history than product —
a decision store, benches, audits, and a working log. It is deliberately kept,
and deliberately kept separate: docs/build-record.md
is the index. Nothing in it is needed to use Nestor.
Development
pip install -e ".[dev]"
bash scripts/ci-test.sh core # fast iteration: trust/core tests
bash scripts/ci-test.sh full # pre-push suite; run in background
ruff check nestor tests # enforced in CI
bandit -r nestor -ll -q # enforced in CI
python bench/bench_accuracy.py # measurements -> bench/results/
Optional integrations never activate merely because their dependency or daemon
is present. Run them deliberately with scripts/ci-test.sh semantic, ollama,
browser, or external; scale/corpus checks are the slow lane. Install
pip install -e ".[browser]" before the browser lane (Playwright must match
the Chromium build on disk — see docs/local-fleet.md). The semantic, ollama,
and external lanes set their opt-in environment flags themselves. Serial wall-clock assertions live in performance, because xdist
or coverage contention makes those numbers meaningless.
Returning to an existing clone: the install persists, the activation does
not — run source .venv/bin/activate in each new shell. The failure mode is
quiet if you forget: the package imports from the repo root without any install,
so snippets keep working while nestor and pytest are missing or stale. If
commands are half-working, check which python first. (Sessions on Claude Code
on the web skip this — a SessionStart hook builds .venv and puts it on PATH.)
One test goes red after you edit or commit, and passes on a re-run:
test_version.py::test_version_agrees_with_the_installed_distribution. The
version comes from git describe --dirty via hatch-vcs, and an editable
install regenerates its metadata during the run when that output changes — so
the first run after any commit or any edit to a tracked file compares a value
captured at import against the regenerated one. Run it again without touching
anything, or pip install -e ".[dev]", and it goes green. CI never sees it:
one install, nothing changing mid-run.
CI runs lint and the test matrix (Python 3.10 and 3.12) on every pull request,
plus a daily scheduled run to catch drift. Ideas, open questions and measured
dead ends live in IDEAS.md — each entry tagged
measured / verified / hypothesis / open.
License
Apache License 2.0 — see LICENSE.
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 nestor_meaning-0.19.0.tar.gz.
File metadata
- Download URL: nestor_meaning-0.19.0.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
702cde48d19c08447fd510ae2a397c8e294e36260567409fb88ad89dbe6099d0
|
|
| MD5 |
8bf4698ef6a1d44c84be4106e3350f8f
|
|
| BLAKE2b-256 |
1f46b8aef08522b3b7f236fcb09869c57409f7a7cd1925897b30f6043ae66a64
|
Provenance
The following attestation bundles were made for nestor_meaning-0.19.0.tar.gz:
Publisher:
publish.yml on Die-Namic-Systems/Nestor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nestor_meaning-0.19.0.tar.gz -
Subject digest:
702cde48d19c08447fd510ae2a397c8e294e36260567409fb88ad89dbe6099d0 - Sigstore transparency entry: 2683963832
- Sigstore integration time:
-
Permalink:
Die-Namic-Systems/Nestor@1fe4dba20428cc29b1defcfd5d1ca1b94d88c181 -
Branch / Tag:
refs/tags/v0.19.0 - Owner: https://github.com/Die-Namic-Systems
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1fe4dba20428cc29b1defcfd5d1ca1b94d88c181 -
Trigger Event:
push
-
Statement type:
File details
Details for the file nestor_meaning-0.19.0-py3-none-any.whl.
File metadata
- Download URL: nestor_meaning-0.19.0-py3-none-any.whl
- Upload date:
- Size: 555.5 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 |
89557d67e50d1f154cfc4798569593df9e1d9cff50889f757c5faaab29339f2a
|
|
| MD5 |
ee8c7c1371596c91c4b8c6f69dbb18f2
|
|
| BLAKE2b-256 |
ed00acc494fdd21479f58a8dde30ee0771b95b22b442b72be34774b080494652
|
Provenance
The following attestation bundles were made for nestor_meaning-0.19.0-py3-none-any.whl:
Publisher:
publish.yml on Die-Namic-Systems/Nestor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nestor_meaning-0.19.0-py3-none-any.whl -
Subject digest:
89557d67e50d1f154cfc4798569593df9e1d9cff50889f757c5faaab29339f2a - Sigstore transparency entry: 2683963881
- Sigstore integration time:
-
Permalink:
Die-Namic-Systems/Nestor@1fe4dba20428cc29b1defcfd5d1ca1b94d88c181 -
Branch / Tag:
refs/tags/v0.19.0 - Owner: https://github.com/Die-Namic-Systems
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1fe4dba20428cc29b1defcfd5d1ca1b94d88c181 -
Trigger Event:
push
-
Statement type: