Over the years, I have built quite a few DevTools: UnoCSS Inspector, Vite Plugin Inspect, Vitest UI, Nuxt DevTools, ESLint Config Inspector, and Node Modules Inspector, among others.
They look quite different, but they are all trying to do the same thing: making implicit states more transparent. Instead of guessing why a utility was generated, how a module was transformed, or which configuration applies to a file, we can inspect the process directly and interact with it.
Despite their different purposes, these tools share a large amount of infrastructure: server-client communication, state synchronization, serialization, static asset hosting, and a web interface. Each tool also needs its own decisions around being embedded, standalone, deployable, or integrated into a larger DevTools experience.
We can see the same pattern across the ecosystem. Frameworks and build tools are building their own DevTools, often with overlapping capabilities such as data inspectors, asset viewers, build analyzers, terminals, and editor integrations. Most of them are coupled not only to the framework, but also to how its development server serves assets, handles requests, and upgrades connections. Similar features are then rebuilt and improved separately.
We want to free DevTools from framework-specific boundaries: make each capability reusable and modular, so it can benefit every supported host. Instead of spreading the work across multiple versions of the same idea, communities could join forces on one tool and make it much better together.
This is the vision of a Universal DevTools Ecosystem I started sharing back in 2023, in Now, and the Future of Nuxt DevTools and Anthony’s Roads to Open Source - The Set Theory:
General
Build Tools
Frameworks Specific
Ecosystem
TanStackThe diagram was aspirational. Finding the right boundary was much harder.
The wish stayed with me through Nuxt DevTools and Vite DevTools. Its scope changed, package names changed, and we learned from each implementation. LLMs also helped us explore and validate the design much faster. After all these iterations, the vision is finally taking a concrete shape.
Let me introduce you to Devframe.
Devframe #
Devframe is a framework-neutral foundation for building a DevTool once, then bringing it to different hosts, standalone surfaces, and agents.
Think of Devframe as the unplugin for DevTools. While unplugin gives plugins a common interface across bundlers, Devframe gives DevTools a common definition and a standard way to be mounted into different environments.
A Devframe definition describes one tool: its capabilities, RPC functions, shared state, web interface, diagnostics, and agent-facing surface. It is then initiated into a Web Standard request handler that can be mounted almost anywhere.
One Definition, One Standard Handler #
Every Devframe starts with defineDevframe(). At its core, it associates the identity of a tool with the capabilities it provides:
import { defineDevframe } from 'devframe'
import { inspectProject } from './rpc'
export default defineDevframe({
id: 'my-tool',
name: 'My Tool',
// Package metadata and client entry omitted...
setup(ctx) {
ctx.scope('my-tool').rpc.register(inspectProject)
},
})The definition is independent of its presentation. initDevframe() turns it into a live instance:
import { initDevframe } from 'devframe/initiate'
import devframe from './devframe'
const devtools = initDevframe(devframe, {
base: '/__my-tool/',
})
devtools.handler
// (request: Request) => Promise<Response>
devtools.nodeMiddleware
// (req: IncomingMessage, res: ServerResponse, next: () => void) => voidBehind this handler, Devframe serves the tool’s web interface, connection metadata, live RPC, authentication, and the optional MCP endpoint under one namespace. The tool is no longer tied to a particular development server API; its boundary is simply the Web Standard Request and Response. This handler-first model is greatly inspired by Comark.
Modern frameworks, runtimes, and build tools already converge around this boundary. Hono and Nitro work with Web Standard requests directly. Next.js and SvelteKit expose route handlers. Vite and Rsbuild accept Connect-style middleware, for which the same instance provides nodeMiddleware:
// server.ts
import { Hono } from 'hono'
import { devtools } from './devtools'
const app = new Hono()
app.all(devtools.base + '*', c =>
devtools.handler(c.req.raw),
)That is almost the entire portability trick. The host still decides how the live RPC connection is attached: it can share the host’s HTTP server, receive its upgrade events, or use a sidecar when the host only exposes request handlers. The choice is advertised through __connection.json and stays invisible to the Devframe client.
This is the boundary I was looking for. Supporting another host no longer means teaching every DevTool about another plugin API. If the host can mount a Web Standard handler or middleware, it can host a Devframe. Framework-specific packages can still provide nicer conventions, but they become thin integrations over the same interface.
Adapters as Conveniences #
Mounting the handler directly is the lowest-level option. For common entry points, higher-level adapters package the same foundation into familiar forms. A definition can become a standalone CLI, a dedicated dev server, a Vite DevTools plugin, an MCP server, or a static report:
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
import { createBuild } from 'devframe/adapters/build'
import { createCac } from 'devframe/adapters/cac'
import { createDevServer } from 'devframe/adapters/dev'
import { createMcpServer } from 'devframe/adapters/mcp'
import devframe from './devframe'
// Pick the entry points your package needs:
export const runCli = () => createCac(devframe).parse()
export const startServer = () => createDevServer(devframe)
export const vitePlugin = createPluginFromDevframe(devframe)
export const startMcp = () => createMcpServer(devframe, { transport: 'stdio' })
export const buildReport = () => createBuild(devframe, { outDir: 'dist-static' })A tool can ship several of these entry points from the same package. For example, a build inspector could offer a standalone CLI for any project, generate static reports in CI, appear as a dock inside Vite DevTools, and let an agent query the active build—all backed by one definition.
This is already how node-modules-inspector, ESLint Config Inspector, and vite-plugin-inspect are built today. They remain focused tools with their own interfaces while sharing Devframe underneath. You can find more on the Built with Devframe page.
Devframe has no opinion about the frontend either. It handles the protocol and runtime, while each tool can use the UI framework and design system that suit it. To dogfood that promise, the built-in plugins span Vue, Svelte, Solid, React, and Next.js.
Visual and Agentic #
Once a DevTool has a structured boundary, its visual panel is no longer the only possible interface. With coding agents becoming part of development workflows, the same internal state and capabilities can also be consumed programmatically.
The two interfaces serve different strengths. Visualizations are effective for exploration, overview, and comparison. Agents can retrieve focused context, correlate it with the codebase, and carry out multi-step actions. They can use different presentations while sharing the same source of truth.
In Devframe, RPC functions stay private by default and explicitly opt into agent exposure. The MCP adapter translates those functions, readable resources, and selected shared state into an agent-consumable surface. Descriptions, schemas, and safety metadata help agents understand when and how a capability should be used.
Agent-native DevTools are a first-class goal of Devframe, but the APIs and practices are still being explored. In particular, discoverability, permissions, context usage, and the relationship between visual and agentic workflows will need feedback from real integrations.
Built-in Plugins #
A foundation is only credible when real tools can live on it. To verify Devframe’s capabilities and framework-agnostic design, we ship a few official plugins as usable examples. Each is built with a different frontend framework and can run standalone or be mounted into a supported host.
Data Inspector #
Data Inspector is built with Vue and provides an interactive workbench for live server-side objects. A tool registers an object as a data source, which can then be explored and queried with Jora inside the process that owns it.
Standalone, it can inspect JSON or JSONL files, build a self-contained report, or attach to a running Node.js process. This is useful for inspecting stores, caches, framework contexts, build metadata, or other states that would otherwise require custom logging.
When integrated, other tools only need to contribute data sources. A Vite plugin could expose its plugin container, a framework could expose runtime state, and a test runner could expose its test graph. They reuse the same query workbench and data viewer without building another inspector for every host.

Terminals #
Terminals is built with Svelte and provides a browser-based terminal panel supporting read-only process output and interactive PTY sessions.
Standalone, it can provide a small browser terminal with project-specific command presets. Inside a DevTools host, it becomes a shared surface: build tools, test runners, package managers, and other integrations can launch processes, keep their output isolated, and direct users to the relevant session.
This allows the process-running capability to be decoupled from the tool that renders it. It also avoids hiding subprocess output or mixing every task into the main terminal.

Accessibility Inspector #
Accessibility Inspector is built with Solid. It scans the host application with axe-core, lists WCAG violations, and highlights the corresponding elements on the page. It can also turn the findings into fix prompts for agents, connecting visual inspection with an agentic workflow.
Standalone, the panel and its injected agent can scan any page. Inside a DevTools host, the same scans can also be mirrored into the shared message feed.
It is heavily inspired by @nuxt/a11y, which brought real-time accessibility feedback into Nuxt DevTools. Extracting the idea into a Devframe plugin makes the same capability available beyond Nuxt.

Other official plugins cover assets management, Git, Open Graph previews, Code Server, and Devframe’s own RPC and state inspector. Their commonality is the Devframe definition and protocol, rather than a shared frontend stack.
From One Devframe to a DevTools Host #
So far, each Devframe represents one portable tool. A complete DevTools experience becomes much more interesting when those tools can meet and collaborate.
@devframes/hub is the framework-neutral composition layer. It provides shared concepts such as docks, commands, messages, and terminals. Each Devframe runs against a shared context, allowing tools to contribute capabilities and interact with each other.
The same mounting model also scales to the whole collection. initHub() puts it behind one Web Standard handler:
import { createUi } from '@devframes/hub-ui'
import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate'
import { createDataInspectorDevframe } from '@devframes/plugin-data-inspector'
import { createTerminalsDevframe } from '@devframes/plugin-terminals'
const hub = initHub({
base: DEVFRAMES_HUB_BASE,
devframes: [
createDataInspectorDevframe(),
createTerminalsDevframe(),
],
ui: createUi(),
})
hub.handler
// The whole DevTools ecosystem as Request -> ResponseThe mounted Devframes share one RPC registry, state store, connection, authentication gate, and optional aggregate MCP endpoint. The Hub itself is headless: @devframes/hub-ui provides the reference interface, while a product can bring its own UI without changing the underlying tools.
Now the complete Hub, not only a single Devframe, can be mounted into different environments. The repository includes working reference hosts for Vite, Next.js, Hono, Nitro, and Rsbuild. They are not separate ports of every plugin; each host only connects the same handler and UI entry to its native server API.
Vite DevTools is the first flagship host built on this foundation. It supplies its own Vite-focused interface and integrations while using initHub() for composition and serving. Alongside its own Vite and Rolldown analysis, Vitest UI, and Oxc tooling, it provides a common place for independent DevTools integrations to work together.
Vite plugins can contribute through an additional devtools.setup(ctx) hook. For portable Devframes, createPluginFromDevframe() adapts the definition into that Vite plugin interface:
/// <reference types="@vitejs/devtools-kit" />
import type { Plugin } from 'vite'
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
import { myDevframe } from './devframe'
// A portable Devframe adapted to Vite DevTools
export function MyDevframePlugin() {
return createPluginFromDevframe(myDevframe)
}
// A Vite-specific integration using the hook directly
export function MyVitePlugin(): Plugin {
return {
name: 'my-vite-plugin',
devtools: {
setup(ctx) {
ctx.docks.register({
id: 'my-vite-plugin',
title: 'My Vite Plugin',
type: 'iframe',
url: '/__my-vite-plugin/',
})
},
},
}
}The direct hook can access Vite-specific context. The adapter keeps a Devframe portable. Both target the same Hub and are served through the same standard handler underneath.
Portable Devframes compose behind one standard handler, then framework-specific DevTools inherit and extend the host. Hover, focus, or click any part to explore its responsibility.
Inheriting the Ecosystem #
Portability does not mean every DevTools should become generic. Framework-specific layers can provide richer experiences because they understand their framework’s conventions and runtime. The universal parts can be shared while the final integrations remain specific.
The new Nuxt DevTools v4 is being built on Vite DevTools. It inherits the shared host and available integrations, then adds Nuxt-specific knowledge: pages, modules, auto-imports, server APIs, runtime state, and contributions from the Nuxt module ecosystem.
This brings the original DevTools Kit wish back to where it started, now with a concrete foundation underneath. Nuxt DevTools v4 is expected to ship with Nuxt v5 and will also be available as a manual opt-in for Nuxt 4.
Vue DevTools is migrating to the same Vite DevTools foundation. Vue capabilities such as component and reactivity inspection can then coexist with Vite integrations and general Devframes, while Nuxt inherits them as part of the composition.
Devframe itself is not tied to Vite. The Web Standard handler makes the portability concrete: a future framework DevTools can mount the same Hub and plugins, then add its own knowledge and presentation. It does not get a complete framework-specific experience for free, but it no longer needs to rebuild the foundation before it can begin.
TanStack DevToolsThanks #
This vision has come such a long way with the help of many people.
Great thanks to WEBFANSPLZ for the tremendous amount of work he has put into Vite DevTools. AKRYUM has long inspired me through his work on Vue DevTools and testing framework UIs, and has also spent a lot of time brainstorming and prototyping these DevTools ideas together with me.
HYFDEV helped coordinate with Rolldown and shape the APIs that made Vite DevTools possible. ATINUX planted the seed of Nuxt DevTools, invested so much in building it, and now continues that investment in Vite DevTools. DANIELROE provided valuable feedback on Nuxt DevTools and kept motivating us to push further on bundle size (the installed size of Vite DevTools core dropped by 30 MB from v0.1 to v0.5).
Thanks also to YUYINWS for donating Oxc Inspector to Vite Plus DevTools and continuing to maintain it; and to SAKANA-Y and DVCOLOMBAN for being early adopters and contributing extensively to both Vite DevTools and Devframe.
And, of course, thanks to everyone who has contributed to Vite DevTools, Nuxt DevTools, and Vue DevTools along the way. This work is built on top of all those contributions.
Finally, thanks to VERCEL for supporting these projects and making our ambitious plan for unified DevTools no longer feel like an unreachable dream.
What’s Next #
Devframe v1.0 stabilizes the interface for the community to build and experiment on top of it. Vite DevTools will follow with its stable release, while Nuxt DevTools v4 and the Vue DevTools migration will continue testing the model at the framework level.
This is the first credible implementation toward the modular DevTools infrastructure we imagined years ago, rather than the completion of that vision. There are more hosts to connect, plugin conventions to refine, and agentic practices to discover.
What excites me is not one particular panel or host, but the possibility that a good tool can be built once, travel further, and become better through the effort of more communities. Shared infrastructure underneath; specific and playful experiences on top; structured capabilities available to both humans and agents.
We are still exploring the best practices, especially around agentic interfaces, permissions, and cross-tool collaboration. Any kind of contribution is welcome—integrations, experiments, design ideas, use cases, feedback, or simply trying the tools and sharing what you find.
I am looking forward to seeing what we can build together.