C Claude Code Internals
EN | ES

Bridge & IDE Integration

Two distinct systems. IDE integration connects the CLI to VS Code and JetBrains on the same machine via MCP over localhost. The Bridge connects a CLI instance to claude.ai as a web frontend, enabling remote control from any browser.

2 systems (IDE + Bridge) 2 bridge protocol versions 15 JetBrains IDEs supported 3 bridge spawn modes
i Two completely different systems
IDE integration is local: CLI and editor on the same machine, communicating over localhost MCP. The Bridge is remote: a tunnel between the CLI (anywhere) and claude.ai (browser), with Anthropic's backend in the middle.

Architecture

IDE Integration (local)

VS Code / JetBrains
<─── MCP (SSE/WS) ───>
Claude Code CLI
localhost:port — same machine

Bridge (remote)

claude.ai (browser)
<─── HTTPS/WSS ───>
Anthropic API Backend
<─── SSE/HTTP ───>
Claude Code CLI (worker)

IDE integration

Supported IDEs

VS Code / Cursor / Windsurf auto-install

Extension discovered and auto-installed via code --install-extension anthropic.claude-code-vscode. Communicates via MCP over SSE or WebSocket on localhost.

JetBrains (15 IDEs) manual install

IntelliJ IDEA, WebStorm, PyCharm, PhpStorm, RubyMine, CLion, GoLand, Rider, DataGrip, DataSpell, AppCode, Android Studio, Aqua, RustRover, Writerside. Plugin must be installed manually.

How discovery works

IDE extensions write lockfiles to ~/.claude/ide/<ide-name>-<pid>.lock on startup and remove them on shutdown. Claude Code reads these lockfiles to discover running IDE instances and their connection info (port, transport type, auth token).

IDE MCP transport types

// SSE transport from IDE (read via EventSource)
{ type: 'sse-ide', url: 'http://localhost:PORT/sse', ideName: 'vscode' }

// WebSocket transport from IDE
{ type: 'ws-ide', url: 'ws://localhost:PORT/ws', ideName: 'vscode', authToken?: 'token' }

These are internal transport types, not user-configurable. Set up automatically by the IDE extensions.

Features

File editing sync

When Claude Code edits a file, the IDE is notified via MCP. The IDE shows a diff view and the user can accept or reject changes in the editor.

Context sharing

The IDE can send selected text, open files, and cursor position to Claude Code, enriching its understanding of what the user is working on.

Diff views

openDiffInIde() opens a diff view in the IDE for a specific file. closeDiffTabsInIde() cleans up when changes are accepted.

Bidirectional channel (claude-vscode)

Special notification channel between CLI and VS Code. Sends file edits, feature gate values, analytics. Receives file changes and user actions.

Bridge system (remote control)

The Bridge connects a CLI instance to claude.ai as a web frontend. Use cases: control Claude Code from any browser, run it on a remote server, manage multiple sessions, share sessions via QR codes and URLs.

Two protocol versions

Version Reading Writing Notes
v1 WebSocket (WSS) HTTP POST (batched every 100ms) Environments API + poll loop. Older, more complex.
v2 SSE stream HTTP POST (CCRClient) Direct session creation, simpler. Feature-gated.

Three execution modes

Mode Entry point Description
Standalone claude remote-control / bridgeMain.ts Dedicated process, supports multiple concurrent sessions
REPL In-Process initReplBridge.ts → replBridge.ts Bridge runs within an existing REPL session
Env-less remoteBridgeCore.ts Direct session connection (v2 protocol)

Spawn modes (standalone)

Mode Description
single-session One session in CWD, bridge closes when done
worktree Persistent server, each session gets an isolated git worktree
same-dir Persistent server, all sessions share CWD

Communication protocol

Outbound: CLI → claude.ai

Type Description
assistant Claude's response text
result Tool execution results
partial_assistant Streaming partial responses
status Status updates
control_response Response to a control request
control_request CLI-initiated control request
keep_alive Keepalive ping

Inbound: claude.ai → CLI

Type Description
user User messages from the web UI
control_request Server-initiated control request
control_response Response to CLI's control request
keep_alive Keepalive ping
update_environment_variables Update env vars (token refresh)

Control request subtypes (selected)

Subtype Direction Description
initialize Server → CLI Initialize session, returns commands, models, account, PID
interrupt Server → CLI Interrupt current turn
can_use_tool CLI → Server Request permission to execute a tool (user sees Allow/Deny in browser)
set_model Server → CLI Change the AI model
set_permission_mode Server → CLI Change permission mode
mcp_set_servers Server → CLI Replace dynamic MCP servers
rewind_files Server → CLI Revert file changes
apply_flag_settings Server → CLI Apply feature flag settings from backend
elicitation Server → CLI Request user input for MCP elicitation

Session lifecycle

v1 (Environments API + poll loop)

1
REGISTER POST /v1/environments/bridge → {environment_id, environment_secret}
2
POLL GET /v1/environments/{id}/work/poll every 2s (or 10 min when at capacity)
3
RECEIVE WORK Decode WorkSecret (base64url JSON): session token, API base URL, sources, auth
4
ACKNOWLEDGE POST /v1/environments/{id}/work/{workId}/ack
5
SPAWN CHILD claude --print --sdk-url <ws_url> --session-id <id> --replay-user-messages
6
HEARTBEAT POST /v1/environments/{id}/work/{workId}/heartbeat (JWT auth, no DB hit)
7
DONE POST /v1/sessions/{id}/archive + SIGTERM → 30s grace → SIGKILL

v2 (direct session)

1
CREATE POST /v1/code/sessions (OAuth) → {session_id, session_url}
2
GET JWT POST /v1/code/sessions/{id}/bridge → {worker_jwt, epoch}
3
CONNECT SSE GET {sessionUrl}/worker/events/stream — Authorization: Bearer <worker_jwt>
4
PROCESS Receive via SSE, write via HTTP POST to {sessionUrl}/worker/events
5
REFRESH POST /v1/code/sessions/{id}/bridge → new worker_jwt (5 min before expiry)

Permission flow (remote)

When the CLI needs to execute a tool while running remotely, it sends a can_use_tool control request to the server. The web UI shows the user an Allow/Deny dialog. The response can also include modified tool input or new permission rules.

// Permission response from web UI
{
  behavior: 'allow' | 'deny',
  updatedInput?: Record<string, unknown>,   // Modified tool args
  updatedPermissions?: [                     // New session rules
    { tool: 'Bash(rm:*)', behavior: 'deny' }
  ],
  message?: string
}

Authentication

OAuth token resolution order

  1. 1. CLAUDE_BRIDGE_OAUTH_TOKEN env var (dev only)
  2. 2. OAuth token from OS keychain
  3. 3. Interactive OAuth flow via browser

JWT session token refresh

  • Refresh scheduled 5 min before JWT expiry
  • Fallback: refresh every 30 min if JWT can't be decoded
  • New token sent to child process via update_environment_variables
  • Max 3 consecutive init failures before bridge is disabled

Every request includes: Authorization: Bearer <oauth_token>, anthropic-version: 2023-06-01, anthropic-beta: environments-2025-11-01. For ELEVATED security tier: also X-Trusted-Device-Token.

Constants and timeouts

Constant Value Description
Poll interval (idle) 2,000ms v1: how often to check for new work
Poll interval (at capacity) 600,000ms (10 min) v1: poll interval when all slots are busy
SSE reconnect base delay 1,000ms v2: initial reconnection delay
SSE reconnect max delay 30,000ms v2: max reconnection backoff
SSE reconnect give-up 600,000ms (10 min) v2: stop reconnecting after this
SSE liveness timeout 45,000ms v2: max time without data before reconnect
HybridTransport batch flush 100ms v1: batch outgoing messages
HybridTransport POST timeout 15,000ms v1: HTTP POST timeout
Token refresh buffer 5 min Refresh JWT before expiry
Fallback refresh interval 30 min Refresh if can't decode JWT
Max init failures 3 Disable bridge after 3 consecutive failures
Bridge failure dismiss 10,000ms Auto-dismiss error UI
Session reclaim threshold 5,000ms Reclaim stale sessions older than this
Shutdown grace period 30,000ms SIGTERM → SIGKILL delay for child processes
What the Bridge enables that the CLI alone cannot
The Bridge turns Claude Code into a web-accessible service. With worktree spawn mode, each remote session gets its own isolated git worktree so parallel users never collide. The can_use_tool protocol means the web UI gets full interactive permission prompts, including the ability to modify tool arguments before they execute.