# 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) ```bash 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:` | ## Laptop smoke test (no real OpenClaw needed) ```bash # 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 ...` 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