Guide · @staticflux/capabilities · @staticflux/webmcp · @staticflux/ai · @staticflux/advisors · @staticflux/sandbox
AI, capabilities, WebMCP, advisors & sandbox
Agents are first-class callers, not a side channel: the same typed capabilities, the same gates and confirmations, the same meters and traces as a user clicking a button.
#Capabilities: one pipeline for every caller
export const InsertImageCapability = defineCapability({
id: 'agent/insert-image',
title: 'Insert image',
description: 'Insert an image block into the open document.',
input: s.object({ src: s.string({ minLength: 1 }), alt: s.optional(s.string()) }),
output: s.object({ blockId: s.string() }),
policy: { resource: 'agent/insert-image' },
requiresConfirmation: false,
destructive: false,
costEstimate: () => ({ meter: CreditsMeter.id, amount: 2 }),
});
const insertImage = implementCapability(InsertImageCapability, async (input) => {
const blockId = await doc.insertImage(input.src, input.alt); // Result<string>
return blockId.ok ? ok({ blockId: blockId.value }) : blockId; // output is validated too
});
const result = await registry.invoke(InsertImageCapability, { src }, { subject: 'agent', signal });
Every invocation: validate input → authorize (decide port) → confirm (confirm port) → ensure the owning feature is active → reserve the meter → run → validate output → commit or release — a typed capabilities/invocation machine and a capability.invoke span. Destructive actions by non-user subjects always need confirmation, and the default confirm port fails closed.
#WebMCP: capabilities as agent tools
Register webMcpUnits and every capability declared with exposeToAgents is published as a WebMCP tool (JSON Schemas from the capability schemas, destructiveHint from destructive). Tool calls go through registry.invoke(…, { subject: 'agent' }) — no per-feature WebMCP code. The experimental API is isolated in one adapter; unsupported browsers get a no-op.
#One model-provider port
@staticflux/ai wraps browser built-in AI (Prompt, Summarizer, Translator, Language Detector), decision models (closed options → probabilities), remote LLMs and a mock behind ModelProvider, routed per task by createModelRouter. Availability, including download state and progress, is a reactive fact features gate on. Requests never start a model download implicitly — prepare(task) runs from a user gesture — and AI is never on the critical path: every call is async, cancellable, returns a Result, and has a non-AI fallback.
#Advisors suggest; the framework decides
export const NextChunk = defineDecisionPoint({
id: 'loader/next-chunk',
purpose: 'warmup',
options: ['feature:agent-chat', 'feature:settings', 'feature:billing'],
latency: 'sync',
heuristic: () => 'feature:agent-chat', // deterministic default
});
const advice = advisors.decide(NextChunk, { route: 'studio/doc' }); // never blocks
Decision points (warmup, retention, scheduling, prefetch, messaging timing, sampling) consult heuristic, statistical (a bounded Markov model in a user-data slice), on-device model or remote advisors — time-boxed, clamped by budgets and gates, with the overridden default and outcome recorded. Remote advisors receive only declared, minimized feature vectors.
#Sandboxed third-party plugins
createPluginHost runs untrusted plugins in a sandboxed iframe (opaque origin, strict CSP, allow-scripts only) or a worker, talking typed RPC over a MessagePort. A plugin can only invoke the capabilities granted to it (through the same registry.invoke, as subject plugin), receive declared events and render into a host slot. Every message is rate-, size- and shape-checked; violations beyond a budget kill the plugin.
AGENTS.md on GitHub: @staticflux/capabilities · @staticflux/webmcp · @staticflux/ai · @staticflux/advisors · @staticflux/sandbox