Skip to main content

Git Agent Identity Policy — MC #105779

Agent Git Identity Policy

MC #105779. Author: Kelsey Hightower (FlowForge), maintainer of ~/.claude/hooks/git-author-guard.sh (MC #101291).

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

  1. NEVER git config --global for a persona identity, and NEVER a plain (--local) git config in a repo with sibling worktrees either — use git 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.
  2. 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.
  3. 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 local user.email/user.name) rather than requesting override — this rewrites the author on the existing commit instead of bypassing the check.
  4. Always run git push from 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 $CWD at all, the guard fails closed rather than guessing.
  5. Concurrent worktree clobbering (2026-07-15 late, MC #105778/#105780 incident): git worktrees of the same repo SHARE .git/config by default. A plain git config user.email run in one agent's worktree is --local scope 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; commit e8b369ac went out under the wrong persona email; caught and fixed with git commit --amend --reset-author + git push --force-with-lease before review. This is why step 1 above uses --worktree, not plain git config--worktree scope 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-lease immediately, 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). As of MC #105996, the guard no longer invents a broad ancestry fallback when fetch cannot resolve the exact push destination. It first tries to fetch the exact ref into refs/remotes/<remote>/<branch> and, if needed, uses an exact ls-remote tip only when that commit object exists locally. If the exact remote..local range still cannot be computed, it fails open with a loud WARN and audit entry instead of producing a random RANGE_SHA that blocks legitimate pushes. Treat that WARN as an auth/connectivity issue to fix before the next push.

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 e8b369ac wrong-author, fixed same session