Dashboard Architecture
기준일: 2026-07-26
공식 기준: Dashboard Architecture
Dashboard Architecture 문서는 OpenClaw 공식 문서(web/dashboard-architecture)를 한국어로 정리한 가이드입니다. Session dashboards: architecture and implementation plan (technical design, pre-GA) 명령·설정 키·코드 예시는 공식 문서를 그대로 보존하며, 해석과 절차 안내는 한국어로 제공합니다. 최종 동작은 설치된 CLI 버전과 공식 원문을 확인하세요.
핵심 요약
Session dashboards: architecture and implementation plan (technical design, pre-GA)
한국어 가이드 범위: web/dashboard-architecture 경로의 설정·명령·제약·예시를 학습용으로 재구성합니다.
문서 구성
공식 문서의 주요 섹션은 다음과 같습니다.
- Vision
- 개념
- UX flows
- Interaction tiers
- Widget model and hosting
- Widgets host content; MCP apps are one content kind
- Plugin capability declarations
- Modeled residual: WebRTC data channels
- Transcript display: one widget card
- Server-sourced widgets (pinned MCP apps)
- WorkBoard integration
- Layout: fluid grid
- Data model (per-agent DB)
- Protocol surface
- Agent tools
- What this replaces
- Non-goals (this program)
- Implementation plan
상세 내용
본문
Technical design document for the session dashboard feature, written before and during implementation. It is the source of truth for the build-out. When the feature ships, /web/dashboard becomes the user-facing page and this page stays as the architecture reference.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Vision
Working with an agent today is a text stream. The dashboard makes it a workbench: the agent renders live, interactive widgets; the user pins them onto a persistent surface; chat docks to the side (or hides) and the main content is the board. You go from "talking to the agent" to "operating a control panel the agent built for you" without ever leaving the session.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- A board is a face of a session, not a new object. Every session (thread)
- Agent parity. Everything the user can do on a board, the agent can do
- Native, not embedded. The board is Lit components in the Control UI shell
- Small agent surface. Widgets are addressed by stable name and updated in
- Capabilities over trust. Widget code is arbitrary agent-authored HTML/JS
개념
| Concept | Definition |
|---|---|
| Session (thread) | Existing gateway session, keyed by stable sessionKey. Owned by an agent. |
| Board | The widget face of one session. Exists iff the session has widgets/tabs. Survives /new//reset (attached to sessionKey, not the transcript). |
| Tab | A presentation page of a board: which widgets, their arrangement, and the chat dock state (left/right/bottom/hidden). Boards start with one implicit tab. |
| Widget | Named, sandboxed HTML/JS program owned by the session. Addressed as sessionKey + name. Updated in place by name. |
| Capability manifest | Per-widget declaration of reach: data (read bindings), actions (allowlisted verbs), prompt (send to session), net (allowed origins). |
| Pin (widget) | Moving a transcript widget onto the session's board (user affordance or agent tool arg). Unpin removes it from the board. |
| Pin (session) | Existing sidebar pinning of sessions. A pinned session with a board opens on its board face. |
UX flows
in the transcript exactly as today → hover shows Pin to dashboard → widget appears on the session's board. The agent can pass pin: true to do the same.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Graduation: agent calls
show_widgetin any chat → widget renders inline - Board view: a session with a board gets a face toggle (Chat / Dashboard).
- Drag: user drags widgets; grid auto-compacts (widgets float up, neighbors
- Reset warning:
/new//reseton a board-bearing session asks for - Sidebar: pinned sessions render their board face when they have one.
- Interactions (three tiers, see below): silent state events, visible
Interaction tiers
- State events (default). Widget UI interactions the model should know about but not respond to.
bridge.emitState({...})appends a structured session notice (same mechanism as group-activity notices). No agent turn is started; the model sees accumulated notices on its next run. 2. Prompts (explicit talk).bridge.sendPrompt(text)— requires user activation; sends a visible user message into the session (the docked chat shows it). Rate-limited; each send is user-confirmed unless the widget holds thepromptcapability grant. 3. Automation.bridge.runAction(name, args)— fires a manifest-declared action. Initial verb set:cron.trigger(run an existing cron job now) andbinding.refresh. Cron jobs already run in visible, isolated run-sessions and can use a cheaper model: that is the "small model powers the widget" path. No hidden sessions anywhere.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Widget model and hosting
Widget HTML/JS is authored by the agent (typically via show_widget), wrapped in the standard document shell (CSP meta, size reporter, bridge bootstrap) and rendered in `` (never allow-same-origin).
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Inline (transcript) widgets keep the current canvas-document pipeline:
- Board widgets are session state: bytes live in the owning agent's SQLite
- Update in place: re-emitting a widget with the same
namereplaces the - Byte freezing: granted capabilities bind to the sha256 of the widget
Widgets host content; MCP apps are one content kind
The widget is the OpenClaw primitive: the named, pinned, sized, session-owned board cell with a grant record. What renders inside it is a content kind:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
html— agent-authored viashow_widget, bytes in board storage.mcp-app— a third-party MCP app view (ui://resource from a configured- One sandbox host.
htmlwidgets render through the same hardened - One authorization model. A widget's reach is a granted allowlist,
- Host tools for
htmlwidgets (exposed over the widget bridge, checked openclaw.prompt.send— tier 2; routed through the visible composer,openclaw.state.emit— tier 1 session notices (coalesced, size-capped)openclaw.data.read— parameterized read-only bindings (existingopenclaw.cron.trigger— tier 3 automationnet= CSP. Network reach uses the already-shipped per-widget CSP- Grants. A widget declaring nothing renders immediately (sandboxed,
- Authoring shim. The document wrapper injects
window.openclaw.prompt,
Plugin capability declarations
Enabled plugins can extend the widget host through dashboard.dataBindings and dashboard.actionVerbs in openclaw.plugin.json. Plugin-local ids become grant names prefixed by the plugin id, such as workboard.cards.list and workboard.dispatch; % and . in the plugin-id segment are escaped so a different plugin/local-id split cannot inherit the same persisted grant. During plugin registration, OpenClaw verifies that every binding targets an RPC registered by the same plugin with operator.read and every action targets one with operator.write; invalid declarations fail the plugin load. The validated registry is rebuilt only with plugin lifecycle changes, while widget grants remain per-widget and byte-and-revision-bound.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Modeled residual: WebRTC data channels
The sandbox CSP emits the proposed webrtc 'block' directive, but Chromium's current CSP directive set does not implement it. Scriptable widgets can therefore use WebRTC data channels for egress in current Chromium. The same residual already ships for inline chat widgets and the MCP Apps host on main.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Transcript display: one widget card
Inline display unifies on the widget primitive. When a tool result carries UI — show_widget output or an MCP tool result with an app resource — the system materializes an ephemeral, auto-named widget (session-scoped, pruned) and the transcript renders a single widget card that dispatches on content kind. MCP app auto-display stays exactly as the spec expects (zero extra model work); it just is a widget underneath. This deletes the parallel mcpApp special-cases in chat rendering (surface gating, separate dedup), gives every inline UI the same pin affordance, and makes the widget registry the primary re-open path (transcript-scan reconstruction stays as fallback for never-pinned history). The read-only ticketed standalone host overlaps with boards as a persistent re-open surface — consolidation candidate to evaluate in T6, not assumed.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Server-sourced widgets (pinned MCP apps)
With the unified host, pinning a third-party MCP app is just a widget whose content is fetched from the server instead of stored: board_widgets keeps the descriptor (serverName, toolName, uiResourceUri, originating toolCallId + sessionKey) instead of HTML bytes, and the board re-mints the view lease past the chat-turn 10-minute TTL (re-fetching the ui:// resource on staleness). Chat inline MCP app views get the same Pin to dashboard affordance as agent widgets. Re-opened views are read-only today by design; pinned apps that should stay interactive get a durable grant over the server's app-visible tools (explicit allowlist shown to the operator on pin), decoupled from the minting run. Ungranted pins stay read-only — still useful for display dashboards. v1 pins to the originating session's board; cross-session pinning needs a lease broker and waits. Coordinate with open PR #109807 (ui/message composer routing, theme/size propagation).
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
WorkBoard integration
The WorkBoard integration program keeps cards and boards plugin-owned while stitching dispatched cards back to their session boards through the existing sessionKey and runId, exposing WorkBoard feeds and dispatch through plugin-declared bindings and actions, and composing those results with the existing html and mcp-app widget kinds instead of introducing a WorkBoard-specific widget type.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Layout: fluid grid
12 columns, fixed row height, auto-compacting (gravity-up, push-aside on drag — gridstack semantics, implemented natively; grid math stays pure and DOM-free). Widget layout state per tab: { name, w (1-12), h (rows) } plus order. Agent vocabulary:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
size:sm(3×3) ·md(6×4) ·lg(8×6) ·xl(12×8) ·fullafter: <widgetName>optional ordering anchor; omitted = append- User drags/resizes freely; the same order+size model round-trips.
Data model (per-agent DB)
New tables in agents//agent/openclaw-agent.sqlite (requires an agent-DB schema-version bump — operator sign-off required before this lands):
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
CREATE TABLE board_tabs (
session_key TEXT NOT NULL,
tab_id TEXT NOT NULL, -- slug
title TEXT NOT NULL,
position INTEGER NOT NULL,
chat_dock TEXT NOT NULL DEFAULT 'right', -- left|right|bottom|hidden
created_by TEXT NOT NULL, -- 'user' | 'agent'
PRIMARY KEY (session_key, tab_id)
) STRICT;
CREATE TABLE board_widgets (
session_key TEXT NOT NULL,
name TEXT NOT NULL, -- stable widget name
tab_id TEXT NOT NULL,
title TEXT,
html BLOB NOT NULL, -- wrapped document source
sha256 TEXT NOT NULL,
revision INTEGER NOT NULL,
size_w INTEGER NOT NULL,
size_h INTEGER NOT NULL,
position INTEGER NOT NULL, -- order within tab (auto-compact input)
manifest TEXT NOT NULL DEFAULT '{}', -- capability manifest JSON
grant_state TEXT NOT NULL DEFAULT 'none', -- none|pending|granted|rejected
granted_sha TEXT, -- byte-frozen grant
created_by TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
PRIMARY KEY (session_key, name)
) STRICT;
Protocol surface
RPCs (core method table, typebox schemas in gateway-protocol):
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
board.get { sessionKey }→ tabs + widget metadata (no bytes) —operator.readboard.update { sessionKey, ops[] }— tab CRUD/reorder, widget move/resize/board.widget.put { sessionKey, name, html, manifest, placement }—board.widget.grant { sessionKey, name, decision }—operator.approvalsboard.event { ticket, payload }— ticket-bound tier-1 state event ingest;board.prompt.authorize { ticket }— returns whether a visible prompt sendboard.data.read { ticket, bindingId, params? }— gateway-side allowlistedboard.action { ticket, action, ... }— exact-grant automation dispatchboard.changed { sessionKey, revision, widget? }— persisted state changed;board.command { sessionKey, command }— transient UI drive (agent switches
Agent tools
Three tools total (core, always registered; rendering gated on the inline-widgets client cap as today):
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- `show_widget { title, widget_code, name?, pin?, size?, tab?, after?,
dashboard { action, ... }— board management verbs:read,tab_create,- Existing
crontools cover the automation tier; no new tool needed.
What this replaces
false, never in a stable release (first appeared in 2026.7.2 betas). No migration; a doctor rule removes stale /workspaces/` if present. Harvested ideas: pure grid math, bridge security model (port bootstrap, binding gating, rate limits), byte-frozen approval.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
extensions/workspacesis deleted. Experimental, `enabledByDefault:- Widget hosting moves from
extensions/canvasto core. The canvas doc
Non-goals (this program)
Control UI; the inline-widget path is unchanged).
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Multi-user board sharing/ACLs (future; will arrive via session sharing).
- Native macOS/iOS board rendering (they get it wherever they embed the
- Builtin data widgets (sessions/usage/cron cards) — the capability bridge plus
Implementation plan
Independent worktrees, Codex-built, review+land sequentially. Land-then-fix.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
| # | Branch | Scope | Depends on |
|---|---|---|---|
| T1 | claude/dashboard-remove-workspaces |
Delete workspaces plugin + UI + docs + i18n keys; doctor cleanup rule | — |
| T2 | claude/dashboard-canvas-core |
Promote widget hosting + show_widget to core; canvas plugin keeps node tool; zero behavior change |
— |
| T3 | claude/dashboard-domain |
Agent-DB tables (schema bump), board.* RPCs + events, dashboard tool, show_widget pin/name/manifest args, tier-1 notices, reset-keeps-board |
T2 |
| T4 | claude/dashboard-ui |
Board face + tab strip + fluid auto-compact grid + chat dock (left/right/bottom/hidden) + transcript pin affordance + sidebar board face + reset confirm | T3 (mock-first via dev fixtures) |
| T5 | claude/dashboard-capabilities |
Grant store/UI + byte freezing; move html widgets onto the shared sandbox host; host tools (openclaw.prompt.send/state.emit/data.read/cron.trigger); net CSP; authoring shim |
T3, T4 |
| T7 | claude/dashboard-mcp-apps |
mcp-app content kind: pin affordance on inline app views, descriptor storage, lease re-mint/refresh, durable server-tool grants (reuses shipped MCP Apps host) |
T3, T4 |
| T6 | polish | Live E2E on a scratch gateway (real keys), screenshots, fixes, user-focused /web/dashboard rewrite, enable-by-default review |
all |
실습 체크리스트
- 공식 문서와 로컬 버전을 대조합니다:
https://docs.openclaw.ai/web/dashboard-architecture - 관련 CLI는
openclaw --help및 하위 명령--help로 옵션을 확인합니다. - 설정 변경 시
openclaw config/openclaw doctor로 유효성을 검사합니다. - Gateway·채널·플러그인 변경 후에는 필요 시 Gateway를 재시작합니다.
자주 쓰는 명령·설정 예시
CREATE TABLE board_tabs (
session_key TEXT NOT NULL,
tab_id TEXT NOT NULL, -- slug
title TEXT NOT NULL,
position INTEGER NOT NULL,
chat_dock TEXT NOT NULL DEFAULT 'right', -- left|right|bottom|hidden
created_by TEXT NOT NULL, -- 'user' | 'agent'
PRIMARY KEY (session_key, tab_id)
) STRICT;
CREATE TABLE board_widgets (
session_key TEXT NOT NULL,
name TEXT NOT NULL, -- stable widget name
tab_id TEXT NOT NULL,
title TEXT,
html BLOB NOT NULL, -- wrapped document source
sha256 TEXT NOT NULL,
revision INTEGER NOT NULL,
size_w INTEGER NOT NULL,
size_h INTEGER NOT NULL,
position INTEGER NOT NULL, -- order within tab (auto-compact input)
manifest TEXT NOT NULL DEFAULT '{}', -- capability manifest JSON
grant_state TEXT NOT NULL DEFAULT 'none', -- none|pending|granted|rejected
granted_sha TEXT, -- byte-frozen grant
created_by TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
PRIMARY KEY (session_key, name)
) STRICT;
관련 링크
이 가이드는 공식 문서를 한국어 학습용으로 재구성한 것입니다. 옵션 기본값·플래그 이름은 설치 버전에 따라 달라질 수 있습니다.