Perslis projects · Perslis Floor

Pilot · 1.1.2

Exact answers
from your own data.

Ask a question once. A model writes the procedure, the floor proves it, a person approves it, and you keep a signed tool that answers from your data — offline, exactly, with no model in the loop. When the data can't support an exact answer, it refuses.

PERSLIS FLOOR● RECORDED
you> How much have we paid, by vendor region?

→ tools/call derive_demo_paid_by_region
← DERIVED · model_calls: 0
  Central  11215.45
  East     21576.59
  South     4800.25
  West     32996.02

rows → filter(status = paid) → join(vendors) →
group_by(vendors.region) → sum(amount)

Recorded from the 1.1.2 release over MCP stdio. The demo data is fictional and ships in the download.

No model at answer timeEvery answer carries model_calls: 0 and the exact procedure that produced it.
Exact, or refusedDecimal arithmetic. N/A in a number column, ambiguous dates, duplicate or unmatched lookup keys: refused by name.
Signed and reviewedEach tool passes an eight-check gate, is approved by a person, and is Ed25519-signed.

Why we built it

Most questions about your data are arithmetic.

What did we pay each region? Who are our top three vendors? How many invoices have no PO number? These are not inference problems. They are counting, filtering and adding over data you already hold. Sending them to a model means paying per call for an answer that was checkable all along — and getting a number you cannot check.

Perslis Floor keeps the model where it is useful: reading the question once and composing a procedure from a closed vocabulary. It never writes code. From then on, a small runtime on your machine executes that procedure exactly, every time, and shows its working. It grew out of our symbolic floor research.

The loop, made visible

Ask. Compose. Prove. Approve. Run.

  1. Your questionIn your own words: “how much have we paid, by vendor region?”
  2. A spec, not codeA model composes a pipeline: filter → join → group → sum.
  3. The gateEight checks: real columns, trustworthy data, deterministic, grounded, and the verifier must reject wrong answers.
  4. A personReads what the tool computes, in plain words, next to its answer on the real data — and approves it or not.
  5. Your machineThe signed tool runs locally over MCP. No network, no key, no model.
Why a person? The gate can prove a procedure is correct as written. It cannot prove the procedure means what the question means: a spec for “total paid” that filters status = open passes every mechanical check. So nothing ships until someone reads it and says yes, and the approval is signed into the tool. Editing the tool, its table or the review afterwards voids it.

What we discovered building it

The failures that look like answers.

A gate proves the procedure, not the meaning.

An adversarial review showed a spec labelled “total of paid invoices” that actually summed open ones passing every automated check. That is why every tool now carries a person’s signed approval, and why a changed tool, table or data snapshot voids it.

Our first grounding test refused correct tools.

On 10,000 realistic rows it refused all four correct specs we tried: it only perturbed the first 25 rows, and the matching rows were further down. It now perturbs the rows that actually reach the answer, and it is tested at that scale for every kind of question.

Floats and silent drops look right and are wrong.

9,007,199,254,740,992 + 1 came back unchanged. A lookup silently dropped a $900 invoice and reported $100. Arithmetic is now exact decimal, and a row with no match is refused unless the tool explicitly says otherwise.

A checksum next to a download proves nothing.

Anyone who can replace the zip can replace its checksum. Releases are now signed with a Perslis release key that is published in two places, and the installer refuses anything that does not verify — we tested it against a tampered mirror.

Build status · 26 September 2026

What you can test today.

CapabilityCurrent evidence and limit
Runtime and MCP serverStandard-library Python 3.9+, no dependencies, no network code. Over 300 automated tests pass on Python 3.9 and 3.13; a real Claude Code session called a built kit, reported exact answers and recorded an unanswerable question as a gap.
DataCSV, TSV, JSON, JSONL, SQLite, or a folder of them; re-read when it changes. Measured at 500,000 rows (18 MB CSV): about 1.3 s to load, about 400 MB, about 2.3 s for the first query; repeat answers are cached. Default cap 1 million rows.
Admission and reviewEight-check gate, then a human review signed with the reviewer’s own key; the runtime refuses any tool without a valid reviewer attestation. Four rounds of adversarial review on 26 September; 1.1.2 fixes every finding, each pinned by a regression test.
Signing and releasesTools are Ed25519-signed and the runtime can only verify. Release checksums are signed and verifiable with ssh-keygen; builds are reproducible byte for byte.
Not yetRelative dates (“last 30 days”), parameterised tools, direct database connections, and a self-serve gate. Tools for your data currently come through a pilot.

Try it

Verify, then install. Start with the demo.

Nothing runs until the release signature checks out. Download the installer and the signed checksums, then verify them with the Perslis release key below. The same key is in the GitHub README, so compare the two. Only then run the installer. It fetches the zip, verifies it again, unpacks it to ~/perslis-floor and runs the demo: fictional invoices and vendors, with six reviewed and signed tools.

V=1.1.2; B=https://github.com/AgewellEPM/perslis-floor/releases/download/v$V
curl -fsSL -O "$B/install.sh" -O "$B/SHA256SUMS" -O "$B/SHA256SUMS.sig"
echo 'releases@perslis.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJfmXcRm2o52skHrajOCntbGMwPIB13CWnzt/tRGxXxd' > perslis_signers
ssh-keygen -Y verify -f perslis_signers -I releases@perslis.com -n perslis-release -s SHA256SUMS.sig < SHA256SUMS
grep ' install.sh$' SHA256SUMS | shasum -a 256 -c -
bash install.sh

We don’t publish a curl … | bash line: piping a script straight from a branch runs it before anything has been verified. Once it’s installed, connect it to Claude Code and ask a question in plain English:

claude mcp add perslis-floor-demo -- python3 ~/perslis-floor/floor-serve.py \
    --data ~/perslis-floor/demo/data --tools ~/perslis-floor/demo/tools

Tools for your data

Send an export and your questions. Get back a kit.

The admission gate and the signing keys stay at Perslis, deliberately: a wrong tool that got signed would answer confidently, offline and forever, with nothing left to re-examine it. In the pilot you send an export (CSV, JSON or SQLite) and your questions; we build each tool, review it and sign it; you get the runtime, your tools and a five-minute guide. Questions that need judgment rather than arithmetic come back marked as needing a model — never as a guess.

Standards behind it

Protocol and cryptography references — not endorsements.

More Perslis work: Jira Monkey · all tools.