Replace the Vercel AI SDK with direct OpenAI SDK calls and a custom AgentLoop. The AI SDK has zero runtime integration today, so removing it costs nothing. Supply chain risk (2-5 releases/day, April 2026 Vercel breach, bus factor of 1) makes it a liability we don't need. Key changes: - ADR-018 accepted: openai package (zero runtime deps) replaces ai SDK - AgentLoop handles multi-step tool execution explicitly (~300 LOC vs AI SDK's ~2700 LOC streamText) - Hub owns UIMessage/UIPart/ToolCallState types (extends ADR-016) - Hub owns streaming protocol (subset of AI SDK's UIMessageChunk wire format with step boundaries, error handling, usage tracking) - operationToOpenAITool() maps TypeBox schemas directly, no adapter - Trade-off: ~1100 LOC total new code for the savings of 6+ transitive deps, supply chain risk, and release cadence coupling Updates AGENTS.md constraints and dependencies, adds OQ-63/OQ-64/OQ-65 and Theme 11 (Inference & LLM Integration) to open questions.
4.9 KiB
4.9 KiB
AGENTS.md
Project orientation for agents working in this repository.
Project
@alkdev/hub — Hub API server for the alk.dev platform. Deno + TypeScript, this is a standalone Deno project (not a workspace). Spokes are separate packages/repos.
Repository Structure
src/
config/ — Configuration types, encrypted config loading
crypto/ — AES-256-GCM, PBKDF2, key management
logger/ — Logtape configuration
storage/ — Drizzle table definitions, relations, client, migrations
server/ — Hono HTTP server, routes, middleware
auth/ — API key auth (keypal), session tokens
coordination/ — coord.spawn/status/message/notify/abort/detect
redis/ — Redis EventTarget setup, event routing
inference/ — OpenAI-compatible proxy, LLM key management, AgentLoop, hub-own streaming
docs/
architecture/ — Architecture specs (see overview.md for index)
decisions/ — ADRs
research/ — Research docs
reviews/ — Review docs
tasks/
architecture/ — Architecture-phase tasks (storage/ has detailed tasks)
migrations/ — Drizzle SQL migrations
External Dependencies (npm, pinned)
| Package | Version | Purpose |
|---|---|---|
@alkdev/operations |
0.1.0 | Operations registry, call protocol, MCP adapter, ResponseEnvelope |
@alkdev/pubsub |
0.1.0 | PubSub, event targets (Redis/WS/Worker), operators, EventEnvelope |
@alkdev/taskgraph |
0.0.2 | Task graph construction, analysis, frontmatter |
@alkdev/flowgraph |
0.1.0 | Workflow graph: DAG construction, ujsx templates, reactive execution |
@alkdev/typebox |
0.34.49 | Runtime type schemas (fork of @sinclair/typebox 0.x LTS) |
@alkdev/drizzlebox |
0.1.0 | TypeBox schema generation from Drizzle tables |
hono |
4.12.23 | HTTP framework |
drizzle-orm |
0.45.2 | Postgres ORM |
ioredis |
5.10.1 | Redis client |
keypal |
0.2.0 | API key management |
openai |
TBD (pin on add) | OpenAI API client for LLM calls (zero runtime deps) |
pg |
8.21.0 | Postgres driver |
@hono/mcp |
0.3.0 | MCP server middleware |
@logtape/logtape |
2.1.1 | Structured logging |
@modelcontextprotocol/sdk |
1.29.0 | MCP SDK |
Key Patterns
- Operations: Everything is a typed operation with TypeBox schemas.
IOperationDefinitiondefines name, namespace, type (QUERY/MUTATION/SUBSCRIPTION), input/output schemas, access control, and handler. Registered inOperationRegistry, called viaregistry.execute()(returnsResponseEnvelope<T>) or call protocolPendingRequestMap/CallHandler. See operations.md and call-graph.md. - PubSub:
@alkdev/pubsubwithEventEnvelopepattern for structured cross-process messages.createPubSubwith pluggableTypedEventTarget—EventTarget(in-process),RedisEventTarget(cross-process),WebSocketEventTarget(hub<->spoke),WorkerEventTarget. 13 operators. - Task graph:
@alkdev/taskgraphfor task DAG construction, analysis (critical path, parallel groups, bottlenecks, risk), and frontmatter parsing. - Flow graph:
@alkdev/flowgraphfor workflow DAG construction, operation/call graph management, ujsx template composition, reactive execution, and type-compatibility analysis. Wraps graphology with DAG enforcement. - Drizzle+TypeBox: Storage pattern uses
@alkdev/drizzleboxfor automatic TypeBox schema generation from Drizzle table definitions. Drizzle tables are the source of truth. - No Effect: We do not use Effect. Plain async/await throughout.
- call ≡ subscribe: At protocol level, a call and a subscription are the same thing with different consumption patterns. See call-graph.md.
Running
# Install dependencies
deno install
# Run tests
deno task test
# Type check
deno task typecheck
# Lint
deno lint
Constraints
- Deno runtime (latest stable), TypeScript strict mode
- Postgres for all persistent state (Drizzle ORM)
- Redis for cross-process events (ioredis)
- OpenAI SDK (
openaipackage) for LLM calls — no AI SDK (see ADR-018) - TypeBox for all runtime schemas (
@alkdev/typebox, not Zod or @sinclair/typebox) - Hono for HTTP server
- WebSocket for hub<->spoke transport (not SSE as primary)
- Pin dependency versions in deno.json — update manually when needed, fix bugs upstream first
- No mocked/stubbed implementations — real code only
- No Effect dependency
- No DbType.Table storage abstraction — use @alkdev/drizzlebox pattern
- Do not duplicate code from
@alkdev/operations,@alkdev/pubsub,@alkdev/taskgraph, or@alkdev/flowgraph— use the npm packages
Security
- No secrets in git: .gitignore excludes .env*, *.key, *.pem
- No secrets in environment variables: See hub-config.md — all secrets come from encrypted config or Docker secrets
- No private IPs/hostnames in git: Infrastructure docs contain only patterns, not actual server addresses
- Config file encryption: Sensitive fields are AES-256-GCM encrypted, see hub-config.md and ADR-008