# SlexKit Full LLM Documentation Version: 0.4.0 This file concatenates SlexKit's canonical English Markdown docs. `slex` fences are preserved exactly. # README URL: / Raw Markdown: /README.md Source: README.md
Streaming Live EXpressions Kit
"Docs as tools, tools as docs." Render explicit Markdown fences as live, stateful UI blocks.
Documentation · Components · Specification · AI / Agents · 简体中文
`) and mounting live previews.
```ts
function boot(options?: BootOptions): void;
type BootOptions = {
selector?: string;
sourceControls?: boolean;
theme?: ThemeMode;
dir?: MountOptions["dir"];
labels?: MountOptions["labels"];
};
```
Default selector covers: `language-slex`.
Hosts like React/Streamdown or Obsidian should typically use the Markdown runtime host directly rather than `boot()`.
### `register(type, renderer, options)`
Registers a component type with a render function and state mode.
```ts
function register(
type: string,
renderer: ComponentRenderer,
options?: ComponentRegistrationOptions
): void;
type ComponentRenderer = (
props: Record,
name: string,
ctx: RenderContext
) => HTMLElement | void;
type ComponentRegistrationOptions = {
state?: "value" | "checked" | "enabled" | "readable" | "none";
};
```
### `configureComponentScope(options)`
Configures a flush function for component scope. Framework adapters use it to synchronize DOM after reactive updates.
```ts
function configureComponentScope(options: { flush?: () => void }): void;
```
## Validation and conformance
### `validateSlexSource(source, options)`
Validates Slex source after parsing. The result includes `schemaVersion`, `protocolVersion`, `logicProfileVersion`, usage lists, and warning codes. Syntax failures return a diagnostic.
```ts
function validateSlexSource(
source: string,
options?: { mode?: "trusted" | "secure" }
): ValidationResult;
```
### `runSlexConformance(options)`
Runs the bundled standard fixtures against the current validator. Pass `fixtureId` to run one fixture.
```ts
function runSlexConformance(options?: { fixtureId?: string }): ConformanceReport;
```
## Namespace store
`namespace` is the state domain. Multiple mounts with the same namespace share one store:
- New `g` is deep-merged into the old `g` (functions overwrite, objects recursively merge, arrays replace, scalars overwrite).
- New `layout` replaces the current layout (no deep merge for layout).
- Component instance state is persisted within the namespace.
- Expression caches are managed per namespace.
This allows a document, message domain, or tool panel to update its UI incrementally while preserving state.
## Component instance state
Named components can expose instance state. Which prop is writable depends on the component's registered state mode:
| Mode | Writable prop | Behavior |
|------|---------------|----------|
| `value` | `value` | Writable from expressions and events |
| `checked` | `checked`, `value` | Both synced, writable |
| `enabled` | `enabled` | Switch enabled state, writable |
| `readable` | (none) | Readable from expressions, write emits a console warning |
| `none` | (none) | No state exposed |
```js
{
layout: {
"slider:threshold": { value: 42 },
"text:preview": { "$content": "'Threshold: ' + threshold.value" }
}
}
```
Repeatedly named components share namespace-level state. `$for` items with the same component name also share one state instance.
## Lifecycle hooks
The runtime calls convention-based hooks on the `g` object:
```
g.onMount_() // after component is appended to DOM
g.onUnmount_() // before component is removed from DOM
g.onUpdate_() // after $for item index or item reference changes
```
These hooks fire for normal components, `$if` branches, and `$for` slots. Root cleanup and `disposeNamespace()` trigger `onUnmount`.
## Component disposer
Framework components, event listeners, subscriptions, and external resources should bind their cleanup to the component DOM element:
```ts
import { register, attachComponentDisposer } from "slexkit/runtime";
register("custom", (props, name, ctx) => {
const el = ctx.document.createElement("div");
const stop = subscribeSomething();
attachComponentDisposer(el, stop);
return el;
});
```
The runtime calls the disposer when the element is unmounted. The official Svelte adapter uses this mechanism to destroy Svelte component instances.
## Expression evaluation context
Expressions in `$` read-pipes and statements in `on*` write-pipes can access these variables:
| Variable | Type | Availability |
|----------|------|--------------|
| `g` | reactive state proxy | always |
| `api` | host-injected capabilities | if `api` option passed to `mount()` |
| `$event` | event data | `on*` handlers only |
| `$item` | current array item | `$for` context only |
| `$index` | current array index | `$for` context only |
| `$key` | current item key | `$for` context only |
| named component state | e.g. `threshold.value` | named components |
Expression evaluation uses `new Function()` in trusted mode. Evaluation errors are caught and produce a console warning with namespace and path information; the last known value is used as a fallback.
---
# Host Integration
URL: /docs/reference/integration
Raw Markdown: /docs/reference/integration.md
Source: site/content/reference/integration/en-US.md
---
title: Host Integration
category: Reference
status: ready
order: 40
summary: "MarkdownRuntimeHost, trusted and secure host integrations, Svelte custom hosts, Streamdown, Tiptap, Obsidian, and custom adapters."
slexkitRenderMode: component
---
# Host Integration
How to integrate SlexKit into Markdown renderers, chat hosts, document viewers, and custom platforms.
## Core concepts
### Artifact
An artifact is a group of Slex blocks belonging to the same document, message, or note. Hosts identify an artifact by an `artifactId` and group related blocks into one runtime domain.
In **trusted mode**, the runtime prefixes each block's namespace with the artifact ID to prevent cross-document state pollution. `disposeArtifact()` releases all namespace stores for that artifact.
In **secure mode**, all fences in one artifact are combined into a single sandbox iframe. The runtime uses artifact slots to sync rendered heights back to the original Markdown placeholder containers.
### Block
A block is a single Slex block: one renderable unit. It has:
- A source (Slex expression object or source string).
- A container element (where the rendered output goes).
- An optional `artifactId` (for grouping into an artifact).
### Cleanup
Every block mount returns a cleanup function. The host must call it when the block is removed. For artifact-level cleanup, call `disposeArtifact(artifactId)`. For global cleanup, call `disposeAll()`.
## MarkdownRuntimeHost
The `SlexKitMarkdownRuntimeHost` is the recommended API for Markdown-based hosts. It handles mode selection, artifact management, and block lifecycle.
```ts
import {
createSlexKitMarkdownRuntimeHost,
getSlexKitMarkdownRuntimeHost,
installSlexKitMarkdownRuntimeHost
} from "slexkit";
```
### Interface
```ts
type SlexKitMarkdownRuntimeHost = {
configure(options: Partial): void;
getMode(): "trusted" | "secure";
mountBlock(block: SlexKitMarkdownBlock): () => void;
disposeBlock(container: HTMLElement): void;
disposeArtifact(artifactId: string): void;
disposeAll(): void;
};
type SlexKitMarkdownBlock = {
artifactId?: string;
blockId?: string;
source: SlexExpression | string;
container: HTMLElement;
stateOnly?: boolean;
theme?: ThemeMode;
dir?: MountOptions["dir"];
labels?: MountOptions["labels"];
executionMode?: MountOptions["executionMode"];
};
type SlexKitMarkdownRuntimeOptions = {
mode?: "trusted" | "secure";
policy?: HostRuntimePolicy;
hostAdapter?: HostRuntimeAdapter;
secureFrame?: boolean | SecureFrameOptions;
theme?: ThemeMode;
dir?: MountOptions["dir"];
labels?: MountOptions["labels"];
executionMode?: MountOptions["executionMode"];
};
```
`executionMode: "preview"` is for speculative renders of repaired streaming prefixes. In preview mode, trusted mounts render readable UI but freeze write handlers, component emits, lifecycle hooks, and `api.*` capabilities. Blocks can override a host-level default by passing `executionMode` directly to `mountBlock()`.
### Global singleton
The module provides a global singleton for convenience:
```ts
// Install explicitly
const runtime = installSlexKitMarkdownRuntimeHost({
mode: "secure",
policy: { execution: { maxUnresponsiveMs: 30000 } },
secureFrame: { runtimeUrl: "/slexkit.runtime.js" }
});
// Or use lazy global (auto-creates with defaults on first call)
const runtime = getSlexKitMarkdownRuntimeHost();
```
Use the singleton when the entire application shares one runtime configuration. Avoid it when different host contexts need different policies.
## Trusted mode integration
Trusted mode runs Slex source in the host page realm. Use for local documents, application-generated content, or reviewed Slex source.
```ts
const runtime = createSlexKitMarkdownRuntimeHost({
mode: "trusted",
theme: "host-shadcn"
});
// Detect a slex fence at position
const cleanup = runtime.mountBlock({
artifactId: "doc-1",
source: fenceSource,
container: fenceContainer
});
// When the fence container is removed
runtime.disposeBlock(fenceContainer);
// When the document is closed
runtime.disposeArtifact("doc-1");
// When the plugin or page unloads
runtime.disposeAll();
```
In trusted mode, the runtime automatically scopes namespaces by artifact ID (`::`) to prevent different documents from polluting each other's state.
State-only blocks (no `layout`, only `g` updates) are detected automatically and ingested via `ingest()`. Subsequent renderable blocks in the same artifact can read that state.
## Secure mode integration
Secure mode runs Slex source in a sandbox iframe. Use for untrusted or agent-generated Markdown.
```ts
const runtime = createSlexKitMarkdownRuntimeHost({
mode: "secure",
policy: {
execution: { maxUnresponsiveMs: 30000 }
},
secureFrame: {
runtimeUrl: "/slexkit.runtime.js"
},
theme: "host-shadcn"
});
const cleanup = runtime.mountBlock({
artifactId: "agent-msg-1",
source: agentGeneratedDsl,
container: fenceContainer
});
```
Omitted capability policies deny access by default. Add `network`, `timer`, `animation`, or `canvas` policy objects only when the host intentionally enables those capabilities.
### Artifact slot bridge
When multiple secure blocks belong to the same artifact, they share one sandbox iframe. The first block (in document order) becomes the iframe anchor. Other blocks act as slots; their containers receive position and height updates from the sandbox via the postMessage bridge.
```html
```
This allows state sharing across fences within one artifact while keeping all execution confined to one sandbox.
### `runtimeUrl` requirements
The `runtimeUrl` must serve the SlexKit runtime as an ES module with:
```
Access-Control-Allow-Origin: *
Content-Type: text/javascript
```
The build output includes `dist/runtime.js` for this purpose. The `slex copy-runtime` command copies that module to `public/slexkit.runtime.js` by default so existing secure-frame URLs can stay stable. Configure the CDN or static file server to serve it with the correct headers.
## Svelte custom Markdown host
The SlexKit website uses Svelte plus a custom Markdown renderer instead of a packaged Svelte Markdown adapter. The public contract is still `createSlexKitMarkdownRuntimeHost`; the Svelte pieces are host code.
```js
import { mount, unmount } from "svelte";
import { createSlexKitMarkdownRuntimeHost } from "slexkit";
import MarkdownRenderer from "./MarkdownRenderer.svelte";
export function renderMarkdown(content, container, options = {}) {
const runtimeHost = options.slexkitRuntimeHost ?? createSlexKitMarkdownRuntimeHost({
mode: options.runtimeMode ?? "trusted",
theme: "host-shadcn"
});
const app = mount(MarkdownRenderer, {
target: container,
props: {
content,
runtimeHost,
artifactId: options.artifactId,
slexkitRenderMode: options.slexkitRenderMode ?? "component"
}
});
return () => unmount(app);
}
```
Use this as an implementation reference when the host owns its Markdown AST or Svelte renderer. Do not treat `site/markdown/*` as a separately versioned package API.
## Streamdown / React integration
The `@slexkit/streamdown` package provides a React/Streamdown custom renderer:
```tsx
import { Streamdown } from "streamdown";
import { slexkitRenderer } from "@slexkit/streamdown";
import "@slexkit/theme-shadcn/style.css";
import "@slexkit/streamdown/style.css";
export function Message({ markdown }: { markdown: string }) {
return (
{markdown}
);
}
```
The renderer handles `slex` fences. It supports both trusted and secure runtime modes and can delegate to a shared Markdown runtime host instance.
During token streaming, `streaming="repair"` is the default for trusted renders. A parseable source mounts immediately; a source missing only EOF closing tokens mounts as preview; uncertain prefixes stay on the placeholder; clear syntax errors still render diagnostics. Use `streaming="stable"` to render only already-parseable prefixes, or `streaming={false}` to wait for the closing fence. Secure runtime and secure runtime-host renders do not execute repaired prefixes in the host realm.
## Tiptap integration
The `@slexkit/tiptap` package provides a framework-free Tiptap `CodeBlock` extension:
```ts
import StarterKit from "@tiptap/starter-kit";
import { Markdown } from "@tiptap/markdown";
import { createSlexKitTiptapExtension } from "@slexkit/tiptap";
import "@slexkit/theme-shadcn/style.css";
import "@slexkit/tiptap/style.css";
const extensions = [
StarterKit.configure({ codeBlock: false }),
Markdown,
createSlexKitTiptapExtension({ artifactId: "doc-1" })
];
```
The adapter only takes over `codeBlock` nodes with `language === "slex"`. Non-Slex code blocks remain ordinary Tiptap code blocks, and Markdown import/export keeps standard ` ```slex ` fences through Tiptap's Markdown extension.
Each editor instance gets one trusted Markdown runtime host by default. Blocks in that editor share an artifact ID, so state-only fences can seed later renderable fences. Pass `runtimeHost` or `artifactId` when the host needs explicit lifecycle ownership.
## Obsidian integration
The official Obsidian plugin is available at and registers the `slex` fenced code block processor:
```ts
// In the plugin:
registerMarkdownCodeBlockProcessor("slex", (source, el, ctx) => { ... });
```
The adapter renders blocks in **reading mode only** and does not write back to the vault. Blocks within the same note share a trusted artifact runtime.
**Important**: The Obsidian adapter uses trusted mode because it renders content from the user's local vault. It is not designed as a security boundary for untrusted or agent-generated Markdown.
## Writing a custom host adapter
To integrate SlexKit into a custom Markdown renderer or chat host:
### 1. Detect fence language
Only process fences tagged with `slex`. Never scan plain JavaScript, JSON, or untagged code blocks.
### 2. Create a runtime host
```ts
import { createSlexKitMarkdownRuntimeHost } from "slexkit";
const runtime = createSlexKitMarkdownRuntimeHost({
mode: "trusted", // or "secure"
theme: "host-shadcn"
});
```
### 3. Mount blocks
For each detected fence, create a container element and mount:
```ts
function processFence(source: string, fenceIndex: number) {
const container = document.createElement("div");
// Insert container at the fence position in the document
const cleanup = runtime.mountBlock({
artifactId: "message-42",
source,
container
});
return cleanup;
}
```
### 4. Manage lifecycle
```ts
// When a single block is removed
runtime.disposeBlock(container);
// When the entire artifact (message/document) is removed
runtime.disposeArtifact("message-42");
// When the plugin/page unloads
runtime.disposeAll();
```
### 5. Handle secure mode
If using secure mode, serve `slexkit.runtime.js` as a public ES module with the correct CORS headers, and configure `secureFrame.runtimeUrl`.
## Fallback rendering
SlexKit-capable hosts should still include the raw fence content or a plain text fallback in the DOM for environments that don't support SlexKit. The runtime replaces the container children, so fallback text is only visible before mount or after disposal.
---
# Security Runtime
URL: /docs/reference/security
Raw Markdown: /docs/reference/security.md
Source: site/content/reference/security/en-US.md
---
title: Security Runtime Contract
category: Reference
status: ready
order: 50
summary: "Threat model, sandbox iframe deployment, host policy, postMessage bridge, and fail-closed behavior."
slexkitRenderMode: component
---
# Security Runtime Contract
The secure runtime defines what untrusted Slex source can and cannot do, how the host authorizes capabilities, and how sandbox isolation works.
## Threat model
- The host page and host application are trusted.
- Slex source may be untrusted.
- Secure artifacts run inside a sandbox iframe.
- The iframe uses an opaque origin by default (no `allow-same-origin`).
- Slex source must not access the host DOM, cookies, `localStorage`, `IndexedDB`, or host global objects.
Secure mode confines expression execution to an isolated environment and consolidates sensitive capabilities under the host `policy` and `api.*`.
## Authorization source
The sole authorization source is the `HostRuntimePolicy` provided by the host. Slex source fields such as `capabilities`, `permissions`, `api`, or other top-level declarations cannot grant themselves authority.
All capabilities are accessed through `api.*`:
```
api.get(url, options)
api.post(url, body, options)
api.fetch(url, options)
api.setTimeout(fn, ms)
api.clearTimeout(id)
api.setInterval(fn, ms)
api.clearInterval(id)
api.raf(fn)
api.cancelRaf(id)
api.createCanvas(width, height)
api.getCanvasContext(canvas, contextId, options)
api.onDispose(fn)
api.now()
api.isTimeoutError(error)
api.isNetworkError(error)
api.isPolicyError(error)
api.errorMessage(error)
```
Capabilities not exposed through `api.*` are unsupported.
## HostRuntimePolicy
```ts
type HostRuntimePolicy = {
network?: {
enabled: boolean;
methods: ("GET" | "POST")[];
allowOrigins: string[];
allowHeaders?: string[];
allowContentTypes?: string[];
credentials: "omit" | "same-origin" | "include";
timeoutMs: number;
maxBodyBytes: number;
maxResponseBytes?: number;
};
timer?: {
enabled: boolean;
maxTimers: number;
minIntervalMs: number;
};
animation?: {
enabled: boolean;
};
canvas?: {
enabled: boolean;
maxCanvases?: number;
maxPixels?: number;
allowedContexts?: ("2d" | "webgl" | "webgl2" | "bitmaprenderer")[];
};
execution?: {
heartbeatIntervalMs?: number;
maxUnresponsiveMs?: number;
};
};
```
### Network policy
Network is denied by default unless `policy.network.enabled` is `true`. The policy constrains:
- HTTP method (only listed methods allowed)
- Origin (supports `*`, exact match, `protocol://*` protocol wildcard, and `protocol://*.domain` subdomain wildcard)
- Request headers (only listed headers pass; `Authorization`, `Cookie`, `Proxy-Authorization`, `Set-Cookie`, and Sec-Fetch headers are always blocked)
- Credentials mode
- Request body size
- Request timeout
- Response body size
- Response content-type
`hostAdapter.fetch` can replace the actual request implementation. `hostAdapter.onNetworkLog` is observational only; it must not alter runtime behavior.
### Timer, animation, and canvas
- **Timer**: denied by default. When enabled, subject to `maxTimers` (total concurrent) and `minIntervalMs` (minimum delay). All timers and intervals are cleaned up on dispose.
- **Animation**: denied by default. Controlled via `animation.enabled`; `api.raf` is the only animation primitive.
- **Canvas**: denied by default. When enabled, subject to `maxCanvases`, `maxPixels`, and `allowedContexts`.
### Execution monitoring
`execution.heartbeatIntervalMs` controls how often the sandbox sends a heartbeat to the host. `execution.maxUnresponsiveMs` defines the maximum silence before the sandbox is terminated as unresponsive.
## HostRuntimeAdapter
The adapter allows the host to override or observe runtime behavior:
```ts
type HostRuntimeAdapter = {
fetch?: (request: HostFetchRequest) => Promise;
onNetworkLog?: (event: RuntimeNetworkLogEvent) => void;
onRuntimeError?: (event: RuntimeErrorEvent) => void;
now?: () => number;
setTimeout?: (fn: () => void, ms: number) => TimerId;
clearTimeout?: (id: TimerId) => void;
setInterval?: (fn: () => void, ms: number) => TimerId;
clearInterval?: (id: TimerId) => void;
requestAnimationFrame?: (fn: (time: number) => void) => RafId;
cancelAnimationFrame?: (id: RafId) => void;
};
```
`onNetworkLog` and `onRuntimeError` are audit hooks; they must not change runtime behavior. Errors thrown within them are silently caught.
## Sandbox iframe deployment
The secure frame imports the main runtime module from a `runtimeUrl`:
```ts
mountSecureArtifact(script, container, {
frame: {
runtimeUrl: "/slexkit.runtime.js"
}
});
```
This URL must serve as a public ES module and return:
```
Access-Control-Allow-Origin: *
Content-Type: text/javascript
```
This is server or deployment layer configuration; it cannot be set from frontend JavaScript.
### CSP
The sandbox iframe is served via `srcdoc` with a strict Content-Security-Policy:
```
default-src 'none'
script-src 'nonce-{random}' 'unsafe-eval' {runtimeOrigin}
connect-src 'none'
img-src data: blob:
style-src 'unsafe-inline'
font-src data:
form-action 'none'
base-uri 'none'
```
A random nonce is generated for each frame instance. `unsafe-eval` is required because Slex source expression evaluation uses `eval()` inside the sandbox.
### Sandbox attribute
The iframe requires `allow-scripts`. `allow-same-origin` is **blocked by default** because it would weaken the opaque origin isolation. Only set `unsafeAllowSameOrigin: true` explicitly if the host accepts the risk:
```ts
frame: {
unsafeAllowSameOrigin: true, // only with explicit host acceptance
sandbox: "allow-scripts allow-same-origin"
}
```
Do not add `allow-same-origin` to fix CORS or debugging issues.
## postMessage bridge protocol
The host and sandbox communicate via `window.postMessage`. All messages are tagged with `channel: "slexkit-secure"`.
### Host -Sandbox messages
| Type | Purpose |
|------|---------|
| `mount` | Sends Slex source, policy, theme to render |
| `dispose` | Tells sandbox to tear down |
| `fetch-result` | Returns fetch response or error |
| `slots` | Synchronizes artifact slot positions |
### Sandbox -Host messages
| Type | Purpose |
|------|---------|
| `ready` | Runner module loaded and listening |
| `mounted` | Artifact render confirmed |
| `disposed` | Sandbox teardown acknowledged |
| `heartbeat` | Periodic liveness signal |
| `error` | Mount or runtime error |
| `fetch` | Proxied network request |
| `slot-size` | Artifact slot height report |
Every host→sandbox message includes an `id` and `token`. The token is opaque, cryptographically random, and scoped to a single mount instance. Messages with mismatched tokens are rejected.
Messages are verified: the sandbox checks `event.source === window.parent`; the host checks `event.source === iframe.contentWindow`.
## Artifact slot bridge
Multiple Markdown fences belonging to one artifact share a single sandbox iframe. The host sends slot rectangles to the sandbox, which renders each fence's output inside the corresponding slot container. The sandbox reports each slot's rendered height back via `slot-size` messages.
A `ResizeObserver` on the host side and inside the sandbox keeps positions and heights synchronized. This preserves visual continuity across fences while keeping all execution confined to one isolation context.
## Heartbeat watchdog
When `execution.maxUnresponsiveMs` is set, the host monitors the sandbox heartbeat interval. If no heartbeat arrives within the threshold, the iframe is terminated, a diagnostic alert (`role="alert"`) is rendered, and a `console.error` is emitted.
## Fail-closed behavior
If the iframe cannot load the runtime, does not send a ready/mounted message, or the heartbeat times out, SlexKit:
1. Removes the unresponsive iframe.
2. Renders a `role="alert"` diagnostic element with a description of the failure.
3. Emits the same information via `console.error`.
Load timeout is configurable via `frame.loadTimeoutMs` (default: 8000ms).
## Escape hatches
### `unsafeInlineExecution`
Allows a secure artifact to execute inline in the host page with an injected secure runtime API. **Intended for testing or host-trusted content only.** Not recommended for untrusted paths.
```ts
mountSecureArtifact(script, container, {
policy,
hostAdapter,
unsafeInlineExecution: true
});
```
### `unsafeAllowSameOrigin`
Allows `allow-same-origin` in the sandbox attribute. **Reduces isolation strength**; only use when the host explicitly accepts the risk.
```ts
frame: {
sandbox: "allow-scripts allow-same-origin",
unsafeAllowSameOrigin: true
}
```
## Sandbox hardening
When the sandbox runner starts, it hardens the global scope:
**Blocked network globals** -`fetch`, `XMLHttpRequest`, `WebSocket`, `EventSource`, `Worker`, `SharedWorker`, and `navigator.sendBeacon` are replaced with functions that throw, ensuring all network traffic must go through the bridge.
**Blocked scheduling globals** -`setTimeout`, `setInterval`, `requestAnimationFrame` are replaced with functions that throw, directing code to `api.setTimeout()`, `api.setInterval()`, and `api.raf()`.
**Canvas prototype wrapping** -`HTMLCanvasElement.prototype.getContext` is wrapped to enforce canvas policy on context creation. `OffscreenCanvas` is replaced with a subclass that validates dimensions on construction.
## Maintenance principles
- New capabilities must define a policy field first, then an `api.*` method, then the bridge.
- Slex source declarations are never an authorization source.
- Default to opaque origin.
- Always fail closed.
- Log and error hooks are observational; they must not alter runtime behavior.
---
# Packages
URL: /docs/reference/packages
Raw Markdown: /docs/reference/packages.md
Source: site/content/reference/packages/en-US.md
---
title: Packages
category: Reference
status: ready
order: 60
summary: "SlexKit npm package roles, install combinations, publish contents, and release checks."
slexkitRenderMode: component
---
# Packages
SlexKit v0/beta package references list npm packages, install commands, and release checks.
## Package Map
```
slexkit (root package)
├── runtime entry
├── Svelte component registrations
├── ToolHost
├── default styles
└── secure iframe runner
@slexkit/runtime ─── re-exports slexkit/runtime
@slexkit/components-svelte ─── re-exports slexkit/components-svelte
@slexkit/theme-shadcn ─── CSS only
@slexkit/streamdown ─── React/Streamdown renderer
@slexkit/assistant-ui ─── assistant-ui Streamdown text wrapper
@slexkit/tiptap ─── framework-free Tiptap NodeView adapter
@slexkit/mcp ─── read-only MCP server for AI agents
```
`@slexkit/runtime` and `@slexkit/components-svelte` are published npm packages, but their code wraps the root `slexkit` package. They are not independent implementation packages; installing them still requires installing `slexkit`. `@slexkit/theme-shadcn` is CSS-only and contains no runtime implementation.
## slexkit (root)
The main implementation package. It contains the runtime engine, official Svelte components, ToolHost, and styles.
```sh
npm install slexkit
```
```js
import { mount, disposeNamespace, boot } from "slexkit";
import "slexkit/style.css"; // default styles (includes all component CSS)
```
`slexkit/dist/style.css` is a compatibility alias for the same distributed CSS bundle; do not import both paths.
Version helpers are exported from both the root and runtime entries:
```js
import { SLEXKIT_VERSION, SLEX_PROTOCOL_VERSION, getSlexKitInfo } from "slexkit";
```
The root package also ships the `slex` CLI:
```sh
slex copy-runtime public/slexkit.runtime.js
slex validate ./artifact.slex --mode secure
slex validate --standard
```
`slex validate --standard` runs the bundled Slex conformance fixtures against the validator shipped with the package. Use `--json` for CI or agent consumption.
## @slexkit/runtime
Component-free runtime entry point. Does not auto-register any official Svelte components.
```sh
npm install slexkit @slexkit/runtime
```
```js
import { mount, register, createSecureRuntime } from "@slexkit/runtime";
```
Use this to register a custom component set instead of the bundled Svelte components.
## @slexkit/components-svelte
Side-effect import that registers all official Svelte components into the runtime registry.
```sh
npm install slexkit @slexkit/runtime @slexkit/components-svelte
```
```js
import { mount } from "@slexkit/runtime";
import "@slexkit/components-svelte";
```
Public component specs: action (1), component (1), content (6), data (1), disclosure (2), display (3), feedback (2), input (6), layout (4), navigation (1), tooling (3).
## @slexkit/theme-shadcn
CSS theme bundle (shadcn/ui compatible).
```sh
npm install @slexkit/theme-shadcn
```
```js
import "@slexkit/theme-shadcn/style.css";
```
## @slexkit/streamdown
React/Streamdown custom renderer for Markdown-hosted SlexKit fences.
```sh
npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom
```
```tsx
import { Streamdown } from "streamdown";
import { slexkitRenderer } from "@slexkit/streamdown";
import "@slexkit/theme-shadcn/style.css";
import "@slexkit/streamdown/style.css";
export function Message({ markdown }: { markdown: string }) {
return (
{markdown}
);
}
```
Processes `slex` fences. Supports both trusted and secure runtime modes.
## @slexkit/assistant-ui
assistant-ui message text wrapper for SlexKit fences. It delegates Markdown rendering to `@assistant-ui/react-streamdown` and only overrides the `slex` language block with `@slexkit/streamdown`.
```sh
npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom
```
```tsx
import { MessagePrimitive } from "@assistant-ui/react";
import { SlexKitAssistantStreamdownText } from "@slexkit/assistant-ui";
import "@slexkit/theme-shadcn/style.css";
import "@slexkit/assistant-ui/style.css";
export function AssistantMessage() {
return (
{({ part }) =>
part.type === "text" ? (
) : null
}
);
}
```
The runtime defaults to secure. assistant-ui tool calls and ToolHost flows still use their own integration layers.
## @slexkit/tiptap
Tiptap extension for rendering explicit `slex` code blocks as SlexKit previews while preserving normal fenced code block Markdown roundtrip.
```sh
npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown
```
```ts
import StarterKit from "@tiptap/starter-kit";
import { createSlexKitTiptapExtension } from "@slexkit/tiptap";
import "@slexkit/theme-shadcn/style.css";
import "@slexkit/tiptap/style.css";
const extensions = [
StarterKit.configure({ codeBlock: false }),
createSlexKitTiptapExtension({ artifactId: "doc-1" })
];
```
The extension only takes over code blocks whose language is `slex`; ordinary code blocks stay native to Tiptap. It uses a trusted Markdown runtime host unless configured otherwise. Add `@tiptap/markdown` when loading or exporting Markdown.
## Obsidian plugin
The official Obsidian plugin lives in a separate release repository: .
Install **SlexKit** through Obsidian Community Plugins for normal vault use. Use BRAT or manual GitHub release assets only when testing unreleased builds from `slexkit/obsidian-slexkit`.
The community plugin is marked desktop-only and compatible with Obsidian 1.5.0+.
The plugin treats the user's local vault as trusted and uses trusted runtime mode. Do not use it as a sandbox for third-party or agent-generated Markdown; the v0 adapter does not include secure sandbox support.
## @slexkit/mcp
Read-only MCP server for AI agents. It serves generated LLM docs, component metadata, examples, runtime docs, ToolHost docs, and Slex source validation.
```sh
npx -y @slexkit/mcp
```
The server does not modify project files. Use it when an agent needs SlexKit component or runtime context.
## Installation matrix
| Use case | Install command |
|----------|----------------|
| Quick start, everything included | `npm install slexkit` |
| Component-free, custom components | `npm install slexkit @slexkit/runtime` |
| With Svelte components | `npm install slexkit @slexkit/runtime @slexkit/components-svelte` |
| Add shadcn theme | `npm install @slexkit/theme-shadcn` |
| React/Streamdown host | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom` |
| assistant-ui host | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom` |
| Tiptap editor host | `npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown` |
| Obsidian plugin | Install **SlexKit** from Obsidian Community Plugins |
| AI agent MCP server | `npx -y @slexkit/mcp` |
## v0 Package Layout
In v0, the root `slexkit` package carries the main implementation. Scoped `@slexkit/*` packages provide clearer install entry points. If these become physical packages later, source code, build output, and publish workflows need to split together.
## Release Check
Check all scoped packages together before publishing:
```sh
bun run build
bun run test
bun run lint
bun run smoke:release
npm pack --dry-run --json
slex validate --standard --json
```
The release smoke packs and installs every scoped package in this repository, verifies public entry points, verifies CSS subpath exports, runs the installed `slex validate --standard --json`, and starts the MCP stdio binary to check `initialize`, `tools/list`, and `slexkitValidate`.
Before publishing, check that `npm pack --dry-run --json` includes `dist/standard/*` and `scripts/cli.mjs`. Standard artifacts must match `package.json`, `SLEX_PROTOCOL_VERSION`, and the bundled conformance fixtures.
---
# Slex Standard Artifacts
URL: /docs/reference/standard
Raw Markdown: /docs/reference/standard.md
Source: site/content/reference/standard/en-US.md
---
title: Slex Standard Artifacts
category: Reference
status: ready
order: 65
summary: "JSON artifacts for the Slex envelope, component catalog, logic profile, capabilities, conformance fixtures, and manifest."
slexkitRenderMode: component
---
# Slex Standard Artifacts
SlexKit provides machine-readable JSON files for agents, host runtimes, MCP servers, and package users. These files describe Slex as a Markdown-embedded UI artifact with local state and logic, not as a pure JSON card catalog.
The JSON files are generated from the TypeScript runtime registry, component specs, runtime version constants, expression capability metadata, and conformance fixtures.
## Files
- [`/standard/slex-standard-manifest.json`](/standard/slex-standard-manifest.json): version, protocol, logic profile, artifact paths, and hashes.
- [`/standard/slex-expression.schema.json`](/standard/slex-expression.schema.json): JSON Schema for the Slex envelope, `namespace`, `g`, `layout`, component keys, and directive fields.
- [`/standard/slex-component-catalog.json`](/standard/slex-component-catalog.json): public component props, dynamic flags, generated prop JSON Schema, state modes, children, examples, docs, and per-component hashes.
- [`/standard/slex-logic-profile.json`](/standard/slex-logic-profile.json): `$` read-pipes, `on*` write-pipes, `$if`, `$for`, `$key`, context variables, reserved names, component state, and secure-mode native capability policy.
- [`/standard/slex-capabilities.catalog.json`](/standard/slex-capabilities.catalog.json): deterministic `std.*` functions and policy-gated `api.*` secure runtime capabilities.
- [`/standard/slex-conformance.json`](/standard/slex-conformance.json): valid, warning, and invalid fixtures with stable expected diagnostic codes, paths, and values.
## Validation Model
Validation is parse-first:
1. Parse the JavaScript object literal source.
2. Validate the Slex envelope and component-key shape.
3. Compare component names and props against the generated component catalog.
4. Scan logic strings and source text against the logic profile.
5. Return stable diagnostic and warning codes.
`validateSlexSource()` keeps its previous structured output and adds `schemaVersion`, `protocolVersion`, and `logicProfileVersion`. Secure-mode diagnostics should guide authors toward policy-gated `api.*` capabilities instead of treating all logic as forbidden.
Warnings are path-aware after parsing. For example, an unknown `std.*` call in `layout.text:value.$text` and a native `fetch()` call in `g.load` produce different stable paths, so tools can point to one expression instead of rewriting the whole artifact.
## Run Conformance
Use the bundled conformance runner to verify that SlexKit's validator still matches the published standard fixtures:
```sh
slex validate --standard
slex validate --standard --json
slex validate --standard --fixture valid-full-envelope
```
Use file validation for a single Slex source:
```sh
slex validate ./artifact.slex --mode secure
slex validate ./artifact.slex --mode trusted --strict
```
Conformance validates source shape, logic profile diagnostics, capability checks, and warning stability. It is not a visual renderer screenshot test.
## Diagnostic Codes
Clients use `code`, `path`, and `value` for program logic. `message` is for display.
| Code | Severity | Meaning |
|---|---|---|
| `syntax` | error | JavaScript object literal parsing failed. Returned as `diagnostic.code`, not a warning. |
| `unsupported_protocol` | warning | The optional `slex` marker does not match the supported protocol version. |
| `invalid_component_key` | warning | A component key does not match the `type:identifier` shape. |
| `invalid_directive_type` | warning | A structural directive such as `$if`, `$for`, or `$key` has an invalid value type. |
| `unknown_component` | warning | The component type is not present in the generated component catalog. |
| `unknown_prop` | warning | A component prop is not declared by that component's public spec. |
| `unknown_std_member` | warning | A logic expression references a `std.*` helper outside the published capability catalog. |
| `unknown_api_member` | warning | A logic expression references an `api.*` member outside the secure runtime capability catalog. |
| `native_secure_capability` | warning | Secure mode source uses native browser capability names such as `fetch`, timers, or `WebSocket`; use policy-gated `api.*` instead. |
| `reserved_context_shadowing` | warning | `g` keys or component identifiers shadow reserved expression context names. |
Paths refer to the parsed source tree, for example `g.load` or `layout.text:value.$text`. If parsing fails, validation can still return source-level usage warnings, but not parsed-tree paths.
## Conformance Fixture Contract
`slex-conformance.json` contains `valid`, `warning`, and `invalid` fixtures. Each fixture has an `id`, `mode`, source text, and an `expected` object.
- `expected.ok` is the validator success state.
- `expected.warnings` is the warning set for the fixture. The runner fails if an expected warning is missing or if an extra warning appears.
- Warning matching uses `code`, and when present also `path` and `value`.
- `expected.diagnostic` is the expected parse diagnostic code for invalid fixtures.
- Fixture IDs stay stable. If behavior changes, add a new fixture ID.
The conformance suite checks source validation semantics only. It does not assert component screenshots, browser layout, CSS output, or host adapter lifecycle behavior.
## Versioning Policy
SlexKit exposes separate version fields:
- `packageVersion`: npm package version, from `package.json`.
- `protocolVersion`: accepted Slex source protocol marker, `0.1`.
- `schemaVersion`: generated artifact schema generation, using date-style values.
- `logicProfileVersion`: expression, context, stdlib, and secure capability profile version.
Compatible package releases may update catalog hashes, add components or props, add examples, or improve messages without changing `protocolVersion`.
Changes that alter source interpretation, remove or rename diagnostic codes, change expression semantics, or change secure capability behavior require a protocol or logic profile review. Artifact hashes are for cache invalidation, not semantic versioning.
## Difference From A2UI
A2UI describes cross-platform declarative UI. SlexKit describes Markdown-embedded, stateful, executable UI artifacts; the host chooses trusted runtime or secure runtime.
JSON Schema describes the envelope and catalog. The JavaScript expression profile is part of the standard because local logic and state are part of the artifact.
---
# ToolHost
URL: /docs/reference/toolhost
Raw Markdown: /docs/reference/toolhost.md
Source: site/content/reference/toolhost/en-US.md
---
title: ToolHost
category: Reference
status: ready
order: 70
summary: "Structured user-input UI for confirmations, choices, forms, and templates."
slexkitRenderMode: component
---
# ToolHost
ToolHost bridges tool calls to interactive UI. When a model asks for confirmation, a choice, or form input, ToolHost renders the structured UI in the browser and returns the user's response as a `ToolResult`.
## Concepts
When a model emits a tool call such as `confirm-action` or `fill-form`, ToolHost compiles it into a standard `SlexExpression` and mounts it using the core runtime. The mounted UI uses `submit:actions` to submit the user's input and settle a Promise.
ToolHost is **separate from display-oriented `slex` fences**. Display components render information; ToolHost components collect structured user input and return it programmatically.
### Submit
`submit:actions` reads the fields listed in `returnKeys`, calls the ToolHost runtime, and resolves the `ToolRenderHandle.promise` with a `ToolResult`.
Do not use `submit` in display fences or component demos. Use `button` for ordinary interactions; use `submit:actions` only when the host is waiting for a structured tool result.
## Public API
### `renderToolCall(call, container) → ToolRenderHandle`
Compiles a tool call into a SlexExpression, mounts it, and returns a handle.
```ts
function renderToolCall(call: ToolCall, container: HTMLElement): ToolRenderHandle;
```
```ts
type ToolRenderHandle = {
promise: Promise; // Resolves when user submits or ignores
dispose: () => void; // Clean up the rendered UI
};
type ToolResult =
| { toolCallId?: string; toolName: string; status: "submitted"; value: Record }
| { toolCallId?: string; toolName: string; status: "ignored"; value: null };
```
**Usage:**
```js
import { renderToolCall } from "slexkit";
const handle = renderToolCall(
{
id: "call_001",
name: "confirm-action",
arguments: {
title: "Delete file?",
description: "This action cannot be undone.",
confirmLabel: "Delete",
requireReason: true,
},
},
document.getElementById("tool-container"),
);
handle.promise.then((result) => {
console.log(result.status); // "submitted" or "ignored"
console.log(result.value); // { confirmed: true, reason: "Obsolete file" }
handle.dispose();
});
```
### `registerToolTemplate(name, compiler)`
Register a custom tool template. The compiler function receives the tool arguments and returns a `SlexExpression`.
```ts
function registerToolTemplate(name: string, compiler: ToolTemplateCompiler): void;
type ToolTemplateCompiler> = (
args: TArgs,
runtime: ToolRuntime,
call: ToolCall,
) => SlexExpression;
type ToolRuntime = {
submit: (value: Record) => void;
ignore: () => void;
};
```
## Built-in templates
### `confirm-action`
Yes/no confirmation dialog. Supports an optional reason field.
**Arguments (`ConfirmActionArguments`):**
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `title` | `string` | `"Confirm action"` | Dialog title |
| `description` | `string` | — | Optional explanation text |
| `confirmLabel` | `string` | `"Confirm"` | Submit button label |
| `ignoreLabel` | `string` | `"Ignore"` | Cancel button label |
| `requireReason` | `boolean` | `false` | Show a reason text input |
| `reasonLabel` | `string` | `"Reason"` | Label for the reason input |
| `reasonPlaceholder` | `string` | `"Add a reason"` | Placeholder for the reason input |
**Result value:**
| Key | Type | Description |
|-----|------|-------------|
| `confirmed` | `boolean` | Always `true` when submitted |
| `reason` | `string` | User's reason text (only if `requireReason: true`) |
**Example:**
```js
renderToolCall({
name: "confirm-action",
arguments: {
title: "Delete project?",
description: "This will permanently delete all files.",
confirmLabel: "Delete",
requireReason: true,
},
}, container);
```
### `choose-options` / `option-list`
Single or multi-select option list. `option-list` is an alias for `choose-options` — behavior is identical.
**Arguments (`ChooseOptionsArguments` / `OptionListArguments`):**
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `title` | `string` | `"Choose options"` | Dialog title |
| `description` | `string` | — | Optional explanation text |
| `options` / `items` | `OptionListItem[]` | `[]` | List of selectable items |
| `multiple` | `boolean` | `true` | Allow multiple selection |
| `selected` | `string[]` | auto | Pre-selected item IDs |
| `minSelected` | `number` | `0` | Minimum required selections |
| `maxSelected` | `number` | `Infinity` | Maximum allowed selections |
| `submitLabel` | `string` | `"Submit"` | Submit button label |
| `ignoreLabel` | `string` | `"Ignore"` | Cancel button label |
**OptionListItem:**
| Field | Type | Description |
|-------|------|-------------|
| `label` | `string` | Display text (required) |
| `id` | `string` | Unique identifier (defaults to `value` or index) |
| `value` | `string` | Submitted value (defaults to `id`) |
| `description` | `string` | Secondary text shown after label |
| `selected` | `boolean` | Pre-selected state |
| `disabled` | `boolean` | Disabled state |
**Rendering:**
- When `multiple: true` (default): renders **checkboxes**
- When `multiple: false`: renders a **radio group**
**Result value:**
| Key | Type | Description |
|-----|------|-------------|
| `selected` | `string[]` | IDs of selected items |
**Example:**
```js
renderToolCall({
name: "choose-options",
arguments: {
title: "Select dependencies",
options: [
{ id: "react", label: "React", description: "UI library" },
{ id: "vue", label: "Vue", description: "Progressive framework" },
{ id: "svelte", label: "Svelte", description: "Compiled framework", selected: true },
],
multiple: true,
minSelected: 1,
maxSelected: 2,
},
}, container);
```
### `fill-form`
Multi-field form with various field types.
**Arguments (`FillFormArguments`):**
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `title` | `string` | `"Fill form"` | Form title |
| `description` | `string` | — | Optional explanation text |
| `fields` | `FormField[]` | `[]` | Form field definitions |
| `values` | `Record` | — | Initial field values |
| `submitLabel` | `string` | `"Submit"` | Submit button label |
| `ignoreLabel` | `string` | `"Ignore"` | Cancel button label |
**FormField:**
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | `string` | (required) | Field name (used as key in result value) |
| `type` | `FormFieldType` | `"text"` | Field type |
| `label` | `string` | `name` | Display label |
| `description` | `string` | — | Help text below the field |
| `placeholder` | `string` | — | Input placeholder |
| `required` | `boolean` | `false` | Require non-empty value to submit |
| `disabled` | `boolean` | `false` | Disable the field |
| `value` | `unknown` | — | Initial value |
| `options` | `Array<{label, value}>` | — | Options for `select` type |
**FormFieldType:**
| Type | Renders | Description |
|------|---------|-------------|
| `text` | `` | Free-form text |
| `number` | `` | Numeric input, value is `number \| null` |
| `engineering` | `` with SI prefix parsing | Accepts values like `"10kΩ"`, `"100nF"`, `"1.5MegHz"`. Parsed with `parseEngineeringNumber()`. State includes `raw`, `number`, `valid`, `prefix`, `unit`, `normalized` |
| `select` | `