Perslis Research · v1.1.2 · Pilot

Exact answers from your own data.
No model in the loop.

Ask a question about your data once. Get back a signed tool your AI assistant can call from then on. It runs offline and free, it's exact, and it refuses instead of guessing.

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

Verified install: nothing runs until the release signature checks out. There's no curl | bash.

claude ⟷ perslis-floor (MCP stdio)● recorded
0model calls per answer
0dependencies: standard library only
0lines of network code
Exactdecimal arithmetic, no floats
Try it

Six questions. Four ways to break it.

These are the demo tools that ship in the download, over fictional invoices and vendors. Pick a question to see what the tool computes and the exact answer the runtime returned. Then try to break it.

Every output on this page was recorded on 2026-09-27 from the real v1.1.2 release, over MCP stdio. Nothing was typed by hand. Run python3 floor-serve.py --data demo/data --tools demo/tools --check to reproduce it.

How it works

A model proposes. The floor checks. A person approves. You run it.

01 · SPEC

A model writes a spec, never code

It composes a pipeline from a closed vocabulary, such as rows → filter → join → group_by → sum. There's no way out into Python.

02 · GATE

Eight checks prove it

Columns exist, the data supports an exact answer, and the result is deterministic. The verifier rejects near-misses, the spec abstains without evidence, and the answer moves when the data moves.

03 · REVIEW

A person approves it

The reviewer reads what the tool computes in plain words, next to its answer on the real data, plus any warnings. They sign the approval with their own key, and the runtime refuses any tool without a valid approval.

04 · RUN

It runs on your machine

Ed25519-signed and served over MCP. Every answer carries its derivation and model_calls: 0.

Why a person, and not just the gate? The gate can prove a spec is correct as written. It can't prove the spec means what the question means: a spec for "total paid" that filters status == 'open' passes every mechanical check. So nothing ships until someone reads what it computes, next to its answer, and says yes. Editing the spec afterwards voids that approval.
What it will not do

It fails closed.

Guess

No evidence gives NO_EVIDENCE, and no matching rows gives NO_VALUE. It never fills the gap with a plausible number.

Skip what it can't read

N/A in a number column, 03/04/2026 in a date column, a corrupt JSON row, or a file still being written: each is refused by name, never silently dropped.

Undercount or double-count

A lookup key that appears twice would double-count, and a row with no match would vanish from a total. Both are refused unless the tool explicitly (and signed) says otherwise.

Run a tool nobody admitted

The runtime holds only public keys, so it can check signatures but can't create them. An edited tool is refused by name, and the rest keep working.

Round a total

Totals, minimums and maximums are exact decimals: 9007199254740992 + 1 = 9007199254740993. Only an average rounds, to 10 places, and the tool says so.

Phone home

There is no network code. Shareable logs record which tools ran and why a call was refused, with no values and no question text. Your questions stay in tools/private/.

Verify everything

Don't take our word for it.

Releases are signed with a Perslis release key. The same public key is pinned here, in the GitHub README and at perslis.com. Compare them: a key published in only one place proves nothing.

# the release key (identical on perslis.com and GitHub)
echo 'releases@perslis.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJfmXcRm2o52skHrajOCntbGMwPIB13CWnzt/tRGxXxd' > perslis_signers

# 1. the checksums really come from Perslis
ssh-keygen -Y verify -f perslis_signers -I releases@perslis.com -n perslis-release -s SHA256SUMS.sig < SHA256SUMS

# 2. the files you downloaded match the signed checksums; every file inside matches the manifest
grep ' perslis-floor-1.1.2.zip$' SHA256SUMS | shasum -a 256 -c -
grep ' install.sh$' SHA256SUMS | shasum -a 256 -c -
unzip perslis-floor-1.1.2.zip && cd perslis-floor-1.1.2 && shasum -a 256 -c MANIFEST.sha256

# 3. there is no network code
grep -rnE "socket|urllib|http|requests" floor_runtime/   # finds nothing

Builds are reproducible byte for byte: the same sources produce the same SHA-256.

Status

Pilot, honestly.

PILOT · v1.1.2 It's tested end to end, including a real MCP client calling a built kit, on Python 3.9 (the macOS default) and 3.13.

MeasuredValue
Load 500k rows (18 MB CSV)≈ 1.3 s, ≈ 400 MB RAM (M-series laptop)
First query after the data changes≈ 2.3 s at 500k rows; repeat answers are cached until the file changes
Admitting one spec (authoring side)≈ 27 s at 500k rows
Not yetWhy it matters
Relative dates ("last 30 days")They make the answer depend on the clock. Absolute date ranges work.
Parameterised toolsIt's one tool per question for now; "total for vendor X" needs a tool per X.
More than 1M rows in memoryThat's the default cap; --max-rows raises it. Export a narrower slice for bigger data.
Direct database connectionsDeliberately left out (no network). Export to CSV or SQLite instead.
Tools for your data

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

The admission gate and the signing keys stay at Perslis. A wrong spec that got signed would answer confidently, offline and forever, so the part that decides stays where it can be maintained. You send an export (CSV, JSON or SQLite) and your questions in your own words. We build each tool, review it and sign it. You get this 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.