Skip to main content
Glama
WXBR
by WXBR
README.md
# ShipReceipt

**A receipt for every “done.”** ShipReceipt turns a delivery claim into fresh, machine-checkable local evidence: the claim, safe deterministic probes, captured output, exit codes, relevant file hashes, and a portable report.

Tests tell you what ran. ShipReceipt tells a reviewer which exact completion claim those tests support—and when later changes mean that proof is no longer fresh.

[![CI](https://github.com/WXBR/shipreceipt/actions/workflows/ci.yml/badge.svg)](https://github.com/WXBR/shipreceipt/actions/workflows/ci.yml)
[![Live demo](https://img.shields.io/badge/live_demo-shipreceipt.vercel.app-D94B18.svg)](https://shipreceipt.vercel.app)
[![Demo video](https://img.shields.io/badge/demo_video-2%3A44-315F88.svg)](https://youtu.be/3KCSkylMyxw)
![License: MIT](https://img.shields.io/badge/license-MIT-1D1B17.svg)

[![ShipReceipt landing page](docs/assets/hero.png)](https://shipreceipt.vercel.app)

## Why it exists

Coding agents are good at confident summaries. Reviewers need a tighter contract:

```text
“The release marker is valid.”
       ↓
claim + files + executable argv + captured evidence + file hashes
       ↓
verified / contradicted / unverified / stale
```

If a relevant file changes after a probe runs, ShipReceipt marks the claim **stale**. It does not leave yesterday’s green check pretending to prove today’s tree.

## Quickstart

Requires Node 20+ and npm.

```sh
npm install
npm run build

# Create a receipt in the current repository
node packages/cli/dist/index.js init

# Record a narrow claim. Everything after -- is executable plus argv, never a shell string.
node packages/cli/dist/index.js claim "The unit suite passes." \
  --file packages/core/src/core.ts -- node --test

# Direct CLI execution needs an explicit approval flag; previously allowlisted contracts can re-run without it.
node packages/cli/dist/index.js run clm_yourclaim --approve
node packages/cli/dist/index.js status
node packages/cli/dist/index.js export --format html --out shipreceipt-report.html
```

### See the full state machine in 10 seconds

```sh
npm run smoke
```

The smoke fixture creates a passing claim, a failing claim, then modifies the passing claim’s tracked file. Its final status contains `stale` and `contradicted`; it also exports a static HTML report.

For the browser demo:

```sh
npm run build --workspace=@shipreceipt/web
npx serve packages/web/dist -l 4173
```

The dashboard’s buttons run an in-browser fixture only. To use the same UI against a real local receipt, start its local-only reader after building:

```sh
npm run live --workspace=@shipreceipt/web -- --root /path/to/repository
```

It serves `packages/web/dist` and a local `/receipt.json` status endpoint; it never executes probes. The hosted static demo never executes commands or reads a visitor’s filesystem.

## CLI

| Command | Purpose |
| --- | --- |
| `init [--root path]` | Create `.shipreceipt/receipt.json`. |
| `claim "text" --file path -- executable argv` | Add a claim and a deterministic probe. |
| `allow <id>` | Allowlist a claim’s full probe contract for later local re-runs. |
| `run <id> --approve` | Execute its probes with limits and capture evidence. |
| `status` | Print the current state for every claim. |
| `export --format json|html --out file` | Write a portable receipt. |
| `demo [--root path]` | Build the bundled contradiction/staleness scenario. |

`--root` is supported on every command. A probe’s command is stored as an executable and argv array. There is no shell interpolation or `shell: true` path. `run` needs an explicit `--approve`, unless the full probe contract (argv, cwd, timeout, expected exit, files, and allowed environment names) was previously recorded with `allow`.

## Receipt states

| State | Meaning |
| --- | --- |
| `unverified` | No complete probe evidence exists. |
| `verified` | Every probe exited with its expected code and current file hashes match evidence. |
| `contradicted` | A probe failed, timed out, or exited unexpectedly. |
| `stale` | Relevant file hashes no longer match those recorded at probe time. |

## Codex plugin and MCP

The repository includes a repo-local marketplace at `.agents/plugins/marketplace.json` and an installable plugin in `plugins/shipreceipt`.

Build first, then add the repository marketplace and install the plugin:

```sh
codex plugin marketplace add /path/to/shipreceipt
codex plugin add shipreceipt@shipreceipt-marketplace
```

The plugin carries a self-contained bundled stdio MCP server and exposes five deterministic tools:

- `shipreceipt_init`
- `shipreceipt_claim`
- `shipreceipt_run` (runs only contracts already allowlisted through the local CLI)
- `shipreceipt_status`
- `shipreceipt_report`

The skill at `plugins/shipreceipt/skills/shipreceipt/SKILL.md` instructs Codex to use narrow claims, explain intended execution, and cite a receipt ID/status rather than claim success from prose. MCP callers cannot self-approve execution: after a claim is recorded, the user must inspect and allowlist its full probe contract through the local `shipreceipt allow <id>` CLI command before `shipreceipt_run` can execute it. `npm run build` refreshes the plugin-local MCP bundle before installation.

![Freshness and contradiction states](docs/assets/demo-states.png)

You can smoke the server directly using newline-delimited JSON-RPC:

```sh
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | node packages/mcp/dist/index.js
```

## Architecture

```text
Codex skill / CLI / MCP
          │
          ▼
  @shipreceipt/core
  schemas · safe runner · hash snapshots · receipt store
          │
          ▼
 .shipreceipt/receipt.json ──► status / HTML report / local dashboard
```

The core library owns schemas, hashing, persistence, status calculation, redaction, and command execution. The CLI and MCP server are thin adapters. The web dashboard is static and uses a bundled demo state; it can be hosted without credentials. See [architecture notes](docs/architecture.md) and [decisions](docs/decisions.md).

## Safety and threat model

ShipReceipt is local-first, but running a probe is still code execution. The runner:

- requires explicit approval in the CLI and MCP interface;
- stores commands as executable plus argv and sets `shell: false`;
- restricts probe working directories to the receipt root;
- uses a default 30-second timeout capped at two minutes;
- caps each stdout/stderr stream at 64 KiB;
- forwards no environment variables unless named in the probe allowlist, except the minimal inherited `PATH` needed to locate an executable;
- applies best-effort redaction to common token/key, authorization, cookie, URL-credential, cloud-key, and private-key forms before storing output.

The receipt’s hashes and chain are **tamper-evident only within a documented threat model**. Before status, export, or execution, ShipReceipt verifies event linkage, every current claim/evidence binding, evidence hashes, and probe contracts; an integrity failure fails closed rather than reporting a green claim. Someone who can rewrite the receipt and all local files can still rewrite its history. Hashes prove consistency of what ShipReceipt recorded; they do not establish identity, remote provenance, or a secure audit trail. Do not put secrets in commands, claims, or files. See [security notes](docs/security.md).

## Deployment

`vercel.json` builds and serves `packages/web/dist` as a static site. It has no server code and no command-execution endpoint. For another static host, run `npm run build --workspace=@shipreceipt/web` and publish that same directory.

## Development and verification

```sh
npm install
npm run lint
npm run typecheck
npm test
npm run build
npm run smoke
npm run plugin:check
```

## Build Week / Codex disclosure

This is an OpenAI Build Week 2026 submission. GPT-5.6 in a persistent Codex session accelerated implementation: workspace setup, TypeScript core/CLI/MCP/dashboard code, tests, fixture, documentation drafts, and verification iteration. Human product decisions defined the problem, local-first evidence model, safety boundaries, visual direction, project scope, and final review criteria. No OpenAI API key is required: GPT-5.6 runs in the authenticated Codex host, while ShipReceipt itself is deterministic local tooling. See the public [Codex build trace](docs/build-trace.md).

## License

MIT. See [LICENSE](LICENSE).