AI
The NetScript AI stack is a set of composable seams for building agentic chat and tool-calling surfaces on the same contracts-first, hexagonal foundation as the rest of the framework. It is deliberately layered: a provider-agnostic engine at the design center, an MCP client stack that turns external MCP servers into agent tools, a durable-chat runtime that turns a Fresh route into a chat whose history survives reload and reconnect, and an app-owned chat UI you copy into your workspace and keep. Each layer stands on its own and each is published — you can adopt one without pulling in the others.
That layering is the build-efficiency argument: whether the next slice of your app is written by you or generated by an agent, each capability is one published seam away — install it, wire the port, and the vocabulary already matches the layer above — instead of a bespoke integration to design before the feature work starts.
The story: a chat that stops being a demo
The first version of an AI feature is usually a chat box holding its transcript in component state — and it works until it meets reality. A reload mid-answer loses the in-flight tool call. The answer needs a chart, and now model output is being glued into the DOM by hand. The agent needs a capability that lives behind an external MCP server, and suddenly you are writing a protocol client. Each failure lands on a different layer of this stack, and each layer answers exactly one of them:
- history that survives — the durable-chat runtime backs the session with a durable stream and one projection reducer, so reload, reconnect, and multi-tab replay all converge on the same transcript;
- model-authored UI without raw HTML — the chat UI renders
render_uipayloads through a curated block vocabulary with depth limits and safe fallbacks; - external capabilities as ordinary tools — the MCP client stack pools servers, injects auth, and registers remote tools into the same registry the agent loop dispatches;
- one vocabulary underneath — the engine owns the contracts all of the above speak, so the layers compose instead of adapting to each other.
The two planes — never build chat on the wrong primitive
NetScript models real-time state in two distinct planes, and the single most common mistake is reaching for the wrong one. A StreamDB shape and a durable chat session look adjacent — both are live and durable — but they answer different questions.
| Axis | StreamDB shapes (data) | Durable chat sessions (AI chat) |
|---|---|---|
| Unit | A collection / row shape | One chat session (append-only chunk log) |
| Identity | Keyed by row id inside a named shape | Keyed by sessionId — one stream per chat |
| Write model | CRUD mutations reconciled into the shape | Append-only sanitized chunks |
| What survives | The current materialized rows | The full replayable log (messages + tool cards) |
| Read primitive | useLiveQuery over a shape |
resolveChatSnapshot + live useChat |
| Use it for | Lists, boards, tables, dashboards | Conversational, streaming, tool-calling chat |
A chat needs the session plane because a tool call is a multi-chunk, mid-stream
event: it moves through pending → streaming → complete and cannot be expressed as a
single reconciled row without losing those intermediate states. Reach for
durable streams when you want live list/board/table
data; reach for durable chat when you want a replayable
conversation. Conflating them is the documented root of the plane confusion — keep
them distinct.
The engine is the design center
@netscript/ai is a ports-and-adapters (hexagonal) core with zero
@netscript/* dependencies. Every capability — telemetry, tool registry, embeddings,
vision, MCP transport, the agent loop, memory — is a port: an interface the
composition root wires at startup, defaulting to a no-op or throwing implementation
until you inject a real one. Providers register themselves through side-effect
imports (import "@netscript/ai/anthropic", mirroring @netscript/kv/redis), so
the base engine pulls no vendor SDK you did not ask for. Models are addressed by a
"provider:model" reference string, e.g. "anthropic:claude-sonnet-4-5".
Because the engine owns the vocabulary — the Message/ContentPart content model,
the AgentChunk streaming union, the tool and MCP contracts — every layer above it
speaks the same types. And because telemetry is a port, an agent run is observable
the moment you inject a real TelemetryPort: the loop opens a gen_ai.chat span
per run and a gen_ai.chat.turn span per model turn, and records tool calls as
gen_ai.tool.call events. The engine reference is the full map.
Thin plugins, centralized convention
The AI capability follows the framework's plugin doctrine (Architecture Doctrine
ch. 11): R-PLUGIN-THIN — every convention-bearing primitive lives in a core
@netscript/* package, and a plugin carries only its own specifics — and
R-PLUGIN-SEAM — a plugin's contract lives in its -core sibling and conforms to
the base contract in @netscript/plugin. In practice the engine (@netscript/ai)
owns the vocabulary, @netscript/plugin-ai-core owns the /v1/ai oRPC contract, and
@netscript/plugin-ai stays a thin delivery shell — all three published at
0.0.6. This split is what keeps the published surface coherent: the runtime
layers (@netscript/fresh/ai, the fresh-ui copy registry) are self-contained, and
adopting the engine later changes nothing about them.
One comparison
Medusa's hero names "Agents and Developers" as co-audiences and its agent story is a progressive narrative — agents build a store feature, then optimize it, then operate the running store. Convex ships "backend building blocks for your agents" as components on its reactive backend. NetScript's AI stack occupies the same layered-investment shape with a different center of gravity: the layers here are the published framework surface itself — a JSR engine package, subpath exports, and a copy-registry you own — wired to the same contracts-first backend the rest of your app is built on, rather than a product layer alongside it. The trade is explicit: NetScript does not ship an agents-operate-your-app product tier today; it ships the seams those products are made of.
Where to go next
The MCP client stack: transports, injected auth, multi-server pooling, and safe rendering of ui:// resources from tool results.
Guide Durable chatTurn a Fresh route into a durable AI chat: history and in-flight tool calls survive reload, reconnect, and multi-tab.
Guide Chat UIThe fresh-ui `ai` copy-registry: composer, message thread, tool-call cards, and the generative-UI block renderer — copied into your app and owned by you.
Reference AI engine@netscript/ai: the provider-agnostic runtime, contracts vocabulary, ports, tools, agent loop, MCP transports, and provider adapters.
Related Durable streamsThe other real-time plane — live list/board/table data over the durable-stream server.
Related Web LayerThe Fresh page and island model the durable-chat runtime plugs into.
API Reference @netscript/aiGenerated symbols for the AI engine package.
API Reference @netscript/plugin-aiGenerated symbols for the thin AI plugin delivery shell.
API Reference @netscript/plugin-ai-coreGenerated symbols for the AI plugin's reusable contract and composition core.
Learn, do, look up
A durable, tool-calling chat with MCP and live streaming.
Do RecipesTask-oriented recipes for this area, one problem each.
Look up `@netscript/ai` referenceGenerated API reference. Related units: `plugin-ai`, `mcp`.
Understand The plugin systemThe design rationale behind this pillar.