Skip to content

Change your commit name #5

Description

@ableinc

When you're working on a task, use a different commit user name and email, so that I can differentiate between tasks you're doing and tasks created by the actual human repo author.

Activity

  1. ableinc commented on Aug 22, 2026

    @ableinc
    OwnerAuthor

    Plan

    Give agent-authored commits their own git identity (config-driven), so they're visibly distinct from the human author's

    Context

    Issue #5 asks that commits the loop produces carry a different git user name/email than the repo owner's, so a human can tell agent work apart from their own at a glance.

    Two gaps today:

    1. git.Manager already has AuthorName/AuthorEmail fields (internal/git/workspace.go:29-32) with fallbacks coding-agent-loop / coding-agent-loop@localhost (author()/email(), lines 264-276), applied via -c user.name=… in CommitAll — but nothing ever sets them: cmd/agent.go:171 constructs the Manager without them, and there is no config key at all. The identity is therefore unconfigurable.
    2. More importantly, the harness is not the only committer. systemPrompt in internal/orchestrator/prompt.go:41 explicitly says "You MAY commit your work locally. If you do not, the harness commits it for you." — and CommitAll short-circuits when the tree is clean (workspace.go:247-249, comment: "agent committed its own work"). When Claude commits, the claude subprocess inherits the host environment and the clone's config, which resolve to the host's global gitconfig — i.e. the human repo author. That is exactly the confusion the issue reports, and it's the path that fires most often, since capable models usually do commit their own work.

    So the fix is: make the identity configurable, and make it apply to every commit made under a harness worktree, not just the harness's own fallback commit.

    Approach

    1. New git config block — internal/config/config.go

    • Add type GitConfig struct { AuthorName string \json:"author_name"`; AuthorEmail string `json:"author_email"` }and aGit GitConfig `json:"git"`field onConfig`.
    • Populate in Default():
      • author_name: "coding-agent-loop[bot]"
      • author_email: "coding-agent-loop@users.noreply.github.com"
        The [bot] suffix is GitHub's convention for machine authors, and a bare @users.noreply.github.com address deliberately maps to no GitHub account, so the commit renders with the bot name and no human avatar/hovercard. (This supersedes the current @localhost fallback — see Decisions below.)
    • Extend Validate() with a cheap sanity check: reject a name or email containing <, >, or a newline, since those characters corrupt the commit header line git builds. Empty is legal and means "use the built-in default" (matching how author()/email() already behave).
    • No migration needed: Load overlays JSON onto Default(), so a deployed config.json without a git block simply gets the defaults. DisallowUnknownFields only rejects unknown keys, so adding a field is backward compatible.

    2. Apply the identity to the shared clone — internal/git/workspace.go

    • Add a small unexported applyIdentity(ctx, repoPath) that runs git config user.name … and git config user.email … (through the existing m.run helper, reusing m.author()/m.email()), and call it from EnsureRepo after the clone/fetch, on every pass — it's idempotent and costs two local git invocations per run.
    • This is the key mechanism: linked worktrees created by AddWorktree share $GIT_COMMON_DIR/config with the clone under ReposRoot, so a local user.name/user.email there overrides the host's global gitconfig for every commit in every worktree of that repo — Claude's included. These clones are harness-owned and never used by a human, so writing to their config is safe. Side benefit: a service user with no global gitconfig at all can now commit, where today Claude's own git commit would fail outright.
    • Leave the explicit -c user.name=… flags in CommitAll (workspace.go:253-257) as-is: independent of repo config, and defense in depth.
    • Add an exported IdentityEnv() []string returning GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, built from the same author()/email() fallbacks so the resolution logic stays in one place.

    3. Pass the identity into the Claude subprocess — internal/claude/runner.go + internal/orchestrator/loop.go

    • Add Env []string to claude.Options and, in Run, set cmd.Env = append(os.Environ(), opts.Env...) (currently cmd.Env is left nil, i.e. inherit; the explicit append preserves that behaviour and is the same pattern git.Manager.run already uses at workspace.go:93).
    • In loop.go:562, add Env: o.opts.Git.IdentityEnv() to the claude.Options literal. It applies to both phases; harmless on the read-only plan run.
    • Env vars outrank repo config in git's precedence order, so this holds even if Claude's cwd resolution or a stray config ends up somewhere unexpected — belt and braces with step 2, which additionally covers commits made outside the Claude process.

    4. Tell the agent not to fight it — internal/orchestrator/prompt.go

    Add one bullet to systemPrompt's "harness owns version control" list (near line 40): "Do NOT change git's user.name/user.email or pass --author/--reset-author; the harness has already set the commit identity for this worktree." Keeps a helpful model from "fixing" the unfamiliar author.

    5. Wiring and surfaces

    • cmd/agent.go:171 — set AuthorName: cfg.Git.AuthorName, AuthorEmail: cfg.Git.AuthorEmail on the gitpkg.Manager literal.
    • config.example.json — add the "git": { "author_name": …, "author_email": … } block. (The repo-root config.json that embedded.go compiles in is gitignored and generated by make config from this template, so the template is the only file to touch.)
    • README.md — add the block to the config JSON sample (~line 240), two rows to the field table (~line 300), and one sentence in the flow description at step 6 noting that both harness-made and agent-made commits carry this identity while the PR itself is still opened by the gh token's owner.

    Tests

    • internal/config/config_test.go — defaults are populated; a git block in JSON overlays correctly; a name/email containing < is rejected by Validate (mirroring the existing TestEmptyLabelIsRejected style).
    • internal/git/workspace_test.go — extend TestWorktreeLifecycle (which already sets AuthorName: "agent") to assert git log -1 --format=%an <%ae> after CommitAll. Add a new test for the important case: with t.Setenv("GIT_CONFIG_GLOBAL", <temp file naming "Human Author">), run EnsureRepo + AddWorktree, write a file, then commit without any -c flags (simulating Claude), and assert the commit is attributed to the agent identity, not the global one. Requires git ≥ 2.32 for GIT_CONFIG_GLOBAL; the file already skips when git is unavailable.
    • internal/claude/runner_test.go — reuse the stubCLI helper: a stub that echoes $GIT_AUTHOR_NAME into the result event (or a side file), asserting Options.Env reaches the child.
    • internal/orchestrator/prompt_test.go — assert the new system-prompt bullet is present, matching the existing prompt assertions.

    Decisions / risks for the reviewer

    • Default email change. The current hardcoded fallback is coding-agent-loop@localhost; I propose coding-agent-loop@users.noreply.github.com (and name coding-agent-loop[bot]) so GitHub renders it sensibly. Any commits already pushed keep their old identity — this only affects new ones. If you'd rather not touch the existing fallback, keep workspace.go's hardcoded values and set the new defaults only in config.Default(); the two would then disagree, which is why I'd rather align them.
    • Config placement. New top-level "git" block rather than folding into "workspace", since it mirrors internal/git.Manager. Easy to move if you prefer workspace.author_name.
    • Writing config into the shared clone. This mutates <repos_root>/<owner>/<name>/.git/config. Those clones are created and owned solely by the daemon, so no human config is at risk — but it is the one place this change writes outside a worktree, and worth a conscious ack.
    • Out of scope, adjacent: the PR and issue comments are still created by the gh token's account, so GitHub attribution of the PR is unchanged — only commit authorship moves. Likewise, if a host global config sets commit.gpgsign=true, Claude's own commits could fail signing under a service user; that's pre-existing behaviour and I'd leave it alone unless you want commit.gpgsign=false set alongside the identity.

    Reply with exactly implement to approve this plan and start the change. Reply with anything else and the plan will be revised to address it.

    coding-agent-loop run 38ef73c7-56fb-4e29-8436-075567754a33, model claude-opus-5, cost $1.3554

  2. ableinc commented on Aug 23, 2026

    @ableinc
    OwnerAuthor

    implement

  3. ableinc commented on Aug 23, 2026

    @ableinc
    OwnerAuthor

    The coding agent could not complete this issue (attempt 2).

    claude run failed: claude exited with error: exit status 1 (stderr: )
    

    It will try again after Sun, 23 Aug 2026 11:11:10 UTC (the wait doubles with each consecutive failure). Remove the agent-ready label to stop it retrying.

    coding-agent-loop run bf2f4698-998c-4cfb-8742-afd0c07b7219

  4. 25 remaining items

  5. ableinc commented on Aug 24, 2026

    @ableinc
    OwnerAuthor

    The coding agent could not complete this issue (attempt 8).

    claude run failed: claude exited with error: exit status 1 (stderr: )
    

    It will try again after Mon, 24 Aug 2026 18:47:11 UTC (the wait doubles with each consecutive failure). Remove the agent-ready label to stop it retrying.

    coding-agent-loop run 7bf2f54f-5f56-4c70-a7fc-1a7a26a864c2

  6. ableinc commented on Aug 24, 2026

    @ableinc
    OwnerAuthor

    The coding agent could not complete this issue (attempt 9).

    claude run failed: claude exited with error: exit status 1 (stderr: )
    

    It will try again after Tue, 25 Aug 2026 18:48:11 UTC (the wait doubles with each consecutive failure). Remove the agent-ready label to stop it retrying.

    coding-agent-loop run 724680db-201d-44b1-a1fd-19bdece60544

  7. ableinc commented on Aug 25, 2026

    @ableinc
    OwnerAuthor

    Opened a draft pull request for this issue: #9

    Tests failed (make test) — see the PR for output.

    Comment implement again if you want another attempt at this issue.

    coding-agent-loop run 80c2bb9b-398c-4870-98bc-cfc08a4528c3

  8. added a commit that references this issue on Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions