Minimal TypeScript orchestrator core — Web UI as plugin
Minimal TypeScript orchestrator core — Web UI as plugin
Section titled “Minimal TypeScript orchestrator core — Web UI as plugin”Related: Cloud agent orchestrator · 2026-09-28 Pi SDK sessions worktrees and TS coordinator · Lightweight Grokbot Clone
Patterns worth stealing
Section titled “Patterns worth stealing”| Source | Steal | |
|---|---|---|
| OpenHands Agent Server | Independent REST + WebSocket; conversation/workspace/file/command APIs; immutable persisted events with search/replay | docs · events |
OpenCode serve | Standalone HTTP + OpenAPI + SSE; TUI is just a client of the same server | server |
| Continue | Typed ToCore / FromCore protocol; abstract messenger transport | protocol |
| Goose | Server API for agent/session lifecycle; streaming events; reconnect-friendly | API |
| Temporal | Client / Server / Worker split; durable event history; workers poll queues | architecture |
| LSP | UI starts/connects to a server; JSON-RPC; UI does not own analysis state | spec |
| Aider | Anti-pattern for core: CLI-first; UIs wrap process + stream-json — OK as adapter, not as the design |
Recommended core surface
Section titled “Recommended core surface”orchestrator-core CLI HTTP / JSON-RPC control API event bus + append-only event store worker registry + task queueMinimal capabilities:
interface Orchestrator { createSession(input: CreateSession): Promise<Session>; sendMessage(id: SessionId, input: MessageInput): Promise<void>; cancel(id: SessionId): Promise<void>; getSnapshot(id: SessionId): Promise<SessionSnapshot>; readEvents(id: SessionId, cursor?: string): Promise<EventPage>; subscribe(id: SessionId, listener: EventListener): Unsubscribe;}Expose at least: POST /sessions, POST /sessions/:id/messages, POST /sessions/:id/cancel, GET /sessions/:id, GET /sessions/:id/events?cursor=…, GET /health, GET /openapi.json.
SSE first for the Web UI plugin; add WebSocket only when bidirectional streaming or interactive approvals need it. Keep the internal bus transport-neutral.
Persistence: append-only event log (stable ids, timestamps, session id, type, payload, schema version). Snapshots / derived state separate. Replay reconstructs after restart. Cursors + short replay buffer so reconnecting UIs do not lose events. Bootstrap: subscribe before snapshot, buffer, then apply snapshot + buffered events (avoid race).
Workers: separate processes/modules that register capabilities and poll a queue. Core schedules and records; workers run Pi sessions, tools, long jobs. Temporal-shaped without requiring Temporal on day one.
Web UI as plugin (keypoint 2)
Section titled “Web UI as plugin (keypoint 2)”The UI should:
- Discover the core (configured URL or local process launcher).
- Use a generated OpenAPI client for commands/queries.
- Subscribe to SSE before sending prompts.
- Rehydrate from snapshot + cursor.
- Render sessions, messages, tool calls, approvals, logs, diffs.
- Never own orchestration state or worker processes.
Fits Lightweight Grokbot Clone as interface + monitor panel against this core.
Bottom line for Noa
Section titled “Bottom line for Noa”Build the core like a small OpenCode server + LSP, use OpenHands-style immutable events, add Temporal-style workers when durability and parallel worktree runs justify it. Pi sessions are workers’ concern; the core owns run lifecycle, events, and the plugin contract.