TL;DR The setting that actually removes it is
attributionin yoursettings.json({"commit": "", "pr": ""}): it works at the CLI level, so it doesn't matter what the model decides to write. I also keep a rule in my globalCLAUDE.mdthat forbids it explicitly. That's not redundant paranoia: Claude Code's own default commit template includes that line as an example, and without an instruction overriding it, the model can end up writing it itself, bypassing the setting entirely. Two layers, not one.
Every commit Claude Code makes for you ships with an extra line by default: Co-Authored-By: Claude <noreply@anthropic.com>, sometimes with a 🤖 Generated with Claude Code line above it. It's not a bug, it's the built-in attribution convention. And plenty of people are annoyed by it: there's an open feature request in the Claude Code repo asking for exactly this, a full Hacker News thread, and several developer TILs walking through how to remove it. I've had this banned in my global CLAUDE.md since day one: never, under any circumstance, add "By Claude Code" or similar when touching Git or GitHub. For a while I thought that was enough.
Why CLAUDE.md alone isn't enough
A CLAUDE.md tells the model what to do, it doesn't enforce it. Claude Code ships with a default example template for creating commits that includes that attribution line as part of the message. If your CLAUDE.md doesn't explicitly override it, the model reaches for that template and writes the line as plain text inside the message, not as something the CLI appends separately. The result in your history looks the same, but the mechanism is different, and that matters: rely on the instruction alone, and it only takes a long session where context gets diluted, a poorly worded CLAUDE.md, or a commit made outside the normal flow, for the line to sneak back in.
The setting that actually enforces it: attribution
// ~/.claude/settings.json (every project) or .claude/settings.json (just this one)
{
"attribution": {
"commit": "",
"pr": ""
}
}
commit controls the line added to commit messages. pr controls the note added to pull request descriptions created by gh pr create. Setting both to empty removes them entirely: not just Co-Authored-By, but the Generated with Claude Code line that usually rides along with it.
Unlike CLAUDE.md, this doesn't depend on the model remembering anything: the CLI itself decides what gets appended to the final message, so it doesn't matter if the model "forgets" the rule halfway through a session.
Coming from an older version? You might have includeCoAuthoredBy: false in your settings.json. It still works, but it's deprecated in favor of attribution, which splits commit and PR instead of one all-or-nothing switch.
// before
{ "includeCoAuthoredBy": false }
// now
{ "attribution": { "commit": "", "pr": "" } }
Before and after
$ git log -1
commit a1b2c3d
Author: Juan <juan@example.com>
Fix retry logic in payment handler
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
With attribution set to empty:
$ git log -1
commit a1b2c3d
Author: Juan <juan@example.com>
Fix retry logic in payment handler
The two layers I run
attributionin my globalsettings.json(~/.claude/settings.json), so no project inherits it by default unless I say so.- A line in my global
CLAUDE.md: "never, under any circumstance, add 'By Claude Code' or similar when interacting with Git or GitHub." It's not decoration: it covers the placesattributiondoesn't reach, like a message Claude hand-writes inside a script, or a note that slips out outside the normal commit flow.
Neither the setting nor the instruction alone is perfect. Together, they are. And while you're deciding what goes where, here's the full map: CLAUDE.md is read as guidance, settings.json is enforced whether Claude follows it or not. This is exactly that principle, applied to a real case.
Reference
| Setting | Where it lives | What it covers | Level |
|---|---|---|---|
attribution.commit |
settings.json (user, project, or local) |
Line added to commit messages | CLI, deterministic |
attribution.pr |
settings.json (user, project, or local) |
Note added to PR descriptions via gh pr create |
CLI, deterministic |
includeCoAuthoredBy |
settings.json (deprecated) |
All-or-nothing switch, attribution's predecessor |
CLI, deterministic |
A rule in CLAUDE.md |
CLAUDE.md (any level) |
Any message the model writes outside the normal flow | Instruction, not enforced |
Official docs: Claude Code settings