@reopt-ai/opt-devtool
v1.0.1
Published
Development-only devtool overlay for opt-ui, opt-datagrid, opt-editor, and opt-shell.
Maintainers
Readme
@reopt-ai/opt-devtool
Development-only devtool overlay for the opt design modules. Inspect focus
flow, ARIA wiring, composite zones, harness state boundaries, theme tokens,
Brandapp SDK wiring, and live snapshots from opt-datagrid / opt-editor /
opt-shell in one floating panel.
Skill support
There is no dedicated opt-devtool-install skill in
reopt-ai/reopt-skills yet.
Install it manually as a development-only dependency, keep the render behind a
production guard, and connect only the engine bridges the app uses.
Install
bun add -D @reopt-ai/opt-devtoolreact, react-dom, @reopt-ai/opt-ui, and (optionally) the engine
packages you want bridges for must already be present.
Quick start
Mount the provider once near the root of the app, render <OptDevtool />
in development, and call the per-engine bridges where you control the engine
state:
"use client";
import { OptDevtool, OptDevtoolProvider } from "@reopt-ai/opt-devtool";
export function DevtoolHost({ children }: { children: React.ReactNode }) {
return (
<OptDevtoolProvider>
{children}
{process.env.NODE_ENV !== "production" && <OptDevtool />}
</OptDevtoolProvider>
);
}The panel is hidden by default and toggles with Ctrl+Shift+F.
Pass defaultOpen to start visible.
Multi-export
Import the bridge for the engine you want to inspect:
| Sub-path | Hook | Purpose |
| -------------------------------- | -------------------------- | ------------------------------------------------------ |
| @reopt-ai/opt-devtool | — | OptDevtool, OptDevtoolProvider, types |
| @reopt-ai/opt-devtool/datagrid | useDataGridDevtoolBridge | DataGrid runtime / selection / remote telemetry |
| @reopt-ai/opt-devtool/editor | useEditorDevtoolBridge | EditorSpec mode / streaming / selection / integrations |
| @reopt-ai/opt-devtool/brandapp | useBrandappDevtoolBridge | Brandapp ID, auth/env, EAV, AI, route wiring |
| @reopt-ai/opt-devtool/harness | useShellDevtoolBridge | Harness manifest / state boundaries / adapter status |
| @reopt-ai/opt-devtool/theme | useThemeDevtoolBridge | Resolved theme tokens, contrast pairs, palette config |
| @reopt-ai/opt-devtool/ui | — | Configure event constants for runtime control |
Each useXxxBridge({ id, label, order? }) returns { inspect(snapshot) }.
Call inspect() whenever the engine state you want to expose changes:
const { inspect } = useDataGridDevtoolBridge({ id: "users-grid", label: "Users" });
useEffect(() => {
inspect(buildSnapshot(grid));
}, [grid.activeCell, grid.selection, ...]);The harness and theme bridges also auto-listen for SHELL_SNAPSHOT_EVENT /
SHELL_THEME_EVENT dispatched by ShellProvider, so a manual bridge
call is optional when you only want the default panel.
Brandapp SDK bridge
Use @reopt-ai/opt-devtool/brandapp to expose the Brandapp connection points
that make SDK integration debuggable: brandappId, masked client ID, required
env presence, auth/EAV/AI feature status, route wiring, schema hash, and notes.
The bridge does not import @reopt-ai/brandapp-sdk; pass a serializable
snapshot from the app so secrets can stay server-only.
If snapshot is provided, the Brandapp bridge is controlled by that prop.
The returned inspect and clear callbacks are for uncontrolled snapshots and
will not override the prop-driven view.
"use client";
import { useBrandappDevtoolBridge } from "@reopt-ai/opt-devtool/brandapp";
export function BrandappDevtoolBridge() {
useBrandappDevtoolBridge({
id: "brandapp",
label: "Brandapp",
snapshot: {
brandappId: "brandapp_123",
clientId: "clie...9abc",
baseUrl: "https://api.reopt.ai",
auth: { status: "configured", provider: "better-auth / Reopt OAuth" },
eav: { status: "configured", schemaHash: "eav-hash" },
ai: { status: "configured", routePath: "/api/design-agent" },
env: [
{ name: "BRANDAPP_ID", present: true, required: true, scope: "server" },
{
name: "BRANDAPP_CLIENT_SECRET",
present: true,
required: true,
scope: "server",
note: "value hidden",
},
],
},
});
return null;
}Runtime control
Toggle internal state from any frame on the same window by dispatching
OPT_DEVTOOL_CONFIGURE_EVENT:
import { OPT_DEVTOOL_CONFIGURE_EVENT } from "@reopt-ai/opt-devtool/ui";
window.dispatchEvent(
new CustomEvent(OPT_DEVTOOL_CONFIGURE_EVENT, {
detail: { visible: true, showTabOrder: true, showInspect: false },
}),
);Available OptDevtoolConfig flags: visible, showGuide, showTabOrder,
showSpatialNav, showEventLog, showComponentTrace, showComponentTree,
showInspect, showComponentLabels, showCompositeBounds.
Keyboard
| Shortcut | Action |
| ------------------------------------------------ | ------------------------ |
| Ctrl+Shift+F | Toggle the devtool panel |
| Click on element while 인스펙트 toggle is on | Pin inspect target |
| Click again | Unpin |
Notes
- Development-only:
sideEffects: falseso unused bridges tree-shake out, but it is still a good idea to gate<OptDevtool />behindNODE_ENV. - Reads private React Fiber expando keys (
__reactFiber$,__reactInternalInstance$,__reactContainer$) to surface component ancestry. Wrapped in try/catch so failures degrade silently. - The legacy
opt-ui-helper-configureevent is still accepted for backward compatibility but is deprecated and will be removed in 0.3.0.
