Skip to content

Instantly share code, notes, and snippets.

@sorrycc
Created February 25, 2026 01:01
Show Gist options
  • Select an option

  • Save sorrycc/9b9ac045d5329ac03084a465345b59c3 to your computer and use it in GitHub Desktop.

Select an option

Save sorrycc/9b9ac045d5329ac03084a465345b59c3 to your computer and use it in GitHub Desktop.

Remote Control (Tengu Bridge) — Implementation Reference

Extracted from versions/2.1.52/cli.js (Claude Code v2.1.52, built 2026-02-24) Purpose: Enable a local CLI agent session to be accessed/controlled from a web UI (claude.ai/code)


Table of Contents

  1. Architecture Overview
  2. Feature Gating
  3. Entry Points
  4. API Client
  5. Standalone Bridge Flow
  6. Main Poll Loop
  7. Session Spawner
  8. In-REPL Bridge
  9. Transport Layer (HybridTransport)
  10. State Management
  11. Session Activity Tracking
  12. Status Display
  13. Error Handling
  14. Security Model
  15. Constants & Configuration

1. Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                     claude.ai/code (Web UI)                 │
└──────────────────────────┬──────────────────────────────────┘
                           │ HTTPS / WSS
                           ▼
┌─────────────────────────────────────────────────────────────┐
│              Anthropic Environments API                     │
│  /v1/environments/bridge     (register/deregister)          │
│  /v1/environments/{id}/work/poll  (long-poll for work)      │
│  /v1/sessions/{id}/events    (send events)                  │
└──────────────────────────┬──────────────────────────────────┘
                           │
              ┌────────────┴────────────┐
              │                         │
   ┌──────────▼──────────┐   ┌──────────▼──────────┐
   │  Standalone Bridge   │   │   In-REPL Bridge    │
   │  `claude remote-     │   │  `/remote-control`  │
   │   control`           │   │   slash command      │
   │                      │   │                      │
   │  Spawns child claude │   │  Runs in-process,    │
   │  processes for each  │   │  shares the existing │
   │  session             │   │  REPL session        │
   └──────────────────────┘   └──────────────────────┘

Two operation modes:

  • Standalone (claude remote-control): A dedicated bridge process that spawns child claude processes for each remote session
  • In-REPL (/remote-control): Runs within an existing interactive claude session, making it remotely accessible

2. Feature Gating

Feature Flag Check

// cli.js:456447
function isBridgeEnabled() {
  // Checks the "tengu_ccr_bridge" feature flag, defaults to false
  return getFeatureFlag("tengu_ccr_bridge", false);
}

Skill Registration Guard

// cli.js:511920
function isRemoteControlEnabled() {
  return isBridgeEnabled() && isPolicyAllowed("allow_remote_sessions");
}

Constants

// cli.js:511600-511612
var BRIDGE_MAX_LIFETIME_MS = 86400000;      // 24 hours
var DEFAULT_SESSION_TIMEOUT_MS = 86400000;   // 24 hours

var BRIDGE_LOGIN_INSTRUCTION =
  "Remote Control is only available with claude.ai subscriptions. " +
  "Please use `/login` to sign in with your claude.ai account.";

var BRIDGE_LOGIN_ERROR =
  "Error: You must be logged in to use Remote Control.\n\n" +
  "Remote Control is only available with claude.ai subscriptions. " +
  "Please use `/login` to sign in with your claude.ai account.";

3. Entry Points

A. CLI Subcommand Entry

// cli.js:592883-592915
// Accepts multiple aliases for the subcommand
if (
  args[0] === "remote-control" ||
  args[0] === "rc" ||
  args[0] === "remote" ||
  args[0] === "sync" ||
  args[0] === "bridge"
) {
  trackEvent("cli_bridge_path");

  // Load and validate configs
  const { enableConfigs } = await import("configs");
  enableConfigs();

  const { isBridgeEnabled } = await import("bridge-flags");
  const { BRIDGE_LOGIN_ERROR } = await import("bridge-constants");
  const { bridgeMain } = await import("bridge-main");
  const { getClaudeAIOAuthTokens } = await import("oauth");

  // Must be logged in
  if (!getClaudeAIOAuthTokens()?.accessToken) {
    console.error(BRIDGE_LOGIN_ERROR);
    process.exit(1);
  }

  // Must have feature flag
  if (!isBridgeEnabled()) {
    console.error(
      "Error: Remote Control is not enabled for your account. Contact your administrator."
    );
    process.exit(1);
  }

  // Must pass org policy
  const { waitForPolicyLimitsToLoad, isPolicyAllowed } = await import("policy");
  await waitForPolicyLimitsToLoad();
  if (!isPolicyAllowed("allow_remote_sessions")) {
    console.error(
      "Error: Remote Control sessions are disabled by your organization's policy."
    );
    process.exit(1);
  }

  await bridgeMain(args.slice(1));
  return;
}

B. Slash Command Registration

// cli.js:511924-511943
var remoteControlCommand = {
  type: "local-jsx",
  name: "remote-control",
  aliases: ["rc"],
  description: "Connect this terminal for remote-control sessions",
  isEnabled: isRemoteControlEnabled,
  get isHidden() {
    return !isRemoteControlEnabled();
  },
  immediate: true, // executes immediately, no further prompt needed
  load: () => import("./remote-control-call"),
  userFacingName() {
    return "remote-control";
  },
};

C. Environment Kind Detection

// cli.js:590557-590558
// When running as a bridge child process, set the entrypoint type
if (process.env.CLAUDE_CODE_ENVIRONMENT_KIND === "bridge") {
  setEntrypoint("remote-control");
}

4. API Client

Factory Function

// cli.js:535875-536068
function createBridgeApiClient({ baseUrl, getAccessToken, runnerVersion, onDebug }) {
  function log(msg) {
    onDebug?.(msg);
  }

  let emptyPollCount = 0;
  const LOG_EVERY_N_POLLS = 100;

  function makeHeaders(accessToken) {
    return {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json",
      "anthropic-version": "2023-06-01",
      "anthropic-beta": "environments-2025-11-01",
      "x-environment-runner-version": runnerVersion,
    };
  }

  function requireToken() {
    const token = getAccessToken();
    if (!token) throw Error(BRIDGE_LOGIN_INSTRUCTION);
    return token;
  }

  // Auto-refresh on 401
  async function withTokenRefresh(requestFn, label) {
    let token = requireToken();
    let response = await requestFn(token);
    if (response.status !== 401) return response;

    log(`[bridge:api] ${label}: 401 received, attempting token refresh`);
    if (await refreshOAuthToken(token)) {
      log(`[bridge:api] ${label}: Token refreshed, retrying request`);
      const newToken = requireToken();
      const retryResponse = await requestFn(newToken);
      if (retryResponse.status !== 401) return retryResponse;
      log(`[bridge:api] ${label}: Retry after refresh also got 401`);
    } else {
      log(`[bridge:api] ${label}: Token refresh failed`);
    }
    return response;
  }

  return {
    // Register this bridge environment with the server
    async registerBridgeEnvironment(config) {
      log(`[bridge:api] POST /v1/environments/bridge bridgeId=${config.bridgeId}`);
      const response = await withTokenRefresh(
        (token) =>
          axios.post(
            `${baseUrl}/v1/environments/bridge`,
            {
              machine_name: config.machineName,
              directory: config.dir,
              branch: config.branch,
              git_repo_url: config.gitRepoUrl,
            },
            { headers: makeHeaders(token), timeout: 15000, validateStatus: (s) => s < 500 }
          ),
        "Registration"
      );
      validateResponse(response.status, response.data, "Registration");
      return response.data; // { environment_id, environment_secret }
    },

    // Long-poll for work items (sessions to handle)
    async pollForWork(environmentId, environmentSecret, signal) {
      validateParam(environmentId, "environmentId");
      let prevCount = emptyPollCount;
      emptyPollCount = 0;

      const response = await axios.get(
        `${baseUrl}/v1/environments/${environmentId}/work/poll`,
        {
          headers: makeHeaders(environmentSecret),
          params: { block_ms: 900, ack: true },
          timeout: 10000,
          signal,
          validateStatus: (s) => s < 500,
        }
      );

      validateResponse(response.status, response.data, "Poll");

      if (!response.data) {
        emptyPollCount = prevCount + 1;
        if (emptyPollCount === 1 || emptyPollCount % LOG_EVERY_N_POLLS === 0) {
          log(`[bridge:api] GET .../work/poll -> ${response.status} (no work, ${emptyPollCount} consecutive empty polls)`);
        }
        return null;
      }

      log(`[bridge:api] GET .../work/poll -> ${response.status} workId=${response.data.id} type=${response.data.data?.type}`);
      return response.data;
    },

    // Acknowledge receipt of work
    async acknowledgeWork(environmentId, workId, token) {
      validateParam(environmentId, "environmentId");
      validateParam(workId, "workId");
      const response = await axios.post(
        `${baseUrl}/v1/environments/${environmentId}/work/${workId}/ack`,
        {},
        { headers: makeHeaders(token), timeout: 10000, validateStatus: (s) => s < 500 }
      );
      validateResponse(response.status, response.data, "Acknowledge");
    },

    // Stop a work item
    async stopWork(environmentId, workId, force) {
      validateParam(environmentId, "environmentId");
      validateParam(workId, "workId");
      const response = await withTokenRefresh(
        (token) =>
          axios.post(
            `${baseUrl}/v1/environments/${environmentId}/work/${workId}/stop`,
            { force },
            { headers: makeHeaders(token), timeout: 10000, validateStatus: (s) => s < 500 }
          ),
        "StopWork"
      );
      validateResponse(response.status, response.data, "StopWork");
    },

    // Deregister environment on shutdown
    async deregisterEnvironment(environmentId) {
      validateParam(environmentId, "environmentId");
      const response = await withTokenRefresh(
        (token) =>
          axios.delete(`${baseUrl}/v1/environments/bridge/${environmentId}`, {
            headers: makeHeaders(token),
            timeout: 10000,
            validateStatus: (s) => s < 500,
          }),
        "Deregister"
      );
      validateResponse(response.status, response.data, "Deregister");
    },

    // Retrieve session details (e.g., to get the title)
    async getSession(sessionId) {
      validateParam(sessionId, "sessionId");
      const response = await withTokenRefresh(
        (token) =>
          axios.get(`${baseUrl}/v1/sessions/${sessionId}`, {
            headers: makeHeaders(token),
            timeout: 10000,
            validateStatus: (s) => s < 500,
          }),
        "GetSession"
      );
      validateResponse(response.status, response.data, "GetSession");
      return response.data;
    },

    // Archive a completed session
    async archiveSession(sessionId) {
      validateParam(sessionId, "sessionId");
      const response = await withTokenRefresh(
        (token) =>
          axios.post(
            `${baseUrl}/v1/sessions/${sessionId}/archive`,
            {},
            { headers: makeHeaders(token), timeout: 10000, validateStatus: (s) => s < 500 }
          ),
        "ArchiveSession"
      );
      if (response.status === 409) return; // already archived
      validateResponse(response.status, response.data, "ArchiveSession");
    },

    // Send permission response events back to a session
    async sendPermissionResponseEvent(sessionId, event, token) {
      validateParam(sessionId, "sessionId");
      const response = await axios.post(
        `${baseUrl}/v1/sessions/${sessionId}/events`,
        { events: [event] },
        {
          headers: {
            Authorization: `Bearer ${token}`,
            "Content-Type": "application/json",
            "anthropic-version": "2023-06-01",
            "anthropic-beta": "environments-2025-11-01",
          },
          timeout: 10000,
          validateStatus: (s) => s < 500,
        }
      );
      validateResponse(response.status, response.data, "SendPermissionResponseEvent");
    },
  };
}

Response Validation

// cli.js:536070-536157
function validateResponse(status, data, label) {
  if (status === 200) return;

  const message = extractMessage(data);
  const errorType = extractErrorType(data);

  switch (status) {
    case 401:
      throw new BridgeFatalError(
        `${label}: Authentication failed (401)${message ? `: ${message}` : ""}. ${BRIDGE_LOGIN_INSTRUCTION}`,
        401, errorType
      );
    case 403:
      throw new BridgeFatalError(
        isExpiredError(errorType)
          ? "Remote Control session has expired. Please restart with `claude remote-control` or /remote-control."
          : `${label}: Access denied (403)${message ? `: ${message}` : ""}. Check your organization permissions.`,
        403, errorType
      );
    case 404:
      throw new BridgeFatalError(
        message ?? `${label}: Not found (404). Remote Control may not be available for this organization.`,
        404, errorType
      );
    case 410:
      throw new BridgeFatalError(
        message ?? "Remote Control session has expired. Please restart with `claude remote-control` or /remote-control.",
        410, errorType ?? "environment_expired"
      );
    case 429:
      throw Error(`${label}: Rate limited (429). Polling too frequently.`);
    default:
      throw Error(`${label}: Failed with status ${status}${message ? `: ${message}` : ""}`);
  }
}

function isExpiredError(errorType) {
  if (!errorType) return false;
  return errorType.includes("expired") || errorType.includes("lifetime");
}

function extractErrorType(data) {
  if (data && typeof data === "object") {
    if ("error" in data && data.error && typeof data.error === "object" &&
        "type" in data.error && typeof data.error.type === "string")
      return data.error.type;
  }
  return undefined;
}

function extractMessage(data) {
  if (data && typeof data === "object") {
    if ("message" in data && typeof data.message === "string") return data.message;
    if ("error" in data && data.error && typeof data.error === "object" &&
        "message" in data.error && typeof data.error.message === "string")
      return data.error.message;
  }
  return undefined;
}

class BridgeFatalError extends Error {
  status;
  errorType;
  constructor(message, status, errorType) {
    super(message);
    this.name = "BridgeFatalError";
    this.status = status;
    this.errorType = errorType;
  }
}

5. Standalone Bridge Flow

// cli.js:537500-537789 (simplified / reconstructed)
function parseBridgeArgs(args) {
  let verbose = false, sandbox = false, debugFile, sessionTimeoutMs, help = false;
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (arg === "--help" || arg === "-h") help = true;
    else if (arg === "--verbose" || arg === "-v") verbose = true;
    else if (arg === "--sandbox") sandbox = true;
    else if (arg === "--no-sandbox") sandbox = false;
    else if (arg === "--debug-file" && i + 1 < args.length) debugFile = resolve(args[++i]);
    else if (arg.startsWith("--debug-file=")) debugFile = resolve(arg.slice(13));
    else if (arg === "--session-timeout" && i + 1 < args.length)
      sessionTimeoutMs = parseInt(args[++i], 10) * 1000;
    else if (arg.startsWith("--session-timeout="))
      sessionTimeoutMs = parseInt(arg.slice(18), 10) * 1000;
  }
  return { verbose, sandbox, debugFile, sessionTimeoutMs, help };
}

function printHelp() {
  console.log(`
Remote Control - Connect your local environment to claude.ai/code

USAGE
  claude remote-control

DESCRIPTION
  Remote Control allows you to control sessions on your local device from
  claude.ai/code (https://claude.ai/code). Run this command in the
  directory you want to work in, then connect from the Claude app or web.

NOTES
  - You must be logged in with a Claude account that has a subscription
  - Run \`claude\` first in the directory to accept the workspace trust dialog
`);
}

async function bridgeMain(args) {
  const { verbose, sandbox, debugFile, sessionTimeoutMs, help } = parseBridgeArgs(args);
  if (help) { printHelp(); return; }

  const cwd = resolve(".");

  // 1. Enable configs and check workspace trust
  const { enableConfigs, checkHasTrustDialogAccepted } = await import("configs");
  enableConfigs();
  if (!checkHasTrustDialogAccepted(false)) {
    console.error(`Error: Workspace not trusted. Please run \`claude\` in ${cwd} first.`);
    process.exit(1);
  }

  // 2. Initialize error logging and analytics
  const { initializeErrorLogSink } = await import("error-log");
  const { initializeAnalyticsSink } = await import("analytics");
  initializeErrorLogSink();
  initializeAnalyticsSink();

  // 3. Set working directory state
  const { setOriginalCwd, setCwdState } = await import("cwd");
  setOriginalCwd(cwd);
  setCwdState(cwd);

  // 4. Validate OAuth
  const { getClaudeAIOAuthTokens, clearOAuthTokenCache, checkAndRefreshOAuthTokenIfNeeded } =
    await import("oauth");
  if (!getClaudeAIOAuthTokens()?.accessToken) {
    console.error(BRIDGE_LOGIN_ERROR);
    process.exit(1);
  }

  // 5. First-run consent dialog
  const { getGlobalConfig, saveGlobalConfig } = await import("configs");
  if (!getGlobalConfig().remoteDialogSeen) {
    const rl = createInterface({ input: process.stdin, output: process.stdout });
    console.log(`
Remote Control lets you access this CLI session from the web (claude.ai/code)
or the Claude app, so you can pick up where you left off on any device.

You can disconnect remote access anytime by running /remote-control again.
`);
    const answer = await new Promise((resolve) => {
      rl.question("Enable Remote Control? (y/n) ", resolve);
    });
    rl.close();
    saveGlobalConfig((cfg) => {
      if (cfg.remoteDialogSeen) return cfg;
      return { ...cfg, remoteDialogSeen: true };
    });
    if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
      process.exit(0);
    }
  }

  // 6. Security: reject non-HTTPS (except localhost)
  const apiBaseUrl = getOauthConfig().BASE_API_URL;
  if (apiBaseUrl.startsWith("http://") &&
      !apiBaseUrl.includes("localhost") &&
      !apiBaseUrl.includes("127.0.0.1")) {
    console.error("Error: Remote Control base URL uses HTTP. Only HTTPS or localhost HTTP is allowed.");
    process.exit(1);
  }

  // 7. Gather git info
  const branch = await getBranch();
  const gitRepoUrl = await getRemoteUrl();
  const machineName = getMachineName();
  const bridgeId = randomUUID();

  const config = {
    dir: cwd,
    machineName,
    branch,
    gitRepoUrl,
    maxSessions: 1,
    verbose,
    sandbox,
    bridgeId,
    environmentId: randomUUID(),
    apiBaseUrl,
    sessionIngressUrl: apiBaseUrl,
    debugFile,
    sessionTimeoutMs,
  };

  // 8. Create API client
  const apiClient = createBridgeApiClient({
    baseUrl: apiBaseUrl,
    getAccessToken: () => getClaudeAIOAuthTokens()?.accessToken,
    runnerVersion: "2.1.52",
    onDebug: debug,
  });

  // 9. Register environment
  let environmentId, environmentSecret;
  try {
    const result = await apiClient.registerBridgeEnvironment(config);
    environmentId = result.environment_id;
    environmentSecret = result.environment_secret;
  } catch (err) {
    trackEvent("tengu_bridge_registration_failed", {
      status: err instanceof BridgeFatalError ? err.status : undefined,
    });
    console.error(
      err instanceof BridgeFatalError && err.status === 404
        ? "Remote Control environments are not available for your account."
        : `Error: ${err instanceof Error ? err.message : String(err)}`
    );
    process.exit(1);
  }

  // 10. Create session spawner and status display
  const sessionSpawner = createSessionSpawner({
    execPath: process.execPath,
    env: process.env,
    verbose,
    sandbox,
    debugFile,
    onDebug: debug,
    onActivity: (sessionId, activity) => { /* ... */ },
    onPermissionRequest: (sessionId, request, token) => { /* ... */ },
  });
  const statusDisplay = createStatusDisplay({ verbose });

  // 11. Create initial session
  let initialSessionId = null;
  try {
    initialSessionId = await createBridgeSession({
      environmentId,
      title: "Remote Control session",
      events: [],
      gitRepoUrl,
      branch,
      signal: abortController.signal,
    });
  } catch (err) {
    debug(`[bridge:init] Session creation failed (non-fatal): ${err.message}`);
  }

  // 12. Set up signal handlers
  const abortController = new AbortController();
  const onSigInt = () => { debug("[bridge:shutdown] SIGINT received"); abortController.abort(); };
  const onSigTerm = () => { debug("[bridge:shutdown] SIGTERM received"); abortController.abort(); };
  process.on("SIGINT", onSigInt);
  process.on("SIGTERM", onSigTerm);

  // 13. Set up stdin for raw key input (Ctrl+C, Space=toggle QR)
  const onKeyPress = (data) => {
    if (data[0] === 3 || data[0] === 4) { process.emit("SIGINT"); return; }
    if (data[0] === 32) statusDisplay.toggleQr();
  };
  if (process.stdin.isTTY) {
    process.stdin.setRawMode(true);
    process.stdin.resume();
    process.stdin.on("data", onKeyPress);
  }

  // 14. Enter main poll loop
  try {
    await mainPollLoop(
      config,
      environmentId,
      environmentSecret,
      apiClient,
      sessionSpawner,
      statusDisplay,
      abortController.signal,
      undefined, // backoff config (uses defaults)
      Infinity,  // max lifetime
      initialSessionId,
      async () => {
        clearOAuthTokenCache();
        await checkAndRefreshOAuthTokenIfNeeded();
        return getClaudeAIOAuthTokens()?.accessToken;
      }
    );
  } finally {
    // Cleanup
    process.off("SIGINT", onSigInt);
    process.off("SIGTERM", onSigTerm);
    process.stdin.off("data", onKeyPress);
    if (process.stdin.isTTY) process.stdin.setRawMode(false);
    process.stdin.pause();
  }

  process.exit(0);
}

6. Main Poll Loop

// cli.js:537065-537380 (reconstructed)

// Backoff configuration defaults
const BACKOFF_DEFAULTS = {
  connInitialMs: 2000,
  connCapMs: 120000,       // 2 minutes max between connection retries
  connGiveUpMs: 600000,    // 10 minutes before giving up on connection
  generalInitialMs: 500,
  generalCapMs: 30000,     // 30 seconds max between general retries
  generalGiveUpMs: 600000, // 10 minutes before giving up on general errors
};

const RETRYABLE_ERRORS = new Set([
  "ECONNREFUSED", "ECONNRESET", "ETIMEDOUT", "ENETUNREACH", "EHOSTUNREACH",
]);

async function mainPollLoop(
  config,           // { dir, maxSessions, sandbox, verbose, ... }
  environmentId,
  environmentSecret,
  apiClient,
  sessionSpawner,
  statusDisplay,
  signal,
  backoff = BACKOFF_DEFAULTS,
  maxLifetimeMs = BRIDGE_MAX_LIFETIME_MS,
  initialSessionId,
  refreshTokenFn
) {
  const localAbort = new AbortController();
  if (signal.aborted) localAbort.abort();
  else signal.addEventListener("abort", () => localAbort.abort(), { once: true });

  const localSignal = localAbort.signal;
  const activeSessions = new Map();   // sessionId -> spawned process handle
  const sessionStartTimes = new Map(); // sessionId -> timestamp
  const sessionWorkIds = new Map();    // sessionId -> workId
  const sessionTimeouts = new Map();   // sessionId -> timeout handle
  const completedWorkIds = new Set();

  // Token refresh scheduler (refreshes access tokens for active sessions)
  const tokenRefresher = refreshTokenFn
    ? createTokenRefreshScheduler({
        getAccessToken: refreshTokenFn,
        onRefresh: (sessionId, newToken) => {
          const session = activeSessions.get(sessionId);
          if (session) session.updateAccessToken(newToken);
        },
        label: "bridge",
      })
    : null;

  const loopStartTime = Date.now();

  // Reconnection state
  let connBackoff = 0, generalBackoff = 0;
  let connErrorStart = null, generalErrorStart = null;
  let lastPollTime = null;

  // Status update interval
  let statusInterval = null;

  statusDisplay.printBanner(config, environmentId);
  if (initialSessionId) statusDisplay.setAttached(initialSessionId);

  function updateStatus() {
    if (activeSessions.size === 0) {
      statusDisplay.updateIdleStatus();
      return;
    }
    const [sessionId, handle] = [...activeSessions.entries()].pop();
    const startTime = sessionStartTimes.get(sessionId);
    if (!startTime) return;
    const currentActivity = handle.currentActivity;
    if (!currentActivity || currentActivity.type === "result" || currentActivity.type === "error") return;
    const elapsed = formatDuration(Date.now() - startTime);
    const recentTools = handle.activities
      .filter((a) => a.type === "tool_start")
      .slice(-5)
      .map((a) => a.summary);
    statusDisplay.updateSessionStatus(sessionId, elapsed, currentActivity, recentTools);
  }

  function startStatusUpdates() {
    stopStatusUpdates();
    updateStatus();
    statusInterval = setInterval(updateStatus, 1000);
  }

  function stopStatusUpdates() {
    if (statusInterval) { clearInterval(statusInterval); statusInterval = null; }
  }

  // Session exit handler factory
  function onSessionExit(sessionId, startTime, handle) {
    return (exitStatus) => {
      const workId = sessionWorkIds.get(sessionId);
      activeSessions.delete(sessionId);
      sessionStartTimes.delete(sessionId);
      sessionWorkIds.delete(sessionId);

      const timeout = sessionTimeouts.get(sessionId);
      if (timeout) { clearTimeout(timeout); sessionTimeouts.delete(sessionId); }
      tokenRefresher?.cancel(sessionId);

      const duration = Date.now() - startTime;
      debug(`[bridge:session] sessionId=${sessionId} exited status=${exitStatus} duration=${formatDuration(duration)}`);
      trackEvent("tengu_bridge_session_done", { status: exitStatus, duration_ms: duration });

      statusDisplay.clearStatus();
      stopStatusUpdates();

      const stderr = handle.lastStderr.length > 0 ? handle.lastStderr.join("\n") : undefined;

      switch (exitStatus) {
        case "completed":
          statusDisplay.logSessionComplete(sessionId, duration);
          statusDisplay.logStatus(`To reconnect: claude --resume ${sessionId}`);
          break;
        case "failed":
          const errorMsg = stderr ?? "Process exited with error";
          statusDisplay.logSessionFailed(sessionId, errorMsg);
          statusDisplay.logStatus(`To reconnect: claude --resume ${sessionId}`);
          break;
        case "interrupted":
          statusDisplay.logVerbose(`Session ${sessionId} interrupted`);
          break;
      }

      // Archive session and track completed work
      if (exitStatus !== "interrupted" && workId) {
        pollSessionTitle(apiClient, sessionId, statusDisplay, activeSessions);
        completedWorkIds.add(workId);
      }

      // If session ended non-interruptedly, abort loop to tear down environment
      if (exitStatus !== "interrupted" && !localSignal.aborted) {
        debug("[bridge:session] Session ended, aborting poll loop to tear down environment");
        localAbort.abort();
        return;
      }

      // All sessions done, go back to idle
      if (activeSessions.size === 0 && !localSignal.aborted) {
        debug("[bridge:work] All sessions finished, transitioning to idle");
        startStatusUpdates();
      }
    };
  }

  // Start idle status if no initial session
  if (!initialSessionId) startStatusUpdates();

  // ═══════════════════════ MAIN LOOP ═══════════════════════
  while (!localSignal.aborted) {
    // Check max lifetime
    if (maxLifetimeMs !== Infinity && Date.now() - loopStartTime >= maxLifetimeMs) {
      statusDisplay.logStatus("Maximum runtime reached, shutting down…");
      break;
    }

    const AT_CAPACITY_DELAY = 30000;

    try {
      // Long-poll for work
      const work = await apiClient.pollForWork(environmentId, environmentSecret, localSignal);

      // On successful poll, reset all error state
      if (connErrorStart !== null || generalErrorStart !== null) {
        const disconnectedMs = Date.now() - (connErrorStart ?? generalErrorStart ?? Date.now());
        statusDisplay.logReconnected(disconnectedMs);
        trackEvent("tengu_bridge_reconnected", { disconnected_ms: disconnectedMs });
      }
      connBackoff = 0; generalBackoff = 0;
      connErrorStart = null; generalErrorStart = null;
      lastPollTime = null;

      // No work available
      if (!work) {
        await sleep(activeSessions.size >= config.maxSessions ? AT_CAPACITY_DELAY : 1000, localSignal);
        continue;
      }

      // At capacity
      if (activeSessions.size >= config.maxSessions) {
        debug(`[bridge:work] At capacity (${activeSessions.size}/${config.maxSessions}), skipping`);
        await sleep(AT_CAPACITY_DELAY, localSignal);
        continue;
      }

      // Already completed this work
      if (completedWorkIds.has(work.id)) {
        debug(`[bridge:work] Skipping already-completed workId=${work.id}`);
        await sleep(1000, localSignal);
        continue;
      }

      // Decode work secret (contains session_ingress_token)
      let workSecret;
      try {
        workSecret = decodeWorkSecret(work.secret);
      } catch (err) {
        statusDisplay.logError(`Failed to decode work secret for workId=${work.id}: ${err.message}`);
        trackEvent("tengu_bridge_work_secret_failed", {});
        continue;
      }

      // Handle work by type
      switch (work.data.type) {
        case "healthcheck":
          debug("[bridge:work] Healthcheck received");
          break;

        case "session": {
          const sessionId = work.data.id;
          validateParam(sessionId, "session_id");

          // Token update for existing session
          const existing = activeSessions.get(sessionId);
          if (existing) {
            existing.updateAccessToken(workSecret.session_ingress_token);
            tokenRefresher?.schedule(sessionId, workSecret.session_ingress_token);
            debug(`[bridge:work] Updated access token for existing sessionId=${sessionId}`);
            break;
          }

          // Reject if a different session is active
          if (activeSessions.size > 0) {
            debug(`[bridge:work] Rejecting foreign sessionId=${sessionId} while other sessions active`);
            break;
          }

          // Build the SDK URL for the child process
          const sdkUrl = buildSessionIngressUrl(config.sessionIngressUrl, sessionId);

          debug(`[bridge:session] Spawning sessionId=${sessionId} sdkUrl=${sdkUrl}`);
          trackEvent("tengu_bridge_session_started", { active_sessions: activeSessions.size });

          // Spawn child claude process
          const handle = sessionSpawner.spawn(
            { sessionId, sdkUrl, accessToken: workSecret.session_ingress_token },
            config.dir
          );

          activeSessions.set(sessionId, handle);
          sessionWorkIds.set(sessionId, work.id);
          const startTime = Date.now();
          sessionStartTimes.set(sessionId, startTime);

          statusDisplay.logSessionStart(sessionId, `Session ${sessionId}`);
          startStatusUpdates();
          statusDisplay.setAttached(sessionId);

          // Poll for session title asynchronously
          pollSessionTitle(apiClient, sessionId, statusDisplay, activeSessions);

          // Set session timeout
          const timeoutMs = config.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
          if (timeoutMs > 0) {
            const timer = setTimeout(() => {
              debug(`[bridge:session] sessionId=${sessionId} timed out after ${formatDuration(timeoutMs)}`);
              trackEvent("tengu_bridge_session_timeout", { timeout_ms: timeoutMs });
              statusDisplay.logSessionFailed(sessionId, `Session timed out after ${formatDuration(timeoutMs)}`);
              handle.kill();
            }, timeoutMs);
            sessionTimeouts.set(sessionId, timer);
          }

          // Schedule token refresh and set up exit handler
          tokenRefresher?.schedule(sessionId, workSecret.session_ingress_token);
          handle.done.then(onSessionExit(sessionId, startTime, handle));
          break;
        }

        default:
          debug(`[bridge:work] Unknown work type: ${work.data.type}, skipping`);
          break;
      }

    } catch (err) {
      if (localSignal.aborted) break;

      if (err instanceof BridgeFatalError) {
        if (isExpiredError(err.errorType)) statusDisplay.logStatus(err.message);
        else statusDisplay.logError(err.message);
        trackEvent("tengu_bridge_fatal_error", { status: err.status, error_type: err.errorType });
        break;
      }

      const errMsg = extractErrorMessage(err);
      const now = Date.now();

      // Detect system sleep (large time gap)
      if (lastPollTime !== null && now - lastPollTime > getSleepThreshold(backoff)) {
        debug(`[bridge:work] Detected system sleep, resetting error budget`);
        connErrorStart = null; connBackoff = 0;
        generalErrorStart = null; generalBackoff = 0;
      }
      lastPollTime = now;

      if (isConnectionError(err) || isTimeoutError(err)) {
        // Connection error: exponential backoff with separate budget
        if (!connErrorStart) connErrorStart = now;
        const elapsed = now - connErrorStart;

        if (elapsed >= backoff.connGiveUpMs) {
          statusDisplay.logError(`Server unreachable for ${Math.round(elapsed / 60000)} minutes, giving up.`);
          trackEvent("tengu_bridge_poll_give_up", { error_type: "connection", elapsed_ms: elapsed });
          break;
        }

        generalErrorStart = null; generalBackoff = 0;
        connBackoff = connBackoff ? Math.min(connBackoff * 2, backoff.connCapMs) : backoff.connInitialMs;
        const delay = addJitter(connBackoff);

        statusDisplay.updateReconnectingStatus(formatMs(delay), formatDuration(elapsed));
        await sleep(delay, localSignal);

      } else {
        // General error: separate exponential backoff budget
        if (!generalErrorStart) generalErrorStart = now;
        const elapsed = now - generalErrorStart;

        if (elapsed >= backoff.generalGiveUpMs) {
          statusDisplay.logError(`Persistent errors for ${Math.round(elapsed / 60000)} minutes, giving up.`);
          trackEvent("tengu_bridge_poll_give_up", { error_type: "general", elapsed_ms: elapsed });
          break;
        }

        connErrorStart = null; connBackoff = 0;
        generalBackoff = generalBackoff ? Math.min(generalBackoff * 2, backoff.generalCapMs) : backoff.generalInitialMs;
        const delay = addJitter(generalBackoff);

        statusDisplay.updateReconnectingStatus(formatMs(delay), formatDuration(elapsed));
        await sleep(delay, localSignal);
      }
    }
  }

  // ═══════════════════════ SHUTDOWN ═══════════════════════
  stopStatusUpdates();
  statusDisplay.clearStatus();

  const totalDuration = Date.now() - loopStartTime;
  trackEvent("tengu_bridge_shutdown", { active_sessions: activeSessions.size, loop_duration_ms: totalDuration });

  // Kill remaining active sessions
  if (activeSessions.size > 0) {
    debug(`[bridge:shutdown] Shutting down ${activeSessions.size} active session(s)`);
    // ... graceful shutdown of child processes, then deregister environment
  }
}

// Cancellable sleep helper
function sleep(ms, signal) {
  if (signal?.aborted) return Promise.resolve();
  return new Promise((resolve) => {
    const timer = setTimeout(resolve, ms);
    if (signal) {
      signal.addEventListener("abort", () => { clearTimeout(timer); resolve(); }, { once: true });
    }
  });
}

7. Session Spawner

// cli.js:536242-536410 (reconstructed)
import { spawn } from "child_process";
import { createInterface } from "readline";
import { createWriteStream } from "fs";
import { tmpdir } from "os";
import { join, dirname } from "path";

function sanitizeId(id) {
  return id.replace(/[^a-zA-Z0-9_-]/g, "_");
}

function createSessionSpawner(options) {
  // options: { execPath, env, verbose, sandbox, debugFile, onDebug, onActivity, onPermissionRequest }

  return {
    spawn(sessionInfo, cwd) {
      // sessionInfo: { sessionId, sdkUrl, accessToken }
      const safeId = sanitizeId(sessionInfo.sessionId);

      // Determine debug log file path
      let debugLogFile;
      if (options.debugFile) {
        const dotIdx = options.debugFile.lastIndexOf(".");
        debugLogFile = dotIdx > 0
          ? `${options.debugFile.slice(0, dotIdx)}-${safeId}${options.debugFile.slice(dotIdx)}`
          : `${options.debugFile}-${safeId}`;
      } else if (options.verbose) {
        debugLogFile = join(tmpdir(), "claude", `bridge-session-${safeId}.log`);
      }

      // Build child process arguments
      const childArgs = [
        "--print",
        "--sdk-url", sessionInfo.sdkUrl,
        "--session-id", sessionInfo.sessionId,
        "--input-format", "stream-json",
        "--output-format", "stream-json",
        "--replay-user-messages",
        ...(options.verbose ? ["--verbose"] : []),
        ...(debugLogFile ? ["--debug-file", debugLogFile] : []),
      ];

      // Environment variables for the child
      const childEnv = {
        ...options.env,
        CLAUDE_CODE_OAUTH_TOKEN: undefined,
        CLAUDE_CODE_ENVIRONMENT_KIND: "bridge",
        ...(options.sandbox && { CLAUDE_CODE_FORCE_SANDBOX: "1" }),
        CLAUDE_CODE_SESSION_ACCESS_TOKEN: sessionInfo.accessToken,
        CLAUDE_CODE_POST_FOR_SESSION_INGRESS_V2: "1",
      };

      options.onDebug(
        `[bridge:session] Spawning sessionId=${sessionInfo.sessionId} sdkUrl=${sessionInfo.sdkUrl}`
      );

      // Spawn the child claude process
      const child = spawn(options.execPath, childArgs, {
        cwd,
        stdio: ["pipe", "pipe", "pipe"],
        env: childEnv,
        windowsHide: true,
      });

      const activities = [];
      let currentActivity = null;
      const lastStderr = [];

      // Read stderr for debug output
      if (child.stderr) {
        createInterface({ input: child.stderr }).on("line", (line) => {
          if (options.verbose) process.stderr.write(line + "\n");
          if (lastStderr.length >= 50) lastStderr.shift();
          lastStderr.push(line);
        });
      }

      // Read stdout for structured session output (stream-json)
      if (child.stdout) {
        createInterface({ input: child.stdout }).on("line", (line) => {
          // Parse activity events from JSON lines
          const events = parseActivityEvents(line, sessionInfo.sessionId, options.onDebug);
          for (const event of events) {
            if (activities.length >= 100) activities.shift();
            activities.push(event);
            currentActivity = event;
            options.onActivity?.(sessionInfo.sessionId, event);
          }

          // Handle control requests (permission, interrupt)
          let parsed;
          try { parsed = JSON.parse(line); } catch {}
          if (parsed && typeof parsed === "object" && parsed.type === "control_request") {
            const request = parsed.request;
            if (request?.subtype === "can_use_tool" && options.onPermissionRequest) {
              options.onPermissionRequest(sessionInfo.sessionId, parsed, sessionInfo.accessToken);
            } else if (request?.subtype === "interrupt") {
              if (!child.killed) {
                options.onDebug(`[bridge:session] Interrupt received, killing child pid=${child.pid}`);
                child.kill(process.platform === "win32" ? undefined : "SIGTERM");
              }
            }
          }
        });
      }

      // Promise that resolves when the child exits
      const done = new Promise((resolve) => {
        child.on("close", (code, signal) => {
          if (code === 0 || code === null) resolve("completed");
          else resolve("failed");
        });
      });

      return {
        activities,
        get currentActivity() { return currentActivity; },
        lastStderr,
        done,
        kill() { child.kill(); },
        updateAccessToken(token) {
          // Write new token to child's stdin
          child.stdin?.write(JSON.stringify({ type: "token_update", token }) + "\n");
        },
      };
    },
  };
}

8. In-REPL Bridge

// cli.js:558482-559011 (reconstructed, key logic)

async function initReplBridge(options) {
  const {
    onInboundMessage,
    onPermissionResponse,
    onInterrupt,
    onSetModel,
    onSetMaxThinkingTokens,
    onStateChange,
    initialMessages,
    previouslyFlushedUUIDs,
  } = options ?? {};

  // ---- Gate checks ----
  if (!isBridgeEnabled()) return null;
  await loadPolicies();
  if (!isPolicyAllowed("allow_remote_sessions")) return null;
  if (!getOAuthTokens()?.accessToken) return null;
  if (!(await getOrgUUID())) return null;

  // ---- Gather environment info ----
  const branch = await getBranch();
  const gitRepoUrl = await getRemoteUrl();
  const apiBaseUrl = getOauthConfig().BASE_API_URL;
  const cwd = getCwd();

  const apiClient = createBridgeApiClient({
    baseUrl: apiBaseUrl,
    getAccessToken: () => getOAuthTokens()?.accessToken,
    runnerVersion: "2.1.52",
    onDebug: debug,
  });

  const config = {
    dir: cwd,
    machineName: hostname(),
    branch,
    gitRepoUrl,
    maxSessions: 1,
    verbose: false,
    sandbox: false,
    bridgeId: randomUUID(),
    environmentId: randomUUID(),
    apiBaseUrl,
    sessionIngressUrl: apiBaseUrl,
  };

  // ---- Register environment ----
  let environmentId, environmentSecret;
  try {
    const result = await apiClient.registerBridgeEnvironment(config);
    environmentId = result.environment_id;
    environmentSecret = result.environment_secret;
  } catch (err) {
    debug(`[bridge:repl] Environment registration failed: ${err.message}`);
    return null;
  }

  // ---- Create session ----
  // Derive title from resume flag or latest user message
  let title = "Interactive session";
  const resumeId = getResumeId();
  if (resumeId) {
    title = getSessionTitle(resumeId) ?? title;
  } else if (initialMessages?.length > 0) {
    const userMsgs = [...initialMessages].reverse().filter((m) => m.type === "user");
    for (const msg of userMsgs) {
      const text = extractTextContent(msg.message.content);
      if (text) {
        const stripped = stripMarkdown(text).trim();
        if (stripped) {
          title = stripped.length > 80 ? stripped.slice(0, 77) + "…" : stripped;
          break;
        }
      }
    }
  }

  const sessionId = await createBridgeSession({
    environmentId,
    title,
    events: [],
    gitRepoUrl,
    branch,
    signal: AbortSignal.timeout(15000),
  });
  if (!sessionId) {
    await apiClient.deregisterEnvironment(environmentId).catch(() => {});
    return null;
  }

  // ---- Set up deduplication ----
  const flushedUUIDs = new Set();
  if (initialMessages) for (const msg of initialMessages) flushedUUIDs.add(msg.uuid);
  const deduper = new LRUSet(2000);
  for (const uuid of flushedUUIDs) deduper.add(uuid);

  // ---- Polling loop + WebSocket transport ----
  const abortController = new AbortController();
  let transport = null;
  let currentWorkId = null;
  let reconnectAttempts = 0;
  const MAX_RECONNECTS = 3;

  const bridgeContext = {
    api: apiClient,
    getCredentials: () => ({ environmentId, environmentSecret }),
    signal: abortController.signal,
    onStateChange,

    // Handle work items from the poll loop
    onWorkReceived: (workSessionId, ingressToken, workId) => {
      if (workSessionId !== sessionId) {
        debug(`[bridge:repl] Rejecting foreign session: expected=${sessionId} got=${workSessionId}`);
        return;
      }

      currentWorkId = workId;
      const oauthToken = getOAuthTokens()?.accessToken;
      if (!oauthToken) return;

      // Close existing transport if any
      if (transport) { transport.close(); transport = null; }

      // Handle control requests from remote
      function handleControlRequest(request) {
        if (!transport) return;
        let response;
        switch (request.request.subtype) {
          case "initialize":
            response = {
              type: "control_response",
              response: {
                subtype: "success",
                request_id: request.request_id,
                response: {
                  commands: [],
                  output_style: "normal",
                  available_output_styles: ["normal"],
                  models: [],
                  account: {},
                  pid: process.pid,
                },
              },
            };
            break;
          case "set_model":
            onSetModel?.(request.request.model);
            response = {
              type: "control_response",
              response: { subtype: "success", request_id: request.request_id },
            };
            break;
          case "set_max_thinking_tokens":
            onSetMaxThinkingTokens?.(request.request.max_thinking_tokens);
            response = {
              type: "control_response",
              response: { subtype: "success", request_id: request.request_id },
            };
            break;
          case "interrupt":
            onInterrupt?.();
            response = {
              type: "control_response",
              response: { subtype: "success", request_id: request.request_id },
            };
            break;
          default:
            response = {
              type: "control_response",
              response: {
                subtype: "error",
                request_id: request.request_id,
                error: `REPL bridge does not handle control_request subtype: ${request.request.subtype}`,
              },
            };
        }
        transport.write({ ...response, session_id: sessionId });
      }

      // Create new HybridTransport (WebSocket + HTTP POST)
      const ingressUrl = buildSessionIngressUrl(apiBaseUrl, workSessionId);
      const newTransport = new HybridTransport(
        new URL(ingressUrl),
        { Authorization: `Bearer ${oauthToken}`, "anthropic-version": "2023-06-01" },
        workSessionId,
        () => ({
          Authorization: `Bearer ${getOAuthTokens()?.accessToken ?? oauthToken}`,
          "anthropic-version": "2023-06-01",
        })
      );

      transport = newTransport;

      // On connect: flush initial messages
      newTransport.setOnConnect(() => {
        if (transport !== newTransport) return;
        debug("[bridge:repl] Ingress transport connected");
        onStateChange?.("connected");

        // Flush initial messages on first connect
        if (initialMessages?.length > 0) {
          const toFlush = convertToTransportFormat(
            initialMessages.filter(
              (m) => (m.type === "user" || m.type === "assistant") && !previouslyFlushedUUIDs?.has(m.uuid)
            )
          );
          if (toFlush.length > 0) {
            debug(`[bridge:repl] Flushing ${toFlush.length} initial message(s)`);
            const tagged = toFlush.map((e) => ({ ...e, session_id: sessionId }));
            newTransport.writeBatch(tagged);
          }
        }
      });

      // On data: forward inbound messages, handle control requests
      newTransport.setOnData((data) => {
        processInboundData(data, deduper, onInboundMessage, onPermissionResponse, handleControlRequest);
      });

      // On close: handle reconnection
      newTransport.setOnClose((code) => {
        if (transport !== newTransport) return;
        transport = null;
        if (code === 1000) {
          onStateChange?.("failed", "Remote Control session ended");
          abortController.abort();
        } else {
          onStateChange?.("reconnecting", `Remote Control connection lost (code ${code})`);
          // Fall back to poll loop for reconnection
          if (currentWorkId) {
            apiClient.stopWork(environmentId, currentWorkId, false).catch(() => {});
          }
        }
      });
    },

    // Re-register environment when lost (e.g., server-side expiry)
    async onEnvironmentLost() {
      reconnectAttempts++;
      if (reconnectAttempts > MAX_RECONNECTS) return null;

      // Close transport, stop current work
      if (transport) { transport.close(); transport = null; }
      if (currentWorkId) {
        await apiClient.stopWork(environmentId, currentWorkId, true).catch(() => {});
        currentWorkId = null;
      }

      // Archive old session & deregister old environment
      await archiveBridgeSession(sessionId).catch(() => {});
      await apiClient.deregisterEnvironment(environmentId).catch(() => {});

      // Re-register
      try {
        const result = await apiClient.registerBridgeEnvironment(config);
        environmentId = result.environment_id;
        environmentSecret = result.environment_secret;
      } catch {
        return null;
      }

      // Re-create session
      const newSessionId = await createBridgeSession({
        environmentId,
        title: getSessionTitle(getResumeId()) ?? title,
        events: [],
        gitRepoUrl,
        branch,
        signal: AbortSignal.timeout(15000),
      });
      if (!newSessionId) return null;

      sessionId = newSessionId;
      reconnectAttempts = 0;
      return { environmentId, environmentSecret };
    },
  };

  // Return teardown function and bridge context
  return {
    teardown: () => {
      abortController.abort();
      if (transport) { transport.close(); transport = null; }
      apiClient.deregisterEnvironment(environmentId).catch(() => {});
    },
    sessionId,
    bridgeContext,
  };
}

9. Transport Layer (HybridTransport)

// cli.js:553160-553239 (reconstructed)

const POST_MAX_RETRIES = 10;
const POST_INITIAL_BACKOFF_MS = 500;
const POST_MAX_BACKOFF_MS = 8000;

// Converts WebSocket URL to HTTP POST URL
function wsUrlToPostUrl(wsUrl) {
  const protocol = wsUrl.protocol === "wss:" ? "https:" : "http:";
  let pathname = wsUrl.pathname;
  pathname = pathname.replace("/ws/", "/session/");
  if (!pathname.endsWith("/events")) {
    pathname = pathname.endsWith("/") ? pathname + "events" : pathname + "/events";
  }
  return `${protocol}//${wsUrl.host}${pathname}${wsUrl.search}`;
}

// HybridTransport extends a base WebSocket transport class
// Adds HTTP POST fallback for reliable event delivery
class HybridTransport extends BaseTransport {
  postUrl;

  constructor(url, headers, sessionId, getHeaders, options) {
    super(url, headers, sessionId, getHeaders, options);
    this.postUrl = wsUrlToPostUrl(url);
    debug(`HybridTransport: POST URL = ${this.postUrl}`);
  }

  // Send a single event via HTTP POST
  async write(event) {
    return this.postEvents([event], event.type);
  }

  // Send multiple events in a batch via HTTP POST
  async writeBatch(events) {
    if (events.length === 0) return;
    return this.postEvents(events, `batch(${events.length})`);
  }

  // Internal POST with retry logic
  async postEvents(events, label) {
    const sessionToken = getSessionToken();
    if (!sessionToken) {
      debug("HybridTransport: No session token available for POST");
      return;
    }

    const headers = {
      Authorization: `Bearer ${sessionToken}`,
      "Content-Type": "application/json",
    };

    for (let attempt = 1; attempt <= POST_MAX_RETRIES; attempt++) {
      try {
        const response = await axios.post(
          this.postUrl,
          { events },
          { headers, validateStatus: () => true }
        );

        if (response.status === 200 || response.status === 201) {
          debug(`HybridTransport: POST success type=${label}`);
          return;
        }

        // Client errors (except 429) are not retryable
        if (response.status >= 400 && response.status < 500 && response.status !== 429) {
          debug(`HybridTransport: POST returned ${response.status} (client error), not retrying`);
          return;
        }

        debug(`HybridTransport: POST returned ${response.status}, attempt ${attempt}/${POST_MAX_RETRIES}`);
      } catch (err) {
        debug(`HybridTransport: POST error: ${err.message}, attempt ${attempt}/${POST_MAX_RETRIES}`);
      }

      if (attempt === POST_MAX_RETRIES) {
        debug(`HybridTransport: POST failed after ${POST_MAX_RETRIES} attempts, continuing`);
        return;
      }

      // Exponential backoff
      const delay = Math.min(POST_INITIAL_BACKOFF_MS * Math.pow(2, attempt - 1), POST_MAX_BACKOFF_MS);
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
}

10. State Management

// cli.js:525393-525402 — Initial state shape
const initialBridgeState = {
  replBridgeEnabled: false,         // Is the bridge feature turned on?
  replBridgeExplicit: false,        // Did the user explicitly enable it (vs auto)?
  replBridgeConnected: false,       // Are we connected to the server?
  replBridgeSessionActive: false,   // Is a remote session actively running?
  replBridgeReconnecting: false,    // Are we attempting to reconnect?
  replBridgeConnectUrl: undefined,  // URL shown to user for connecting
  replBridgeSessionUrl: undefined,  // URL of active session
  replBridgeEnvironmentId: undefined,
  replBridgeSessionId: undefined,
  replBridgeError: undefined,       // Error message if failed
};

// cli.js:591727-591736 — Also initialized in REPL startup
// replBridgeEnabled defaults to `remoteControlAtStartup` config value

// State transitions:
// Enable:     { replBridgeEnabled: true, replBridgeExplicit: true }
// Connected:  { replBridgeConnected: true, replBridgeSessionActive: false, replBridgeConnectUrl, replBridgeSessionUrl, ... }
// Active:     { replBridgeConnected: true, replBridgeSessionActive: true }
// Reconnect:  { replBridgeReconnecting: true, replBridgeSessionActive: false }
// Error:      { replBridgeError: message, replBridgeReconnecting: false, replBridgeSessionActive: false, replBridgeConnected: false }
// Disable:    { replBridgeEnabled: false, replBridgeExplicit: false }
// Reset:      all fields back to initial values

11. Session Activity Tracking

// cli.js:536180-536240 (reconstructed)

// Maps internal tool names to human-readable labels
const TOOL_NAME_MAP = {
  // e.g., "bash" -> "Bash", "read_file" -> "Read", etc.
};

function formatToolSummary(toolName, input) {
  const label = TOOL_NAME_MAP[toolName] ?? toolName;
  const detail =
    input.file_path ??
    input.filePath ??
    input.pattern ??
    input.command?.slice(0, 60) ??
    input.url ??
    input.query ??
    "";
  return detail ? `${label} ${detail}` : label;
}

function parseActivityEvents(jsonLine, sessionId, onDebug) {
  let parsed;
  try { parsed = JSON.parse(jsonLine); } catch { return []; }
  if (!parsed || typeof parsed !== "object") return [];

  const events = [];
  const now = Date.now();

  switch (parsed.type) {
    case "assistant": {
      const content = parsed.message?.content;
      if (!Array.isArray(content)) break;

      for (const block of content) {
        if (!block || typeof block !== "object") continue;

        if (block.type === "tool_use") {
          const name = block.name ?? "Tool";
          const input = block.input ?? {};
          const summary = formatToolSummary(name, input);
          events.push({ type: "tool_start", summary, timestamp: now });
          onDebug(`[bridge:activity] sessionId=${sessionId} tool_use name=${name}`);
        } else if (block.type === "text") {
          const text = block.text ?? "";
          if (text.length > 0) {
            events.push({ type: "text", summary: text.slice(0, 80), timestamp: now });
            onDebug(`[bridge:activity] sessionId=${sessionId} text "${text.slice(0, 100)}"`);
          }
        }
      }
      break;
    }

    case "result": {
      const subtype = parsed.subtype;
      if (subtype === "success") {
        events.push({ type: "result", summary: "Session completed", timestamp: now });
      } else if (subtype) {
        const error = parsed.errors?.[0] ?? `Error: ${subtype}`;
        events.push({ type: "error", summary: error, timestamp: now });
      }
      break;
    }
  }

  return events;
}

12. Status Display

Status Line (In-REPL)

// cli.js:574799-574821 (reconstructed)
function BridgeStatusLine({ bridgeSelected }) {
  const enabled = useStore((s) => s.replBridgeEnabled);
  const connected = useStore((s) => s.replBridgeConnected);
  const sessionActive = useStore((s) => s.replBridgeSessionActive);
  const reconnecting = useStore((s) => s.replBridgeReconnecting);
  const error = useStore((s) => s.replBridgeError);
  const explicit = useStore((s) => s.replBridgeExplicit);

  if (!isBridgeEnabled() || !enabled) return null;

  const { label, color } = getStatusLabelAndColor({ error, connected, sessionActive, reconnecting });

  // Only show non-error status if explicitly enabled
  if (!explicit && label !== "Remote Control failed" && label !== "Remote Control reconnecting") {
    return null;
  }

  return (
    <Text color={bridgeSelected ? "background" : color} inverse={bridgeSelected} wrap="truncate">
      {label}
      {bridgeSelected && <Text dimColor> · Enter to view</Text>}
    </Text>
  );
}

Bridge Status Message

// cli.js:516435-516444
function createBridgeStatusMessage(url) {
  return {
    type: "system",
    subtype: "bridge_status",
    content: `/remote-control is active. Code in CLI or at ${url}`,
    url,
    isMeta: false,
    timestamp: new Date().toISOString(),
    uuid: generateUUID(),
  };
}

13. Error Handling

Error Categories

HTTP Status Handling
200 Success
401 Auto-refresh token, retry once; if still 401, throw fatal
403 Check if expired session; throw fatal
404 Environment not available; throw fatal
410 Session expired; throw fatal with "environment_expired"
429 Rate limited; throw (non-fatal, retry via backoff)
5xx Never reach (validateStatus filters < 500)

Reconnection Strategy

Connection errors (ECONNREFUSED, ECONNRESET, ETIMEDOUT, etc.):
  - Initial delay: 2 seconds
  - Max delay: 2 minutes (exponential backoff with jitter)
  - Give up after: 10 minutes continuous failure

General errors (unexpected API errors):
  - Initial delay: 500ms
  - Max delay: 30 seconds (exponential backoff with jitter)
  - Give up after: 10 minutes continuous failure

System sleep detection:
  - If time gap between polls exceeds threshold, reset error budgets
  - Prevents giving up due to laptop sleep / suspend

14. Security Model

1. HTTPS enforced:
   - Non-localhost HTTP base URLs are rejected at startup
   - Only HTTPS or localhost HTTP allowed

2. OAuth-only:
   - Requires claude.ai subscription access tokens
   - Tokens auto-refreshed on 401

3. Environment secrets:
   - registerBridgeEnvironment returns environment_secret
   - Used for polling authentication (separate from OAuth token)

4. Work secrets:
   - Each work item contains an encrypted secret
   - Decoded to extract session_ingress_token
   - Used for WebSocket/POST authentication to session ingress

5. Session tokens:
   - Periodically refreshed via token refresh scheduler
   - Updated in child processes via stdin JSON message

6. Sandbox mode:
   - Optional --sandbox flag sets CLAUDE_CODE_FORCE_SANDBOX=1
   - Restricts file system access in child sessions

7. Workspace trust:
   - Requires prior trust dialog acceptance for the working directory
   - Prevents remote access to untrusted directories

8. Organization policy:
   - "allow_remote_sessions" policy can disable feature org-wide

15. Constants & Configuration

// Timing
const BRIDGE_MAX_LIFETIME_MS = 86400000;       // 24 hours
const DEFAULT_SESSION_TIMEOUT_MS = 86400000;   // 24 hours
const STATUS_UPDATE_INTERVAL_MS = 1000;        // 1 second

// API
const ANTHROPIC_BETA_HEADER = "environments-2025-11-01";
const ANTHROPIC_VERSION = "2023-06-01";

// Backoff
const CONN_INITIAL_MS = 2000;
const CONN_CAP_MS = 120000;      // 2 minutes
const CONN_GIVE_UP_MS = 600000;  // 10 minutes
const GENERAL_INITIAL_MS = 500;
const GENERAL_CAP_MS = 30000;    // 30 seconds
const GENERAL_GIVE_UP_MS = 600000; // 10 minutes

// Transport
const POST_MAX_RETRIES = 10;
const POST_INITIAL_BACKOFF_MS = 500;
const POST_MAX_BACKOFF_MS = 8000;

// Retryable network errors
const RETRYABLE_ERRORS = new Set([
  "ECONNREFUSED", "ECONNRESET", "ETIMEDOUT", "ENETUNREACH", "EHOSTUNREACH",
]);

// Poll
const POLL_BLOCK_MS = 900;
const POLL_TIMEOUT_MS = 10000;

// Session spawner
const MAX_STDERR_LINES = 50;
const MAX_ACTIVITIES = 100;

// REPL bridge
const MAX_RECONNECT_ATTEMPTS = 3;
const UUID_DEDUP_CAPACITY = 2000;

// CLI aliases for the subcommand
const REMOTE_CONTROL_ALIASES = ["remote-control", "rc", "remote", "sync", "bridge"];

// Slash command aliases
const SLASH_COMMAND_ALIASES = ["rc"];

// Environment variables set on child processes
// CLAUDE_CODE_ENVIRONMENT_KIND = "bridge"
// CLAUDE_CODE_SESSION_ACCESS_TOKEN = <token>
// CLAUDE_CODE_POST_FOR_SESSION_INGRESS_V2 = "1"
// CLAUDE_CODE_FORCE_SANDBOX = "1" (if --sandbox)

Implementation Checklist

To implement a similar remote control system in another agent:

  1. API Layer: Implement the Environments API client (register, poll, ack, stop, deregister, sessions)
  2. Auth: OAuth token management with auto-refresh on 401
  3. Feature Gating: Feature flags + organization policy checks
  4. Standalone Mode: CLI subcommand that registers an environment and enters the poll loop
  5. Session Spawner: Spawn child agent processes with stream-json I/O for each remote session
  6. Poll Loop: Long-polling with dual-track exponential backoff (connection vs general errors), sleep detection
  7. In-Process Mode: Slash command that shares the current session with the remote UI
  8. Transport: WebSocket for real-time streaming + HTTP POST fallback for reliability
  9. Control Protocol: Handle initialize, set_model, set_max_thinking_tokens, interrupt control requests
  10. State Management: Track connection state, session state, errors, reconnection status
  11. Activity Tracking: Parse agent output to extract tool usage and text for status display
  12. Status Display: Show connection status, session activity, reconnection progress
  13. Graceful Shutdown: Handle SIGINT/SIGTERM, kill child processes, deregister environment
  14. Security: HTTPS enforcement, workspace trust, sandbox mode, token isolation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment