--- status: draft last_updated: 2026-05-18 --- # Hub Architecture: alk.dev API ## Overview The hub is the central API server hosted at `api.alk.dev`. It extends the spoke with orchestration capabilities, persistent storage, and coordination logic. The hub manages agent sessions, coordinates work across spoke runners, and exposes the public-facing API. **Reference**: See spoke-runner.md (hub/spoke model). The `ade_hub` package contains directional stubs (WorkerPool, Dispatcher) — coherent but not production architecture. See spoke-runner.md for the actual design. ## Design Principles 1. **Hub shares core with spoke, adds orchestration** — both hub and spoke depend on `@alkdev/operations` and `@alkdev/pubsub` for operations, pubsub, and call protocol. Hub adds stateful coordination, persistence, and HTTP serving on top. 2. **Stabilize API in TS, rewrite in Rust later** — Deno + TypeScript for initial production. API contract matters more than runtime performance until scale demands it 3. **Postgres for all persistent state** — single Postgres instance (configured host:port from encrypted config) 4. **Redis for cross-process events** — replaces opencode's single-process EventEmitter/Effect PubSub. Redis 7 is deployed on the hub server (configured Redis host:port from encrypted config). See infrastructure.md. 5. **Operations as the universal abstraction** — everything is a typed operation with TypeBox schemas ## Components ### From core (shared with spoke) | Component | Location | Notes | | ----------------- | ------------------------------------------------------ | ------------------------------------------------------------------------- | | Operations system | `@alkdev/operations` | Registry, scanner, types, env, FromOpenAPI, FromSchema, SchemaAdapter | | PubSub | `@alkdev/pubsub` | createPubSub + operators, Redis/WebSocket/Worker EventTargets | | MCP client | `@alkdev/operations/from-mcp` | createMCPClient, MCPClientLoader (for connecting to external MCP servers) | | Call protocol | `@alkdev/operations` (see call-graph.md) | PendingRequestMap, CallHandler, call ≡ subscribe | | Call graph | `@alkdev/taskgraph` (see call-graph.md) | Graphology-based, needed for SDD workflow orchestration | | Operation graph | `@alkdev/taskgraph` (see call-graph.md) | Static type-compatibility graph, call templates | ### New / Simplified for alk.dev | Component | Description | Replaces | | -------------------- | ---------------------------------------------------- | -------------------------------------------------- | | Storage | Drizzle + Postgres with `@alkdev/drizzlebox` pattern | Previous DbType.Table abstraction (too complex, dropped) | | Redis EventTarget | Available in `@alkdev/pubsub` as `RedisEventTarget`. `TypedEventTarget` impl backed by Redis pub/sub | opencode's in-process EventEmitter/Effect PubSub | | Container spoke (deferred) | Spoke that extends base spoke with Docker + opencode container lifecycle. Will also need a variant for vast.ai compute. | opencode's multi-project-in-process model | | Agent session system | AI SDK `streamText` + `UIMessage` persistence | opencode's Effect-based SessionProcessor | | MCP server | `@hono/mcp` StreamableHTTPTransport with discovery+call pattern | per-container MCP servers | ### Dropped (not needed) | Component | Reason | | -------------------------------- | -------------------------------------------------- | | Sandbox (QuickJS) | Hub doesn't execute untrusted code | | iroh-gossip / P2P | Redis pub/sub covers multi-process; P2P is future | | DbType.Table storage abstraction | `@alkdev/drizzlebox` pattern from ade-v0 is cleaner | | Effect dependency | Unnecessary complexity; AI SDK handles LLM streams | ## Hub Responsibilities 1. **Serve public API** at `api.alk.dev` — Hono HTTP server 2. **Manage spoke runners** — registration, heartbeat, capability discovery 3. **Orchestrate agent workflows** — coordinator, decomposer, implementation specialist roles from SDD process 4. **Persist all state** — sessions, messages, projects, task graphs, coordination mappings 5. **Route events** — Redis pub/sub for cross-process, WebSocket for hub↔spoke, SSE for compatibility 6. **Proxy LLM calls** — OpenAI-compatible proxy endpoint that keeps provider keys server-side 7. **Expose MCP endpoint** — shared tools (websearch, coordination, git operations) for all opencode containers 8. **Track call graph** — observe, abort cascade, and replay agent workflows ## Data Flow ``` Client (browser/CLI) │ ├── HTTP ──→ Hono API (api.alk.dev) │ ├── Operations registry │ ├── Drizzle + Postgres │ └── Redis pub/sub (hub-internal) │ ├── WebSocket ──→ Call protocol (hub ↔ spokes bidirectional) │ ├── Dispatches call.requested to spokes │ └── Receives call.responded/call.error from spokes │ └── MCP ──→ @hono/mcp endpoint (search/schema/call for legacy systems) │ └── Thin adapter over hub.list/hub.search/hub.schema/hub.call Spokes (dev env, client, compute) │ ├── Connect ──→ Hub via WebSocket (wss://api.alk.dev/ws) ├── Register ──→ hub.register (identity, operations, spokeType) ├── Receive ──→ call.requested from hub, execute, respond └── Call ──→ hub operations over same WS (bidirectional) ``` ## Relationship to ade_ts The hub design was informed by prior work on API server patterns for spoke orchestration: - **Same**: Operation registry, pubsub, call protocol, call graph, operation graph - **Different**: Postgres instead of DbType.Table, Redis instead of iroh-gossip, AI SDK instead of Effect, WebSocket spoke transport instead of in-process WorkerPool, discovery+call MCP pattern instead of direct tool exposure - **Shared**: Both projects share the same spoke foundation. Architecture docs can be cross-referenced. When ade_ts stabilizes its call protocol and graph patterns, alk.dev can adopt them. ## Open Questions 1. **Redis deployment topology** — Redis is deployed on the hub server. For production with many spokes on a compute server, may want Redis closer to containers for lower pub/sub latency. 2. **API auth model** — API keys with Keypal pattern? Or simpler token auth for stopgap? (Related: spoke-runner.md WebSocket auth question) 3. **SSO with Gitea** — Gitea at git.alk.dev uses its own auth. Should api.alk.dev share sessions?