[BUG] Sessions launched from Claude Desktop onto a remote machine never show the CI/diff panel, even when they created the PR

Status Open
Reported on v2.1.221
Maintainer reply None cached
Activity 1 comment ยท opened Aug 6, 2026

๐Ÿค– Filed by Ivor's Claude Code agent on their behalf.

Correction (edited shortly after filing): the original version of this report claimed the panel appears for gh pr create and only fails for git push. That framing was wrong โ€” it was derived from reading the bundle, not from observing the UI. Checking 20 sessions' transcripts against actual panel behavior shows the differentiator is how the session was launched, not which git command ran. The push/create asymmetry described at the bottom is real but secondary. Original text preserved in the comment below.

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.221; 2.1.222 published same-day and not inspected โ€” see Version note below)

What's Wrong?

Sessions launched from Claude Desktop that execute on a different machine never show the CI-status / change-diff panel โ€” even when the session itself created the PR with gh pr create.

Topology:

  • Machine A โ€” Claude Desktop, used to manage all sessions.
  • Machine B โ€” a Linux VM where the sessions actually run.

Two launch modes, only one of which produces the panel:

| Launch mode | Process on machine B | PR created in-session | Panel in Desktop |
|---|---|---|---|
| Session started from Claude Desktop (bridged cloud session) | --print --sdk-url https://api.anthropic.com/v1/code/sessions/cse_โ€ฆ --session-id cse_โ€ฆ --input-format stream-json | yes, gh pr create ran normally | never |
| claude started manually on machine B, then remote-controlled from Desktop | claude --remote-control <name> --resume <uuid> | yes | appears |

Evidence from 20 local transcripts carrying pr-link records:

  • 19 are Desktop-launched bridged sessions. At least 12 ran a genuine gh pr create (bare invocations such as gh pr create --draft --title โ€ฆ, not piped or filtered). None of them ever produced a panel.
  • 1 is a locally-started, remote-controlled session. That is the only session that has ever shown the panel.

Every one of those sessions has correct pr-link records on disk with the right prNumber / prUrl / prRepository, so the association is computed correctly in all cases โ€” it just never reaches the Desktop UI for the bridged-session mode.

What Should Happen?

A session launched from Claude Desktop and executed on a remote machine should show the same CI-status / change-diff panel as a locally-started remote-controlled session, once it is associated with a PR.

Error Messages/Logs

# Desktop-launched session on machine B. PR was created in-session with `gh pr create`.
# Link is recorded correctly on disk:
$ jq -c 'select(.type=="pr-link")' ~/.claude/projects/<project>/<session-uuid>.jsonl
{"type":"pr-link","sessionId":"<session-uuid>","prNumber":<N>,"prUrl":"https://github.com/<owner>/<repo>/pull/<N>","prRepository":"<owner>/<repo>","timestamp":"..."}
# ...records correct. No panel in Desktop.

# Note the session-id mismatch in this mode: the process is launched with
#   --session-id cse_01XXXXXXXXXXXXXXXXXXXXXX
# but the transcript on disk is <session-uuid>.jsonl and every pr-link record
# carries "sessionId":"<session-uuid>" โ€” not the cse_ id the Desktop side uses.

Steps to Reproduce

  1. Run Claude Desktop on machine A; have a Linux machine B available for execution.
  2. Failing case: start a session from Claude Desktop that executes on machine B. Have it make a change and run gh pr create (bare, output unpiped). Observe {"type":"pr-link",...} records appear in ~/.claude/projects/<project>/<session-uuid>.jsonl on machine B โ€” and no panel in Desktop.
  3. Working case: on machine B run claude directly, then put it into remote control (claude --remote-control <name>), and attach from Desktop on machine A. Have that session run gh pr create. The panel appears.

The only difference between the two is how the session was launched.

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

n/a

Claude Code Version

2.1.221 (Claude Code)

Version note: the code paths below are byte-identical in 2.1.216, 2.1.220 and 2.1.221 (all three inspected directly). 2.1.222 was published the same day this was filed and was not inspected โ€” the npm package is an installer stub, so the logic could not be checked without installing it.

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux (execution machine)

Terminal/Shell

Other โ€” sessions launched from Claude Desktop and executed on a separate machine as bridged cloud sessions (--print --input-format stream-json --output-format stream-json), bash.

Additional Information

Why the local record can't substitute in this mode. linkSessionToPR writes pr-link with a plain appendFile, and mirrorInternalEntry โ€” the CCR upstream channel โ€” is only ever called for last-prompt entries. So nothing carries pr-link off the execution machine. The transcript is also keyed to a local UUID rather than the cse_โ€ฆ session id the Desktop side uses, so even if it were read remotely the ids wouldn't match. That leaves the code_change_published SDK system event as the only channel, and something in the bridged-session path is not delivering it.

Secondary finding โ€” a genuine asymmetry in PR linking, independent of the above. Even in modes where the panel does work, only the create path emits the event. Both paths run from the same command-output scanner:

// create path โ€” links AND emits
async function Yzr(e){
  let [{linkSessionToPR:t},{getSessionId:r}] = await Promise.all([...]);
  let n = r(); if(!n) return;
  if (await t(n, e.prNumber, e.prUrl, e.prRepository), !ZUg(e.prUrl)) return;
  Lv({type:"system", subtype:"code_change_published", provider:e.provider,
      url:e.prUrl, repo:e.prRepository, identifier:String(e.prNumber)});
}

// push path โ€” links only, never emits
if (p && !p.startsWith("-") && !/^\d+$/.test(p) && !uCu.test(c)) yso(p).catch(()=>{});

The push branch already holds prNumber, prUrl and prRepository when it calls linkSessionToPR; it simply doesn't emit. Consequence: sessions that work on an already-open PR (reviewing, pushing follow-up commits, addressing comments) can never surface a panel in any mode. Emitting code_change_published there too would fix that class.

Also observed: the link is recorded even after a failed push (a pre-push hook rejected the attempt with exit 1; pr-link was appended 0.5s later). And gh pr view <n> / gh pr checks <n> never link โ€” naming the PR explicitly in a command has no effect.

Related but distinct:

  • #70637 โ€” gh pr create from a background-job session isn't linked in agents view. Also a "created but not surfaced" case; that one is about background jobs and the agents view rather than launch mode and the CI panel.
  • #77826 โ€” PR badge pinned to the first PR ever linked. Concerns a link that exists; here none is surfaced.
  • #78918 / #84511 โ€” --from-pr resume behavior; consumes links rather than producing them.

Not a config or version problem: no setting, flag, or hook can emit code_change_published โ€” only the CLI's own PR detection does.

View original on GitHub โ†—

This issue has 1 comment on GitHub. Read the full discussion on GitHub โ†—