Pointbreak events may carry an optional Ed25519 signature that authenticates the producer facts. This
page orients you across the three signing flows and the verification ladder. Reference material lives
in cli-reference.md (the pointbreak key family and signing env vars),
storage-model.md (the allowed-signers format and the user-level key home), and
ADR-0010 (the decisions).
This is the load-bearing rule: a write never fails because of signing. Whatever goes wrong while
resolving a key — none configured, an unreadable key home, an unsupported algorithm, a malformed
configured key, or POINTBREAK_SIGNING=off — degrades to an unsigned write at exit 0, with a one-line
advisory diagnostic on stderr. Signing strengthens a write when it can; it never blocks one.
A read surface (with a verification policy and the discovered trust set) renders one of:
unsigned— no signature: no key was configured,POINTBREAK_SIGNING=off, or keygen failed. The write still happened.untrusted_key— signed by a key that is not in the repo's.pointbreak/allowed-signers.jsonallow-list. Tamper-evident and strictly better than unsigned, but not yet bound to an actor.valid— signed by a key enrolled for that actor (or a self-certifyingdid:keyactor whose id is its own signer). The signature verifies and binds.
(invalid is the fourth status — a signature that fails to verify against its claimed key.)
pointbreak key init --name default # generate a key, print its did:key
pointbreak key enroll default --actor actor:git-email:alice@example.com
git add .pointbreak/allowed-signers.json && git commit # the commit is the authorizationThe human opts in explicitly. Until the enrollment is committed, the human's signed events render
untrusted_key; once committed, they render valid.
An agent writing under an actor:agent:* id needs no setup. The first write silently generates a
passphrase-less per-machine key, signs, and prints a notice with the agent's did:key and
pointbreak key enroll. A human reviews and commits the allow-list edit to bind the agent. See
agent-authoring.md. POINTBREAK_SIGNING=off opts out.
CI can sign without any enrollment by making the writing actor be the signing key:
pointbreak key init --name ci
export POINTBREAK_ACTOR_ID="$(pointbreak key show ci --did | jq -r .didKey)"
pointbreak capture --sign-key ci # writer.actorId == signer -> self-certifyingBecause writer.actorId is the signing key's did:key, the event omits the top-level signer and
verifies valid under an empty trust set — no allow-list entry required. The key is ephemeral to the
CI run.
Already sign your git commits with SSH? Sign your review facts the same way — the same move git made
with gpg.format=ssh + user.signingKey. Adopt an existing Ed25519 SSH key as an agent-backed signer
with no new key ceremony:
pointbreak key discover --repo . # inspect Git/OpenSSH evidence
pointbreak key use-ssh ~/.ssh/id_ed25519.pub --name default # adopt; print its did:key
pointbreak key enroll --signer did:key:z6Mk... --actor actor:git-email:alice@example.com
git add .pointbreak/allowed-signers.json && git commit # the commit is the authorizationpointbreak key discover reads local Git SSH signing config and OpenSSH allowed-signers files as setup
evidence. Discovery does not authorize keys: review candidate details first, then choose whether to
adopt signing custody with pointbreak key use-ssh and/or stage Pointbreak trust with pointbreak key enroll --signer. The positional use-ssh argument is either a path to a *.pub file or a
key::ssh-ed25519 AAAA… literal (git's user.signingKey form). Here "agent" is the ssh-agent
key custodian — distinct from a coding or reviewing agent (acting software).
No Ed25519 SSH key yet? Create one (the same key works for git commit signing):
ssh-keygen -t ed25519 -C "you@example.com" # writes ~/.ssh/id_ed25519 and ~/.ssh/id_ed25519.pubLoad it into ssh-agent so signing doesn't prompt every write. Pointbreak signs through the agent, so the private key must be loaded in it:
ssh-add ~/.ssh/id_ed25519 # load it (add --apple-use-keychain on macOS to persist across logins)
ssh-add -l # verify it is listedIf the key is not loaded, pointbreak key list reports agentLoaded: false and a signed write degrades to
unsigned, exit 0 (signing_agent_key_absent) — never blocking, but not yet valid. Load the key
and re-run the write.
ssh-agent custody. The private key is never read: ssh-agent custodies it, and Pointbreak only ever ships the DSSE pre-authentication bytes to the agent and unwraps the returned signature. Encrypted keys, 1Password, and hardware-backed agents all work for free.
Plain ssh-ed25519 only. Other key types are rejected with a clear diagnostic at use-ssh time:
ed25519-sk(FIDO/-sk) signs a hash + flags + counter construction, never the raw message, so a signature from one can never verify under the strict Ed25519 path. Hard exclusion.- RSA and ECDSA are not Ed25519 — rejected, pointing at
pointbreak key init. - No SSHSIG wrapper. The
DSSEv1PAE prefix already supplies domain separation, so Pointbreak sends the bytes to the agent raw (sign flags = 0) and unwraps the SSH-wirestring "ssh-ed25519", string sigresponse to the 64-byte signature ADR-0004 wants. Cross-protocol confusion with the same key is structurally excluded.
Never gates, even though the agent can fail. A network-backed signer can fail where a local file key cannot, so signing-never-gates is kept true by two cooperating mechanisms: an identities-only pre-flight in the resolve layer (connect + confirm the key is loaded — it does not sign) and a tightly-scoped sign-time degrade in the write seam. Every failure mode leaves an unsigned write at exit 0 with a named diagnostic:
| Agent condition | Diagnostic | Outcome |
|---|---|---|
| Agent unavailable (no socket / no pipe / refused) — at pre-flight | signing_agent_unavailable |
unsigned write, exit 0 |
| Key not loaded / globally locked (lists zero identities) — at pre-flight | signing_agent_key_absent |
unsigned write, exit 0 |
| Agent refuses or fails the sign (confirmation deny, agent died) — at sign time | signing_agent_sign_failed |
unsigned write, exit 0 |
Unsupported key algorithm (-sk/RSA/ECDSA) |
signing_key_unsupported_algorithm |
unsigned write, exit 0 |
For an explicitly selected agent-backed key (--sign-key / POINTBREAK_SIGNING_KEY), a pre-flight
failure is terminal — it does not fall through to auto-keygen or the default key.
One prompt per write, not two. Because the pre-flight is identities-only (it never signs), a
confirmation-constrained or hardware agent (ssh-add -c, 1Password, YubiKey) is prompted exactly once
per write — at the real sign. (A probe-sign pre-flight was rejected for exactly this reason: it would
prompt twice.) The will-it-sign question is answered at the real sign, and the sign-time degrade closes
the sub-second window where the agent dies or locks between pre-flight and sign (and a per-key
confirmation deny): the event is left unsigned, still exit 0, with signing_agent_sign_failed. The
file-signer path stays strict — its errors still propagate, so a real bug is never masked. There is no
residual.
Cross-platform. The transport is platform-abstracted: the $SSH_AUTH_SOCK Unix domain socket, and
the Windows named pipe \\.\pipe\openssh-ssh-agent.
Key rotation and revocation are named follow-ons, not yet shipped — only the flows above are available today.