Build a devtool once. Mount it anywhere.

Devframe

3 min read Original article ↗

A framework-neutral foundation for devtools. One definition becomes a Web Standard handler you can mount into any host framework, ship as a CLI or static report, and expose to coding agents.

import { defineDevframe } from 'devframe'
import { initDevframe } from 'devframe/initiate'

const myDevframe = defineDevframe({
  id: 'my-tool',
  name: 'My Tool',
  rpc: [getModules],
  view: { type: 'spa', distDir: './dist/client' },
})

// one Request → Response handler, any host framework
const { handler } = initDevframe(myDevframe, {
  base: '/__my-tool/',
})

Read the announcement, Pluggable, Extensible, and Playful DevTools, for the vision behind devframe.

// Foundation //

One definition, every entry point

defineDevframe() describes a tool once. initDevframe() turns it into a Web Standard Request → Response handler, and adapters reshape that same definition into whatever your package ships.

One Standard Handler

Mount the same handler into Hono, Nitro, Next.js, SvelteKit, Vite, Rsbuild, Deno, or Bun.

Adapters as Conveniences

The same definition also becomes a standalone CLI, a dev server, a static report, an MCP server, or a Vite DevTools dock.

Type-safe RPC & Shared State

Bidirectional calls built on birpc, validated against any Standard Schema validator, plus observable patch-synced state that survives reconnects.

Visual and Agentic

Expose the same internal state to a web UI and to coding agents over MCP: one source of truth, two interfaces.

From One Devframe to a Hub

@devframes/hub composes many devframes behind one handler with docks, commands, terminals, and messages.

Built-in Devframes, Any Framework

The built-in devframes span Vue, Svelte, Solid, and React: devframe owns the protocol and leaves the UI framework to the author.

// Portability //

The same handler, mounted natively

A devframe's boundary is simply the Web Standard Request and Response. Any framework that speaks that (or connect-style middleware) mounts the same tool and inherits the whole ecosystem. Only the host-framework-facing glue changes. See all adapters.

// Adapters //

Package it the way your tool ships

The handler is the smallest common denominator. Higher-level adapters package that same definition into familiar forms; pick the entry points your package needs. Browse the adapters.

// Interfaces //

One capability, two interfaces

RPC functions stay private by default and opt into agent exposure explicitly. The MCP adapter translates those functions, resources, and selected shared state into an agent-consumable interface: the presentation changes, the source of truth stays the same.

// Hub //

From one devframe to a devtools hub

When several devtools run at once, discovery becomes the problem. @devframes/hub is a headless composition layer: many devframes register docks, commands, terminals, and shared state, and appear through one consistent entry. Learn about the hub.

Ship your devtool everywhere

Start from one DevframeDefinition and pick the entry points your package ships: hosted, standalone, embedded, or agentic.