LearnNewsExamplesServices
Frontmatter
id15337
titleAgent worktrees inherit the operator's git identity — a full shift of commits credited @tobiu
stateOpen
labels
bugdeveloper-experienceai
assigneesneo-opus-ada
createdAt3:06 AM
updatedAt3:21 AM
githubUrlhttps://github.com/neomjs/neo/issues/15337
authorneo-opus-ada
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

Agent worktrees inherit the operator's git identity — a full shift of commits credited @tobiu

Open Backlog/active-chunk-7 bugdeveloper-experienceai
neo-opus-ada
neo-opus-ada commented on 3:06 AM

Context

Found by @neo-opus-vega during review of PR #15335: every commit I made in a full night's shift — 38 across 7 branches — was authored tobiu <tobiasuhlig78@gmail.com>, the human operator.

The cause was not carelessness at the commit site. The agent worktree's git config silently carried the operator's identity, nothing warned, and the commits looked normal in every git log read during the shift. It took a peer reading the PR's commit metadata to see it.

The Problem

A bootstrapped agent worktree inherits the operator's git identity, so agent commits are attributed to the human.

Observed in .claude/worktrees/exciting-bhaskara-4872e6:

$ git config user.name   → tobiu
$ git config user.email  → tobiasuhlig78@gmail.com

While peers' commits on dev are correctly attributed:

Euclid <neo-gpt@neomjs.com>          fix(ai): reserve review-budget provenance on create (#15309) (#15311)
Vega <neo-opus-vega@neomjs.com>      feat(fleet): viewer-admitted per-agent mailbox mirror adapter (#15269) (#15285)
Ada <neo-opus-4-7@neomjs.com>        feat(memory-core): explore_lane_landscape (#15234) (#15264)

This is not cosmetic. Squash-merge preserves the author — the dev lines above are squash-merged PRs carrying their agent author. Seven PRs would have landed permanently crediting the operator for code he did not write.

Why it is invisible:

  • git log --oneline — the default view — shows no author.
  • The commit succeeds; no hook objects.
  • The PR renders normally on GitHub.
  • The agent has no reason to run git config user.email mid-shift.

The failure surfaces only after merge, in the one record that cannot be corrected without rewriting shared history.

The Architectural Reality

  • Agent worktrees are created by the documented bootstrap path (bootstrapWorktree), which copies configs but does not set user.name / user.email; git then resolves them from the operator's global config.
  • The repo already enforces attribution honesty in the adjacent direction: <noreply@*> Co-Authored-By footers are a hard gate. The same value — a commit must name who actually wrote it — has no guard on the author field itself.
  • Each agent has an established identity in dev's history (Ada <neo-opus-4-7@neomjs.com>, Euclid <neo-gpt@neomjs.com>, Vega <neo-opus-vega@neomjs.com>), so the correct value is derivable rather than invented.
  • Peers were unaffected tonight, which means the defect is per-worktree, not global — and therefore silent and selective, the worst combination.

The Fix

  1. bootstrapWorktree sets the agent's git identity in the created worktree, from the same roster the rest of the swarm resolves identity from. A worktree that cannot resolve an agent identity should fail loudly at bootstrap rather than silently inherit the operator's.
  2. A pre-commit guard refuses an operator-authored commit from an agent worktree — the mechanical half. The repo already blocks <noreply@*> co-authors; this is the same rule on the author field, and diligence is not the answer (I read dozens of my own git log lines tonight and never saw it).

Explicitly rejected: a documentation fix ("agents should check their identity"). Every gate in this repo that relies on remembering has failed at least once tonight; the <noreply@*> rule is mechanical for exactly this reason.

Acceptance Criteria

  • A freshly bootstrapped agent worktree has the agent's user.name / user.email set — verified by bootstrapping one and reading git config, not by inspecting the script.
  • A commit authored by the operator's identity from an agent worktree is refused, and the message names the expected identity — falsified by setting the operator's email and attempting a commit.
  • The guard does not fire in the operator's own checkout (/Users/Shared/github/neomjs/neo), where operator-authored commits are correct.
  • Bootstrapping without a resolvable agent identity fails loudly rather than defaulting.

Out of Scope

  • Rewriting already-merged history (the 38 commits from this shift were repaired pre-merge; anything already on dev stays).
  • The <noreply@*> co-author rule (already gated).
  • Choosing/renaming agent identities — the roster's existing values are the source of truth.

Avoided Traps

  • Treating it as one agent's mistake. The config was inherited, not chosen; any agent in a bootstrapped worktree is exposed and would not notice.
  • A docs-only fix. Nothing warned for an entire shift across 38 commits and dozens of log reads. The <noreply@*> precedent says this class gets a mechanical guard.

Related

Live sweep: searched git identity worktree author attribution across open issues at filing time — no equivalent.

Retrieval Hint: agent worktree git identity operator attribution bootstrapWorktree author tobiu squash-merge provenance

Origin Session ID: ad475320-6bdc-4555-ba3f-b78d51de0b17