Just like Apple's face ID but for your git commits. Agents can write the code, a human signs it.
AI Agents got super cheap recently. Writing code has never been this easy. People are trusting claude more than themselves, blind approving thousands of lines of codes.
Nobody priced in what that costs. Around 42% of committed code is already AI assisted and most of GitHub now reads like it was generated, because it was. The green squares on your profile used to be a rough signal that a person showed up and did the work. Now they measure how much compute somebody rented overnight, and recruiters still read them like a CV.
Maintainers felt it first and they have stopped being polite about it. Curl killed its bug bounty in January and shut off vulnerability processing entirely for July. Godot auto-bans vibe coded pull requests and said plainly that AI cannot take responsibility for its code. Codeberg's members voted 358 to 144 to ban AI heavy projects. And many more examples.
Then there is the part that costs actual money. People are blind approving. Cursor running Opus 4.6 deleted a company's production database and its backups in nine seconds. On the supply chain side, 341 malicious skills were found on ClawHub, 11.3% of the entire library, and the single most downloaded skill was a credential stealer. In crypto, its even worse, oracle issues, agent hallucinating and using wrong asset values. It is costing not just companies but innocent users.
We are not against AI. Agents should write code, they are good at it, and this is not an attempt to put that back in the box. What we want back is the human in the loop, or, if we are honest about what actually changes behaviour, the human on the hook. Somebody has to be blameable.
Commitment Issues Protocol sits at the moment the signature happens. When a commit needs signing, whether that is you typing git commit, your editor, or an agent running unattended at three in the morning, the request stops. A QR appears, you scan it and show your face, and the signature is released. No face, no signature. The proof is tied to that exact commit so it cannot be lifted onto a different one, and it dies after sixty seconds so nobody can mint a pile of approvals in advance and spend them later.
It is deliberately not all or nothing, because a selfie on every commit is obnoxious and nobody would run it for a week. The organisation decides where the bar sits. Auth code, payment paths and contracts need a live human. Docs, tests and typo fixes do not. A company can require it from contractors but not the core team, or only on release branches, or only past a certain diff size, or only for the repos that touch money. It becomes a dial an engineering org sets centrally and enforces in CI, instead of a personal habit that quietly dies the first week somebody is in a hurry.
The timing is not an accident. Article 50 of the EU AI Act applies from 2 August 2026, with penalties reaching €15,000,000 or 3% of worldwide turnover. Buried inside it is something more interesting than a fine: the disclosure requirement falls away where the content went through human review and a named person holds editorial responsibility for it. European law has just written "a human checked this and somebody is accountable" into statute as the thing that earns you an exemption, and shipped no mechanism whatsoever for proving it.
Everything else is moving the same direction. Okta is building a human principal concept so a service can tell a real person stands behind an agent's actions. NIST opened an AI agent standards initiative in February. There are startups selling liability insurance for agents, and 92% of surveyed large enterprise CISOs say they cannot see their AI identities at all. Agents will keep getting more capable and more autonomous, and the open question is no longer who they are. It is who answers for them.
This is a weekend old and it is a demo. Today it signs commits. The same primitive belongs in front of any action an agent can take on your behalf where being wrong is expensive, and that is where we are taking it.
Three parts: an SSH agent proxy that sits in front of your real agent, a signing service that holds the key and withholds signatures pending approval, and the World ID integration that decides whether a human is actually there.
The proxy is the core. Rather than a git hook or a wrapper command, it implements the SSH agent protocol directly over a Unix socket at ~/.commitment-issues/agent.sock, chmod 600, forwarding everything to your upstream SSH_AUTH_SOCK when one exists. Because git delegates commit signing to whatever agent it is pointed at, this works for every client with zero per-tool integration: terminal git, VS Code, Cursor, or a headless coding agent all go through the same socket. It buffers the byte stream, extracts complete messages and inspects each one. On SSH_AGENTC_SIGN_REQUEST it computes the key fingerprint and, if it matches ours, handles the request itself instead of forwarding. On SSH_AGENT_IDENTITIES_ANSWER coming back from upstream it splices our key into the response, so it shows up in ssh-add -l like any other key and git needs no special configuration to find it. With no upstream agent present it runs standalone and answers identity listings itself.
Configuration goes through the environment rather than mutating anyone's global git config. commitment-issues env prints exports for SSH_AUTH_SOCK plus the numbered GIT_CONFIG_KEY/VALUE pairs that set gpg.format=ssh and user.signingkey, scoped to processes that inherit it. It also sets GIT_COMMITTER_NAME to "Reviewed By Human", leaving the author identity untouched while carrying the claim into git log where a reviewer actually sees it.
The signing service is a small Express 5 API. It loads a PEM PKCS8 Ed25519 key and derives the OpenSSH wire format public key blob by hand, length prefixed string encoding and all, then hashes it into the SHA256: fingerprint in OpenSSH display format. POST /sign/:requestId validates the fingerprint and computes the signature with node:crypto, then does the important bit, which is not returning it. The signature goes into a pending map keyed by request ID and the HTTP response stays open until approval resolves the promise.
On the World side we use IDKit 4.2.2 with Selfie Check, which means the selfieCheckLegacy preset and allow_legacy_proofs: true because Selfie Check is still World ID 3.0 only. The app runs in external mode with the cloud engine and the git-sign action registered in production and staging. The commit SHA goes in as the World ID signal, and the backend checks four things before releasing anything: that the proof verifies against POST /api/v4/verify/{rp_id}, that the nonce inside it is the one we minted within the last sixty seconds, that user_presence_completed is true, and that signal_hash equals hashSignal(commitSha). All four passed on the first real run against a real face with no Orb required. Separately an agent is registered through AgentKit 0.2.0 on World Chain, and AgentBook.lookupHuman() resolves it to a stable anonymous humanId.
Three things were genuinely hacky. The World verify endpoint validates the proof but does not check that the nonce inside it is the one you minted, so we compare it ourselves. Miss that and the freshness guarantee silently evaporates while every response still looks green. @worldcoin/idkit-core cannot load in Node at all, because it fetches its WASM over a file:// URL that Node refuses and exports no initSync to work around it, so we patch globalThis.fetch for about ten lines to run a browser SDK inside a CLI. And the demo trick we like most: commitment-issues session <command> launches your coding agent inside a detached tmux session with the proxy environment applied, and when that agent tries to commit, the QR is pushed up as a tmux display-popup overlaid on the agent's own session. The agent gets interrupted mid run and has to wait for a face.
Where this goes next, technically. The policy layer is a .commitment.yml parsed by a GitHub App that replays attestations as a required status check, so path globs, approver counts and freshness windows are enforced by the org rather than trusted from the developer's machine. Signing more than one commit per human needs a fix for max_verifications: 1, and the clean answer is session proofs via IDKit.createSession() and proveSession(), where session_id gives stable identity across commits while session_nullifier handles per proof replay. That is also what makes per human budgets possible: because AgentKit counts usage per human rather than per key, a daily approval limit follows the person across every agent and machine they run, which is the real defence against rubber stamping. Binding the signal to a hash of the diff rather than just the commit SHA means the human is attesting to specific content. The remaining hole is a compromised machine that displays one diff and signs another, which needs the diff summary rendered on the phone inside the approval itself, and that is the piece we would build first.

