Claude in Chrome native-host wrapper hardcodes a CLI version path → silent CIC death on every CC version bump

Open 💬 1 comment Opened Jun 19, 2026 by growthpigs

Summary

The CIC (Claude in Chrome) extension's native-host wrapper at ~/.claude/chrome/chrome-native-host is auto-generated with a hardcoded path to a specific CC version directory, e.g.:

#!/bin/sh
# Chrome native host wrapper script
# Generated by Claude Code - do not edit manually
exec "/Users/<user>/.local/share/claude/versions/2.1.132" --chrome-native-host

Every CC version bump (CLI auto-upgrade OR Desktop App auto-upgrade of the bundled CC binary) breaks CIC pairing in one of two ways:

| Failure path | Trigger | Symptom |
|---|---|---|
| (A) Version dir deleted | CLI auto-upgrade deletes the old ~/.local/share/claude/versions/X.Y.Z/ directory | Wrapper execs a deleted binary → Chrome native-messaging handshake fails silently |
| (B) Bundle version drift | Desktop App updates its bundled CC to N+1, user-CLI symlink still at N | Wrapper points at stale binary, IPC protocol mismatches live CC sessions → list_connected_browsers returns [] |

In both cases, the failure is silent: no error log, no banner, no exception. list_connected_browsers just returns [] and the user has no idea why CIC tools stopped working. Path (A) was observed on MM1 2026-06-13, broke CIC for ~24h before being caught during a Ratify gate. Path (B) was observed on MM2 2026-06-19, where the Desktop App had auto-bumped to 2.1.181 while the CLI symlink still pointed at 2.1.170 — 11 patch versions behind — and the IPC handshake silently failed.

Reproduction

Any machine with:

  • Claude Code CLI installed via the auto-updating installer
  • Claude Desktop App installed with claude-code bundled (auto-updates independently)
  • CIC extension installed in Chrome / Comet / Chromium-based browser

After ANY CC version bump:

cat ~/.claude/chrome/chrome-native-host
ls -la "$(grep -oE '/[^"]+' ~/.claude/chrome/chrome-native-host | head -1)"
# If missing OR stale, CIC is broken.

From a CC session:

mcp__Claude_in_Chrome__list_connected_browsers
# Returns: [] (silently)

Why it matters

CIC is the only path for logged-in browser verification in CC. When it breaks silently: verification work stalls, users don't know to debug a 4-line shell script, failure persists across all parallel CC sessions, and the diagnostic chain (extension → manifest → wrapper → native-host subprocess → Unix socket bridge → CC session) is opaque to most users.

Proposed fix — dynamic resolver template

Replace the hardcoded version path with a dynamic resolver that picks the highest-version CC binary the Desktop App has installed, with the user-CLI symlink as a fallback. Survives BOTH update paths:

#!/bin/sh
# Chrome native host wrapper script
# Auto-generated by Claude Code. Resolves the highest-version CC binary at runtime
# so future version bumps don't require regenerating this file.
CC_DIR="$HOME/Library/Application Support/Claude/claude-code"
LATEST=$(ls -1 "$CC_DIR" 2>/dev/null | sort -V | tail -1)
BIN="$CC_DIR/$LATEST/claude.app/Contents/MacOS/claude"
if [ ! -x "$BIN" ]; then
  BIN="$HOME/.local/bin/claude"
fi
exec "$BIN" --chrome-native-host

This:

  • ✅ Picks the freshest CC binary even when CLI and Desktop App update at different cadences
  • ✅ Survives CLI version dir deletion (Desktop App bundle dir is the primary lookup)
  • ✅ Falls back to ~/.local/bin/claude for machines without the Desktop App
  • ✅ POSIX shell + standard tools (ls, sort -V, tail) — zero new dependencies
  • ✅ Self-documents

Linux paths need adapting (likely $XDG_DATA_HOME/claude/...), but the pattern (highest-version directory pick) is portable.

Self-healing already shipped at the user layer

Until Anthropic ships an installer-side fix, users can wire a SessionStart hook that auto-heals the wrapper. Reference implementation:

These are maintained at <https://github.com/growthpigs/pai-system> and would be useful as templates for the CC installer team.

Diagnostic evidence (the live failure that prompted this issue)

Diag log from cic-wrapper-autoheal.sh showing the false-positive heal on a dynamic-resolver wrapper (the v1 hook used literal-string grep, extracted $BIN as a string, declared the target missing, reverted to the static-symlink form, which was stale by 11 patch versions on MM2):

2026-06-19T07:03:44Z HEALED target=$BIN → symlink=/Users/<user>/.local/bin/claude
2026-06-19T07:04:08Z OK target=/Users/<user>/.local/bin/claude (exists, executable)

Live system state when CIC was broken on MM2 (Mac mini, T77WYLQMXJ):

~/.claude/chrome/chrome-native-host:
  exec "/Users/<user>/.local/bin/claude" --chrome-native-host  (resolves to 2.1.170)

Live CC sessions running: 2.1.181 (from ~/Library/Application Support/Claude/claude-code/2.1.181/)

Result: list_connected_browsers → []

After applying the dynamic-resolver fix, the wrapper resolves to the matching 2.1.181 binary and list_connected_browsers returns the connected browser.

Acceptance for the upstream fix

If Anthropic accepts the dynamic-resolver template:

  • [ ] CC installer regenerates the wrapper using the dynamic-resolver pattern (or equivalent)
  • [ ] Comment block in the generated wrapper documents the lookup chain
  • [ ] Linux variant uses the appropriate XDG base directory
  • [ ] CHANGELOG entry naming the fix so users on the broken pattern know to delete their old wrapper

The user-layer autoheal hook can then be retired (or kept as belt-and-suspenders).

Related

  • pai-system #252 — v1 autoheal doctrine (static-symlink fix)
  • pai-system #319 — v2 autoheal doctrine (dynamic-resolver fix)
  • pai-system main commits: b8f4c76d4a (v1 hook), fe0fa7c373 (v2 hook + tests), 5e564416ac (cic-doctor + smoke test), 6b4692bcbc (error-patterns evolution)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗