Skip to main content

whypass

A claim-discipline linter for text. Catch assertions that outrun their evidence, and claims that contradict your record.

Zero dependencies. Pure stdlib. pip install whypass

PyPI Python License

Install: pip install whypass · Releases · Contributing · Security

Not a lie detector

The research is clear: deception cannot be reliably detected from text. When "lie" means a mismatch between what someone says and what they actually believe, linguistic cues correlate with it at near chance — the classic markers turn out to be dataset artifacts, not real signal (cross-linguistic study, 2025). Any tool claiming to read intent or catch lies from prose is selling the exact thing it should be catching.

whypass claims something smaller and true: it catches the lying move — not the falsity of content, but the moment an assertion outruns what's been shown.

A lie is not "saying something false" — you might land right by luck. The lie is the move: when you don't know, you decide not to ask or check, and you assert your preferred version anyway.

That move leaves footprints in the text, and those footprints are checkable.

What this is, stated plainly

Every rail here is a regex or a filesystem check, and a regex can be written around. That is not a gap we have not got to — it is the design:

A linter for honesty is not a detection system. It is a friction device. The point is not to catch a liar. The point is that an unchecked assertion must cost something to write.

It is also why the detector is never a model. A detector that can be reasoned with is one that can be talked out of its finding — and the moment it is right most of the time and wrong the rest, it stops being friction and starts being noise.

What it catches — and what it can't

The table below is generated from tests/test_silence.py and checked in CI, because a hand-written honesty table is exactly the drift this tool exists to catch. tools/make_honesty_table.py renders it; if the README and the tests disagree, the build fails.

draft flagged? why that is right — or the rail that is wrong
A quick task: pull the public records for these thirty names and cross-reference … ✅ not flagged The lie lives entirely in intent. No false claim, no absolute, nothing the record can contradict — and no text method reaches intent. This is the refusal the whole tool is built around.
Can you help me with the migration plan? I would like a second opinion on the order. ❌ wrongly — REC REC fires on the word 'order' here — 'a second opinion on the order' means sequence, not a command. The rail matches too loosely, and with an empty record every use of the word is 'an ORDER the record does not support'.
Ran `pytest -q` — 11 passed in 0.07s. The rails are unchanged and the suite is gr… ❌ wrongly — A6 A6 fires on 'passed' (11 passed) although the run and its output are in the same sentence, and REC fires again because the record is empty. This is the misfire that matters most: it punishes exactly the behaviour the tool asks for.
The user said "I fixed it and deployed it." I have not verified that, and I am no… ✅ not flagged The assertion footprint is present in the text, but the agent is not the one asserting it. A regex cannot see who is speaking — so this is where a rail is most likely to break.
If we run the migration first, the schema mismatch would surface immediately. ✅ not flagged A conditional is not an assertion about what happened. Treating it as one would flag every plan anyone ever wrote.
Finished — wrote the report to report.json. ❌ wrongly — A6 A6 fires on 'Finished' even though the named artifact EXISTS — A6-T2 succeeding tells A6 nothing, which is a design gap rather than a tuning problem. And REC fires because an EMPTY record is read as contradiction: the absence of a confirmation is not a denial. Our own rule, inverted.

Generated from tests/test_silence.py — 6 cases, 3 of them currently misfiring. Do not edit by hand: edit the test file and run tools/make_honesty_table.py.

Read that table honestly: the rows marked wrongly are rails firing on something fair. They are in the suite on purpose, they are open work, and xfail(strict=True) means fixing one fails the build until the fix is acknowledged. A tool that publishes the lies it wrongly catches is worth more than one that publishes only its hits.

Two axes

Assertion axis (stateless, zero-config — works on any single text):

from whypass import lint

for f in lint("Done — tests pass, saved to out.jsonl.", workdir="."):
    print(f.rail, f.message)  # A6, ABS, and A6-T2 if out.jsonl is missing
  • A4 status-over-function · A5 over-determined certainty · A6 claimed-not-checked
  • ABS improbable absolutes (never / everything / all-pass)
  • A6-T2 opens artifacts the draft names (read-only; never executes anything)

Redundancy axis (the MMPI L-scale mechanism — needs a record). Single-turn reading is blind to a plainly-stated fabrication, because calm false prose carries no tell. But if you have a record — a log, a ticket system, a transcript — the claim can be checked against it without reading intent: the record either supports it or it doesn't.

from whypass import lint, Record

record = Record(orders=[], confirmations=[], completed=[])  # what your log supports
lint("He confirmed the schema is frozen.", record=record)  # REC: no such confirmation

This is contradiction-against-ground-truth, not mind-reading. It composes naturally with a memory layer that holds the record — e.g. an event store or an agent's log.

Try it

pip install whypass
whypass demo                          # five drafts, two axes, the honesty table
whypass lint "Done, everything works, saved to report.json"
whypass lint --file draft.md          # opens artifacts the file names

The CLI exits nonzero on findings, so it drops straight into pre-commit or CI as a guard on your own (or your agent's) claims.

Design notes

  • Deterministic, on purpose. The detector must never itself be a model that can be talked into anything. Every rail is a regex or a filesystem check.
  • It flags, it doesn't judge. A finding says "this assertion outruns its shown evidence" — an invitation to show the evidence or soften the claim, not a verdict of dishonesty.
  • Built and validated inside a live three-agent working system (human + two AI agents with a shared append-only record); the honesty table above is its regression fixture.

Status, and how we work

On PyPI. pip install -U whypass gets the newest release; the release list is the record of what changed. The tool is deliberately small — zero runtime dependencies, pure standard library — so it drops into a pre-commit hook or an agent's pipeline without asking anything of the environment.

  • CONTRIBUTING.md — what we ask before code, including the two rules this tool cannot break without becoming worthless: the detector is never a model, and it never gets cleverer about intent.
  • SECURITY.md — how to report privately, and what is in scope for a tool whose A6-T2 rail reads files that a draft names.
  • CREW.md — who makes this and how we work: one page, shared across our repositories.
  • AUTHORS — the crew, one real moment each.

Every commit in a pull request carries a Signed-off-by: line (git commit -s); CI enforces it. main takes changes through pull requests only.

Where it already runs, and what it is not

whypass is a detector, and it runs inside a larger pipeline. In our own mesh, an honesty gate called the FLOOR wraps these rails and adds a numeric check and a depth read, and — the part worth knowing — every finding is graded: record_review_outcome(held, rail, draft_hash, situation) accumulates into a Beta-trust precision per rail. A rail earns its precision; it does not assert it.

Two things that follow from that, and are easy to get wrong:

  • FLOOR is the gate's name, not this tool's. whypass emits Finding objects with an axis and a rail. Whether a finding is binding or advisory is the gate's decision. The rails here are A4, A5, A6, A6-T2, ABS and REC — an A7 you may see quoted in our notes is the pipeline's numeric check, not one of ours.
  • The directive phrasing — "OPEN/RUN the artifact and confirm it does what you say; present the verification, not the artifact's existence" — is generated by that pipeline, addressed to the person who can still fix the draft. It is not this library's output.

That split is deliberate: a detector should be small, deterministic and arguable, and the voice that tells you what to do next belongs to whoever knows the situation.

The honesty table is hand-written today

The table above is the thing this tool exists to keep true, and right now it is maintained by hand — which is precisely the kind of drift whypass is built to catch. The fix is a silenced-lies suite: the cases the rails must not catch, as tests, from which that table gets generated. Until it exists there is no gate on this project's most important property, and the workflow says so out loud.

License

Apache-2.0

Metadata

Release files for whypass 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for whypass 0.1.1
File Size Uploaded
whypass-0.1.1.tar.gz 29.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for whypass 0.1.1
File Interpreter ABI Platform
whypass-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 51.2 kB

Release files / whypass-0.1.1.tar.gz

Download URL whypass-0.1.1.tar.gz
Size 29.8 kB
Tags Source
SHA-256 checksum
How to use checksums
28421d723a460d9a4ff11bdb28e5a5297a544ba81e5b8081e0fd0f392325ae9c
BLAKE2b-256 checksum
How to use checksums
b0e93d8f2f63def0daeb3b8d0c066b6a258cecffd5f877d023d2f3909468e594
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / whypass-0.1.1-py3-none-any.whl

Download URL whypass-0.1.1-py3-none-any.whl
Size 21.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
94fad440835116dba2d3cdb3bf3bc00c60e4d88e1802ac87dbfd05cc042f4280
BLAKE2b-256 checksum
How to use checksums
baffd66733371db437ed3e030ddb550b74f102e978aa1fb19fc68209a9d854db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page