PLAYBOOK UC4-SPAWN REV 1.0 FECHA 21 JUN 2026 DEPENDE P0 + UC3

Playbook · UC4 · Spawn Peer Local

Playbook UC4
Spawn Peer Local

Desde una sesión Claude Code en Mac (cl minimax --proxy --channels), ejecutar SpawnPeer para crear una segunda sesión gestionada por el runner local. Verificar que el spawn funciona, que el nuevo peer aparece en ListPeers, y que ambas sesiones pueden comunicarse.

Esfuerzo
20 min
Depende de
P0 (prerequisites) + UC3 (channels)
Bloquea
UC5 (workspace spawn E2E)
Veredicto
⏳ pendiente
Runner daemon NO configurado en Mac Sin verificación runtime
01

Objetivo

Probar el spawn-plane en local: una sesión Claude Code spawnea otra a través del broker + runner daemon. Esto requiere que el Mac tenga un runner corriendo (GATEWAY_MODE=runner) que acepte spawn_orders del broker y ejecute cliLauncher.launch().

drag to pan · scroll to zoom · double-click to fit
Sesión A (Mac)cl minimax--proxy --channelsBroker públicobroker.gateway.mks2508.systemsRunner daemon (Mac)GATEWAY_MODE=runnerRUNNER_ID=macSesión B (spawneada)claude --sdk-urla2a-mcpa2a-mcp(embedded) 1. SpawnPeer{host:'mac', provider:'minimax'} 2. spawn_order WS 3. Bun.spawnclaude --sdk-url4. peer_registered5. spawnId + peerId SendPeerMessage to BCHANNEL PUSH
Sesión A (Mac)cl minimax--proxy --channelsBroker públicobroker.gateway.mks2508.systemsRunner daemon (Mac)GATEWAY_MODE=runnerRUNNER_ID=macSesión B (spawneada)claude --sdk-urla2a-mcpa2a-mcp(embedded) 1. SpawnPeer{host:'mac', provider:'minimax'} 2. spawn_order WS 3. Bun.spawnclaude --sdk-url4. peer_registered5. spawnId + peerId SendPeerMessage to BCHANNEL PUSH
PREREQUISITO — Runner daemon en Mac

Para que UC4 funcione, el Mac necesita un runner daemon corriendo:

cd /path/to/mks-agentics
GATEWAY_MODE=runner \
RUNNER_ID=mac \
BROKER_URL=https://broker.gateway.mks2508.systems \
BROKER_TOKEN=<JWT> \
GATEWAY_PORT=4105 \
bun run apps/gateway-server/src/runner.ts

El runner se conecta al broker vía WS (/ws/runner/mac) y espera spawn_order. Cuando recibe uno, llama a cliLauncher.launch() y responde peer_registered.

Estado actual (2026-06-20): el runner daemon NO está configurado como servicio permanente en Mac. Hay que arrancarlo manualmente para UC4. Esto es parte del trabajo pendiente de spawn-plane (0.18.D+).

02

F1 — Arrancar runner daemon en Mac

5 min

Configurar y arrancar el runner

  • cd apps/gateway-server && bun run src/runner.ts con env vars → arranca El runner inicia y se conecta al broker
  • Log muestra runner online: id=mac Conexión WS al broker establecida
  • curl -s https://broker.gateway.mks2508.systems/api/runners -H 'Authorization: Bearer $JWT' → incluye 'mac' El runner está registrado en el broker
  • curl -s http://localhost:4105/health → 200 OK El runner expone health check local

Variables de entorno para el runner

Env vars requeridas para el runner daemon
VariableValorNota
GATEWAY_MODErunnerActiva modo runner (sin REST API pública)
RUNNER_IDmacIdentificador único del runner
BROKER_URLhttps://broker.gateway.mks2508.systemsWebSocket del broker
BROKER_TOKEN(JWT válido)Auth del WS (?token=<JWT>)
GATEWAY_PORT4105Puerto para --sdk-url de las sesiones spawneadas
GATEWAY_HOST127.0.0.1Solo localhost (F-OPS-1)
CLAUDE_BINARY_PATHclaudeBinary de Claude Code (default)
Arrancar runner daemon
# En una terminal dedicada (TMUX pane o similar):

$ cd /Volumes/KODAK1TB/REPOS\ y\ PROYECTOS/nodejs-bun/mks-agentics

# Generar JWT para el runner:
$ source .env.brk-extract.local
$ JWT=$(curl -s -X POST "$OIDC_TOKEN_ENDPOINT" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials&client_id=$MCP_STANDALONE_CLIENT_ID&client_secret=$MCP_STANDALONE_CLIENT_SECRET&scope=broker" \
    | jq -r '.access_token')

# Arrancar runner:
$ GATEWAY_MODE=runner \
  RUNNER_ID=mac \
  BROKER_URL=https://broker.gateway.mks2508.systems \
  BROKER_TOKEN="$JWT" \
  GATEWAY_PORT=4105 \
  GATEWAY_HOST=127.0.0.1 \
  bun run apps/gateway-server/src/runner.ts

# Output esperado:
→ Runner started: id=mac broker=https://broker.gateway.mks2508.systems localPort=4105
→ runner online: id=mac
03

F2 — Arrancar sesión A con channels {#f2-sessionA}

3 min

Sesión existente que spawnea

  • En otra terminal: cl minimax --proxy --channels Sesión A con channels activos
  • ListPeers → muestra peer A y posiblemente el runner Peer discovery funciona
  • ListPeers NO muestra peer B todavía Aún no se ha spawneado nada
04

F3 — Spawn peer B

5 min

Ejecutar SpawnPeer desde sesión A

  • En sesión A: SpawnPeer con host='mac', provider='minimax', name='spawned-peer-B' MCP tool SpawnPeer → POST /api/spawn del broker
  • El broker enruta el spawn_order al runner 'mac' vía WS runner.ts recibe spawn_order y llama a cliLauncher.launch()
  • La respuesta de SpawnPeer incluye spawnId y status: 'pending' El spawn fue aceptado por el broker
  • En unos segundos, ListPeers muestra 3+ peers (A, B, runner) El peer B se registró tras spawn exitoso
  • GetPeer <peerId-B> → status 'running' La sesión B está viva

SpawnPeer — comandos

Sesión A — spawnear peer B
# Dentro de Claude Code sesión A:

> SpawnPeer name="spawned-peer-B" provider="minimax" host="mac" cwd="/tmp"

→ {
→   "spawnId": "spawn_abc123...",
→   "status": "pending",
→   "host": "mac"
→ }

# Esperar unos segundos y verificar:

> ListPeers
→ [
→   {"id": "a1b2c3d4-...", "kind": "operator", "name": "Claude Code — A", "status": "running"},
→   {"id": "e5f6g7h8-...", "kind": "operator", "name": "spawned-peer-B", "status": "running"},
→   {"id": "mac", "kind": "runner", "name": "mac", "status": "online"}
→ ]

> GetPeer e5f6g7h8-...
→ (card completa del peer B — spawneado exitosamente)
05

F4 — Comunicación post-spawn

3 min

Verificar mensajería entre A y B

  • SendPeerMessage to=<peerId-B> content='hola desde A, spawneada' Mensaje de A a la sesión spawneada B
  • En la terminal del runner, el log muestra peer_registered: spawnId=... peerId=... pid=... Runner confirma el spawn exitoso
  • El mensaje llega a B vía channel-push (si channels=true en el spawn) La sesión spawneada tiene channels porque el runner hereda la config
  • CheckInbox <peerId-B> → el mensaje está en el inbox (fallback) Verificación alternativa si channel-push falla
06

F5 — Stop peer B

2 min

Detener la sesión spawneada

  • StopPeer peerId=<peerId-B> → 200 OK MCP tool StopPeer → broker → runner → stop_order WS
  • Runner log muestra peer_stopped: spawnId=... El runner detuvo el proceso Claude CLI
  • ListPeers → peer B ya no aparece (o status 'stopped') Peer desregistrado correctamente
Debe pasar4 checks
  • Runner se conecta al broker y aparece en /api/runners Runner registry funciona
  • SpawnPeer → spawn_order → peer_registered Spawn-plane local funciona
  • ListPeers muestra el peer spawneado Peer discovery post-spawn
  • StopPeer detiene la sesión spawneada Lifecycle completo: spawn → communicate → stop
Puede fallar (esperable)2 checks
  • El runner no arranca por falta de BROKER_TOKEN Necesita JWT válido de OIDC client_credentials
  • SpawnPeer falla porque el host no coincide con ningún runner Verificar RUNNER_ID y el parámetro host en SpawnPeer
Si falla → bloquea UC51 check
  • El spawn nunca completa (queda en pending) Runner offline, broker no enruta, o cliLauncher falla
Q1

¿Está el runner daemon corriendo en Mac? prerequisite

Verificar con curl http://localhost:4105/health

Sí → 200 OK El runner está listo para recibir spawn_orders.
No → connection refused Arrancar el runner manualmente (F1). Si no está corriendo, el broker no tiene a quién enviar el spawn_order y SpawnPeer fallará con RUNNER_OFFLINE o se quedará en pending.
Q2

¿Aparece el peer spawneado en ListPeers? verificación

Después de SpawnPeer, esperar 5-10s y ejecutar ListPeers

Sí → 3+ peers UC4 verde. Spawn-plane local funciona. Se puede proceder a UC5 (workspace spawn).
No → solo 2 peers Revisar logs del runner. Posibles causas: (1) cli-launcher falló (binary no encontrado), (2) loop-guard rechazó el spawn, (3) el broker no enrutó el spawn_order al runner correcto.

Código relevante

Diseño