CLI that verifies Ed25519-signed compute-attestation records from any provider and reports what compute was actually run, by whom, and whether every signature checks out. Read-only reporting layer -- does not sign or generate attestations.
Project description
PaceProof
PaceProof verifies Ed25519-signed compute-attestation records from any provider and tells you exactly which ones are real. A record with a missing, malformed, or tampered signature never gets folded into a "verified" total; it's counted and reported separately, every time, in both human-readable and --json output.
PaceProof does not sign or generate attestations. It is a neutral, read-only ingest/verify/report/dashboard layer over records that are already signed somewhere else. Point it at a directory, file, or URL of signed records and it tells you, verifiably, what compute was actually run, by whom, and whether every record's signature checks out.
Install
paceproof-cli isn't published to npm or PyPI yet, so build from source for now.
TypeScript (npm package, includes the MCP server):
git clone https://github.com/RudrenduPaul/PaceProof.git
cd PaceProof/packages/cli-ts
npm install
npm run build
node dist/bin.js --help
Or link it onto your PATH as paceproof:
npm link
paceproof --help
Python (PyPI package, independent reimplementation):
git clone https://github.com/RudrenduPaul/PaceProof.git
cd PaceProof/packages/cli-py
pip install -e .
paceproof --help
Once published, either package will install with:
# npm install -g paceproof-cli (once published)
# pip install paceproof-cli (once published)
Both commands above were run against this repo's actual source as part of writing this README; the quickstart output below is real, not fabricated.
Features
- Pluggable data-source adapters.
ingestnormalizes arbitrary input into the canonical schema through a documentedAdapterinterface (TypeScript interface, Python ABC). The shippedjsonladapter reads newline-delimited JSON already in canonical form; a provider-specific adapter (e.g. for ComputeLedger's native export) implements the same interface without touching the aggregator, report renderer, or CLI wiring. - Ed25519 verification with strict verified/unverified separation. Every record is checked for schema validity and signature validity. A record that fails either check is never silently merged into a verified total: verified and unverified counts and compute totals are computed from disjoint sets and shown side by side in every report.
- Two independent, parity-tested implementations. The TypeScript package (npm) and the Python package (PyPI) are separate, real implementations, not a wrapper around one or the other. Both produce byte-identical
report --jsonoutput for the same input; a CI job runs the TypeScript CLI's output against the Python CLI's output on a shared fixture in both directions and fails the build on any divergence. - Self-contained static HTML dashboard.
paceproof dashboardrenders a single HTML file with inline CSS and no JavaScript: no CDN fonts, no external scripts, no remote requests of any kind. v0.1 ships one clean light theme; there's no dark-mode toggle yet. - MCP server for agent invocation.
paceproof mcpstarts a Model Context Protocol server exposingverify,ingest, andreportas callable tools, so an orchestrating agent can call PaceProof programmatically instead of shelling out to a human-facing CLI. The tool handlers are thin wrappers around the same aggregator/report functions the CLI itself calls, with no separate reimplementation for the MCP path. - Security-hardened by design, not by afterthought. Aggregation buckets are built with
Object.create(null)so an attacker-controlledproviderorcompute_unitfield like"__proto__"can't polluteObject.prototype. The one network call PaceProof ever makes (ingest <url>) is bounded by a 30-second timeout and a 50 MiB response cap, enforced against the actual streamed byte count rather than trusting aContent-Lengthheader. Every schema field carries an explicit maximum length so oversized input can't be used to exhaust memory before validation runs.
Quickstart
paceproof init
paceproof report ./paceproof-example
paceproof init generates a fresh Ed25519 example keypair and 7 example attestation records: 3 validly signed, and 4 intentionally broken (a tampered payload, a wrong-key signature, a malformed signature, and a missing signature) so verify/report have real failure modes to demonstrate, not just a happy path.
Real output from an actual run against this repo's built CLI:
$ paceproof report ./paceproof-example
PaceProof report -- source: ./paceproof-example
generated at: 2026-08-04T02:54:30.898Z
== VERIFIED ==
records: 3
compute total: 144.50 gpu_hours
== UNVERIFIED (never counted in verified totals above) ==
records: 4
compute total: 1009 gpu_hours
reasons:
- rec-004: signature does not match record contents
- rec-005: signature does not match record contents
- rec-006: signature must decode to 64 bytes, got 4
- rec-007: schema validation failed: (root) must have required property 'signature'
== BY PROVIDER ==
acme-cloud: verified=132 gpu_hours (2 records); unverified_count=0
beta-compute: verified=12.50 gpu_hours (1 records); unverified_count=0
gamma-hpc: verified=(none); unverified_count=2
delta-cloud: verified=(none); unverified_count=2
== BY WORKLOAD TYPE ==
training: verified=128 gpu_hours (1 records); unverified_count=1
inference: verified=12.50 gpu_hours (1 records); unverified_count=1
idle: verified=4 gpu_hours (1 records); unverified_count=1
unknown: verified=(none); unverified_count=1
verify exits non-zero when any record fails (real exit code from an actual run: 1, with 4 unverified records present):
$ paceproof verify ./paceproof-example
Verified: 3
Unverified: 4
FAIL rec-004: signature does not match record contents
FAIL rec-005: signature does not match record contents
FAIL rec-006: signature must decode to 64 bytes, got 4
FAIL rec-007: schema validation failed: (root) must have required property 'signature'
$ echo $?
1
Render a dashboard from the same data:
paceproof dashboard ./paceproof-example --out dashboard.html
Both the TypeScript and Python builds were run against paceproof-example for this README, and both produced the same verified/unverified counts and totals shown above.
CLI command reference
Every table below is copied from the actual --help output of the built TypeScript CLI.
paceproof init [path]
Scaffold an example directory with a sample keypair and validly/invalidly signed example records.
| Argument | Description |
|---|---|
path |
Directory to create (default: ./paceproof-example) |
paceproof verify <path>
Verify Ed25519 signatures on every record found at <path>.
| Option | Description |
|---|---|
--json |
Output structured JSON instead of a human-readable table |
--adapter <name> |
Adapter to use for reading input (default: jsonl) |
paceproof ingest <path-or-url>
Run a named adapter over the input and emit normalized canonical-schema records as JSONL.
| Option | Description |
|---|---|
--adapter <name> |
Adapter to use (default: jsonl) |
--out <file> |
Write JSONL output to a file instead of stdout |
paceproof report <path>
Ingest and verify records at <path>, then aggregate into a summary report.
| Option | Description |
|---|---|
--json |
Output structured JSON instead of a human-readable table |
--adapter <name> |
Adapter to use for reading input (default: jsonl) |
paceproof dashboard <path>
Render a single self-contained static HTML dashboard from a report.
| Option | Description |
|---|---|
--out <file> |
Output HTML file path (default: paceproof-dashboard.html) |
--adapter <name> |
Adapter to use for reading input (default: jsonl) |
paceproof mcp
Start an MCP server exposing verify, ingest, and report as callable tools. TypeScript package only in v0.1: running paceproof mcp from the Python package prints a message pointing to the npm package and exits non-zero.
Every command supports real non-zero exit codes on failure or verification failure, and --help on every subcommand.
How verification works
Every attestation record is a JSON object validated against a single canonical JSON Schema (schema/attestation-record.schema.json), the same file, byte-for-byte, that both the TypeScript and Python packages ship and validate against. A record needs record_id, issued_at, provider, hardware, workload_type, compute_amount, compute_unit, issuer_public_key, and signature; every string field has an explicit maximum length so malformed or oversized input fails fast instead of being parsed first and bounded later.
The signature field is an Ed25519 signature over the canonical JSON encoding of every other field: object keys sorted lexicographically, UTF-8 encoding, no insignificant whitespace, numbers rendered without a leading + or unnecessary trailing zeros. Both implementations produce byte-identical canonical JSON for the same record, so a signature verified by one implementation verifies under the other.
A record is "verified" only if it passes both checks: schema-valid and signature-valid. Anything else (a missing signature, a signature that decodes to the wrong byte length, a signature that doesn't match the payload, a signature made with the wrong key) is "unverified." These two sets are always disjoint in the aggregator's code, not just in the way a report happens to render them: verified and unverified compute totals are accumulated into separate structures, and there is no code path that adds an unverified record's compute_amount into a verified total. A reporting tool that quietly conflates "claimed" and "proven" numbers launders unverifiable claims into something that looks verified, which defeats the point of an audit trail.
Comparison
Star counts and descriptions below were checked live against each project's GitHub API listing and README on 2026-08-03; none is invented or reused from memory.
| Project | Stars | What it does | How it differs from PaceProof |
|---|---|---|---|
| meghabyte/verifiable-training | 10 | Stanford NeurIPS 2024 research code ("Optimistic Verifiable Training by Controlling Hardware Nondeterminism") that eliminates hardware nondeterminism so training runs reproduce byte-identical weights across different GPUs, then builds Merkle trees over checkpoints for a verifier to audit. | Proves that specific training happened as claimed at the weights level, as an attestation-generation research prototype, not an ingest/verify/report tool. No adapters, no cross-provider ingest of pre-existing signed records, no CLI, no cross-language parity, no MCP surface. |
| skypilot-org/skypilot | 10,440 | Multi-cloud AI compute orchestration and cost-aware scheduling across 20+ clouds, Kubernetes, and Slurm. | Cost and utilization visibility and scheduling, not cryptographic verification. It never checks a signature or separates a "verified" number from a "claimed" one; there's no attestation record format involved at all. |
| opencost/opencost | 6,659 | Kubernetes and cloud cost monitoring and allocation visibility (Apache 2.0, originally Kubecost). | Same category as SkyPilot: usage and cost visibility over billing and metrics data, not cryptographic attestation. No Ed25519 verification, no verified/unverified split, no attestation record schema. |
| RudrenduPaul/ComputeLedger | 0 | Provider-agnostic CLI, library, and MCP server for signing, hash-chaining, and independently verifying compute usage receipts (GPU-hours, hardware, workload type) with Ed25519 signatures and a tamper-evident local ledger. | Complementary, not competing: same author's sibling project, and the attestation-generation half of this problem. PaceProof is the ingest/verify/report half. Point it at records from ComputeLedger, or from any other Ed25519-signing source, and it reports on what verifies. |
Broader searches for a directly comparable "ingest signed compute-attestation records from multiple providers, verify Ed25519 signatures, keep verified and unverified totals separate" tool turned up nothing else matching that specific combination as of 2026-08-03. The closest adjacent category is generic hardware remote-attestation verification (e.g. veraison/services, 47 stars, TPM/SEV-SNP/SGX/TDX evidence): a different attestation domain (hardware boot/runtime state, not compute-usage records) with no compute-attestation schema, no adapter model, and no compute-hours reporting.
What PaceProof is, and why it exists
Compute usage claims from AI labs, cloud providers, and infrastructure operators are getting harder to independently verify as the volume of compute-related discourse grows. The real 2026 "Pacing the Frontier" open letter is one example of that industry conversation, cited here only as motivating context. PaceProof is not affiliated with it, was not built in response to any request from its signatories, and makes no claim of endorsement or partnership.
To be direct about the one thing this README needs to be unambiguous about: there is no real "Verified Slowdown" treaty, and no such treaty exists today. That phrase comes from a speculative forecasting scenario at ai-2027.com, not from any actual international agreement, law, or regulatory body. PaceProof does not implement, enforce, or certify compliance with any treaty, law, or regulation, because no such treaty, law, or regulation applicable to this tool exists.
What PaceProof actually is: a neutral, cryptographically-verifiable reporting layer over compute-attestation data you already have. If you (or a provider you work with) already produce signed attestation records, whether through ComputeLedger, a custom signing pipeline, or anything else that emits Ed25519-signed records, PaceProof tells you which of those records actually hold up cryptographically and totals up only the ones that do, split cleanly from the ones that don't. That's useful today for internal audit trails and cross-provider usage transparency. It is not, and does not claim to be, compliance software for a regulation that doesn't exist.
FAQ
Does PaceProof provide legal or regulatory compliance? No. There is no real "Verified Slowdown" treaty or comparable regulation for PaceProof to comply with, and PaceProof makes no compliance claim of any kind. It verifies Ed25519 signatures on records you give it and reports the results. Treat its output as a cryptographic verification report, not a legal or regulatory certification.
Does PaceProof sign or generate attestation records? No. PaceProof is read-only: it ingests, verifies, and reports on records that are already signed elsewhere. If you need to generate signed compute-attestation records, that's a separate concern; see ComputeLedger, a sibling project by the same author, for the signing side.
What happens to a record with a bad signature? Does it just get dropped?
No. A record that fails schema validation or signature verification is never dropped or silently excluded. It's counted in unverified_count, its compute amount is totaled separately in unverified_compute_total_by_unit, and the specific reason it failed (tampered payload, wrong key, malformed signature, missing field) is reported alongside it. Nothing about a failed record disappears from the output.
Can I add support for a provider whose export format isn't JSONL?
Yes, that's what the adapter interface is for. Implement the Adapter interface (TypeScript) or the Adapter ABC (Python): a name and a read(input) method that returns records already normalized to the canonical schema. You don't need to touch the aggregator, the report renderer, or existing CLI wiring beyond registering the new adapter's name.
Does paceproof ingest <url> make arbitrary network calls?
Only the one you explicitly ask for. Every other command operates on local files. ingest <url> is the single opt-in network call in the whole tool, and it's bounded: a 30-second timeout and a 50 MiB response cap enforced against the real streamed byte count, not just a Content-Length header the remote server could lie about.
Why are there two implementations instead of one CLI with bindings?
So each package is a real, independent thing you can install from its native registry (npm or PyPI) without pulling in a runtime for the other language. A shared JSON Schema file and a cross-language parity test suite (run in both directions in CI) keep their report --json output identical, so which implementation you pick doesn't change what you get.
Is the MCP server available in the Python package?
Not in v0.1. paceproof mcp is TypeScript-only for now: running it from the Python package prints a message pointing you to the npm package and exits non-zero. Every other command (init, verify, ingest, report, dashboard) is a full, independent Python implementation.
Contributing
CI (.github/workflows/ci.yml) runs three jobs on every push and PR to main: TypeScript lint + typecheck + test, Python lint (ruff) + typecheck (mypy --strict) + test (pytest) across Python 3.10 and 3.13, and a cross-language parity job that builds the TypeScript CLI, installs the Python CLI, and runs each side's parity test against the other's CLI as a subprocess.
To run everything locally:
# TypeScript
cd packages/cli-ts
npm install
npm run lint
npm run typecheck
npm test # 60 tests, Vitest
# Python
cd packages/cli-py
pip install -e ".[dev]"
ruff check src tests
mypy src
pytest -q # 52 tests
If you change the schema, update schema/attestation-record.schema.json at the repo root and its copies under packages/cli-ts/schema/ and packages/cli-py/src/paceproof_cli/schema/, and update both implementations' validation logic. A parity test in each package's suite checks its local schema copy against the root file and fails CI if they drift.
See ARCHITECTURE.md for the full repo layout, the canonical JSON rules the signature is computed over, and how the adapter interface and MCP server fit together.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
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 paceproof_cli-0.1.0.tar.gz.
File metadata
- Download URL: paceproof_cli-0.1.0.tar.gz
- Upload date:
- Size: 27.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a679542e82921f64d05d99a24a0ae67debb62a287e61186b1cd6c0fd543901d9
|
|
| MD5 |
2aa7dbb7350111bdf0d10abda3ad809a
|
|
| BLAKE2b-256 |
0b45d0e53532b8e274be457094612535c9352a3d3abef0cc0303e1be460c3262
|
Provenance
The following attestation bundles were made for paceproof_cli-0.1.0.tar.gz:
Publisher:
publish-pypi.yml on RudrenduPaul/PaceProof
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
paceproof_cli-0.1.0.tar.gz -
Subject digest:
a679542e82921f64d05d99a24a0ae67debb62a287e61186b1cd6c0fd543901d9 - Sigstore transparency entry: 2339066794
- Sigstore integration time:
-
Permalink:
RudrenduPaul/PaceProof@36f9001d40a0f999146f3f8daae74df034180e14 -
Branch / Tag:
refs/tags/python-v0.1.0 - Owner: https://github.com/RudrenduPaul
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@36f9001d40a0f999146f3f8daae74df034180e14 -
Trigger Event:
release
-
Statement type:
File details
Details for the file paceproof_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: paceproof_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.8 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 |
4a1c3309948c6da4909fe399123794c60e8f0a114121dcb17f85c05bd97cd1eb
|
|
| MD5 |
96da26da01ac6cb7ae36d2dc35399efb
|
|
| BLAKE2b-256 |
f2dbf9ae44f1f2f0f9da7336bbb2b24a9ae54f2be54e3e2e6e36301d85001725
|
Provenance
The following attestation bundles were made for paceproof_cli-0.1.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on RudrenduPaul/PaceProof
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
paceproof_cli-0.1.0-py3-none-any.whl -
Subject digest:
4a1c3309948c6da4909fe399123794c60e8f0a114121dcb17f85c05bd97cd1eb - Sigstore transparency entry: 2339066803
- Sigstore integration time:
-
Permalink:
RudrenduPaul/PaceProof@36f9001d40a0f999146f3f8daae74df034180e14 -
Branch / Tag:
refs/tags/python-v0.1.0 - Owner: https://github.com/RudrenduPaul
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@36f9001d40a0f999146f3f8daae74df034180e14 -
Trigger Event:
release
-
Statement type: