Skip to content

The trust layer

Who reviewed this,
and how sure were they?

Agents made code cheap; the scarce resource is now trust. attest records a commit-keyed answer (reviewer, verdict, confidence) and stores it in git notes so the record travels with the repo. Signing is optional; a policy in .attest.json turns the ledger into a CI gate.

11
policy rules
all optional, permissive defaults
0
services
stored in git notes: no DB, no backend
1
key, optional
Ed25519; unsigned records still valid
5
subcommands
sign · verify · log · export · keygen

The trust primitive

A portable record of what vetted a change.

When an agent lands a change, there is no native record of which agent or human vetted it, and that context is lost the moment the PR merges. attest is that missing primitive: a durable, optionally-signed fact CI and agents can gate on.

A record, keyed to a commit

Attestation

Each attestation answers who or what reviewed this SHA, and at what confidence: a reviewer (agent:claude, human:leif), a confidence in 0...1, an optional verdict, tests-passed and human-approved flags, a timestamp, an optional note, bound to the exact commit.

Stored in git notes

refs/notes/attest

The ledger lives in refs/notes/attest, so the trust record travels with the repository across every git host. No database, no service, no extra infra. Sync it with git push origin "refs/notes/*".

Signing is optional

attest keygen

An unsigned attestation is still a valid record, so attest works with zero setup. Run attest keygen once and pass --sign to attach an Ed25519 signature over a deterministic canonical serialization anyone can verify.

Policy gates CI

.attest.json

.attest.json declares what a commit must carry: an attestation, passing tests, a signature, a human sign-off above a verdict. attest verify exits non-zero when the policy is not met, the contract a CI job or agent loop gates on.

Fed by augur

--from-augur

attest sign --from-augur - ingests an augur verdict and risk score straight from its JSON, so the trust record captures the risk assessment that informed it: a risk-45 diff becomes a 0.55-confidence attestation.

Auditable trail

attest export

attest log reads the ledger for a commit; attest export emits the whole history as one stable JSON document for compliance. The trail is portable, append-only, and verifiable offline.

The record

One attestation, fully spelled out.

An attestation is a small, signed (or unsigned) fact bound to a commit. Multiple attestations can accrue on one commit: an agent's verdict and a human's separate sign-off both count. Every record is machine-readable, so agents and tooling parse it directly.

commit
The SHA this record is bound to.
reviewer
Who or what vetted it: agent:claude, human:leif.
confidence
How sure they were, in 0...1.
verdict
Optional: proceed, review, or block.
testsPassed
Whether the change's tests passed.
humanApproved
Whether a human signed off.
signature
Optional Ed25519 signature, base64.
publicKey
The signing key, so a verifier can check it.

attest log --commit HEAD --json

{
  "commit": "9f2c1a7b04...",
  "reviewer": "agent:claude",
  "confidence": 0.92,
  "verdict": "proceed",
  "testsPassed": true,
  "humanApproved": false,
  "signature": "base64...",
  "publicKey": "base64...",
  "timestamp": 1700000000
}

The CLI

Five subcommands. The whole surface.

Record, verify, read, export, sign. Each command that touches a repo takes --path / -C to point elsewhere, and --json for machine output. Every flag is in the CLI reference.

attest sign

Record an attestation for a commit, written to git notes.

--commit, --reviewer, --confidence, --from-augur, --sign

attest verify

Gate a commit or range against .attest.json; exit non-zero on a violation.

--range, --commit, --policy, --json

attest log

List the recorded ledger, newest-first. The default subcommand.

--range, --commit, --json

attest export

Emit the complete provenance trail as one stable JSON audit document.

--range, --policy, --pretty

attest keygen

Create the Ed25519 key used to sign attestations.

--force

exit code is the contract

attest verify exits 0 when every commit passes and 1 on any violation. That non-zero exit is what a CI job or agent loop gates on.

The policy

Eleven rules, all plain JSON.

.attest.json starts permissive and tightens as a repo accumulates attestations. Every field defaults to lenient, so an empty {} requires only one attestation per commit. A misspelled rule or a missing explicit policy path is a hard error, never a silent pass. See the full policy reference.

Evidence rules: what was claimed

requireAttestation
The commit has no attestations.
requireTestsPassed
No attestation reports testsPassed.
minimumConfidence
The highest recorded confidence is below the floor.
requireHumanApprovalWhenVerdictAtLeast
A verdict is at/above the level but no record is humanApproved.
requireSignatureWhenVerdictAtLeast
A verdict is at/above the level but no record is validly signed.
requireTestsPassedWhenVerdictAtLeast
A verdict is at/above the level but no record reports passing tests.
maxAgeDays
The newest attestation is older than this many whole days.

Identity rules: who vouched

requireSignature
No valid signed attestation exists.
allowedReviewers
Any reviewer falls outside the allow-list (exact, or a prefix when it ends with :).
trustedKeys
Any signed record carries a key not in the trusted set (does not force signing).
signerPinning
A pinned reviewer is unsigned or signed with the wrong key. This is what stops a spoofed human:leif.
# .attest.json: permissive start
{
  "requireAttestation": true,
  "requireTestsPassed": false,
  "minimumConfidence": 0.6,
  "requireHumanApprovalWhenVerdictAtLeast": "block"
}

Trust model: read this before you rely on a gate

A gate is only as strong as the rule that ties a record to a key. requireSignature alone proves only that some key signed, not whose: an attacker can sign with their own key while claiming reviewer: human:leif. To actually stop reviewer spoofing, pin identity to a key with signerPinning, or pair trustedKeys with requireSignature. Confidence and tests-passed gates are satisfied by any record on the commit, so bind them to allowedReviewers or signerPinning too.

The pipeline

augur scores the risk. attest records the trust.

augur answers how risky is this diff, and should a human look?, but that verdict is ephemeral. attest makes it durable: a portable, optionally-signed record of what vetted a change. Together they give an agent loop a stop condition a human can audit later.

An agent gates itself, recording provenance as it goes

# Pipe augur's verdict straight into the trust record
$ augur check --range main..HEAD --json \
  | attest sign --commit HEAD --reviewer agent:claude --from-augur -

# Then gate; escalate to a human on a violation
$ attest verify --commit HEAD \
  || echo "trust not satisfied, escalating"

How the score becomes confidence

--from-augur copies augur's verdict and maps its risk score (0…100) to confidence = 1 − riskScore/100: a risk-45 review diff becomes a 0.55-confidence attestation. Explicit --verdict / --confidence flags override the augur-derived values.

Audit and CI

A trail you can archive, a gate you can drop in.

attest export emits a single, stable JSON document covering the complete trail across a range (sorted keys, commits oldest-first), so it diffs cleanly and is suitable for compliance archival. In CI, run the binary directly or drop in the GitHub Action, which installs a prebuilt attest for the runner: no Swift toolchain required.

attest export: deterministic audit document

$ attest export --range main..HEAD \
  --policy .attest.json --no-pretty > audit.json

# every commit, every record, with verification
{ "version": 1, "allPassed": true,
  "commitCount": 1, "records": [ … ] }

.github/workflows: the trust gate

- uses: actions/checkout@v4
  with: { fetch-depth: 0 }
- uses: CorvidLabs/attest@v0
  with:
    range: origin/main..HEAD
    policy: .attest.json

Pin @v0 to track the latest 0.x, or an exact tag to lock a version. Prebuilt binaries cover GitHub-hosted macOS and Linux x86_64 runners.

Where it ships

Language
Swift 6 (AttestKit library + CLI)
Crypto
swift-crypto (Ed25519), signing optional
Storage
git notes (refs/notes/attest)
Platforms
macOS universal + Linux x86_64
Action
CorvidLabs/attest@v0 (composite, prebuilt binary)
License
MIT

v0.4.0 is live

v0.4.0 shipped 4 days ago (Jun 11, 2026).

See how it fits with spec-sync, fledge, and augur in the toolchain onboarding.