# CLAUDE.md ## Commands - `npm run build` -- compile TypeScript to `dist/` - `npm start` -- run the compiled server (`dist/index.js`) - `npm run dev` -- run from source with `tsx` (no build step) - Default port is `4100`, override with `--port` or `PORT` env var ## Project structure - `src/index.ts` -- Express app: MCP routes, REST API, SSE, static file serving - `src/store.ts` -- In-memory session + message state, EventEmitter for pub/sub - `src/mcp-handler.ts` -- Creates per-request MCP server with `collab_send_message` and `collab_wait_for_reply` tools - `src/prompts.ts` -- Generates role-specific system prompts (initiator vs. responder) with embedded tool instructions and a subagent prompt template - `web/index.html` -- Single-file web UI (no build, no framework, vanilla JS + SSE) ## Key design decisions - **Stateless MCP handlers**: A new `McpServer` + `StreamableHTTPServerTransport` is created per request in `mcp-handler.ts`. All persistent state lives in `Store`. - **Long-poll with EventEmitter**: `collab_wait_for_reply` blocks up to 5 minutes via `store.waitForMessage()`, which uses `EventEmitter` listeners with a re-check after registration to close the race window. The HTTP server timeout is set to 0 to avoid killing these connections. - **Only latest message returned**: `waitForMessage` returns only the most recent delivered message (not history) to save agent context windows. - **Auto-forward toggle**: Messages are either delivered instantly or held as "pending" for human review/edit/reject, controlled per-session. - **Subagent prompt template**: `prompts.ts` includes a copy-paste template for the wait subagent to prevent it from analyzing messages instead of relaying them verbatim. ## Code style - TypeScript strict mode, ES2022 target, Node16 module resolution - ESM (`"type": "module"` in package.json, `.js` extensions in imports) - Express 5, Zod for MCP input validation - No test framework currently set up