Build a devtool once. Mount it anywhere Devframe released a framework that lets developers define a devtool once with `defineDevframe()` and mount it in any host framework through a single Web Standard `Request → Response` handler created by `initDevframe()`. The package ships adapters for frameworks including Hono and the `cac` CLI library, plus an MCP adapter that exposes opted-in RPC functions, resources, and shared state to AI agents, and the `@devframes/hub` headless composition layer for running multiple devtools through one entry point. Build a devtool once. Mount it anywhere. js 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/', } // 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 Adapters as Conveniences Type-safe RPC & Shared State Visual and Agentic // 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 https://devfra.me/adapters/initiate . js import { Hono } from 'hono' import { devtools } from './devtools' const app = new Hono app.all ${devtools.base} , c = devtools.handler c.req.raw // 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 https://devfra.me/adapters . python import { createCac } from 'devframe/adapters/cac' import myDevframe from './my-tool' createCac myDevframe .parse // Interfaces // One capability, two interfaces RPC functions stay private by default and opt into agent exposure explicitly. The MCP adapter https://devfra.me/adapters/mcp translates those functions, resources, and selected shared state into an agent-consumable interface: the presentation changes, the source of truth stays the same. js import { defineRpcFunction } from 'devframe' export const inspectBuild = defineRpcFunction { name: 'inspect-build', type: 'query', handler: = readBuildGraph , } // 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 https://devfra.me/guide/hub . js import { initHub } from '@devframes/hub/initiate' import { createTerminalsDevframe } from '@devframes/plugin-terminals' const hub = initHub { base: '/ devframes/', devframes: createTerminalsDevframe , // ...more devframes , ui: await import '@devframes/hub-ui' .then m = m.createUi , } Ship your devtool everywhere DevframeDefinition and pick the entry points your package ships: hosted, standalone, embedded, or agentic.