Development record
Each person's commit identity lives on their own machine, not in the repository
Context
itd-131 made
the commit identity gate check git's effective author and committer "against
the identity the repo pins" in a committed .abcd/config/identity.json, and
made adopting that pin a step of abcd ahoy install. The pin names one
person. In a repository that takes outside contributions that is wrong for
everyone else: setup reports any other contributor's identity as a required
git_identity.mismatch gap and offers to make them commit as the pinned
person, and abcd's own committed .githooks/pre-commit refuses their commits
with a fix line telling them to set the maintainer's name and email
(iss-2610240830397793).
That contradicts the attribution rule that every commit is honestly authored
by the human who made it.
The pin did two useful things, and both had to survive: it caught a commit
made under a bot's or an AI tool's identity, and it caught a mistyped email of
one's own. The same committed file also carried the repository's default
production_mode (itd-178), which is the repository's setting, not a
person's. And an unattended routine on a fresh machine (a cloud container)
has no person at a terminal to establish an identity for.
The product thinker accepted the reversal on 2026-10-24, in the Decisions of itd-2610240918547728, after considering and declining the alternative of dropping the pin and checking only that the author is a human.
Decision
We will keep each person's commit identity on their own machine, and nothing in a repository will name who may commit to it.
- The record is
{"name": "…", "email": "…"}under the user-level home, read most specific first:~/.abcd.noindex/identity/<root-sha>.jsonfor one repository, keyed on the full object name of its root commit (as the worktree and transcript stores are keyed), else~/.abcd.noindex/identity.json, the machine-wide default. Per repository with a machine-wide default, so a person with a work and a personal identity keeps each where it belongs while the common case is one file. - It is read under the guards every home-scoped declaration takes
(
fsutil.ReadHomeDeclaration, the rules loader's): a regular file this account owns that no other account can write, capped in size, refused behind a symlinked~/.abcd.noindex. A record that is there and fails a guard, or does not parse, fails the check closed; it never reads as no record. - The commit check (
identity.Check,abcd ahoy --identity, and the self-contained shell gate in abcd's own.githooks/pre-commit, which reads the same two files in the same order from$HOME, with no binary) holds the author and committer to that record, and refuses a machine identity, from the one listinternal/core/identity/tool-identities.txt, in either role whether or not a record exists. With no record, a human identity commits: an unattended run on a fresh machine commits as the human identity its launcher supplied, or is refused as a machine. - Setup proposes a person's usual git identity and records it only on their yes, as its own question, only at a terminal; off a terminal, or under the approve-everything flag, it records nothing and says so.
- A repository that still stores the pin is migrated on its owner's machine
(the person whose git identity is the stored one), on a yes at a terminal:
the pin becomes that person's record for the repository, its
production_modemoves to.abcd/config/provenance.json, andidentity.jsonleaves the working tree. On anyone else's machine it is not copied, not removed and not named. - The repository's default production mode stays committed, in
.abcd/config/provenance.json; while a repository has not migrated, the legacy pin'sproduction_modemember is still read when that file is absent.
This supersedes, from itd-131, the decision that the gate checks commits
against an identity the repository pins; the scope item that adopting the gate
writes identity.json behind the config-change approval; and the first link
of the disk-only proposal chain, "pinned → global", which becomes "the
person's own record → global". Its other decisions stand: detection here and
establishment by whatever launches a routine (iss-2608210932052003), a
disk-only proposal chain with no network lookup (adr-38), and
propose-and-confirm at a terminal before repo-local user.* is written.
Alternatives Considered
- Keep the committed pin (itd-131 as shipped). Rejected: it names one person to every contributor and tells them to commit as that person.
- Drop the pin and check only that the author is a human and matches the committer. Considered and declined by the product thinker: it keeps the machine refusal but loses the check that catches a mistyped email of one's own.
- A machine-wide record only. Rejected: a person who commits to work repositories under a work identity and to their own under a personal one would be refused in one set or the other.
- A per-repository record only. Rejected as the only form: every repository would need its own question, while most people commit under one identity everywhere.
- Chosen: per repository, with a machine-wide default, kept on the person's own machine.
Consequences
- No contributor is ever shown or offered another person's identity, and a repository that takes outside contributions needs no per-person setup.
- The commit check is now a person's own commitment: until they record an identity, only a machine identity is refused. A person who never runs setup at a terminal is checked for machines alone.
- An unattended run on a fresh machine needs no record: its launcher supplies
the human identity, and a machine identity is still refused. A git identity
git invents from the account and host name, when none is configured, is not
distinguishable from a supplied one inside the hook; the Go check reports it
as
git_identity.unset. - The shell gate in abcd's own pre-commit hook now reads the person's home directory, and is at least as strict as the Go reader (it refuses a group-writable folder the Go reader admits when the group is the owner's own).
.abcd/config/provenance.jsonis a new committed file, andprovenance.DeclaredModeis the one reader of the repository's default production mode;identity.DeclaredProductionModeis gone.- abcd's own repository still stores the maintainer's pin until the maintainer's next setup moves it; nothing reads it to check commits in the meantime.
Frontmatter
| id | adr-2610241022541063 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-10-24 |
.abcd/development/decisions/adrs/2610241022541063-each-person-s-commit-identity-lives-on.md
open on GitHub ↗ · commit history ↗
References4
- adr-38Implicit checks are disk-only — the network answers only an explicit askrelated
- itd-131The managed-repo identity gate: the human is the author of record on every commit, before the first onerelated
- itd-178Every record written through a command carries its origin and its production mode — stamped by the command, never typed by handrelated
- itd-2610240918547728Every contributor commits as themselvesrelated
mentions3
- iss-2608210932052003abcd launches autonomous bug hunts (and other routines) for the user, opt-in — beyond handing the user a prompt to paste into a cloud routine. Today the bughunt is a Desktop prompt the user wires into an external cloud routine by hand; the direction is abcd owning the launch: the user opts in, and abcd assembles and starts the routine, applying the run contract it already governs (the human git identity per itd-131, the gates, the merge decision, the state issue). This is the realisation of the run seam — adr-27 (run is a pluggable seam, not a bespoke engine), itd-29 (the run operator surface: start/status/pause/resume/ship), itd-107 (routines assemble from one versioned template; the bughunt and a delivery-pipeline archetype), and the reframed iss-381 (the deterministic delivery pipeline survives as an itd-107 archetype, not an engine). When abcd launches the routine it sets the human git identity at launch, which is the clean mechanism the itd-131 identity gate points at for routine commits (vs today's prompt/env workaround). Big, cross-record capability — needs decomposition and likely ideate before it is filable; recorded so the direction is durable.
- iss-2610240830397793the committed identity pin names one person, so it misleads every other contributor: .abcd/config/identity.json pins the product thinker's identity, ahoy install reports any other contributor's identity as a required git_identity.mismatch gap and proposes they commit as the pinned person, and the committed .githooks/pre-commit refuses their commits with 'fix: git config user.name "<login>" && git config user.email ...', telling them to commit under the maintainer's name. That contradicts the attribution rule that every commit is honestly authored by the human who made it, in a repository that takes outside contributions.
- spc-2610241007568207every-person-who-commits-to-a-repository