How OpenClaude Handles Out‑of‑Process Teammate Routing During Startup

Out‑of‑process teammate routing in OpenClaude happens before the main UI loads, using eager flag parsing in src/utils/settings/flagSettings.ts and environment variable detection in src/utils/teammate.ts to identify teammates and wire up the correct provider early.

OpenClaude's multi‑agent architecture allows teammates to run in separate terminal windows via tmux or iTerm2 panes. The routing mechanism that determines whether a process is the leader or an out‑of‑process teammate operates during the bootstrap phase—before main.tsx is even imported—ensuring minimal startup overhead and correct communication channel setup.

Early Flag Parsing in flagSettings.ts

The routing decision begins with eager CLI flag parsing. The eagerLoadSettingsFromArgs function in src/utils/settings/flagSettings.ts executes immediately when the process starts, parsing --settings and --setting-sources flags at lines 23‑24:

// src/utils/settings/flagSettings.ts
// This is needed by bootstrap paths that inspect getInitialSettings()
// before main.tsx is imported, including out-of-process teammate provider routing.
export function eagerLoadSettingsFromArgs(argv = process.argv) {
  const settingsFile = eagerParseCliFlag('--settings', argv);
  if (settingsFile) loadSettingsFromFlag(settingsFile);
  // …additional flag handling…
  return { ok: true };
}

This function returns settings that downstream routing logic consumes before any heavy UI code runs. The comment explicitly notes this timing requirement for out‑of‑process teammate provider routing.

Environment Variable Detection in teammate.ts

Once flags are loaded, OpenClaude checks for teammate identity markers via environment variables. When a launcher spawns an out‑of‑process teammate, it injects CLAUDE_CODE_AGENT_ID and CLAUDE_CODE_TEAM_NAME. The helpers in src/utils/teammate.ts read these variables:

// src/utils/teammate.ts
export function getAgentId(): string | undefined { … }
export function getTeamName(): string | undefined { … }

export function isRunningAsOutOfProcessTeammate(): boolean {
  return !!process.env.CLAUDE_CODE_AGENT_ID && !!process.env.CLAUDE_CODE_TEAM_NAME;
}

These functions fall back to AsyncLocalStorage context for in‑process teammates, making the detection mechanism dual‑mode: environment variables for out‑of‑process, async context for in‑process.

Background Task Registration in spawnMultiAgent.ts

After detection, the leader must register communication channels for the teammate. The spawnMultiAgent utility in src/tools/shared/spawnMultiAgent.ts creates a background‑task entry at line 828:

// src/tools/shared/spawnMultiAgent.ts
// Register a background task entry for an out-of-process (tmux/iTerm2) teammate.
function registerBackgroundTask(taskInfo) {
  backgroundTaskRegistry.add(taskInfo);
}

This registry entry tells the leader's message router to listen for IPC or mailbox messages from the specific teammate ID, ensuring requests reach the correct provider instance.

Optional Startup Profiling

Developers can measure routing overhead using src/utils/startupProfiler.ts. This utility records timing for:

  • eagerLoadSettingsFromArgs execution
  • Environment variable detection
  • Provider instantiation

Profiling helps identify latency introduced by complex flag configurations or slow teammate detection.

Final Wiring to main.tsx

With settings resolved and teammate identity confirmed, the bootstrap calls getInitialSettings() and proceeds to src/main.tsx. The main UI creates the appropriate Provider:

  • In‑process provider — Uses AsyncLocalStorage from src/utils/teammateContext.ts
  • Out‑of‑process provider — Uses IPC channels or mailbox routing via the background task registry

Complete Startup Command Examples

Launch the leader normally:

openclaude --settings ./my-settings.json

Launch an out‑of‑process teammate that triggers early routing:

openclaude --settings ./my-settings.json \
           --agent-id teammate-01 \
           --team-name my-team

The presence of CLAUDE_CODE_AGENT_ID and CLAUDE_CODE_TEAM_NAME in the environment (typically set by the launcher before these commands) causes the routing code to select the out‑of‑process path.

Key Files in the Routing Chain

File Routing Role
src/utils/settings/flagSettings.ts First entry point — eager flag parsing before UI load
src/utils/teammate.ts Environment variable detection and teammate identity
src/tools/shared/spawnMultiAgent.ts Background task registration for cross‑process messaging
src/utils/teammateContext.ts In‑process AsyncLocalStorage counterpart
src/utils/startupProfiler.ts Optional latency measurement
src/main.tsx Final provider instantiation based on resolved settings

Summary

  • Eager parsing in flagSettings.ts runs before main.tsx import to prepare settings early
  • Environment variables (CLAUDE_CODE_AGENT_ID, CLAUDE_CODE_TEAM_NAME) identify out‑of‑process teammates via teammate.ts helpers
  • spawnMultiAgent.ts registers background tasks enabling leader‑to‑teammate message routing
  • Startup profiler tracks routing overhead for optimization
  • Final wiring in main.tsx instantiates the correct provider based on pre‑resolved identity

Frequently Asked Questions

What happens if CLAUDE_CODE_AGENT_ID is set but CLAUDE_CODE_TEAM_NAME is missing?

The isRunningAsOutOfProcessTeammate() function requires both variables to return true. If either is missing, the process falls back to single‑agent or in‑process routing. This safety check prevents partial teammate configuration from causing routing failures.

Can I use the same --settings file for leader and teammate processes?

Yes. The --settings flag is parsed early by eagerLoadSettingsFromArgs in both cases. The routing differentiation happens through environment variables, not settings files, so shared configuration is supported and common in practice.

Why does routing need to happen before main.tsx loads?

Heavy UI initialization including React rendering, terminal UI setup, and provider instantiation occurs in main.tsx. Determining teammate identity before this step avoids wasted work if the process needs a different provider type, and ensures the correct communication channels exist before any messages are sent.

How does the leader know which teammates are active?

The backgroundTaskRegistry in spawnMultiAgent.ts tracks registered tasks by agentId. When a teammate spawns, its registration entry includes the ID and communication endpoint. The leader queries this registry when routing messages, matching incoming requests to the correct teammate handler.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →