Git Agent Identity Policy — MC #105779
Agent Git Identity Policy
The rule
Any builder running inside a Claude Code session that will git commit on an
ALAI repo MUST set a worktree-scoped git identity matching its company
persona BEFORE the first commit:
git -C <worktree-dir> config extensions.worktreeConfig true # once per repo, idempotent
git -C <worktree-dir> config --worktree user.email "<slug>@<company>.alai.no"
git -C <worktree-dir> config --worktree user.name "<Persona Name> (<Company>)"
<worktree-dir> is the actual working-tree directory checked out for this
task (the one the push will run from) — not the main repo clone, not ~.
Use --worktree, NOT a plain git config (which is --local and is
shared across all worktrees of the same repo — see "Concurrent worktree
clobbering" below). extensions.worktreeConfig true only needs to be set
once per repo; re-running it is harmless.
This satisfies the git-author-guard.sh ALLOWLIST so the push proceeds
without triggering the CEO override path.
Why
The global git identity on this machine is user.email = [email protected]
(CEO's real address, used for the CEO's own manual commits). If a builder
session commits without setting a local override, every commit is stamped
[email protected] — a BLOCKLIST match — and git-author-guard.sh blocks the
push on every single CC-session push, not just genuine CEO-direct-commit
violations (HC#1, MC #101291 genesis: Bilko UAT 2026-05-16, 5 direct john@
commits to main). Global override was never enacted (never --global) because
it would corrupt the CEO's own manual-commit provenance system-wide.
Persona -> email table (must match ALLOWLIST_PATTERNS in the guard)
| Company | Domain | Example personas | Worktree-local email pattern |
|---|---|---|---|
| CodeCraft | backend/architecture/db | Petter Graff, Martin Kleppmann, Hadi Hariri, Lee Robinson, Bruce Momjian | *@codecraft.alai.no |
| Vizu | frontend/design systems | Brad Frost, Lea Verou | *@vizu.alai.no |
| Securion | security | Parisa Tabriz, sentinel-architect | *@securion.alai.no |
| FlowForge | devops/infra | Kelsey Hightower | *@flowforge.alai.no |
| Proveo | QA/testing | Angie Jones, James Bach, Lisa Crispin, Dorota Huizinga | *@proveo.alai.no |
| AgentForge | AI/ML/RAG | Chip Huyen, Georgi Gerganov | *@agentforge.alai.no |
| Finverge | fintech/payments | Markos Zachariadis | *@finverge.alai.no |
| Skybound | mobile/BA | Paul Hudson, sentinel-ba | *@skybound.alai.no |
| Lexicon | linguistic QA | Dževad Jahić | *@lexicon.alai.no |
| Skillforge | docs/BookStack | — | *@skillforge.alai.no |
| Resolver | — | — | *@resolver.alai.no |
Use a short task-scoped local part when useful for audit trail, e.g.
[email protected] — the guard matches on domain suffix
only (@codecraft\.alai\.no$), so the local part is free-form.
Full up-to-date routing table (source of truth, not this file):
~/system/agents/specialist-mapping.json.
Hard rules
- NEVER
git config --globalfor a persona identity, and NEVER a plain (--local)git configin a repo with sibling worktrees either — usegit config --worktree(see "The rule" above and item 5 below). A global persona email would corrupt the CEO's own commit provenance and defeat the guard for every repo on the machine; a plain local one clobbers sibling worktrees of the same repo. - NEVER request/use the CEO override token (
/tmp/git-author-override-<sha>) as a substitute for setting the identity correctly. The override exists for genuine CEO emergency pushes (MC #101291 design), not routine builder workflow friction. Requesting it to skip identity setup is a ZAKON #2.5-class shortcut and will be treated as such. - If a commit was already made under the wrong (blocklisted) identity before
this was caught: fix with
git commit --amend --reset-author(after setting the correct localuser.email/user.name) rather than requesting override — this rewrites the author on the existing commit instead of bypassing the check. - Always run
git pushfrom the worktree directory being pushed, not from the main repo checkout with a different branch checked out elsewhere. The guard resolves the commit range from the local ref of the pushed branch (MC #105779 fix), but if that local ref isn't reachable from the invoking$CWDat all, the guard fails closed rather than guessing. - Concurrent worktree clobbering (2026-07-15 late, MC #105778/#105780
incident):
git worktrees of the same repo SHARE.git/configby default. A plaingit config user.emailrun in one agent's worktree is--localscope and silently overwrites the identity another agent set in a sibling worktree of the same repo, if that agent set it the same (non-worktree-scoped) way. Live incident: codecraft-105780 clobbered codecraft-105778's identity mid-session; commite8b369acwent out under the wrong persona email; caught and fixed withgit commit --amend --reset-author+git push --force-with-leasebefore review. This is why step 1 above uses--worktree, not plaingit config—--worktreescope is stored in.git/worktrees/<name>/config.worktree, which is per-worktree and immune to this clobber. Symptom to watch for: a commit shows up with a different agent's persona email than the one you set — that's concurrent clobber, not a typo; remediate with--reset-author+--force-with-leaseimmediately, before anyone reviews the wrong-author commit.
When the guard's fetch fails with an auth error
If push-time verification needs to fetch the target branch and fails with
could not read Username/authentication failed/403 (no PAT configured
for the git remote in this shell), that is an auth gap in this session,
not a signal to abandon identity setup or reach for the override token. Fix:
configure the Azure DevOps PAT as an http.extraHeader on the remote —
git -C <worktree-dir> config http.https://dev.azure.com/.extraHeader \
"Authorization: Basic $(printf 'PAT:%s' "$PAT" | base64)"
— pulling $PAT from Vaultwarden item 776a5d5e-7222-4843-9c76-212122f65e62
("Azure DevOps PAT - alai-holding"): bw get item 776a5d5e --session $(cat /tmp/bw-session).
The guard will fall back to a broader (but still correctly-scoped, post
MC #105779 fix) local scan if the fetch can't be fixed in time; it does not
fail open on an auth error.
Reference
- Guard implementation:
~/.claude/hooks/git-author-guard.sh - Guard genesis: MC #101291 (Bilko UAT 2026-05-16 incident)
- This policy: MC #105779 (2026-07-15), triggered by false-flag on commit 78108536 during MC #105776 and the identity-friction pattern it exposed
- Concurrent worktree clobbering amendment: MC #105778/#105780 incident
(2026-07-15 late), commit
e8b369acwrong-author, fixed same session