Devframe
Devframe is the container for one devtool integration, portable across viewers. You describe a single tool — its RPC surface, its data model, its SPA, its CLI shape — and Devframe deploys the same definition through any number of runtime adapters: a standalone CLI, a self-contained static report, an embedded SPA, an MCP server, or mounted inside a multi-integration hub.
Devframe's surface is one tool. Hub-level features — docking, the command palette, terminal aggregation, cross-tool toasts — live in @vitejs/devtools-kit. To drop a Devframe app into Vite DevTools, wrap it with createPluginFromDevframe from @vitejs/devtools-kit/node; the kit synthesises the dock entry from your definition's id / name / icon / basePath and routes the hub-level ctx fields (docks, terminals, …) accordingly.
Experimental
The Devframe API is still in development and may change between versions. The agent-native surface (agent on defineRpcFunction, ctx.agent, and the MCP adapter) is additionally flagged as experimental.
Design principles
Devframe keeps its surface small and pushes hub-level UX to the kit consuming it:
- Single-integration scope. Devframe describes one tool. Anything that only matters across tools — docks, palette, cross-tool toasts, unified terminals — belongs in the DevTools Kit.
- Headless. Hook into
onReady,cli.configure, and friends to print your own startup banners and styling — Devframe stays out of the way. - App-owned file watching. Wire your own watcher (chokidar, fs.watch, …) and signal change via
ctx.rpc.sharedState.set(...)or event-typed RPCs. - Context-aware mount paths. Standalone adapters (
cli,spa,build) serve at/by default; hosted adapters (vite,embedded, kit'screatePluginFromDevframe) serve at/.<id>/. Override viaDevtoolDefinition.basePath. - SPAs own their base at runtime. Build with relative asset paths (
vite.base: './');connectDevtooldiscovers the effective base from the executing script's location. - CLI flags compose. The
cacinstance is exposed to both the devtool (cli.configure) and the caller ofcreateCli, so capability flags and app flags merge cleanly.
What Devframe provides
| Subsystem | What it does |
|---|---|
| Devtool Definition | One defineDevtool call describes your tool once; the adapters deploy it anywhere. |
| RPC | Type-safe bidirectional calls built on birpc + valibot. Supports query, static, action, and event types. |
| Shared State | Observable, patch-synced state that survives reconnects and bridges server ↔ browser. |
| Diagnostics | Coded warnings/errors via logs-sdk — registered into the host logger so adapters and consumers share the same surface. |
| Streaming | One-way (RPC streaming) and two-way (uploads) channel primitives for long-running data. |
| When Clauses | VS Code-style conditional expressions for docks, commands, and custom UI. |
| Client | Browser-side RPC client (connectDevtool) with auto-auth and WebSocket / static modes. |
| Agent-Native | Opt-in exposure of your tool's surface to coding agents over MCP. |
Hub-only subsystems — Dock System, Commands, Messages, Terminals — live in the Vite DevTools Kit docs.
Architecture
Install
pnpm add devframedevframe ships ESM-only and has no Vite dependency. Adapters with optional peers (the MCP adapter needs @modelcontextprotocol/sdk) surface the requirement at import time.
Hello, Devframe
A minimal devtool with a CLI entry point:
import { defineDevtool, defineRpcFunction } from 'devframe'
import { createCli } from 'devframe/adapters/cli'
const devtool = defineDevtool({
id: 'my-devtool',
name: 'My Devtool',
icon: 'ph:gauge-duotone',
cli: {
distDir: 'client/dist',
},
setup(ctx) {
ctx.rpc.register(defineRpcFunction({
name: 'my-devtool:hello',
type: 'static',
jsonSerializable: true,
handler: () => ({ message: 'hello' }),
}))
},
})
await createCli(devtool).parse()Drop the same definition into Vite DevTools — the kit auto-derives the iframe dock entry from id / name / icon / basePath:
// vite.config.ts
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
import devtool from './my-devtool'
export default {
plugins: [createPluginFromDevframe(devtool)],
}Run it:
node ./my-devtool.js # dev server on http://localhost:9999/
node ./my-devtool.js build # self-contained static deploy in dist-static/
node ./my-devtool.js mcp # stdio MCP server (experimental)The CLI adapter serves the SPA at / by default. When the same devtool is embedded inside a host (vite, kit, embedded), the default becomes /.my-devtool/. Override either side via defineDevtool({ basePath }).
Adapters at a glance
Devframe deploys the same DevtoolDefinition through one of these adapters:
| Adapter | Entry | Target |
|---|---|---|
cli | createCli(d).parse() | Standalone CLI with dev / build / mcp subcommands |
vite | createVitePlugin(d, opts?) | Plain Vite plugin that mounts the SPA |
build | createBuild(d, opts?) | Self-contained static deploy with baked RPC dumps |
| kit (bridge) | createPluginFromDevframe(d, opts?) (from @vitejs/devtools-kit/node) | Mount the devtool into Vite DevTools' hub UI |
embedded | createEmbedded(d, { ctx }) | Runtime registration into an existing host |
mcp | createMcpServer(d, opts) | Model Context Protocol server |
createPluginFromDevframe lives in the kit because mounting into a multi-integration hub is a kit responsibility. See Adapters for the full reference.
Dependency boundary
Devframe is the lowest-level package in the Vite DevTools monorepo and is positioned to be extracted into its own repo. Imports from Vite or any @vitejs/* package are out of scope, in source and at the dependency-graph level. Hub-only concepts (docks, terminals, messages, commands) belong in the layers above:
@vitejs/devtools-kit— the hub. Owns docking, terminals, messages, and the command palette; providescreatePluginFromDevframeto bridge a Devframe app into Vite DevTools.@vitejs/devtools— the integration. Vite plugin that wraps the kit and exposes Vite DevTools' own UI.
For porting an existing inspector, use the cli adapter standalone and createPluginFromDevframe (from @vitejs/devtools-kit/node) to surface it inside Vite DevTools.
What's next
- Devtool Definition — understand
defineDevtooland theDevToolsNodeContext - Adapters — pick the right deployment target for your tool
- RPC — define type-safe server functions your client can call
- Agent-Native — expose your devtool to Claude Desktop, Cursor, or any MCP client