Skip to content

Prewarm Process Usage Guide

Applicable to: @tencent-ai/codebuddy-code (cbc / codebuddy)

The prewarm process lets cbc complete cold startup and suspend (load bundle → container initialization → authentication → product configuration → MCP discovery), so that when awakened via local IPC it only needs to bind a working directory and can immediately serve. This is ideal for scenarios requiring "sub-second session startup" (e.g., serve/acp gateways, session pools, scheduler pre-launch).

Benefit: Local benchmarks show single-session startup wait reduced from approximately 3.7s to ~1ms.

Disabled by default. Only enabled when --prewarm is explicitly passed; does not affect any existing usage.

Quick Start

1. Start a Prewarmed Process (Standby)

bash
cbc --prewarm --prewarm-id pool1

The process will complete cold startup, then suspend at a local IPC endpoint in standby (without binding a working directory):

  • macOS / Linux: unix socket /tmp/codebuddy-prewarm-pool1.sock (permission 0600, current user only; socket directory can be overridden via env CODEBUDDY_CODE_PREWARM_SOCKET_PATH)
  • Windows: named pipe \\.\pipe\codebuddy-prewarm-pool1

--prewarm-id can be omitted; defaults to using the process PID as the identifier.

2. List / Activate (Lightweight Management Command cbc-prewarm)

cbc-prewarm is a pure Node zero-dependency lightweight command that does not load the main program bundle and returns in milliseconds.

bash
# List prewarmed processes discovered on the current machine
cbc-prewarm list

# Health check
cbc-prewarm ping pool1

# Query status (idle / activating / active)
cbc-prewarm status pool1

# Activate: bind to target working directory and start serving
cbc-prewarm activate pool1 --cwd /path/to/project -- --serve

Arguments after -- in activate are passed through to the awakened process (equivalent to normal cbc <args>). After activation, the process chdirs to --cwd, enters the corresponding mode based on the passed-through arguments (e.g., --serve / --acp), and proactively closes the IPC socket (one-time activation; afterwards it communicates through its own service port).

--cwd is optional: When omitted, the prewarmed process retains the working directory from cold startup (no chdir, no cwd change broadcast). This is suitable for callers that don't need to switch directories and just want to reuse the prewarmed container. Only pass --cwd when you need to bind to a specific project directory.

Mode is unrestricted: The passed-through arguments can be any normal cbc arguments. Persistent modes like --serve, --acp, etc. all take effect as-is — the prewarmed process has no restrictions or rewrites on modes. Pass --serve / --acp for persistent services; without a persistent mode flag, it takes the one-shot command path, exiting after execution (headless with no TTY).

External Program Integration (IPC Protocol)

To activate a prewarmed process from your own program, connect to the local socket / pipe and send one line of JSON (NDJSON, one message per line), then read one line of JSON response.

Address Convention

macOS/Linux : <dir>/codebuddy-prewarm-<id>.sock   (<dir> defaults to /tmp)
Windows     : \\.\pipe\codebuddy-prewarm-<id>

The unix socket directory defaults to /tmp and can be overridden via the env CODEBUDDY_CODE_PREWARM_SOCKET_PATH (e.g., when /tmp is noexec / read-only mounted, or when you need to place it in a controlled directory). Both the process side and the client side read the same env to stay aligned. Windows named pipe has no directory concept and is unaffected by this env.

Messages

jsonc
// Health check
{ "cmd": "ping" }
// → { "ok": true, "cmd": "ping", "status": "idle", "pid": 12345 }

// Query status
{ "cmd": "status" }
// → { "ok": true, "status": "idle"|"activating"|"active", "cwd": "...", "endpoint": "..." }

// Activate (cwd is optional — omit to retain cold-start cwd; args are passed through to cbc)
{ "cmd": "activate", "cwd": "/path/to/project", "args": ["--serve"], "sessionId": "optional" }
// → { "ok": true, "cmd": "activate", "status": "activating", "cwd": "..." }

// Activate and wait for ACP business readiness (opt-in; recommended with --port 0)
{
  "cmd": "activate",
  "ackMode": "ready",
  "cwd": "/path/to/project",
  "args": ["--serve", "--port", "0"],
  "sessionId": "session-1"
}
// → Only responds after ACP /api/v1/acp initialization completes:
// {
//   "ok": true,
//   "cmd": "activate",
//   "status": "active",
//   "pid": 12345,
//   "sessionId": "session-1",
//   "cwd": "/path/to/project",
//   "endpoint": "http://127.0.0.1:54321/api/v1/acp"
// }

activate can only succeed once; repeated activations return { ok: false, error: "already activated" }.

ackMode defaults to omitted, maintaining backward-compatible immediate ACK: the IPC server returns status: "activating" as soon as it receives the request, which does not mean the HTTP listener or ACP routes are ready yet. Hosts that need to hand the endpoint directly to downstream clients should explicitly pass "ackMode": "ready":

  • The child process uses --port 0 to let the kernel assign a contention-free port.
  • The response is delayed until the HTTP listener has started and ACP /api/v1/acp has completed initialization.
  • The ready response carries the actual non-zero port, pid, and the pass-through sessionId; the caller should verify all three.
  • After the ready ACK is flushed, the prewarm IPC is closed and cleaned up; subsequent communication goes through the returned ACP endpoint.
  • The caller should use a timeout window that covers the full cold startup; WorkBuddy waits 180 seconds by default. If the connection drops prematurely, agent-cli will not terminate the already-ready serve process on its own; the host should still reclaim processes it cannot take over.

Node.js Example

js
const net = require('net');

function prewarmAddr(id) {
  if (process.platform === 'win32') {
    return `\\\\.\\pipe\\codebuddy-prewarm-${id}`;
  }
  const dir = (process.env.CODEBUDDY_CODE_PREWARM_SOCKET_PATH || '').trim() || '/tmp';
  return require('path').join(dir, `codebuddy-prewarm-${id}.sock`);
}

function activate(id, { cwd, args = [] }) {
  return new Promise((resolve, reject) => {
    const sock = net.connect(prewarmAddr(id), () => {
      sock.write(JSON.stringify({ cmd: 'activate', cwd, args }) + '\n');
    });
    let buf = '';
    sock.on('data', d => {
      buf += d;
      const nl = buf.indexOf('\n');
      if (nl >= 0) { sock.end(); resolve(JSON.parse(buf.slice(0, nl))); }
    });
    sock.on('error', reject);
  });
}

// Activate pool1, bind to target directory and start in serve mode
const res = await activate('pool1', { cwd: '/Users/me/project-A', args: ['--serve'] });
console.log(res); // { ok: true, cmd: 'activate', status: 'activating', cwd: '...' }

The example above demonstrates the default immediate ACK. If you need the ACP-ready boundary, change the sent content to:

js
sock.write(JSON.stringify({
  cmd: 'activate',
  ackMode: 'ready',
  sessionId: 'session-1',
  cwd,
  args: ['--serve', '--port', '0'],
}) + '\n');

Behavior and Constraints

  • One process, one session: Each prewarmed process binds to a working directory only once in its lifetime (at the moment of activation), then is discarded. To serve multiple directories, prewarm multiple processes (with different --prewarm-id values), each independent and non-interfering.
  • Working directory isolation: After activation, the process chdirs and broadcasts a cwd change. File watchers automatically rebind, and project-level caches (settings / memory / skills / plugins / product configuration) are automatically invalidated and rescanned, ensuring no stale configuration from the temporary prewarm directory is read.
  • USER-level configuration sharing: User-level settings / authentication / MCP under ~/.codebuddy/ are naturally shared across all prewarmed processes.
  • Security: Unix socket permissions are tightened to 0600 (owner only), preventing other users on the same machine from connecting and hijacking.
  • Exit cleanup: Graceful exit (SIGINT/SIGTERM) or completion of activation automatically cleans up the socket; sockets left behind by SIGKILL are automatically overwritten on the next startup with the same id.

Configuration

Prewarm-related parameters can only be configured via CLI flags: --prewarm / --prewarm-id <id> / --prewarm-force.

You can also override the unix socket directory via env:

envPurposeDefault
CODEBUDDY_CODE_PREWARM_SOCKET_PATHCustom unix socket directory (e.g., /dev/abc/, trailing slash optional). The process side creates and the client side reads the same env. Unix only; Windows named pipe is unaffected/tmp