Bug: `/remote-control` intermittently unavailable — `tengu_ccr_bridge` flag flips to `false` after background GrowthBook cache refresh
Environment
| Field | Value |
|---|---|
| Plan | Max (20x), stripe_subscription |
| hasExtraUsageEnabled | true |
| hasAvailableSubscription | false (see §4 — assessed as red herring) |
| Platform | macOS |
| CC Version | Latest (2.1.76) |
---
Observed Behaviour
Reliable reproduction sequence:
/logoutinside CC + logout of Claude Desktop +pkill -f claudeclaude login→/remote-controlis available,tengu_ccr_bridge: truein~/.claude.json- After some interval (next session or background refresh),
/remote-controldisappears - Inspection of
~/.claude.jsonshowstengu_ccr_bridge: falseincachedGrowthBookFeatures
Failure modes:
/remote-control→ "Unknown skill: remote-control" (command hidden)claude remote-control→ "Remote Control is not yet enabled for your account"
The flag state is the single consistent differentiator between working and broken states.
---
Code Path (from decompiled cli.js)
function isBridgeEnabled() {
return getFeatureFlag("tengu_ccr_bridge", false);
}
function isRemoteControlEnabled() {
return isBridgeEnabled() && isPolicyAllowed("allow_remote_sessions");
}
/remote-control command visibility is gated entirely on isBridgeEnabled(). Default is false — so any failure to fetch or evaluate the GrowthBook flag results in RC being hidden. The allow_remote_sessions policy is not the constraint here (Max personal account, no org policy).
---
hasAvailableSubscription: false — Red Herring
~/.claude.json shows:
"hasAvailableSubscription": false,
"oauthAccount": {
"hasExtraUsageEnabled": true,
"billingType": "stripe_subscription"
}
The RC code path (isRemoteControlEnabled()) does not reference hasAvailableSubscription. Confirmed non-blocking: RC works immediately post-login despite this field being false throughout.
---
GrowthBook Cache Mechanism
CC caches GrowthBook feature flags in ~/.claude.json under cachedGrowthBookFeatures. This cache is:
- Populated on login — fresh server evaluation returns
tengu_ccr_bridge: true - Refreshed periodically in background — subsequent evaluation returns
tengu_ccr_bridge: false - Not manually overridable — any manual edit to the cache file is overwritten on next startup/refresh
Note: heartbeat_interval_ms: 0 and session_keepalive_interval_ms: 0 appear in the bridge poll config — likely downstream symptoms of the flag being false, not an independent cause.
---
Differential Diagnosis
Hypothesis A: Staged Rollout
- Against: Flag returns
trueimmediately on fresh login for the same account. A pure staged rollout would return a consistent value regardless of login state. - Verdict: Unlikely
Hypothesis B: GrowthBook Cohort Assignment Keyed on Session/Device Identifier ← Most Probable
- For: Fresh login produces new session context → new GrowthBook evaluation →
true. Background refresh uses stale/different session context →false. Explains flag instability for the same account. - For: Consistent with issue #28583 where
tengu_ccr_bridgewasfalseon macOS buttrueon Ubuntu for the same account — different device = different cohort assignment. - Verdict: Most probable root cause
Hypothesis C: OAuth Token Refresh Drops Required Scope
- For: Background token refresh has a known race condition across multiple CC sessions (issue #24317). A refreshed token without the required scope could cause server-side GrowthBook evaluation to return
false. - Verdict: Plausible compounding factor, especially with multiple concurrent CC sessions
Hypothesis D: CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC / DISABLE_TELEMETRY
- Confirmed absent from shell profile.
- Verdict: Eliminated
---
Diagnostic Questions
- What attribute is GrowthBook using as the user identifier for
tengu_ccr_bridgecohort assignment? If it is session ID, device ID, or OAuth token ID rather than account UUID, that is the direct cause of instability.
- Is
tengu_ccr_bridgeintended to be account-stable for Max subscribers? If yes, the cohort assignment logic has a bug. If no, it is in active A/B rollout and the login-cycle workaround is expected behaviour.
- Does server-side GrowthBook evaluation for
cachedGrowthBookFeaturesrefresh take OAuth token scope into account? If so, a token refresh droppinguser:sessions:claude_codewould corrupt the cached flag on the next refresh cycle.
- What triggers
cachedGrowthBookFeaturesbackground refresh? Time-based TTL, session start, or API call? Understanding the trigger would allow isolation of exactly when the flag flips.
---
Related Issues
| Issue | Relevance |
|---|---|
| #28583 | Same flag false on macOS, true on Ubuntu — same account. Confirms device/session-keyed cohort assignment. |
| #33119 | CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC blocks GrowthBook entirely — separate cause, same symptom |
| #24317 | OAuth token refresh race condition across concurrent sessions — potential compounding factor |
| #29430 | Widespread regression: RC unavailable post re-auth for Max subscribers |
| #33580 | tengu_amber_quartz (voice flag) same pattern — cache overwritten on startup — confirms systemic GrowthBook cache instability |
---
Recommended Fix
Short-term: Pin GrowthBook cohort assignment for tengu_ccr_bridge to account UUID (or oauthAccount.id) rather than session/device identifier. This ensures the flag is stable across sessions, background refreshes, and re-authentications.
Medium-term: If the flag is in staged rollout, expose explicit eligibility feedback rather than silently defaulting to false — Max subscribers should not require a login cycle to access a plan-entitled feature.
Current workaround: claude logout && claude login — restores access until next background cachedGrowthBookFeatures refresh.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗