# Signed commits

> zev signs every new commit on your computer with the repository's Ed25519 key. Add the key to your account once and Zaryn shows those commits as Verified, with your name.

Source: https://zaryn.xyz/docs/en/signed-commits

A commit says who wrote it, but anyone can type any name into their zev config. A **signature** proves which key made the commit. zev signs every new commit on your computer, and Zaryn shows a commit as **Verified** only when the key that signed it is on the account it names.

```diagram
type: cards
title: What each label means
---
✓ | Verified | a good signature by a key on an account; the commit list names that account
✍ | Signed | a good signature by a key no account has added yet
· | No label | no signature, for example a commit made with commit.sign false
```

## How it works

```diagram
type: sequence
title: From zev commit to Verified
lanes: Your computer | Zaryn
alt: zev commit signs the commit hash with the repository's key and keeps the signature in .zev/signatures; zev push uploads the commit and then the signatures; Zaryn checks each signature against its commit and shows it as Verified when the key is on an account
---
note Your computer : zev commit: sign "zev commit <hash>" with .zev/identity | accent
Your computer -> Zaryn : zev push: the commit's objects, then its signatures
note Zaryn : check each signature against its commit hash; keep the first one | good
Zaryn --> Your computer : how many it kept, and how many are Verified on your account
```

- The signature covers the commit's hash, and the hash covers the files, the message, the author and the parent. Change one byte and the signature no longer fits.
- Each repository has its own key, in `.zev/identity`. `zev signing-key` prints it.
- zev keeps the signatures in `.zev/signatures` and sends them after the commits on the next push. A signature the server already has is not sent again.
- The server checks every signature before keeping it. A commit keeps its first signature: a later one can't replace it.

## Show your commits as Verified

Run this once in each repository you push from:

```bash
zev signing-key add --label laptop
```

zev sends the repository's public key to your account. From then on, every commit it signed shows as **✓ Verified** in the commit list and on the commit page, with your name. Commits signed before you added the key count too.

You can also add a key on the web: **Security → Commit signing keys**. Run `zev signing-key` in the repository and paste the key it prints.

```diagram
type: flow
title: Why Zaryn never links a key by itself
---
Pushing is not proof | a push token can leak; it says nothing about who owns a key | warn | 🔑
~ zev signing-key add
Only you link it | a key counts once its account adds it | good | ✓
~ first come
One account per key | even after removal, nobody else can claim it | accent | 🔒
```

## Merge only Verified commits

A repository's admins can require it: **⚙ Settings → Merge only Verified commits**. A pull request then merges only when every commit it brings is Verified. The pull request's checklist says how many aren't, and nobody can force the merge past it, not even an admin.

```diagram
type: flow
title: A pull request under the rule
---
Unsigned commits | the checklist: 2 commits aren't Verified; Merge is off | warn | ✍
~ zev sign-commits, zev push
Every commit Verified | the check turns green | good | ✓
~ Merge
Merged | the target branch only ever gets Verified commits | accent | 🔒
```

The rule also guards one branch against direct pushes, `main` unless you name another in the same settings. A push that would bring it a commit that isn't Verified is refused, and zev says how many and what to run. Other branches take anything, so you can push work in progress and open a pull request; its check covers those commits. zev hands signatures over before it moves a branch, so a signed push goes through in one step.

```bash
zev push-api origin main
# Push refused: 1 new commit(s) on main aren't Verified, and this repository takes only Verified commits there
zev sign-commits 1
zev push-api origin main     # Push complete
```

Scripts and agents can read and set it too: `GET` and `PUT /v1/repos/<owner>/<repo>/signing-rule` with `{"require_verified": true, "branch": "main"}`. The commit list (and the `zaryn_commits` tool of `zev mcp`) shows each commit's signature.

## Commands

```bash
zev signing-key                    # this repository's key, and whether new commits are signed
zev signing-key add [--label x]    # add it to your account: its commits show as Verified
zev signing-key ls                 # the signing keys on your account, with how many commits each signed
zev signing-key rm <id>            # remove one: its commits show as Signed, not Verified
zev verify <commit>                # check a commit's signature here (a short hash is enough)
zev sign-commits [N]               # sign the last N commits that have no signature (default 100)
zev config set commit.sign false   # stop signing new commits in this repository
```

## Questions

**I lost the computer.** Remove the key with `zev signing-key rm <id>` or on the Security page. Its commits stop showing as Verified, and nobody else can add that key to their account.

**I cloned on a new computer.** The new copy gets its own key the first time it signs. Run `zev signing-key add` there too.

**Commits from before signing existed.** `zev sign-commits` signs them with the repository's key. Push, and they show up.

**How is this different from `zev sign <cid>`?** `zev sign` signs any object with your identity, for proofs you hand to someone. Commit signing is automatic and shows on Zaryn.

See also [Advisories and lineage](/docs/en/advisories) for marking commits as compromised, and [Verified storage](/docs/en/verified-storage) for proof that Zaryn keeps what you pushed.
