# How the OMC Team CLI Spawns Real tmux Workers for Codex, Gemini, and Claude

> Discover how the omc team CLI creates isolated tmux sessions for Codex, Gemini, and Claude agents. Learn about pane topologies, binary path resolution, and launch commands for efficient AI workflows.

- Repository: [Bellman/oh-my-claudecode](https://github.com/Yeachan-Heo/oh-my-claudecode)
- Tags: how-to-guide
- Published: 2026-03-27

---

**The OMC team CLI spawns isolated tmux sessions for each AI agent by creating pane topologies, resolving binary paths via model contracts, and sending launch commands through tmux `send-keys` to run Codex, Gemini, and Claude in separate terminal environments.**

The `omc team` command turns your terminal into a multi-agent control center by orchestrating *real* tmux workers for OpenAI's Codex, Google's Gemini, and Anthropic's Claude. Unlike background process wrappers, the OMC team CLI creates tangible tmux sessions you can attach to, inspect, and debug. This architecture ensures each AI worker operates in an isolated terminal environment while remaining fully manageable through the orchestration layer.

## Creating the tmux Session Topology

The spawn process begins in [`src/team/tmux-session.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/tmux-session.ts) with `createTeamSession()`, which establishes the tmux infrastructure for the entire team. This function determines whether to split the current tmux window, open a dedicated window, or fall back to a detached session based on your current terminal state.

The function sanitizes session names through `sessionName()` to ensure tmux compatibility, then executes raw tmux commands including `new-session`, `split-window`, and `select-layout` to construct the pane grid. Each worker receives its own tmux pane within this topology, creating physical isolation between agents.

## Resolving Agent Binaries and Launch Arguments

Before spawning, the CLI resolves the correct binary and launch configuration through [`src/team/model-contract.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/model-contract.ts). The `buildWorkerArgv()` function validates team and worker names, then calls `resolveValidatedBinaryPath()` to locate the agent-specific CLI—`codex`, `gemini`, or `claude`—on the host system.

This layer injects worker-specific environment variables including `OMC_TEAM_WORKER` and model-specific configurations. It also assembles launch flags such as model selection parameters and `--prompt-mode` flags when supported, creating a complete argument vector for each agent type.

## Spawning Workers in tmux Panes

The actual spawning occurs in `spawnWorkerInPane()` within [`src/team/tmux-session.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/tmux-session.ts). This function receives the pane ID and a `WorkerPaneConfig` object, then orchestrates the launch through three precise steps:

1. **Validation**: Calls `validateTeamName()` to ensure the session identifier is safe for tmux
2. **Command Construction**: Uses `buildWorkerStartCommand()` to generate a shell-safe command that sources the appropriate rc file, sets environment variables, and executes the binary with `exec`
3. **Pane Injection**: Sends the command to the specific tmux pane using `tmux send-keys -t {paneId} -l {command}`, followed by an `Enter` keystroke

For interactive agents, the CLI then invokes `waitForPaneReady()` to monitor the pane output until the agent's prompt appears (such as `›` for Codex or `❯` for Claude), ensuring the worker is fully initialized before sending the inbox trigger message via `sendToWorker()`.

## Agent-Specific Spawn Flows

Each agent exhibits distinct spawn characteristics handled by the model-contract layer:

### Codex (Full TUI Only)

Codex does not support headless prompt-mode operation. The CLI resolves the binary path through `resolveValidatedBinaryPath('codex')` and launches it without `--prompt-mode` arguments. After spawning, `waitForPaneReady()` watches for the Codex prompt (`›`), then sends the inbox trigger (`new-task:<id>` or `Read … inbox.md`) through `sendToWorker()`.

### Gemini (Prompt-Mode Optimization)

Gemini supports headless operation via `--prompt-mode`. When `isPromptModeAgent('gemini')` returns true, `getPromptModeArgs()` appends flags like `--prompt-mode --instruction 'Read … inbox.md'` to the launch command. Because the task instruction is baked into the launch arguments, the CLI **skips** `waitForPaneReady()` and allows Gemini to execute and exit autonomously.

### Claude (Model-Specific Flags)

Claude spawning follows the Gemini pattern when using prompt-mode, but includes additional model flags such as `--model $CLAUDE_MODEL`. When running in interactive mode, the CLI waits for the Claude prompt (`❯`) before injecting the inbox trigger, identical to the Codex flow.

## Orchestration and Runtime Management

Higher-level coordination happens in [`src/team/runtime.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/runtime.ts) (and [`runtime-v2.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/runtime-v2.ts) for newer CLI entry points). The runtime ties the components together by:

- Calling `createTeamSession()` to establish the tmux infrastructure
- Iterating over the required worker count and calling `createWorkerPane()` for each instance
- Invoking `spawnWorkerInPane()` with the appropriate `WorkerPaneConfig`
- Recording pane IDs and writing a panes-tracking file for session persistence
- Registering workers in the in-memory runtime state for health monitoring and message routing

## Code Examples

### Starting a Team with Three Workers

```bash

# Create a new team called "my-project"

omc team create my-project \
  --agents codex,gemini,claude \
  --workers 3 \
  --cwd /path/to/repo

```

**Internal execution flow:**

```typescript
// runtime.ts (simplified)
const session = await createTeamSession(teamName, workerCount, cwd);
for (let i = 0; i < workerCount; i++) {
  const paneId = await createWorkerPane(session, i);   // tmux split-window
  const config = await buildWorkerConfig(i);          // env + launch args
  await spawnWorkerInPane(session.sessionName, paneId, config);
}

```

### Low-Level Pane Spawning Implementation

The core spawning logic in [`src/team/tmux-session.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/tmux-session.ts):

```typescript
export async function spawnWorkerInPane(
  sessionName: string,
  paneId: string,
  config: WorkerPaneConfig
): Promise<void> {
  // 1️⃣ Validate the team name (sanitises for tmux)
  validateTeamName(config.teamName);

  // 2️⃣ Build the safe shell command that tmux will execute
  const startCmd = buildWorkerStartCommand(config);

  // 3️⃣ Send the command to the pane (literal mode, no extra quoting)
  await execFileAsync('tmux', ['send-keys', '-t', paneId, '-l', startCmd]);
  await execFileAsync('tmux', ['send-keys', '-t', paneId, 'Enter']);
}

```

### Constructing Launch Arguments for Claude

Binary resolution and argument building in [`src/team/model-contract.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/model-contract.ts):

```typescript
const argv = buildWorkerArgv('claude', {
  teamName: 'my-project',
  workerName: 'worker-0',
  cwd: '/path/to/repo',
  resolvedBinaryPath: undefined,          // resolve from contract
  model: 'claude-3-opus-20240229',       // derived from env or default
  extraFlags: [],                         // can include --prompt-mode
});

// argv => ['/usr/local/bin/claude', '--model', 'claude-3-opus-20240229']

```

### Prompt-Mode Optimization for Gemini

Headless execution bypasses interactive waiting:

```typescript
// src/team/runtime.ts – after building launch args
if (isPromptModeAgent('gemini')) {
  const promptArgs = getPromptModeArgs('gemini', generateTriggerMessage(teamName, workerName));
  launchArgs.push(...promptArgs);   // e.g. ['--prompt-mode', '--instruction', 'Read … inbox.md']
}

```

When `isPromptModeAgent` returns `true`, the CLI **does not** call `waitForPaneReady()` because the agent exits after processing the supplied instruction.

## Summary

- The OMC team CLI creates physical tmux sessions through `createTeamSession()` in [`src/team/tmux-session.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/tmux-session.ts), ensuring each agent runs in an isolated terminal environment
- Binary resolution and argument construction happen via `buildWorkerArgv()` and `resolveValidatedBinaryPath()` in [`src/team/model-contract.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/model-contract.ts)
- Workers spawn through `spawnWorkerInPane()` using `tmux send-keys` to inject shell commands that source rc files and execute the agent binary with `exec`
- **Codex** always runs in full TUI mode with prompt-waiting logic, while **Gemini** and **Claude** support `--prompt-mode` for headless execution
- Runtime orchestration in [`src/team/runtime.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/src/team/runtime.ts) manages pane creation, worker registration, and session persistence through panes-tracking files

## Frequently Asked Questions

### How does the CLI handle tmux session conflicts?

The `sessionName()` utility sanitizes team names to remove characters that tmux interprets specially, ensuring valid session identifiers. If a session already exists, the CLI either attaches to it or creates a uniquely named detached session, preventing naming collisions while maintaining the requested worker topology.

### Can I attach to a running worker pane manually?

Yes. Because the OMC team CLI spawns *real* tmux sessions rather than background processes, you can use standard tmux commands like `tmux attach-session -t {team-name}` or `tmux select-pane -t {paneId}` to interact directly with Codex, Gemini, or Claude workers. The session topology is tracked in the panes-tracking file written by [`runtime.ts`](https://github.com/Yeachan-Heo/oh-my-claudecode/blob/main/runtime.ts).

### What environment variables are injected into each worker?

Each worker receives `OMC_TEAM_WORKER` identifying its role, along with model-specific variables such as `CODEX_MODEL`, `GEMINI_MODEL`, or `CLAUDE_MODEL` depending on the agent type. These are set through the `WorkerPaneConfig` and sourced into the shell environment before the agent binary executes via `buildWorkerStartCommand()`.

### Why does Codex require different handling than Gemini or Claude?

Codex lacks a `--prompt-mode` flag for headless operation, requiring the CLI to maintain an interactive TUI session. This necessitates calling `waitForPaneReady()` to detect the Codex prompt (`›`) before sending task instructions, whereas Gemini and Claude can receive instructions via launch arguments and exit immediately without interactive monitoring.