Alien Agent ID — Git
SSH-signed commits whose signing key is — when the agent is bound — tied via the SSO-issued id_token (cnf.jkt) to a verified human owner. Each commit carries:
- An SSH signature in the commit object (visible via
git log --show-signature). Agent-ID-JKT: <thumbprint>in the commit message — always; plusAgent-ID-Owner: <sub>when the agent is human-backed (L1/L2).- A v3 proof bundle attached as a git note under
refs/notes/agent-idcontaining the agent's public JWK, plus the SSO-signed id_token when bound.
Binding is optional — commit works at any assurance level. A fresh, unbound agent (L0) commits with its key alone: still SSH-signed, still independently verifiable as "this key", just with no human attestation. Bind later (agent-id-core auth + bind) and subsequent commits become human-backed (L1 anonymous / L2 linked) with no key change. Verification reports the level it proves.
Verification is universal: it does not require the agent's local state, only the commit and its proof note. For a bound commit the verifier walks SSH sig → agent_jwk → cnf.jkt → SSO RS256 signature → verified owner sub; for an L0 commit it confirms SSH sig → agent_jwk → JKT trailer and reports level 0.
Resolve the CLI
bin/cli.mjs lives in this plugin's directory. In the examples below, CLI is ${CLAUDE_PLUGIN_ROOT}/bin/cli.mjs — the ${CLAUDE_PLUGIN_ROOT} path is filled in for you when the skill loads.
Setup (one-time)
After agent-id-core init (or bootstrap) has produced a keypair — binding is not required for setup — configure git signing:
node CLI setup
This writes $stateDir/ssh/{agent-id, agent-id.pub, allowed_signers} and prints the public key. Add it to GitHub (Settings → SSH and GPG keys → New SSH key → Key type: Signing Key) to earn the Verified badge on commits.
Make a signed commit
node CLI commit --message "feat: implement auth flow"
node CLI commit --message "fix: handle empty body" --push # push commit + proof note
node CLI commit --message "release: 1.2.0" --push --remote upstream
Output is JSON: { ok, commitHash, signed, level, assurance, jkt, ownerSub, proofAttached, pushed, notesPushed, ... }. level is 0 (self-asserted), 1 (anonymous-human), or 2 (linked); an unbound agent commits at level 0 and emits a notice.
A normal git commit still works but skips trailers, signing, and the proof note.
Verify a commit's provenance
node CLI verify --commit HEAD # current commit
node CLI verify --commit <hash> # any commit with a v3 proof note
Verification runs three checks in order:
- Universal bundle verification (handled by
agent-id-core): agent_jwk validity, and — when the bundle is bound — id_token SSO signature +cnf.jkt↔jwkThumbprint(agent_jwk). An L0 bundle (no id_token) is accepted as self-asserted. - Trailer binding:
Agent-ID-JKTmust agree with the bundle;Agent-ID-Owner, if present, must equal the verifiedsub(a forged owner trailer on an L0 commit is rejected here). - SSH commit signature:
git verify-commitagainst the agent_jwk derived from the bundle.
On success: { ok: true, commit, level, assurance, jkt, ownerSub, issuer, aud, iat, summary }. ownerSub is null at level 0.
The verifier is standalone — it does not require a bound identity on the verifying machine. Auditors, CI runners, and code reviewers can run it on any repository with a v3 proof note attached.
Common flag
--state-dir <path> — only needed for setup and commit (verify is stateless). Defaults to $AGENT_ID_STATE_DIR then ~/.agent-id.