Skip to main content

showwork

CI PyPI version

Make your AI agents show their work.

showwork runs the checks an agent supplies and keeps an append-only receipt. Version 0.6.0 separates file observations from declared behavior tests. A clean outcome close requires passing acceptance checks, and CI checks that the full receipt was committed.

A passing check only proves what it tests. showwork cannot judge whether a requirement covers the request or a test matches its description. GolfFly exposed that gap in our own use. Read the incident and fix.

Zero dependencies. Stdlib only. One append-only ledger.

Read the portable spec-v0.5 ledger specification. Install the Claude Code Stop-hook adapter or run showwork init for Cursor, Claude, and a CI draft.

Surveyed 2026-09-03: 0 GitHub stars, 1 fork, 448 lifetime PyPI downloads. Day-0 False Done Rate, measured by showwork on the author's own fleet, 21 sessions, 2026-07, not independently measured: 42.9% contained a false done. These are historical results from the selected corpus, not a general detection rate. Source: docs/false-done-rate-day0.md.

The problem

An agent reports "done: I updated the config, logged the decision, and moved the task file." Two of those three things never happened. Your logs show the agent ran. Your traces show what tools it called. Nothing checks whether the outcome it asserted is true.

That gap is why agent pilots die before production, and it's what audit-trail requirements (EU AI Act, HIPAA, SOC 2) actually ask for: not "what did the agent do," but "prove the record is faithful."

The model

  1. Claims are falsifiable or they're just prose. When an agent (or its harness) reports a completed change, it appends a structured claim to the ledger: a file changed, a path moved, a metric holds, a command passes. Free-form prose is recorded but never counted as proof.
  2. Verification is deterministic. showwork verify re-checks every claim against the filesystem and locked commands. No LLM judges an LLM.
  3. The exit gate requires declared acceptance checks. showwork finish --status ok verifies the session's own claims first. Missing requirements, failed checks, and disabled checks refuse the close (exit 2). Fix the behavior or close as blocked. The bypass is stamped on the record either way.
  4. The ledger is append-only. Corrections are retraction records that reference the original claim. History is never rewritten.
  5. Undeclared damage is not GREEN. session.start snapshots the project tree. verify and finish go RED if a file that existed at start is deleted or changed and no active claim named that path. That is issue #64.

Quickstart

Paste this into an empty directory. The first close is supposed to fail. The refusal is the product.

pip install showwork

python -m showwork is the same CLI after install. Use it if showwork is not on PATH.

showwork start --session first-look --agent cursor
showwork require --session first-look --id config --scope artifact --description 'config/api.yaml exists' --check-json '{"type":"file_exists","path":"config/api.yaml"}'
showwork claim --session first-look --claim "config/api.yaml exists" --type file_exists --path config/api.yaml
showwork finish --session first-look --status ok
claims: RED (0/1 verified)
REFUSED: a clean close requires this session's claims to verify.

Then make the claim true and close clean:

python -c "from pathlib import Path; p=Path('config'); p.mkdir(exist_ok=True); (p/'api.yaml').write_text('timeout: 30\n')"
showwork retract --session first-look --claim "config/api.yaml exists" --reason "file was not written yet"
showwork claim --session first-look --claim "config/api.yaml exists" --type file_exists --path config/api.yaml
showwork finish --session first-look --status ok
Outcome: VERIFIED. Declared acceptance checks passed.
Scope: 0 behavior checks, 1 artifact check. Undeclared requirements: unknown.
session.finish recorded: first-look

Put the same loop on your own repo in one command:

showwork init

That writes a Cursor rule, a Claude Code Stop hook, and docs/ci/showwork-verify.yml. Copy the YAML into .github/workflows/ when you are ready to gate CI. A Cursor walk is in docs/walks/cursor.md.

Audit any day or any session after the fact:

showwork verify --date 2026-07-09
showwork verify --session first-look --json

Check types

type asserts
file_exists a file is present
file_contains a regex matches (or is absent from) a file
path_moved source is gone, destination exists
frontmatter a YAML frontmatter field equals a value
glob_count a glob's match count satisfies == >= <= > <
command a locked command exits as expected (python <script under project root> only; no shell, no metacharacters, no escape)
http_probe an HTTP(S) endpoint returns an exact status and optional body substring, with redirects disabled
git_state the local tree is clean/dirty, on an exact branch, or at a commit prefix

Vacuous checks are rejected, not blessed: a regex that matches the empty string, or a glob count that's always true (>= 0), returns an error instead of a pass. A checker that lets an agent record a bogus "done" is worse than no checker.

http_probe uses a fixed timeout and response-size cap. Network checks are disabled by default in the GitHub Action for fork safety; enable them only for trusted same-repository workflows with allow-network: true.

git_state runs fixed, non-shell Git queries against the declared project root. It accepts at least one of clean, branch, or a seven-plus-character commit prefix, so an empty check cannot pass as proof.

Command checks default to 120 seconds. For a larger suite, set SHOWWORK_COMMAND_TIMEOUT_SECONDS=300 in the runner environment. Values must be whole seconds from 1 through 3600; invalid values refuse execution. The receipt records the chosen limit. A timeout remains an error and never proves success. This changes the execution budget, not the declared tests or their assertions.

Tamper-evident by construction (v0.2)

Every appended record carries the SHA-256 of the record before it, so "append-only" is provable, not promised:

showwork audit
# showwork audit  =>  GREEN  (34/34 records chained)
#   OK  claims-2026-07-16.jsonl  head ad93b1103b7bfc04

Alter, delete, or reorder one byte of chained history and the audit goes RED at the exact line. Publishing a file's head hash anywhere out-of-band (a commit message, a post) anchors the entire history behind it. Spec: SPEC.md § Integrity chain. A zero-dependency Node auditor (js/showwork-audit) is held to the same frozen conformance fixtures as the Python reference.

Concurrent sessions do not share a file. Two agents with distinct session slugs (cursor-fix-nav, codex-fix-nav) write .showwork/sessions/<id>.jsonl and .showwork/claims/<id>.jsonl. Git then merges two paths, not one hash chain. Worktree checkouts keep receipts in that worktree so the branch carries them. Reuse of one slug is still one writer; merge=union remains only for leftover shared files. The audit still accepts a fork inside one file as GREEN and goes RED on modification, deletion, or reorder. Repos that forbid concurrency can pass showwork audit --strict. Rationale: docs/concurrency.md.

Gate your CI on receipts

- uses: bmdhodl/showwork/actions/verify@v0.6.1
  with:
    session: my-agent-session
    require-tracked: true
    allow-commands: true # Trusted repository branches only

Fails on broken chains, unmet acceptance checks, missing claim definitions, uncommitted receipts, missing outcome closes, and bypass or checks-only closes. For PRs, use changed-since to select every changed receipt. Fork-safe by default (docs/ci.md).

Version 0.6.1 adds an explicit adoption option for repositories with damaged shared legacy ledgers. A full Git commit ID pins those files unchanged. Their audit remains RED; current session receipts and new corruption cannot qualify for that exception. Read the migration limits.

Wrap any agent, no integration

showwork run --session fix-123 --gate -- codex exec "fix the failing test"

Observe mode is exit-transparent; --gate exits 2 when the command reports success but the receipts are RED (docs/adapters.md).

A supervisor UI (BMD desktop) reads the same ledger and never appends:

showwork receipts --task-id first --json
showwork receipts --task-id first --html badges.html

Empty workspace → unknown. Prose-only close → claimed. Check-backed GREEN → verified. Copy-paste for the sidecar: examples/bmd/.

Bound an unattended command by wall clock:

showwork run --session fix-123 --gate --max-seconds 1800 -- codex exec "fix the failing test"

Keep the one line a claim needs instead of a whole log:

showwork run --session fix-123 --keep "Tests .* passed" --keep-as check -- pnpm check

--keep writes only the matching lines to .showwork/artifacts/<session>/check.txt, so the receipt a file_contains claim cites is one line and not eight hundred. It buffers the command's output until the command exits. Anything left in that directory that no active claim names warns YELLOW at verify and finish.

The wrapper terminates the child and records budget_exceeded when the time envelope trips. Tool-call ceilings remain an integration concern because a generic subprocess wrapper cannot see an agent's internal tool stream; use the showwork.RunBudget API or the live hook adapter for that dimension.

The False Done Rate

Receipts make a new number measurable: how often agents claim work that is not backed by reality. Day-0, measured by showwork on the author's own production fleet, 2026-07: 21 sessions, 42.9% contained a false done, every one caught by the gate. That is a self-measurement on a self-selected sample, not an independent audit. Methodology pre-registered, corpus honesty rules included: docs/false-done-rate.md.

Evidence packs for auditors

scripts/evidence_pack.py maps a date range of chain-verified receipts to EU AI Act Art. 12/26(6), SOC 2, and HIPAA record-keeping language, and refuses to generate from a tampered ledger (docs/compliance.md).

Python API

from showwork import record_claim, verify_session, resolve_root, start_session
from showwork.outcomes import record_requirement

root = resolve_root()
start_session(root, "nightly")
record_requirement(root, "nightly", "report", "report file exists", "artifact",
                   {"type": "file_exists", "path": "reports/2026-07-09.md"})
record_claim(root, session="nightly", claim="report written",
             check={"type": "file_exists", "path": "reports/2026-07-09.md"})
state = verify_session(root=root, session="nightly")
assert state["verdict"] == "GREEN"

Provenance

This isn't a spec written on a whiteboard. It's extracted from the verification layer that runs a real one-person, AI-operated company. The system began after one agent confidently reported three completed actions and two were not real. The resulting production ledger now supplies the receipts behind the package.

Read the sanitized case study and reproduce its aggregate metrics.

The sanitized snapshot contains 2,158 claims from 842 sessions. Deterministic checks back 2,152 claims. The ledger preserves 152 retractions and surfaced one malformed line instead of dropping it. Its captured audit was RED at 54/60 verified, because failed proof remains visible rather than becoming a green marketing number.

Where this sits

The 2026 survey Code as Agent Harness (Ning et al., UIUC / Meta / Stanford) argues that code has become the runtime medium agents operate inside rather than the artifact they produce, and it names the layer showwork implements. Its §3.4.4, "Verification through Deterministic Sensors," states the rule plainly: deterministic sensors are "reproducible enough to serve as control signals," and agentic critics "should interpret sensor outputs rather than replace them." Same commitment as no LLM judges an LLM, reached from a literature review instead of from an incident.

Two of the survey's open problems are the ones this package exists for:

  • §5.2.1 Harness-Level Evaluation and Oracle Adequacy. End-task success "conflates the capabilities of the base model, the quality of the harness, the reliability of tools, the informativeness of feedback, and the difficulty of the environment." The False Done Rate measures the substrate rather than the model.
  • §5.2.5 Human-in-the-Loop Safety and Accountability as Harness State. Safety "cannot be delegated to the base model or encoded only as a natural-language instruction." An append-only ledger with a refusing exit gate makes accountability a piece of harness state instead of a sentence in a prompt.

The survey predates this package and does not cite it. It is context for the problem, not an endorsement of the solution.

What showwork is not

  • Not observability. Traces and receipts answer different questions. showwork evaluates explicit checks; author prose is not itself verified.
  • Not agent testing. Test frameworks supply behavioral checks. showwork runs those checks and binds them to declared requirements and a session receipt.
  • Not an LLM judge. Checks are executable predicates. Their quality and coverage still need review; a trivial script can pass without proving useful behavior.

Roadmap

  • More coding-agent adapters (OpenAI Agents SDK / LangGraph middleware)
  • Event stream + point-in-time replay
  • More check types as real outcome gaps emerge
  • False Done Rate at study scale: controlled task sets, per-model corpora
  • Detached signing of ledger heads (external timestamp anchoring)

License

MIT

Metadata

Release files for showwork 0.6.2

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

Source distribution (sdist)

Source distribution for showwork 0.6.2
File Size Uploaded
showwork-0.6.2.tar.gz 219.0 kB Details

Built distribution (wheel)

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

Total release size: 302.2 kB

Release files / showwork-0.6.2.tar.gz

Download URL showwork-0.6.2.tar.gz
Size 219.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f4438c716504c97d7acdcca923186be6aa69566fdcfb57c3773315ec3edf52c6
BLAKE2b-256 checksum
How to use checksums
e6a7c4439ac9d8ef3daa35182c156ce499783f0e43105b135ba79442353a0526
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / showwork-0.6.2-py3-none-any.whl

Download URL showwork-0.6.2-py3-none-any.whl
Size 83.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
72793c902cc7dc14ca626b68ad9c26715cd7351a3c3280f64a32cb089fdd2d23
BLAKE2b-256 checksum
How to use checksums
54f7261b2cdd0ed71ed9bbd053124983f07387991449e7233f92f902754270f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

This release

0.6.2 This release

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

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