Files
SynthesisAgent.OpenclawPlugin/README.md
zhi 0324a47d13 feat: HTTP /v1/chat/completions + WS bridge + process manager
Real first cut. OpenClaw routes agent turns via /v1/chat/completions
(OpenAI-compatible SSE) into our bridge. Bridge ensures a long-lived
claude process per session-key, pushes the user message as
notifications/claude/channel into the running Claude Code, awaits a
reply via the WS connection, streams the reply back as SSE deltas.

- core/process-manager: spawn / track / reap claude processes, auto-confirm
  the --dangerously-load-development-channels dev-mode prompt by piping
  "1\n" to stdin shortly after spawn
- web/bridge-server: unified HTTP + WS server, per-session FIFO queue,
  SSE heartbeat (empty content delta — SSE comments don't reset OpenClaw's
  idle watchdog), reply buffering for streaming progress chunks
- index.ts: definePluginEntry for OpenClaw runtime + standalone-mode main
  for laptop smoke testing (just `bun index.ts`)

Same-machine simplifications: no bridge token, no permission_request
reverse channel. Session key = agent_id::chat_id (contractor-agent
convention).
2026-05-14 13:28:00 +00:00

3.3 KiB

SynthesisAgent.OpenclawPlugin

OpenClaw plugin that routes agent turns through long-lived interactive Claude Code processes. Replaces the contractor-agent claude -p spawn pattern.

Components

index.ts                     plugin entry + standalone-run main
core/config.ts               config + defaults
core/session-mapping.ts      openclaw_session ↔ claude_session_uuid (JSON file)
core/process-manager.ts      spawn / track / reap claude processes
web/bridge-server.ts         HTTP server + WS bridge server in one module

Two ways to run

As OpenClaw plugin (production)

OpenClaw loads index.ts via definePluginEntry. On gateway_start, the bridge server boots on the configured ports.

Standalone (development / testing)

bun index.ts

Same code path, but no definePluginEntry registration — just boots the bridge with default config.

Config (openclaw.plugin.json configSchema)

Key Default Notes
bridgePort 18900 HTTP port for /v1/chat/completions
channelWsPort 18901 WebSocket port for ClaudePlugin connections
permissionMode bypassPermissions Spawned Claude's permission mode
idleKillMs 3 600 000 Idle TTL before SIGTERM
maxProcesses 16 Process pool cap
mappingDbPath ~/.openclaw/synthesis/sessions.json Persistent session map
channelName synthesis Used in --channels server:<channelName>

Laptop smoke test (no real OpenClaw needed)

# 0. Globally register the ClaudePlugin as an MCP server (one-time)
claude mcp add --scope user synthesis -- bun run \
  /path/to/SynthesisAgent.ClaudePlugin/server.ts

# 1. Start OpenclawPlugin standalone (this terminal)
cd SynthesisAgent.OpenclawPlugin
bun install
bun index.ts
#   → HTTP listening on 127.0.0.1:18900
#   → WS  listening on 127.0.0.1:18901/bridge

# 2. POST a chat completion (another terminal)
curl -N -X POST http://127.0.0.1:18900/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'X-Openclaw-Agent-Id: dev' \
  -H 'X-Openclaw-Chat-Id: test-1' \
  -H "X-Openclaw-Workspace: $HOME/some-trusted-dir" \
  -d '{
    "model":"synthesis-claude-bridge",
    "messages":[
      {"role":"user","content":"Reply with exactly the word READY"}
    ]
  }'

Expected flow:

  1. OpenclawPlugin receives request, ensures a claude process for dev::test-1
  2. Spawns claude --channels server:synthesis --dangerously-load-development-channels server:synthesis --resume <new-uuid> ...
  3. ClaudePlugin (inside the claude process) dials ws://127.0.0.1:18901/bridge, sends hello
  4. OpenclawPlugin pushes inbound frame, ClaudePlugin emits notifications/claude/channel
  5. Claude reacts, eventually calls reply(text) tool
  6. ClaudePlugin sends reply WS frame, OpenclawPlugin streams it as SSE delta
  7. curl sees the reply text

Known v1 simplifications (documented punch list)

  • Session-key extraction reads headers only — production OpenClaw routing will need the contractor-agent style "Conversation info" parser
  • No tool-catalog proxy: ClaudePlugin only exposes reply; the model uses Claude Code's built-in tools (Read/Edit/Bash/Grep) for everything else
  • No permission_request reverse channel (full perms by config)
  • No bridge token / auth handshake (same-machine assumption)
  • Standalone mode boots with defaults only; no config flags

License

Apache-2.0