Copy architecture docs, ADRs, storage domain specs, research, reviews, and 56 storage architecture tasks from the alkhub_ts monorepo. Adapt for standalone @alkdev/hub repo structure (src/ not packages/hub/). Sanitize all sensitive information: - Replace private IPs (10.0.0.1) with localhost defaults - Remove internal server hostnames (dev1, ns528096) - Replace /workspace/ private paths with npm package references - Remove hardcoded credentials from examples - Rewrite infrastructure.md without private network details Add Deno project scaffolding: deno.json (pinned deps), .gitignore, AGENTS.md, entry point. Migrate existing code stubs (crypto, config types, logger) with updated import paths.
104 lines
7.1 KiB
Markdown
104 lines
7.1 KiB
Markdown
---
|
|
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?
|