All engineering articles

Open source

Review evidence that stays out of Git history

Screenshots and reports often start on a developer machine and finish in a pull request. Our open source publisher gives that handoff a source commit, verified bytes and a way to recover when it is interrupted.

CobraHQ Engineering

A reviewer needs to see the result of a change: the settings screen after a save, a recording of a mobile flow, or the report from a local check. Those files might be on a laptop while the reviewer runs somewhere else. A local path cannot cross that boundary. Committing every temporary capture adds review output to the source history.

We extracted our capture-publishing tools into Review Evidence Publisher: an MIT-licensed CLI, library and pair of GitHub Actions. It moves selected local files into an immutable Actions artifact and verifies the resulting archive against the source commit and file hashes. The original captures stay on your machine.

A small contract between capture and review

Start with a clean, pushed commit and a directory of selected files. The publisher snapshots regular files, hashes them and writes a manifest containing the repository, source commit, tracking number and bundle identity. The tracking number can be an issue or PR; the tool does not require a particular ticket system.

The snapshot passes through a dedicated GitHub prerelease to the repository's protected default-branch workflow. That workflow validates the transfer and uploads an immutable artifact. The local CLI downloads it again, checks workflow provenance, archive digest, manifest and every file, then removes the temporary transfer and local recovery bundle.

From your machine to the reviewer

  1. 1

    Select local captures

    settings.png · report.json

  2. 2

    Snapshot a manifest

    Source commit + file hashes

  3. 3

    Publish and verify

    Actions artifact · verified download

Verify the archive and file hashes before review. The original captures stay on your machine.

This is useful when browser captures, device recordings or reports are collected outside the CI job that reviews them. Coding agents are one consumer; the same handoff works for a person running local checks. If your files are already produced inside a single CI job and only need downloading, an ordinary upload-artifact step may be all you need.

Using the release in Cobra

Before publishing this post, we adopted v0.1.2 in Cobra. Publication runs in GitHub Actions, but our review and merge tools also verify evidence. Some of those checkouts deliberately never install npm dependencies. We now use the official verified runtime distribution there, pinned to the same source commit as the public Actions for publishing and cleanup. Projects that install dependencies can use the npm example below.

Trying the extracted library ourselves exposed two rough edges. A transient GitHub 502 could stop a metadata read, and our checkouts without npm dependencies needed a supported way to obtain the runtime. Both fixes now live upstream in v0.1.2. Recognised safe metadata reads get at most three attempts within 90 seconds; permanent errors and mutation commands are not replayed by that reader. The runtime distribution guide explains the archive, manifest and standalone verifier for checkouts without an install.

Existing evidence records and interrupted bundles still use the same configuration and recovery identity. Cobra keeps its file integrity checks and small adapters around one upstream publisher instance. Our Markdown review records and human approval rules stay with the project; the upstream runtime stays unmodified.

After merging the adoption, we published a small synthetic report through Cobra's main workflow and downloaded it independently. We compared the original bytes, expected source, bundle identity, archive digest and file hashes, checked authenticated staging, and confirmed that the pinned public Action actually ran. That round trip passed before we resumed this launch post.

Publish a small report

Use Node.js 22 or later on macOS or Linux, with gh, git, zip and unzip installed. Sign in to GitHub CLI with repository access; the permissions guide lists the publisher and cleanup permissions. This release supports GitHub.com.

From your repository:

Terminal · install and add the workflow
npm install --save-dev github:nick-cobra/review-evidence-publisher#v0.1.2
mkdir -p .github/workflows
cp node_modules/review-evidence-publisher/examples/publish-review-evidence.yml .github/workflows/publish-review-evidence.yml

Create review-evidence.config.json, replacing the repository name:

Terminal · review-evidence.config.json
{
  "repository": "your-org/your-repository",
  "visibility": "private"
}

For a public repository, explicitly use "visibility": "public". Selected files are public during the prerelease transfer as well as in the final artifact. Select and redact captures before publishing. The tool does not redact them for you.

The example uses main. If your default branch or workflow filename differs, follow the configuration guide and update the workflow guard to match. For automated consumers, pin its Action to source commit d7c991fef1d20d3bac99b61c0f2242790526139a. Commit and push the setup; merge the publisher workflow into your default branch before using it.

Now run from the clean, pushed candidate you want to review:

Terminal · publish a selected report
captures="$(mktemp -d)"
printf '%s\n' '{"scenario":"settings-save","result":"passed"}' > "$captures/report.json"
npx review-evidence --issue 42 --dir "$captures"

Replace 42 with your tracking number. Add screenshots or recordings from your existing capture tools to that directory before publishing. The same manifest covers them; no browser or mobile framework is required by the publisher.

The result contains artifact.url, runId, artifactId, sourceSha, the archive digest and each file's SHA-256. Use that record in your review tooling. The API guide shows verification against an independently supplied expected source commit and staging the verified files for a reviewer.

A real synthetic handoff

We ran a synthetic report with the verified v0.1.2 runtime, published it through the public project's own workflow and downloaded it again. The source was d7c991fef1d20d3bac99b61c0f2242790526139a; here are the public example run and verified artifact. This demonstrates the transport and readback. It does not represent a test of a CobraHQ product feature.

Terminal · verified public example
Archive SHA-256
4e63c15d8c3b93084c5191ce0d6f9350a838d77d674066ab1a5463bca6f171b3

report.json SHA-256
a67a7fcf0675d348604f58033ea0db06c1ce09195aecc910d2264b8e7fb1332f

The CLI's verified readback is different from simply following a download link. GitHub artifact pages require sign-in, including for public repositories. Review automation can use the library API to check provenance and hashes before reading selected files.

Recover the same bundle

A connection can drop after GitHub accepted an upload or a workflow dispatch. The CLI prints the bundle identity before dispatch and keeps a private local spool until verified readback succeeds.

Terminal · resume the same bundle
npx review-evidence --resume <bundle-sha256>

Resume reconciles the existing transfer and publisher run. It reuses accepted bytes instead of replacing them. To retire a local bundle you no longer need:

Terminal · discard a local bundle
npx review-evidence --discard <bundle-sha256>

Discard leaves the original captures alone. Keep them until review finishes. The operation guide explains abandoned transfers and the optional weekly cleanup Action.

What the evidence establishes

The package verifies selected bytes and their associated source identity. It cannot establish that a screenshot depicts that build, that its content is correct, or that a person approved the change. Capture procedures and review policy belong to the adopting project.

Evidence is temporary. The supplied workflow requests 90 days, subject to repository and organisation limits. The optional pruner uses a 30-day grace after the latest closure of referencing PRs, or after creation for unreferenced artifacts. Open references protect against early cleanup; GitHub's native expiry still applies.

Snapshots are bounded to 1,000 supported files, 100 MiB per file and 200 MiB total. Unsafe paths, symlinks, undeclared archive content and failed live publisher provenance are refused. Files remain review material and are never executed by the package.

See the workflow examples and retention guide before connecting the publisher to your own review process.

Open source · MIT licence

Try Review Evidence Publisher

Start with the README and workflow examples, or use the API in an existing review tool. v0.1.2 has zero runtime npm dependencies.

View on GitHub

Source v0.1.2API and configurationOperation and recoveryMIT licence

Related reading: Sharing mobile simulators between AI coding agents.