Design
Contract-first split
A contract is split from its implementation:
- The contract is pure, isomorphic, and zero-dependency. It carries
name,description,sideEffects,idempotency, optionalauth/concurrencymetadata, andinput/outputschemas — but never a handler. It can ship to a browser, an edge runtime, or a separate client repo. - The implementation (
implement(contract, handler)) lives server-side and may import your DB and services.
A one-line defineAction fuses the two for trivial single-file cases; it splits the contract back out pure, so the isomorphic guarantee holds either way.
The manifest IR
Every contract compiles to a JSON-serializable manifest: per action a name, description, sideEffects, idempotency, optional auth/concurrency, and JSON Schema for input/output (draft 2020-12). The manifest is the single source of truth that every surface and the doctor read.
Schema compilation is tiered (Standard Schema exposes only validate() at runtime, so a universal converter is impossible):
- the built-in
sbuilder compiles directly (it owns its structure); - any schema implementing the
~standard.jsonSchemacompanion spec is used as-is; - a registered per-vendor converter handles the rest;
- otherwise resolution fails loudly with guidance.
A toStrictJsonSchema() transform derives the OpenAI Structured-Outputs variant (additionalProperties: false, all-required, null-union optionals).
Middleware
Cross-cutting concerns compose as typed middleware in @agentora/server: trace, auth, idempotency, concurrency, retry, redact. They run as an onion around the handler: input is validated first, then middleware, then the handler, then output validation. Per-contract metadata (sideEffects, idempotency, auth, concurrency) is data the middleware and doctor read. Stateful middleware take a pluggable Store (in-memory by default).
Surfaces are adapters
Each surface is a function (app) => surface, independently installable. Adding one surface never pulls another into your bundle. The runtime standardizes streaming on Web Streams / async generators and threads an AbortSignal, so adapters run on Node and edge runtimes alike.
defineContract
│
▼
manifest IR ──┬──▶ MCP tools
├──▶ AI SDK tools
├──▶ OpenAI specs
├──▶ HTTP handler
└──▶ doctor score