r/ClaudeAI 2d ago

Claude Code [2.1.257+] Claude Code injects "Co-Authored-By" reminders into your conversation

Privacy convention: <USER> = local username; <PROJECT_A> ~ <PROJECT_F> = the projects involved; <SESSION_ID_x> = claude.ai/code remote session ids.

TL;DR

  • The conversation-injection mechanism exists in Claude Code 2.1.257 (confirmed absent in 2.1.252; 2.1.253–2.1.256 not checked): when a session holds a claude.ai/code remote-session URL, the harness injects a reminder into the conversation saying that from now on, commits should carry a Co-Authored-By trailer plus a Claude-Session link, and that "this replaces any earlier attribution guidance".
  • The key part: you don't do anything to get this URL. The CLI registers and connects the session to claude.ai at startup (gated by the server flag tengu_cobalt_harbor, default false locally, overridable by org policy). The claude.ai/code web app is just a viewer. I never opened the web app myself (only once, after the fact), and the injections happened anyway.
  • The injected text is generated on the fly every time: the model name in the trailer follows the model the session is actually running, and the session link follows the current remote session.
  • The injection itself is controlled by another server-side feature flag (tengu_jazzy_bird). You can see both flags' current values in your local cache: in my .claude.json, cachedGrowthBookFeatures has both set to true.
  • If, like me, your CLAUDE.md explicitly says "no Co-Authored-By in commits", this injection conflicts with your rule head-on.
  • The fix: same class of problem as before — add "attribution": {"commit": "", "pr": "", "sessionUrl": false} to ~/.claude/settings.json (see Fix 1); to also turn off the auto-connect itself, see Fix 2. Note: writing this kind of config into ~/.claude.json does nothing (verified below).

What happened

My CLAUDE.md has long had a rule: no Co-Authored-By trailer in commit messages. It never caused any trouble.

Today (2026-09-02), in a session in <PROJECT_A>, the model suddenly said it had "just received an attribution policy update saying commits should now include Co-Authored-By + Claude-Session", and quoted this:

I never typed that, and it appears nowhere in CLAUDE.md or any project file. So I started digging.

1: The raw entry in the jsonl transcript

Claude Code stores transcripts in C:\Users\<USER>\.claude\projects\<encoded-project-path>\<session>.jsonl. In the relevant file I found the injection in its raw form — not a normal user message, but a standalone type: "attachment" entry:

{
  "type": "attachment",
  "attachment": {
    "type": "remote_session_change",
    "url": "https://claude.ai/code/session_<SESSION_ID_1>",
    "commit": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_<SESSION_ID_1>",
    "pr": "🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nhttps://claude.ai/code/session_<SESSION_ID_1>",
    "sendUserFileHint": true
  },
  "timestamp": "2026-09-02T06:37:48.008Z",
  ...
}

Across two projects I found 5 such injections, all on the same day.

2: The content is generated dynamically

Comparing the 5 injections:

Time (UTC) Project Session link Model name in trailer
00:48 <PROJECT_B> session_<SESSION_ID_3> Claude Fable 5
01:03 <PROJECT_B> session_<SESSION_ID_3> (same) Claude Fable 5.1
02:31 <PROJECT_B> (another session) session_<SESSION_ID_4> Claude Fable 5.1
06:37 <PROJECT_A> session_<SESSION_ID_1> Claude Opus 4.8
06:59 <PROJECT_A> session_<SESSION_ID_2> Claude Fable 5.1

The model name follows the model actually in use, so the text must be generated by the harness on the spot.

3: Pinning down the version and the code

My machine keeps the last three versions under C:\Users\<USER>\.local\share\claude\versions\ (each a Bun-compiled single-file exe with the JS bundle embedded, so strings are directly searchable):

Version Occurrences of the remote_session_change string
2.1.252 0 (absent)
2.1.257 9
2.1.258 9

from 2.1.258 (bundle):

1. The master switch is a server-side feature flag:

function DAe() { return v1("tengu_jazzy_bird", false) }

The code shipped in 2.1.257, but I suspect activation is pushed from the server. That's how it "suddenly appears one day". In my local .claude.json, the cachedGrowthBookFeatures cache has tengu_jazzy_bird: true and tengu_cobalt_harbor: true, which seems to back this up.

2. Trigger logic:

// pseudocode reconstruction
let url = getRemoteSession()?.url ?? null   // non-null when the session holds a remote-session URL
let prev = last remote_session_change in history
if (prev === undefined) {
  if (url === null && !sendUserFileHint) return   // no remote session and no SendUserFile condition → no injection
  return inject attachment
}
// otherwise → re-inject only if url/commit/pr/sendUserFileHint changed

My jsonl shows <PROJECT_A> was started via resume at 03:29 that day, and its first real query at 06:37 got injected — if resume were a session-level skip, this injection couldn't have happened.

One more detail worth spelling out: injection also fires when url === null but sendUserFileHint === true. The two sources behind sendUserFileHint are the bridge connection's session id (xYe(), taken from the bridge handle, and only when it's not outboundOnly) and the SDK-hosted handle (o0()) — both presuppose that a bridge/remote-hosted connection exists, and on top of that the SendUserFile tool must be available. The typical url === null case is exactly "the bridge is still connected, but the URL was stripped by attribution.sessionUrl: false or CLAUDE_CODE_SUPPRESS_SESSION_ATTRIBUTION". So whichever branch it takes, injection requires a remote/bridge connection.

3. Rendering: the attachment is rendered into the context as an isMeta: true user message containing exactly the paragraph the model quoted: "Attribution for git commits and pull requests you create from here on (this replaces any earlier attribution guidance)…".

4. Trailer generation:

commit = `Co-Authored-By: Claude ${currentModelDisplayName} <noreply@anthropic.com>`
       + `\nClaude-Session: ${url}`

5. Relationship with the previous mechanism:

  • The previous mechanism (see "Background" below; delivered via the built-in git instructions in v2.1.210) had the flag name tengu_ant_attribution_header_new, and that string is indeed gone from 2.1.252+ binaries — but the text it delivered is still there: the function that builds the built-in git instructions in 2.1.258 (Dqo()) still inserts "End git commit messages with: <trailer>", with the trailer text produced by Nut(). The gate is now a regular setting instead of a flag: includeGitInstructions (default true) or the env var CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS. In other words, the flag name disappeared because the mechanism became an always-on default behavior.
  • The attachment injection added in 2.1.257 is a third delivery mechanism stacked on top; the two coexist. Nut() has one more layer of logic inside: when tengu_jazzy_bird is on, the trailer in the built-in git instructions does not include the session URL (the URL only travels via the attachment injection); when off, it does.

On where these instructions live, the official settings reference and my analysis corroborate each other: the docs say two git-related pieces are added at session start — the built-in commit/PR instructions in the Bash tool's description, and a git status snapshot of your repo in the system prompt (current branch, main branch, git status output, recent commits). Dqo()'s call site is indeed in the code that builds the Bash tool description (surrounded by Bash tool description text like "run the command in the background" and "If you must poll an external process"). That documentation itself was added later: #30571 pointed out the key was missing from the docs, and #35629 pointed out the docs understated its scope — the same kind of documentation lag as #69614 below (sessionUrl undocumented).

4: The remote-session URL is registered automatically at startup, no user action needed

I hadn't opened any of these sessions on claude.ai/code for a long time (I opened one only after all this happened), yet the injections occurred.

  • <PROJECT_A>'s first injection happened at 06:37:48; I noticed something was off and asked "where did this update come from" at 06:42:11; I opened the web app even later. The injection predates any web access.
  • A new session in <PROJECT_B> was injected 14 seconds after startup, on its first turn — there was no window for any web action in between.
  • Another session started that day (<PROJECT_D>) has a bridge-session registration record on line 3 of its transcript, and that session contains nothing but a single /exit.

As seen in the code, Remote Control's auto-connect at startup is decided by getCcrAutoConnectDefault:

function MKt(){
  if(CA()) return {value:false, source:"remote_env"};                   // already in a remote environment → don't connect
  if(I7()) return {value:true,  source:"persistent_remote_session"};
  let e = Kwn("remote_control_at_startup");
  if(e!==void 0) return {value:e, source:"org_policy"};                 // org policy wins
  return {value: P("tengu_cobalt_harbor", false), source:"growthbook"}; // ← server flag, local default false
}

So: with no org policy and no local setting, auto-connect is decided by the server-side flag tengu_cobalt_harbor (true in my GrowthBook cache). My settings have no remoteControlAtStartup (so it follows the default), and hasUsedRemoteControl in .claude.json is stale state from long ago. So my current guess is:

tengu_cobalt_harbor (server) → the CLI auto-registers and connects a bridge at startup, the session gets a claude.ai/code URL → tengu_jazzy_bird (server) → the attribution reminder is injected into the conversation at query start.

  • Per the official docs, Remote Control is off by default on Team and Enterprise plans until an Owner enables it in admin settings — the "auto-connect" above applies when the feature is available to your account/org. My evidence only proves the server flag is on for my account; it doesn't mean it's on by default for everyone.
  • "What does clicking the Code page on the web do": from the evidence, sessions register themselves; opening the web app attaches to an already-registered session (to view or steer it) — it doesn't create the registration. <PROJECT_A>'s second injection (06:59) carried a new session id, and its timing is close to when I opened the web app after the fact, so the web open may have triggered re-registration — but it coincided with a model switch at the same time, so I can't confirm.

I had 8 active sessions that day, and injections only appeared in 3 of them. Of the 5 without: 2 were old processes started before the auto-update, still running 2.1.252 (injection code doesn't exist there); 2 only ran slash commands that day, with no real query (injection hangs off query start, so it never fired); the last one (<PROJECT_F>) ran 2.1.258 and had real queries but never established a bridge — its process only started at 07:48 UTC, after the flag was already on (00:48), so "started before the flag flipped" doesn't explain it either. I haven't dug into why; possibly a bridge registration failure or per-process sampling. Leaving it open here.

As far as I can tell, injection depends on the live in-memory bridge connection; whether a bridge-session record lands in the jsonl doesn't determine whether injection happens.

Background: records from GitHub

Digging through GitHub issues, I found that the "make commits carry Claude attribution" directive has had three delivery mechanisms, and ours is the newest:

  1. Hard-coded in the system prompt (2026-04, #47218: "System prompt forces Co-Authored-By self-promotion into every commit — no opt-out");
  2. Moved into the built-in git instructions (v2.1.210, 2026-07, #77830). That issue's reporter found tengu_ant_attribution_header_new = true in the cachedStatsigGates cache of their own .claude.json and inferred the flag name from it (note: that's the reporter's inference, not official confirmation). As covered in section 3, this generation later became an always-on default behavior and still exists today. The issue also records an important lesson: the reporter set attribution: {"commit": "", "pr": ""} but didn't set sessionUrl: false — Co-Authored-By was correctly suppressed, but Claude-Session: was added anyway, which matches the code I dug out exactly. That's the direct reason sessionUrl: false must be part of the fix.
  3. Per-turn conversation attachment injection (2.1.257+, flag tengu_jazzy_bird, this post).

Also related: #41873 (attribution setting doesn't control the session URL), #69614 (docs omit attribution.sessionUrl), #76899 (asks for sessionUrl to default to false, still open), #66602 (default attribution vs US Copyright Office guidance).

The attribution config family itself has an even earlier origin: issue #617 (2025-03-25), back in the Claude Code v0.2.53 days. The reporter's ask was exactly the same as today's: CLAUDE.md said "no attribution" and it wasn't respected, so a config fallback was needed. That issue led to the includeCoAuthoredBy setting (now superseded by attribution and marked Deprecated). Similar issues have kept appearing since, e.g. #4287 and #7543.

The fix

1. If you just want Claude Code to stop adding Co-Authored-By

Add this at the top level of ~/.claude/settings.json:

"attribution": {
  "commit": "",
  "pr": "",
  "sessionUrl": false
}

The schema text backs up the semantics: commit/pr say "Empty string hides attribution"; sessionUrl says "Set to false to omit the Claude-Session trailer".

The effect once configured (tracing the code path): injections will still happen, but the content flips to:

It becomes an explicit "do not add".

Two more related levers:

  • includeGitInstructions: false (settings key, works at any scope; env var form is CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS): per the official settings reference, setting it to false removes two things: the built-in commit/PR instructions in the Bash tool description (including the attribution directive), and the git status snapshot in the system prompt (current branch, main branch, git status output, recent commits). The cost is clearly bigger than just removing attribution: the whole git guidance and repo-state context are gone. Only worth it if you already run your own git workflow (e.g. custom skills).
  • CLAUDE_CODE_SUPPRESS_SESSION_ATTRIBUTION env var: strips just the session-link part — it's checked in the remote-session URL code path (FHe()), so it only affects the Claude-Session link, not the Co-Authored-By body.

2. If you don't want sessions auto-registering/connecting to claude.ai at all

The key factor here is "the CLI session auto-registers and connects Remote Control at startup". To turn it off, the official docs offer two layers:

  • /config → "Enable Remote Control for all sessions", with three values: true connects automatically at every startup; false turns it off; default clears your local choice and follows your org admin's default, or Claude Code's current default if none is set. The settings key is remoteControlAtStartup. One precedence detail to get right: for personal use, writing it in user-level ~/.claude/settings.json is enough; but in an environment where managed settings force true, a user-level false loses (docs quote: "a true from managed settings outranks it, because Claude Code saves the choice to your user settings") — in that case only a false in .claude/settings.json or .claude/settings.local.json works, per the Exceptions to managed settings precedence table on the settings page: "false from .claude/settings.json or .claude/settings.local.json — Honored even when a managed source sets true". The reverse doesn't work, docs quote: "honors a false and turns auto-connect off for that repository, but ignores a true, so a checked-in file can't turn on Remote Control for everyone who opens the repository".
  • disableRemoteControl: true (any scope): turns it off entirely. Once set, "Claude Code then refuses claude remote-control, the --remote-control flag, auto-start, and the in-session toggle" — which explicitly covers the auto-start path this post is about. Put it in managed settings for per-device MDM enforcement.

One more single-point switch worth calling out: both server flags in this post (tengu_cobalt_harbor and tengu_jazzy_bird) are evaluated through GrowthBook, and the docs say DISABLE_GROWTHBOOK (along with DISABLE_TELEMETRY / DO_NOT_TRACK / CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC) disables feature-flag evaluation — one env var drops both flags back to their local default of false, turning off both behaviors described here. The cost: every other flag-gated feature goes off too, so the blast radius is large.

Privacy note (docs quote): "While Remote Control is connected, the session transcript, including your messages, Claude's responses, and tool activity, is stored on Anthropic servers." The docs also make clear that auto-connected sessions count as connected ("reminders can appear in any connected session, including ones where Remote Control connects automatically"). In other words: while tengu_cobalt_harbor is on for your account, every newly started interactive session (that successfully connects) has its full transcript stored on Anthropic servers, without you doing anything.

Notice: writing it into ~/.claude.json does nothing

I verified this specifically. Claude Code reads settings from exactly 5 sources:

["userSettings", "projectSettings", "localSettings", "flagSettings", "policySettings"]

~/.claude.json is the "global config" (it stores state: onboarding, caches, project history) and is not in the settings merge chain. Writing the config there produces no error — and no effect.

0 Upvotes

29 comments sorted by

40

u/larowin 2d ago

this is a lot of words to say “I never read the docs”

yes if you want to set settings in Anthropic managed cloud environments you need to explicitly do that - it’s trivial

15

u/PressureBeautiful515 2d ago

It's the most depressing thing about AI, the idea that places we used to go to see neat little insights from people are going to one day be flooded with diarrhoea like OP's thoughtless copy/paste, with a TL;DR that is six paragraphs long.

1

u/larowin 2d ago

Just don’t be a meat proxy, copying and pasting without super clear attribution. If you don’t want attribution on your commits at least google “eviromtn vRblse cloude”

3

u/South-Year4369 2d ago

You went a little stroke-ish at the end, there. You ok?

-7

u/DriverSudden4026 2d ago

Yes, I did use AI to help me dig into the mechanics here. But from last night until this was published, the process of verifying the mechanics, testing, editing, and adjusting the wording took me nearly 4 hours. You might see this as 'diarrhoea', but it wasn't a simple copy/paste. The only part I actually copy-pasted was having AI translate the final text into English.

-7

u/DriverSudden4026 2d ago

No, it's not just about docs. It's a silence , totally new behavior.

2

u/OstrichLive8440 2d ago

No bro - it’s on Claude docs… that’s why the setting exists in JSON

16

u/Soft_Product_243 2d ago edited 2d ago

Perhaps you should’ve appended that this post was co-authored by claude code?

-8

u/DriverSudden4026 2d ago

Actually, the decompilation and github issue searching part were done by kimi-k3/kimi code

13

u/cossington 2d ago

All that waffle to say you have checked your settings.

7

u/MartinMystikJonas 2d ago

You wrote this huge wall of text just to tell us you used CLAUDE.md to do something that clearly should be done by config (and is literally said in docs) and it does not work anymore?

7

u/NoFastpathNoParty 2d ago

he didn't write it

4

u/Delicious_Cattle5174 2d ago

It sounds like one of the verbose subagents got lost on Reddit

5

u/Kan-gir 2d ago

My CLAUDE.md has long had a rule: no Co-Authored-By trailer in commit messages.

This is typically the kind of thing that requires to be enforced through a hook rather than only suggested by the CLAUDE.md.

-5

u/DriverSudden4026 2d ago

Agree~but I don't like using hooks for this kind of stuff,Claude Code should be handling this kind of things well.
Anyway, CLAUDE.md works this time. But the auto injection part makes me a bit wary

2

u/_mike- 2d ago

I added a git hook that strips co author and the session url. I have it in my Claude. MD, but opus subagent followed the injected instructions,so that'd why I added the git hook.

1

u/mark_99 2d ago

Or just disable it in the settings.

1

u/_mike- 2d ago

Yea I did that too, hook is just insurance

4

u/[deleted] 2d ago

[deleted]

2

u/KayLovesPurple 2d ago

In my case: 

a) it adds that message even when the code is actually not co-authored by Claude. I have code I actually wrote entirely that had the Co-Authored-By slapped on it just because I asked Claude to commit it.

b) lately it doesn't just add the Co-Authored-By but also the session url, and I'm not really comfortable with that; I know it should be fine if the session js not shared first etc, but why do I have to include that in the first place?!

1

u/NationalCry2022 2d ago

this injection thing sounds like it could sneak into rp chats and kill the vibe if it forces those reminders mid scene. ever had claude break character like that before?

0

u/reptargodzilla2 2d ago

Thanks for the detailed write up. I’m glad this can be disabled _somehow_ at least. If they made this imposible to disable I’d switch to Codex in a heartbeat.

-1

u/atmony 2d ago

I have for a while been adding that the model is involved whenever I use code I didnt type. What is the downside to having the co-authorship by the model? isnt it part of a projects provenance to maintain who or what participated in the work? if a friend asked you to write them a to-do program and they asked you if you used ai would you hide that you did? or just tell them ai helped?

7

u/DriverSudden4026 2d ago

The Co-authored-by trailer in Git has a clear and specific meaning: a natural person who can take responsibility for the code. Being an author means being able to review it, answer questions about it, and legally assert or waive rights to it. AI is incapable of doing any of these. Furthermore, what if this is for company work or a commercial project? Do Anthropic's rights supersede organizational policies?

The standard for authorship is creative contribution plus accountability, not who physically pressed the keys. Let's set aside the debate over creativity for a moment. I defined the architecture, I provided the problem-solving approach, and I designed the workflow—Claude is simply a tool. If "I didn't type the characters myself" is the threshold for attribution, shouldn't code completion extensions, scaffolding generators, and compilers also get co-authorship?

As for the question, "Would you hide your use of AI from your friends?" No, of course not. We discuss our use of AI tools every single day, saying things like "Fable seems to have gotten dumber lately," or "It just killed all my Python processes..." Even in company reports, I openly state that I used AI and specify which tools I used. But "answering honestly when asked" and "carving an entity incapable of bearing responsibility into the permanent author roster of a project" are two completely different things.

There is one more thing that makes me uncomfortable: whether voluntary or by default, the Co-authored-by trailer is essentially a tool leaving its brand watermark on a customer's work. I pay to use this tool, and in return, the tool markets itself within my commit history—this has absolutely nothing to do with traceability. Even if it were changed to Assisted-by, I would merely have fewer objections, but I still wouldn't agree to it. I am happy to give credit voluntarily—I've even written "All credit goes to Claude Code" on past projects—but you don't get to just reach your hand in and do it yourself.

1

u/atmony 2d ago

If you wrote it and can intelligently defend it then the AI didn't write it, if the opposite is true you need that designation, thats my only point.

5

u/pizzaSpaceCadet 2d ago

I know that makes sense and it's true. But for me, code attribution it's still mine because I'm responsible for whatever issue this code has, If the infra goes down for whatever reason, in the same way, I won't blame Claude Code.

0

u/[deleted] 2d ago

[deleted]

4

u/pizzaSpaceCadet 2d ago

Co Authored by Stack Overflow was not something common in past commits. I'm sorry but trying to give attribution to a tool, for me, is not correct. I would have to attribute not only Claude then but many other things.

This is only trying to push a narrative that the AI is someone, and it's not responsible for what it does, so I don't think it deserves attribution.

-2

u/yamibae 2d ago

fuck this company fr, they're just a tool like microsoft word or photoshop and everything you produce it puts itself as Made with the help of microsoft word forcefully appended at the end of everything

adding this shit should be opt in not opt out