Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

verify-run

A local, deterministic gate that decides whether a consequential command is allowed to run — and leaves a signed receipt you can replay offline.

Alpha. Everything runs on your machine. No account, no database, no browser, no network call, no telemetry.

The problem

Software is increasingly allowed to act: agents run shell commands, pipelines deploy, workflows move money. The usual controls are a code review before the fact and a log line after it. Neither tells you why a specific action was permitted, under which rules, against which evidence — and neither lets anyone check that answer later without trusting whoever wrote the log.

verify-run puts one deterministic decision between the intent and the action, and records it in a form that can be recomputed from its own inputs.

Install

python -m pip install verify-run

Requires Python 3.11 or newer. Two dependencies: PyYAML and cryptography.

90-second quickstart

mkdir demo && cd demo
vfy init --template pipeline-gate
initialized  .
  rulebook   rulebook.yaml   (template pipeline-gate)
  runtime    local-033506d02ab8629c
  store      .vfy
  keys were generated in .vfy/keys; the private halves are never printed.

The template gates a deploy on two things: the branch, and fresh passing tests. Provide both — a program to gate, and the command that reports test status:

mkdir -p bin ci
printf '#!/bin/sh\nprintf "deployed %s\\n" "$1"\n' > bin/deploy.sh && chmod +x bin/deploy.sh
printf '#!/bin/sh\nprintf %s "\\"passed\\""\n' '' > ci/last-test-result.sh && chmod +x ci/last-test-result.sh

Now gate the deploy:

vfy run --identity branch=main -- bin/deploy.sh v1.2.3
ALLOW   bin/deploy.sh v1.2.3   rule: tests-green-on-main
        rule_allow: Tests green on main within freshness bound.
        receipt .vfy/receipts/r-b4b83611eecc18cf00ca07a0.json
        executed, exit 0

Try it from the wrong branch, and from a state where the tests cannot be read:

BLOCK   bin/deploy.sh v1.2.3   rule: wrong-branch
        rule_block: Deploys only from main.
        receipt .vfy/receipts/r-075c672f2cb9c2fc2c859194.json
        nothing executed

HOLD    bin/deploy.sh v1.2.3
        evidence_unsettled tests: Evidence could not settle this rule.
        receipt .vfy/receipts/r-940642b37391e90eba0091c8.json
        nothing executed

List what happened, and recompute any of it:

vfy receipts list
vfy replay .vfy/receipts/r-b4b83611eecc18cf00ca07a0.json
ALLOW   r-b4b83611eecc18cf00ca07a0
  verification  signature verified
  replay        recomputed and identical
  authorization verified against the recorded bindings

Every transcript above is real output from this version. Full walkthrough: docs/quickstart.md.

Four outcomes, never collapsed

Outcome Meaning Exit code
ALLOW The rulebook and the evidence authorize this exact action. 0 (13 if the command itself failed)
BLOCK The rulebook reached a negative result. The receipt names which rule. 10
HOLD The rulebook cannot settle it — evidence missing, stale, or conflicting. Not a failure. 11
ERROR The request was malformed; evaluation never validly began. Not a decision. 12

HOLD is the one most systems get wrong. "I don't know" is a different answer from "no", and merging them is how a gate starts silently guessing.

The workflow

vfy init      create a workspace from a template
vfy check     evaluate a candidate without running it (evidence is still acquired)
vfy run       gate a command
vfy replay    verify and recompute a stored decision
vfy receipts  list, or show one with verification and replay

check is a preview: it reaches a decision and writes nothing. It does acquire the evidence the rulebook declares, which for an exec declaration means running that evidence command — it is the candidate's own action that never starts. run is the governed path — it evaluates, and on ALLOW it issues a single-use authorization bound to that exact command, consumes it, launches, records what happened, signs a receipt, and stores everything replay needs.

The rulebook

rulebook_id: pipeline-gate
version: 1.0.0
adopted_at: "2026-08-05T00:00:00Z"
track: [branch]
evidence:
  - {id: tests, source: exec, ref: "./ci/last-test-result.sh", max_age_seconds: 900}
rules:
  - id: tests-green-on-main
    when: 'identity.branch == "main" and fresh(tests) and evidence.tests == "passed"'
    outcome: ALLOW
    reason: Tests green on main within freshness bound.
  - id: tests-red
    when: 'fresh(tests) and evidence.tests == "failed"'
    outcome: BLOCK
    reason: Tests failed.
default_outcome: HOLD
authorization: {ttl_seconds: 300, single_use: true}

Rules are tried in order; the first one that is true decides. A rule that cannot be settled stops the walk and holds. See docs/rulebook-reference.md.

Supported evidence

  • file — a local JSON file.
  • exec — a local command whose stdout is JSON.

http is not implemented in this alpha. A rulebook may declare it — the bundled claims-gate template does — and nothing is faked: the item is recorded as missing, the rulebook holds, and the CLI names the source. That is the correct answer for evidence nobody acquired, not a defect.

Not in this alpha

HTTP evidence, watch mode, serve mode, hosted registry or vault, fleets, accounts, billing, a browser interface, device/GPIO support, and the npm runtime. None of these exist here.

What replay does and does not mean

Replay recomputes the decision from the exact recorded rulebook, candidate, and evidence snapshot, and compares the result byte for byte. It also verifies the receipt's signature against a key registry you supply.

Replay does not re-run the command, re-acquire evidence, contact any system, or establish that the world changed. A receipt records that a runtime reported an exit status — not that a deploy succeeded. See docs/receipts-and-replay.md.

Security model, briefly

  • Trust roots are key registries you control. An artifact never certifies itself.
  • An authorization is issued only on ALLOW, bound to the exact command, rulebook, and evidence digests, and is single-use — consumed before the process starts.
  • No shell is ever involved. Arguments are passed literally.
  • The parent environment is not inherited; a gated command sees only what your config names.
  • This is not a sandbox. The command runs with your privileges.
  • Exactly-once external execution is not claimed. A crash after consumption and before launch spends the authority without acting; a crash after launch may change the world without a stored receipt. Both are stated plainly rather than papered over.

Full boundaries, including what is deliberately not guaranteed: docs/security.md.

Determinism

Evaluation is a pure function of the pinned rulebook, the candidate, and the frozen evidence snapshot. It reads no clock, no randomness, no environment, no network, and no locale. The same canonical inputs produce byte-identical outputs — which is what makes replay checkable at all.

Timestamps, key generation, and nonces live at the command-line edge and enter the trusted layers only as recorded values.

Python support

Requires >=3.11. Developed and fully tested on CPython 3.14 (macOS, arm64); continuous integration covers 3.11, 3.12, and 3.13 on Linux. Other platforms are expected to work but are not yet proven — see docs/security.md for the exact platform caveats.

Development

python -m venv .venv && .venv/bin/pip install -e .
.venv/bin/python -m unittest discover -s tests -t .

Standard-library unittest, no test-framework dependency. The spec/ directory is the authority and fixtures/ holds the golden vectors; implementations conform to them, never the reverse.

Decision replay conformance

The same declared inputs deterministically settle to one of four non-collapsible terminal classes; an exact ALLOW creates action-bound authority; and the resulting artifact permits the recorded decision to be independently verified and fully recomputed without trusting the platform database.

That claim is now written down as a public, vendor-neutral contract with fixtures anyone can run: Decision Replay Conformance Profile v1, profile id decision-replay-v1. verify-run is its first reference implementation, not its definition.

sh tools/conformance_reference_run.sh

That installs verify-run==0.1.0a2 from PyPI into a clean environment, runs the 30 fixtures against it, and writes a result document.

Replay recomputes the recorded decision. It does not re-execute the action, does not reacquire evidence, and does not prove the action's effects occurred in the world. A result is a self-test, not certification: nobody accredits this profile, and a PASS is meaningful only together with the profile version and fixture-manifest digest it names. See docs/conformance/claims.md for exactly what a result lets you say, and §16 of the contract for what it deliberately does not establish.

Current reference result: PASS, 30/30 fixtures, verify-run 0.1.0a2, fixture manifest 756029f681ad7587….

Alpha status

Version 0.1.0a2. The decision semantics, canonical form, and receipt format are frozen and covered by golden vectors — 0.1.0a2 changed none of them, and every 0.1.0a1 receipt still verifies and replays. The command surface is the five commands above. Interfaces may still change before 1.0; recorded artifacts carry a spec_version so a future change cannot silently reinterpret an old receipt.

License

Apache-2.0. See LICENSE and NOTICE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

verify_run-0.1.0a3.tar.gz (370.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

verify_run-0.1.0a3-py3-none-any.whl (87.7 kB view details)

Uploaded Python 3

File details

Details for the file verify_run-0.1.0a3.tar.gz.

File metadata

  • Download URL: verify_run-0.1.0a3.tar.gz
  • Upload date:
  • Size: 370.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.2

File hashes

Hashes for verify_run-0.1.0a3.tar.gz
Algorithm Hash digest
SHA256 b260e0890cd1cf71d96915ecd1793b2e2f949f602b36e75f619f8350b27e0c43
MD5 ac14d5d08427fb9595646e92ef4a5bce
BLAKE2b-256 fba5716da3ce5c175b3becd6920fc11ab861fc46a8e78845499163970c9b745c

See more details on using hashes here.

File details

Details for the file verify_run-0.1.0a3-py3-none-any.whl.

File metadata

  • Download URL: verify_run-0.1.0a3-py3-none-any.whl
  • Upload date:
  • Size: 87.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.2

File hashes

Hashes for verify_run-0.1.0a3-py3-none-any.whl
Algorithm Hash digest
SHA256 2b4d294e9f530eb8b3e5dd5163c575c01b99114d15725f9874fba4fba9811a84
MD5 b28a741ff3c1faa10302fe3c03f0104c
BLAKE2b-256 98e70f539d1b3f0803f0f5abc9f5ad57037728d78ad9add70850104e0c1ac1c6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page