Give Claude its own forgejo identity for issues, PRs and commit authorship #108

Open
opened 2026-09-17 14:31:21 +01:00 by liamjd · 0 comments
Owner

Low priority — tooling, not gameplay. Like #106, parked so the findings survive; nothing here blocks game work.

Claude's issues, PRs and commits all currently appear under liamjd. Issue #106 and PR #107 were opened by Claude but are indistinguishable from ones filed by hand.

Three identities, not one

The conflation is the whole problem — these come from three different places and are fixed separately:

# Identity Source today What it affects
1 Commit author/committer user.name / user.email in the global gitconfig; no local override in this repo git blame, the name on each commit
2 Push actor the wincred credential for git.liamjd.net forgejo's "X pushed to branch" events
3 API actor fj's stored token who opened the issue or PR

#3 is the real complaint — it attributes an action to a person who did not take it. #1 is softer, since commits already carry a Co-Authored-By: Claude Opus 5 trailer.

Decided

Do #3 and #1. Skip #2.

Making pushes appear as the bot needs a second credential for the same host, which means a username-qualified remote (https://claude-bot@git.liamjd.net/...) as an extra remote, because wincred keys on <user>@<host>. The credential section of CLAUDE.md exists because that area has already caused trouble twice, and the payoff is one line in an activity feed. Not worth it.

For #1, set only GIT_AUTHOR_* and leave the committer alone. Git then records author = claude-bot, committer = Liam, which is exactly what happened in git's own vocabulary, and keeps git blame honest without pretending the bot did the directing.

Steps

1. Forgejo, as admin (cannot be done from Claude Code — needs the admin UI, or an admin-scoped token):

  • Create user claude-bot at /admin/users/new.
  • An email can belong to only one forgejo account, so it cannot reuse liamjdavison@gmail.com. liamjdavison+claude@gmail.com works: forgejo treats it as distinct and it still reaches the same inbox. This matters for #1 too — forgejo links a commit to an account by matching the author email, so the bot's git email must be the address on its account or the commits will show as an unlinked plain name.
  • Check whether the instance requires email confirmation; if so, either set the account active directly as admin or the login will stall.
  • Add claude-bot as a collaborator with Write on this repo (Settings → Collaborators). Without write access fj pr create fails.
  • Generate an access token as that user, with repository and issue write scopes. Forgejo's scopes are granular and fj fails obscurely when one is missing, so confirm against the token screen on this forgejo version rather than assuming the names.

2. Claude Code side:

fj stores one token per host and fj auth has no per-host account switching — but FJ_TOKEN overrides the stored config, as CLAUDE.md already records. So an env block applies the bot identity to every command Claude runs while leaving the user's own terminal fj untouched:

// .claude/settings.local.json
{
  "env": {
    "FJ_TOKEN": "<claude-bot's token>",
    "GIT_AUTHOR_NAME": "claude-bot",
    "GIT_AUTHOR_EMAIL": "liamjdavison+claude@gmail.com"
  }
}

Trap: .claude/ does not exist in this repo and is not in .gitignore. That file holds a plaintext token, so the ignore entry has to be added in the same breath as the file, not afterwards.

3. Docs: CLAUDE.md's "Credentials come from stored config" line describes a single account and needs to describe two, including which token is which. Note the existing warning about keeping fj's token separate from git's push token still applies, and now there are three tokens in play.

Caveats

  • The ! prefix runs commands inside the Claude Code session, so anything typed that way inherits the bot env and would be committed as claude-bot.
  • This is per-machine: the desktop needs the same settings.local.json, and it cannot be shared through git because of the token.
  • Closes #N trailers work the same whoever opens the PR.
  • Nothing here changes who can merge; that stays a human action.

AC

  • claude-bot exists, is a Write collaborator, and its token is in .claude/settings.local.json
  • .claude/settings.local.json is gitignored, verified by git status showing nothing after it is written
  • An issue filed by Claude shows claude-bot as the author
  • A commit made by Claude shows author claude-bot, committer Liam
  • The commit is linked to the bot account in forgejo's UI, not shown as an unlinked name — proves the email matches
  • CLAUDE.md describes both accounts and which token is used where
**Low priority — tooling, not gameplay.** Like #106, parked so the findings survive; nothing here blocks game work. Claude's issues, PRs and commits all currently appear under `liamjd`. Issue #106 and PR #107 were opened by Claude but are indistinguishable from ones filed by hand. ## Three identities, not one The conflation is the whole problem — these come from three different places and are fixed separately: | # | Identity | Source today | What it affects | |---|---|---|---| | 1 | Commit author/committer | `user.name` / `user.email` in the **global** gitconfig; no local override in this repo | `git blame`, the name on each commit | | 2 | Push actor | the wincred credential for `git.liamjd.net` | forgejo's "X pushed to branch" events | | 3 | API actor | `fj`'s stored token | **who opened the issue or PR** | **#3 is the real complaint** — it attributes an *action* to a person who did not take it. #1 is softer, since commits already carry a `Co-Authored-By: Claude Opus 5` trailer. ## Decided **Do #3 and #1. Skip #2.** Making pushes appear as the bot needs a second credential for the same host, which means a username-qualified remote (`https://claude-bot@git.liamjd.net/...`) as an extra remote, because wincred keys on `<user>@<host>`. The credential section of CLAUDE.md exists because that area has already caused trouble twice, and the payoff is one line in an activity feed. Not worth it. For #1, set **only** `GIT_AUTHOR_*` and leave the committer alone. Git then records **author = claude-bot, committer = Liam**, which is exactly what happened in git's own vocabulary, and keeps `git blame` honest without pretending the bot did the directing. ## Steps **1. Forgejo, as admin** (cannot be done from Claude Code — needs the admin UI, or an admin-scoped token): - Create user `claude-bot` at `/admin/users/new`. - **An email can belong to only one forgejo account**, so it cannot reuse `liamjdavison@gmail.com`. `liamjdavison+claude@gmail.com` works: forgejo treats it as distinct and it still reaches the same inbox. This matters for #1 too — forgejo links a commit to an account by matching the author email, so the bot's git email must be the address on its account or the commits will show as an unlinked plain name. - Check whether the instance requires email confirmation; if so, either set the account active directly as admin or the login will stall. - Add `claude-bot` as a **collaborator with Write** on this repo (Settings → Collaborators). Without write access `fj pr create` fails. - Generate an access token **as that user**, with repository and issue write scopes. Forgejo's scopes are granular and `fj` fails obscurely when one is missing, so confirm against the token screen on this forgejo version rather than assuming the names. **2. Claude Code side:** `fj` stores one token per host and `fj auth` has no per-host account switching — but `FJ_TOKEN` overrides the stored config, as CLAUDE.md already records. So an `env` block applies the bot identity to every command Claude runs while leaving the user's own terminal `fj` untouched: ```jsonc // .claude/settings.local.json { "env": { "FJ_TOKEN": "<claude-bot's token>", "GIT_AUTHOR_NAME": "claude-bot", "GIT_AUTHOR_EMAIL": "liamjdavison+claude@gmail.com" } } ``` **Trap: `.claude/` does not exist in this repo and is not in `.gitignore`.** That file holds a plaintext token, so the ignore entry has to be added in the same breath as the file, not afterwards. **3. Docs:** CLAUDE.md's "Credentials come from stored config" line describes a single account and needs to describe two, including which token is which. Note the existing warning about keeping `fj`'s token separate from git's push token still applies, and now there are three tokens in play. ## Caveats - The `!` prefix runs commands inside the Claude Code session, so anything typed that way inherits the bot env and would be committed as `claude-bot`. - This is per-machine: the desktop needs the same `settings.local.json`, and it cannot be shared through git because of the token. - `Closes #N` trailers work the same whoever opens the PR. - Nothing here changes who can *merge*; that stays a human action. ## AC - [ ] `claude-bot` exists, is a Write collaborator, and its token is in `.claude/settings.local.json` - [ ] `.claude/settings.local.json` is gitignored, verified by `git status` showing nothing after it is written - [ ] An issue filed by Claude shows `claude-bot` as the author - [ ] A commit made by Claude shows author `claude-bot`, committer `Liam` - [ ] The commit is linked to the bot account in forgejo's UI, not shown as an unlinked name — proves the email matches - [ ] CLAUDE.md describes both accounts and which token is used where
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
liamjd/UntitledColonyBuilder#108
No description provided.