diff --git a/docs/canvases/agent-bundle-walkthrough.canvas.tsx b/docs/canvases/agent-bundle-walkthrough.canvas.tsx
new file mode 100644
index 000000000..b2b1e0b32
--- /dev/null
+++ b/docs/canvases/agent-bundle-walkthrough.canvas.tsx
@@ -0,0 +1,971 @@
+import {
+ BarChart,
+ Callout,
+ Card,
+ CardBody,
+ CardHeader,
+ CollapsibleSection,
+ Divider,
+ Grid,
+ H1,
+ H2,
+ H3,
+ Pill,
+ Row,
+ Stack,
+ Stat,
+ Table,
+ Text,
+ useHostTheme,
+ type CSSProperties,
+} from "cursor/canvas";
+
+/* ---------------------------------------------------------------- helpers */
+
+const MONO =
+ 'ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace';
+
+function Kicker({ children }: { children: string }) {
+ const t = useHostTheme();
+ return (
+
+ {children}
+
+ );
+}
+
+function MonoBlock({ text, dim }: { text: string; dim?: boolean }) {
+ const t = useHostTheme();
+ const style: CSSProperties = {
+ background: t.fill.quaternary,
+ border: `1px solid ${t.stroke.tertiary}`,
+ borderRadius: 6,
+ color: dim ? t.text.secondary : t.text.primary,
+ fontFamily: MONO,
+ fontSize: 12,
+ lineHeight: "18px",
+ margin: 0,
+ overflowX: "auto",
+ padding: "10px 12px",
+ whiteSpace: "pre",
+ };
+ return
{text};
+}
+
+function StageBox({
+ title,
+ detail,
+ emphasized,
+}: {
+ title: string;
+ detail: string;
+ emphasized?: boolean;
+}) {
+ const t = useHostTheme();
+ return (
+
+
+ {title}
+
+
+ {detail}
+
+
+ );
+}
+
+function FlowArrow() {
+ const t = useHostTheme();
+ return (
+
+ {"\u2192"}
+
+ );
+}
+
+function StepMarker({ n }: { n: number }) {
+ const t = useHostTheme();
+ return (
+
+ {n}
+
+ );
+}
+
+function WireStep({
+ n,
+ title,
+ channel,
+ payload,
+ note,
+ last,
+}: {
+ n: number;
+ title: string;
+ channel: string;
+ payload?: string;
+ note?: string;
+ last?: boolean;
+}) {
+ const t = useHostTheme();
+ return (
+
+
+
+
+ {title}
+
+ {channel}
+
+
+ {note !== undefined && (
+
+ {note}
+
+ )}
+ {payload !== undefined && (
+
+
+
+ )}
+
+
+ );
+}
+
+/* ------------------------------------------------------------ wire bodies */
+
+const AUTHORED_TREE = `my-plugin/
+ agent-bundle.config.ts defineConfig({ plugin, targets, ... })
+ src/
+ mcp/curator/tools/search.tsx MCP tool (id: tool:curator/search)
+ mcp/curator/resources/catalog.tsx
+ mcp/curator/prompts/curate.tsx
+ mcp/curator/apps/panel.tsx MCP App (config.resourceUri)
+ events/tool/before.tsx event route (id: event:tool/before)
+ events/stop.tsx event route (id: event:stop)
+ providers/build-info.ts context provider factory
+ cli/library/audit.ts CLI command "library audit"
+ scripts/verify-release.ts plain script -> scripts/*.mjs
+ state.ts defineState({ id, lifetime, budgets })
+ skills/curate/SKILL.md agent skill (or rendered SKILL.tsx)
+ rules/style.mdc Cursor rules component
+ commands/triage.md chat command (Claude + Cursor)`;
+
+const TOOL_ROUTE_SNIPPET = `// src/mcp/curator/tools/search_audible.tsx (examples/audiobook-curator)
+export const config = {
+ annotations: { openWorldHint: true, readOnlyHint: false },
+ description: "Search Audible regions and return ranked identity evidence...",
+}; // statically extracted, never executed
+export const inputSchema = operation.inputSchema; // zod, runtime boundary
+export const resultSchema = operation.resultSchema;
+
+export default async function Route({ input, signal }: ToolRouteProps) {
+ const receipt = await operation.handler(input, { signal });
+ return ; // renders Agent.* elements
+}`;
+
+const EVENT_ROUTE_SNIPPET = `// src/events/tool/after.tsx (examples/rsc-agent-runtime)
+export const config = {
+ runtime: 'standalone', // 'shared' (warm IPC runtime) | 'standalone'
+ targets: ['claude', 'codex'],
+ timeoutMs: 30_000, // budget inside the host's native deadline
+ tools: ['file.write'], // canonical selector -> per-host matcher regex
+};
+
+export default async function AfterFileEdit({ canonical, native, signal }: AgentEventRouteProps) {
+ // canonical.provenance = { host, hostContractRevision, nativeEvent, source: 'native' }
+ const snapshot = await kernel.recordEdit({ idempotencyKey: canonical.idempotencyKey, ... });
+ return (
+
+ {\`Recorded \${path} from \${canonical.provenance.host}.\`}
+
+ );
+}`;
+
+const CLAUDE_HOOKS_JSON = `// claude/hooks/hooks.json - real emitted bytes (examples/hooks-and-scripts)
+{
+ "hooks": {
+ "SessionStart": [
+ {
+ "hooks": [
+ {
+ "command": "node \\"\${CLAUDE_PLUGIN_ROOT}/hooks/session-start-session-start-7ab7e8a5.mjs\\"",
+ "type": "command"
+ }
+ ]
+ }
+ ]
+ }
+}
+// Cursor keeps a flat document instead:
+// { "version": 1, "hooks": { "preToolUse": [ { "command": "node \\"\${CURSOR_PLUGIN_ROOT}/...\\"", "matcher": "^Write$" } ] } }`;
+
+const WIRE_STDIN = `{
+ "hook_event_name": "PreToolUse",
+ "session_id": "6f9a2c1e-4d15-4a44-9be2-6b8f0f6f2a10",
+ "transcript_path": "/home/dev/.claude/projects/acme/transcript.jsonl",
+ "cwd": "/home/dev/acme",
+ "permission_mode": "default",
+ "tool_name": "Write",
+ "tool_input": { "file_path": "src/payments.ts", "content": "..." },
+ "tool_use_id": "toolu_01H8KQ2ZC4"
+}`;
+
+const WIRE_IPC_REQUEST = `{
+ "protocolVersion": 1,
+ "artifactEpoch": "17903a885df8d142e2fc4457e61bb34479e81a8f4cc64e24cb92db49eaabe3f1",
+ "event": "tool/before",
+ "hostContractRevision": "2.1.250",
+ "target": "claude",
+ "native": { ...the stdin envelope, byte-for-byte... }
+}
+// socket: /tmp/agent-bundle-/event-.sock (mode 0600)
+// endpointId = "::" - two installs never share a runtime`;
+
+const WIRE_RENDER_PROPS = `props = {
+ canonical: {
+ event: "tool/before",
+ idempotencyKey: sha256({ event, native, target }),
+ observedAt: "2026-09-01T23:41:07.512Z",
+ provenance: { host: "claude", hostContractRevision: "2.1.250",
+ nativeEvent: "PreToolUse", source: "native" },
+ sequence: 1,
+ },
+ native: { ...frozen structuredClone of the envelope... },
+ signal, // aborted when the socket drops or the client times out
+}
+// runAgentRequest installs host/session/workspace axes read from the envelope,
+// then the react-server Flight worker renders the route's default component.`;
+
+const WIRE_IPC_RESPONSE = `{
+ "protocolVersion": 1,
+ "artifactEpoch": "17903a88...eaabe3f1",
+ "status": "ok",
+ "output": {
+ "hookSpecificOutput": {
+ "hookEventName": "PreToolUse",
+ "permissionDecision": "deny",
+ "permissionDecisionReason": "payments.ts is frozen during release week"
+ }
+ }
+}
+// on failure: { "status": "error", "code": "epoch-mismatch" | "invalid-message" | "runtime-failed", ... }`;
+
+const WIRE_STDOUT = `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
+ "permissionDecisionReason":"payments.ts is frozen during release week"}}`;
+
+const STATE_SNIPPET = `// src/state.ts - one direct defineState call (AB4818 otherwise)
+export default defineState({
+ id: 'library-index',
+ lifetime: 'workspace-durable', // request | process | workspace-durable | external
+ budgets: { maxStateBytes: 262144, maxRevisions: 64 }, // fail closed: budget-exceeded
+});`;
+
+/* ------------------------------------------------------------------ page */
+
+export default function AgentBundleWalkthrough() {
+ const t = useHostTheme();
+
+ return (
+
+ {/* ============================================================ hero */}
+
+ Framework walkthrough
+ agent-bundle, end to end
+
+ Author agent behavior as React Server Components; compile it into a
+ route-graph IR; emit native, independently distributable artifacts
+ for each host; and execute hooks and MCP tools as Flight renders
+ against a warm runtime. Flight is an internal transport only — the
+ hosts see their own native JSON contracts, pinned by revision.
+
+
+
+
+
+
+
+
+
+
+ {/* ======================================================== pipeline */}
+
+ The pipeline: author → compile → emit → install → execute
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source: packages/agent-bundle/src — routes/graph.ts, config/validate.ts,
+ build/entries.ts + entry-shell.ts, adapters/*, install/install.ts.
+
+
+
+
+
+ {/* ======================================================= authoring */}
+
+ 1 · Authoring model: files are the app
+
+ One flat config owns identity and policy; everything executable is a
+ conventional file whose path is its identity. A route module is one
+ async default Server Component plus statically extractable
+ config,
+ inputSchema, and
+ resultSchema exports — there is no
+ execute/render split (exporting either is the AB4811 error).
+
+
+
+ Conventional source tree
+
+
+
+
+
+ real route}>
+ src/mcp/curator/tools/search_audible.tsx
+
+
+
+
+
+
+ Route kinds compiled into the graph
+ src/mcp/<server>/{tools,resources,prompts,apps}/*.tsx, tool:curator/search, "Flight render in the generated MCP server"],
+ ["event-route", src/events/<family>/*.tsx, src/events/stop.tsx, event:tool/before, "Hook wrapper → IPC → warm runtime (or standalone)"],
+ ["cli", src/cli/**/*.ts(x) — nesting is the command path, cli:library/audit, "Generated package bin; .tsx renders via dispatcher"],
+ ["script", src/scripts/*.ts(x) — direct children only, script:verify-release, "scripts/.mjs (+ -flight.mjs worker when rendered)"],
+ ["provider", src/providers/*.ts — factory, not addressable, provider:build-info, "Wraps every render with request-scoped context values"],
+ ]}
+ />
+
+ Source: routes/graph.ts routeGlobs + classifyModule; routes/types.ts. Config always
+ wins: modules claimed by explicit scripts/hooks/bin/lib/mcp config never become routes.
+
+
+
+
+
+ {/* ===================================================== compile+val */}
+
+ 2 · Compile and validate: one immutable IR, structured diagnostics
+
+ Discovery globs the conventional roots, rejects unsafe identity
+ segments, and refuses to choose sides on any collision — an MCP
+ server with both discovered routes and an explicit entry is a hard
+ AB4800 error until routes.servers.<id> picks
+ a mode. The graph digest covers only project-relative identity, so equal
+ trees hash equally on every machine. Every failure is one diagnostic:
+ stable AB code, severity, message, and usually a recovery hint.
+
+
+ AB30xx, "Skill documents: Markdown parsing and rendered-skill compilation"],
+ [AB40xx, "Plugin metadata, skill fields, package identity (AB4008 version mismatch)"],
+ [AB41xx / AB42xx, "Normalized-model invariants; hook configuration and native hook sources"],
+ [AB43xx / AB44xx / AB46xx, "MCP servers and Apps; scripts; assets and the generated-runtime floor"],
+ [AB47xx, "Package build (bin/lib, AB4716 declaration replay), migration nudges, prebuilt payloads"],
+ [AB48xx, "Route graph: collisions AB4800–AB4803, static config grammar AB4805/AB4806, route contract AB4810/AB4811, event vocabulary + CLI command-graph collisions AB4813, CLI argv grammar AB4814, shared-runtime placement AB4817, state AB4818–AB4821"],
+ [AB494x, "Providers: default-factory contract, key uniqueness, reserved processLifetime"],
+ [AB5000 / AB60xx, "CLI and adapter failures; built-artifact validation against pinned schemas"],
+ [AB70xx, "Host installation; read-only Doctor probes AB7300–AB7316; dev rebuilds (AB7103)"],
+ [AB8xxx / AB9xxx, "Dev server configuration; eval selection, harnesses, persisted runs"],
+ ]}
+ />
+
+ Source: docs/diagnostics.md. Only error severity gates a build; warnings and infos never block.
+
+
+
+ A route's config export is parsed with the TypeScript compiler from a bounded literal
+ grammar (object/array/string/number literals, as/satisfies casts). Anything dynamic
+ compiles with an empty config beside a named AB4806 error. The same static approach
+ projects each CLI route's zod inputSchema onto kebab-case argv options (AB4814 when a
+ construct leaves the grammar) — the module's real zod schema still validates at run time.
+
+
+
+
+
+ {/* ======================================================== emission */}
+
+ 3 · Per-host emission: adapters, pinned contracts, provenance
+
+ Each adapter projects the normalized model against a pinned host
+ capability table (a JSON file with observed versions, evidence
+ strings, and per-event support states) and validates its output
+ against pinned host schemas whose sha256 hashes ship in the artifact
+ manifest. Every capability is supported or{" "}
+ unavailable with a written reason — never a
+ silent guess.
+
+ .claude-plugin/plugin.json,
+ .codex-plugin/plugin.json,
+ .cursor-plugin/plugin.json,
+ plugin.json],
+ ["Marketplace",
+ .claude-plugin/marketplace.json,
+ .agents/plugins/marketplace.json,
+ .cursor-plugin/marketplace.json,
+ "—"],
+ ["Hooks wiring",
+ "hooks/hooks.json, grouped { matcher, hooks: [{ type: 'command', command }] }",
+ "same grouped shape; hook processes get PLUGIN_ROOT / PLUGIN_DATA",
+ "hooks/hooks.json, flat { command, matcher?, timeout? } entries",
+ "none — Agent Plugins 1.0.0 defines no hooks"],
+ ["MCP registration",
+ .mcp.json (stdio + streamable HTTP),
+ .mcp.json,
+ mcp.json at plugin root,
+ "plugin.json mcp block, ${PLUGIN_ROOT} tokens"],
+ ["Skills / rules / commands",
+ "skills + commands",
+ "skills",
+ "skills + rules + commands",
+ "skills"],
+ ["Path token",
+ {"${CLAUDE_PLUGIN_ROOT}"},
+ "relative paths + PLUGIN_ROOT cwd",
+ {"${CURSOR_PLUGIN_ROOT}"},
+ {"${PLUGIN_ROOT}"}],
+ ["Install",
+ "claude plugin marketplace add ./ + install --scope user|project|local",
+ "codex plugin add @ (user scope)",
+ "copy to ~/.cursor/plugins/local/ (no non-interactive verb)",
+ "distribution profile — no single host install location"],
+ ]}
+ />
+
+ Source: src/adapters/capabilities/*.json (observed 2026-08-28…09-01) and src/adapters/{claude,codex,cursor,portable}.ts.
+ A composite "plugin" target emits one directory loadable by both Claude and Codex, with a
+ universal hook wrapper that discriminates the host at run time via PLUGIN_ROOT.
+
+
+
+ Emitted artifact size by target and file kind (bytes)
+
+
+ X: target directory · Y: total bytes, summed per emitted-file kind. Portable has no
+ hook wrapper — its spec defines no hooks. Source: examples/hooks-and-scripts
+ dist/agent-bundle.manifest.json.
+
+
+
+ Provenance in every artifact
+
+ agent-bundle.manifest.json records, per emitted file, its sha256 and the exact
+ source inputs that produced it, plus the project revision (the artifact epoch),
+ each target's adapter revision, capability-table hash, and the sha256 of every
+ pinned host schema it was validated against. agent-bundle.hooks.json is the
+ canonical hook index across targets.
+
+
+ Source: dist/agent-bundle.manifest.json fields files[].sha256, files[].sourceInputs,
+ project.revision, targets[].schemas[].
+
+
+
+
+
+
+
+ {/* ================================================== HOOKS DEEP DIVE */}
+
+ Deep dive
+ 4 · The hooks pipeline: what is on the wire at every step
+
+ Two authoring shapes share the emitted hooks.json wiring. A{" "}
+ plain handler hook{" "}
+ (config hooks: { sessionStart: { handler } })
+ compiles into a self-contained wrapper that decodes the native envelope, calls the
+ default-export function, and encodes the result — no IPC. An{" "}
+ event route{" "}
+ (src/events/**) compiles into a thin
+ client that forwards the validated envelope over a per-user Unix socket (a named pipe on
+ Windows) to the warm runtime living inside the generated MCP server process, where the
+ route component renders as a Flight request. The walkthrough below is the event-route
+ path for a Claude PreToolUse on a{" "}
+ tool/before route.
+
+
+
+ generated wiring}>
+ What the host actually invokes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Failure semantics: fail closed, one narrow fallback
+ runtime-unavailable, "No live socket (connect refused / missing)", "Standalone fallback if the route declares runtime or fallback 'standalone'; otherwise nonzero exit"],
+ [runtime-timeout, "No reply within timeoutMs (default 5 s)", "Nonzero exit — never a fabricated response"],
+ [epoch-mismatch, "Wrapper and runtime built from different artifact epochs", "Nonzero exit; no fallback — stale code never answers"],
+ [invalid-message, "Payload over 1 MiB, non-JSON, or off-schema", "Nonzero exit"],
+ [runtime-failed, "Render threw, socket error, endpoint contention", "Nonzero exit"],
+ ]}
+ />
+
+ Source: src/events/ipc.ts (EventRuntimeTransportError, requestEventRuntime) and the
+ generated wrapper in src/adapters/hook-contract.ts — fallback fires only on
+ runtime-unavailable with fallback: 'standalone'.
+
+
+
+ The standalone path
+
+ A route with runtime: 'standalone' (or
+ as fallback) bundles the route module into the wrapper itself: the same
+ createCanonicalEventProps builds identity, the component resolves in-process
+ (Server Components and Agent protocol elements only), and the same
+ projectEventDocument lowers the output. No shared state, no warm process —
+ identical wire contract to the host.
+
+
+
+ AB4817 guards placement: an event route requiring the shared runtime on a target
+ with no generated MCP entry hosting it — and no standalone fallback — fails the build.
+
+
+
+
+
+
+
+ The event runtime server claims its endpoint with an exclusive{" "}
+ .lock file recording pid and (on
+ Linux) the /proc start time. A stale claim is reclaimed only when its owner is
+ provably dead — signal-0 probe plus start-time comparison — and on Linux the
+ reclamation itself is serialized through a kernel-released abstract-socket gate, so
+ a namespace squatter can force bounded retries (100 × 10 ms) but never steal
+ ownership. Live endpoints are never stolen; unverifiable claims stay fail-closed.
+ Reads use StringDecoder for chunk-safe UTF-8; each connection gets an
+ AbortController wired to close/end/error so orphaned renders cancel; teardown
+ removes the socket only when its device and inode still match the one it created.
+
+
+ Source: src/events/ipc.ts — claimEndpoint, reclaimOrphanedEndpointClaim,
+ tryAcquireEndpointRecoveryGate, readOneMessage, closeServer.
+
+
+
+
+
+
+
+ {/* ==================================================== event matrix */}
+
+ 5 · Event families × hosts
+
+ The v1 vocabulary is seven canonical families. Six are supported on
+ all three interactive hosts under their native names;{" "}
+ workspace/open is supported on
+ Cursor as a fire-and-forget observation (the optional native pluginPaths
+ return is deliberately not modeled) and stays unavailable on Claude and
+ Codex — with a written reason per host, not a silent gap.
+
+ session/start, "SessionStart", "SessionStart", "sessionStart", "—"],
+ [tool/before, "PreToolUse", "PreToolUse", "preToolUse", "—"],
+ [tool/after, "PostToolUse", "PostToolUse", "postToolUse", "—"],
+ [stop, "Stop", "Stop", "stop", "—"],
+ [agent/start, "SubagentStart", "SubagentStart (adds turn_id, model, permission_mode)", "subagentStart", "—"],
+ [agent/stop, "SubagentStop", "SubagentStop", "subagentStop", "—"],
+ [workspace/open, "unavailable: no such event", "unavailable: no such event", "workspaceOpen (observe-only; optional pluginPaths return not modeled)", "unavailable: spec defines no hooks"],
+ ]}
+ />
+
+
+ What each event may answer
+
+
+ Source: events/projection.ts projectEventDocument and the wrapper validateResult in
+ adapters/hook-contract.ts — illegal combinations throw before anything reaches the host.
+
+
+
+ Canonical tool selectors → native matchers
+ file.read, ^Read$, "—", ^Read$],
+ [file.write, ^(?:Write|Edit)$, ^(?:apply_patch|Edit|Write)$, ^Write$],
+ [shell, ^Bash$, ^Bash$, ^Shell$],
+ [mcp, ^mcp__, ^mcp__, ^MCP:],
+ [agent, "—", "—", ^Task$],
+ ]}
+ />
+
+ A hook can also pin host-scoped native tool names; a selector no target can map is a
+ per-target diagnostic, never a silently empty matcher.
+
+
+
+
+ standalone example}>
+ src/events/tool/after.tsx — a real event route
+
+
+
+
+
+
+
+
+
+ {/* ======================================================== MCP flow */}
+
+ 6 · MCP tools: the same architecture, request-shaped
+
+
+
+
+
+
+
+
+
+
+ The generated entry carries the compiled route table as data and hands a warm worker to
+ the shared server runtime (createGeneratedRouteMcpServer). Each tools/call validates
+ input with the route's real zod schema, renders the async default component inside
+ runAgentRequest — with providers, the state kernel, and the notice ledger bound —
+ streams Flight bytes back, and projects them onto MCP: progress reports become
+ notifications, Agent.Result becomes structured content validated by resultSchema. MCP
+ Apps embed their built HTML into the bundle as resources keyed by resourceUri. When the
+ bundle has event routes, exactly one generated server also hosts the event runtime IPC
+ socket — that is the warm runtime hooks talk to, so hooks share process state with tools.
+
+
+ Source: build/entry-shell.ts (generatedRouteMcpEntrySource, generatedRouteFlightWorkerSource),
+ src/mcp-server-runtime.ts (startEventRuntime, projectMcpRenderStream), build/entries.ts.
+
+
+
+
+
+ {/* ==================================================== supporting */}
+
+ 7 · Supporting systems
+
+
+ State
+
+
+
+
+ Drivers supply storage for exactly one lifetime — memory for request/process,
+ SQLite under the plugin root's state/ for workspace-durable; external needs
+ embedder wiring and is rejected for generated mounting (AB4820). Budgets
+ (bytes, revisions, commit latency) fail closed with budget-exceeded. Doctor
+ inventories durable stores by filesystem metadata only — it never opens a database.
+
+
+
+
+
+ Notices
+
+
+
+ An append-only ledger co-mounted with state (reserved id, AB4821). A notice
+ targets a recipient — the conjunction of observed identity axes — and moves
+ through evidenced states only: pending, attempted, expired, unavailable,
+ withdrawn. Delivery is attempted on the next event render; a recipient-scoped
+ MCP inbox resource (agent-bundle://notices/inbox) exposes pending notices with
+ exposure receipts. No host claims are fabricated.
+
+
+ pending
+ attempted
+ expired
+ unavailable
+ withdrawn
+
+
+
+
+
+ Context axes
+
+
+
+ Inside any route, await agent() returns the request context: host, session,
+ actor, and workspace each as an Observed value — either
+ { state: 'available', value, source } or
+ { state: 'unavailable', reason }. Honest absence is the contract: a CLI
+ render reports host unavailable ('unsupported-surface') rather than inventing
+ one. Capabilities (command, filesystem, network, projectRoot) follow the same
+ shape; src/providers/* factories add request-scoped values beside the
+ framework-owned processLifetime.
+
+
+
+
+
+
+
+
+
+
+ {/* ======================================================== dev loop */}
+
+ 8 · The dev loop: epochs, Workbench, doctor, install
+
+ agent-bundle dev watches the project, serializes rebuilds, and commits each successful
+ build as an immutable epoch under .agent-bundle/epochs/<uuid>/ with an
+ active-epoch.json pointer — the same epoch identity that fences hook IPC, so a stale
+ wrapper can never talk to a newer runtime. A package-build failure never invalidates a
+ committed artifact epoch (it surfaces as the AB7103 warning and retries). Generated
+ route declarations publish atomically to .agent-bundle/routes.d.ts.
+
+
+
+ Workbench (desktop web UI over the dev server)
+
+
+
+ Doctor and install
+
+ agent-bundle doctor is strictly read-only (AB7300–AB7316): host CLI probes,
+ installed-bundle inventory, bundle-to-source comparison, registration proof, event
+ runtime endpoint health, and durable-state inventory. It never repairs anything.
+
+
+
+ Every target directory is independently distributable with a generated INSTALL.md;
+ cursor/portable/plugin targets also ship a standalone install.mjs whose staged copy
+ is idempotent for identical content, refuses version or content collisions, and
+ never touches sudo or PATH. The packed proof level (agent-bundle/test) runs the
+ same mcp-server-runtime in memory, and deleted-source proofs verify artifacts stay
+ self-contained after the source tree is gone.
+
+
+
+
+
+
+
+ {/* ========================================================== footer */}
+
+
+ Verified against /fast/projects/agent-bundle source: routes/{graph,types,contract,public}.ts ·
+ config/validate.ts · adapters/hook-contract.ts + capabilities/*.json ·
+ events/{ipc,project,projection}.ts · build/{entries,entry-shell}.ts ·
+ mcp-server-runtime.ts · rsc-runtime state/notices/agent-request · docs/diagnostics.md +
+ docs/framework-mode.md · examples/{hooks-and-scripts,audiobook-curator,rsc-agent-runtime}.
+ Wire payloads in section 4 are illustrative values over verified shapes. Reflects the
+ post-PR-#280 split of React rendering (events/project.ts) from envelope projection
+ (events/projection.ts). Host capability facts pinned at Claude Code 2.1.250, Codex
+ 0.147.0, Cursor 2026-08-28, Agent Plugins 1.0.0 (observed 2026-08-28 … 2026-09-01).
+
+
+ Generated 2026-09-01 · colors follow the host theme ({t.kind})
+
+
+
+ );
+}