Control UI
기준일: 2026-07-26
공식 기준: Control UI
Control UI 문서는 OpenClaw 공식 문서(web/control-ui)를 한국어로 정리한 가이드입니다. Browser-based control UI for the Gateway (chat, activity, nodes, config) 명령·설정 키·코드 예시는 공식 문서를 그대로 보존하며, 해석과 절차 안내는 한국어로 제공합니다. 최종 동작은 설치된 CLI 버전과 공식 원문을 확인하세요.
핵심 요약
Browser-based control UI for the Gateway (chat, activity, nodes, config)
한국어 가이드 범위: web/control-ui 경로의 설정·명령·제약·예시를 학습용으로 재구성합니다.
문서 구성
공식 문서의 주요 섹션은 다음과 같습니다.
- Quick open (local)
- Device pairing (first connection)
- Pair a mobile device
- Personal identity (browser-local)
- Runtime config endpoint
- Gateway host status
- Language support
- Appearance themes
- Manage plugins
- Apps and extensions
- Sidebar navigation
- New session page
- What it can do (today)
- Import assistant memory
- MCP page
- Activity tab
- Operator terminal
- Browser panel
- Chat behavior
- Connection loss and reconnect
- PWA install and web push
- Hosted embeds
- Chat transcript layout
- Chat message width
- Tailnet access (recommended)
- Insecure HTTP
- Content security policy
- Avatar route auth
- Assistant media route auth
- Approval links
상세 내용
본문
The Control UI is a small Vite + Lit single-page app served by the Gateway:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- default:
http://<host>:18789/ - optional prefix: set
gateway.controlUi.basePath(e.g./openclaw)
Quick open (local)
If the Gateway is running on the same computer, open http://127.0.0.1:18789/ (or http://localhost:18789/).
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
connect.params.auth.tokenconnect.params.auth.password- Tailscale Serve identity headers when
gateway.auth.allowTailscale: true - trusted-proxy identity headers when
gateway.auth.mode: "trusted-proxy"
Device pairing (first connection)
After gateway auth succeeds, connecting from a new browser or device usually requires a one-time pairing approval, shown as disconnected (1008): pairing required.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Direct local Control UI connections from a loopback TCP peer (
127.0.0.1or::1, typically reached aslocalhost) with no forwarded/proxy headers can auto-approve device pairing only after gateway auth succeeds and the browser presents device identity. In token/password mode, the first connection still needs the configured shared secret; this auto-approval is not a token bypass. - Direct loopback needs no shared secret only when
gateway.auth.mode: "none"is explicitly configured. That disables gateway auth and is not the recommended Control UI setup. Tailscale Serve and trusted-proxy modes can avoid a pasted shared secret only when their respective identity checks succeed. - Tailscale Serve can skip the pairing round trip for Control UI operator sessions when
gateway.auth.allowTailscale: true, Tailscale identity verifies, and the browser presents its device identity. Device-less browsers and node-role connections still follow the normal device checks. - Direct Tailnet binds and LAN browser connects still require explicit approval. Browser profiles without device identity cannot use loopback auto-approval.
- Each browser profile generates a unique device ID, so switching browsers or clearing browser data requires re-pairing.
openclaw devices list
openclaw devices approve <requestId>
Pair a mobile device
An already paired administrator can create the iOS/Android connection QR without opening a terminal:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Personal identity (browser-local)
The Control UI supports a per-browser personal identity (display name and avatar) attached to outgoing messages, for attribution in shared sessions. It lives in browser storage, scoped to the current browser profile, and is not synced to other devices or persisted server-side beyond the normal transcript authorship metadata on messages you send. Clearing site data or switching browsers resets it to empty.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Runtime config endpoint
The Control UI fetches its runtime settings from /control-ui-config.json, resolved relative to the gateway's Control UI base path (for example /__openclaw__/control-ui-config.json under base path /__openclaw__/). That endpoint is gated by the same gateway auth as the rest of the HTTP surface: unauthenticated browsers cannot fetch it, and a successful fetch requires a valid gateway token/password, Tailscale Serve identity, or a trusted-proxy identity.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Gateway host status
Open Settings → General to see the Gateway Host card with the Gateway machine, LAN address, operating system, runtime, uptime, CPU load, memory, and state-volume disk space. The card refreshes every 10 seconds while visible through the system.info Gateway RPC, which requires the operator.read scope. Older Gateways and connections without that scope omit the card.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Language support
The Control UI localizes itself on first load based on your browser locale. To override it later, open Settings -> General -> Language (the picker lives on the General page, not under Appearance).
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Supported locales:
en,ar,de,es,fa,fr,hi,id,it,ja-JP,ko,nl,pl,pt-BR,ru,th,tr,uk,vi,zh-CN,zh-TW - Non-English translations are lazy-loaded in the browser.
- The selected locale is saved in browser storage and reused on future visits.
- Missing translation keys fall back to English.
Appearance themes
The Appearance panel has the built-in Claw, Knot, and Dash themes (Claw is default), plus one browser-local tweakcn import slot. To import a theme, open the tweakcn editor, choose or create a theme, click Share, and paste the copied link into Appearance. The importer also accepts https://tweakcn.com/r/themes/ registry URLs, editor URLs like https://tweakcn.com/editor/theme?theme=amethyst-haze, relative /themes/ paths, raw theme IDs, and default theme names such as amethyst-haze.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
OpenClaw system care
Open Settings → Ask OpenClaw to talk to the system setup and repair agent. Outside onboarding, this page can show at most one dismissible event chip per visit. It stays silent for routine Gateway traffic and reacts only to health snapshots that report a disabled configuration reloader, a configured channel disconnect/degradation, a failed channel probe, or unavailable channel credentials. A newer event replaces the pending chip only when it is more severe; dismissing or using the chip silences event prompts for that visit. Clicking the chip sends its diagnosis question as a real openclaw.chat message, so the transcript records the request and OpenClaw performs the diagnosis. Onboarding never shows these event chips.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Manage plugins
Open Plugins in the sidebar, or use /settings/plugins relative to the configured Control UI base path, to browse and manage plugins without leaving the Control UI. 예를 들어, a base path of /openclaw uses /openclaw/settings/plugins. The page is always available, even when every optional plugin is disabled.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Apps and extensions
Open Apps from the sidebar More menu, the command palette, or the sidebar agent menu (Get the apps), or use /apps relative to the configured Control UI base path. The page collects install links for every OpenClaw companion surface: the iOS and Android apps, the Apple Watch and Wear OS companions bundled with them, the macOS, Windows, and Linux desktop apps, the Chrome extension, the in-app Plugins hub with ClawHub, and the Discord community and docs.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Sidebar navigation
The sidebar organizes everything around the agent. The identity row at the top is the active agent; below it, the Pages section starts with Home — the agent's rolling main session, badged with its unread or running state — followed by the pinned destinations (Automations and Plugins by default). The customize control on the Pages header opens a menu with every other destination, including Usage and plugin-provided tabs, plus Edit pinned items; right-clicking the navigation area opens the pin editor directly. The session list below splits into zones: Threads for the agent's chat sessions (the main session stays behind Home; sessions it spawned appear here as top-level threads, and named threads show without a type prefix), Groups for group and room conversations, and Coding for sessions bound to a managed worktree or exec node (rows show a repo ⎇ branch line plus the node host), ACP-backed harness sessions, and the Codex/Claude CLI catalogs. Coding starts collapsed on first run and remembers your choice; its collapsed header keeps the true count and shows a running indicator while contained sessions work. Custom groups (the session category) and Pinned rows sit above Threads, and assigning a session to a custom group always wins over the automatic zone classification. The Threads header holds the sort control (Created or Last updated, Group by, and a persisted Status filter for Active, Archived, or All) and the + that opens the New session page. Archived rows stay inline, dimmed with an archive glyph; they do not contribute unread or attention state and stay outside lineage promotion. Opening a session moves the selection highlight without reordering rows. Parent sessions with recent child runs show a disclosure and child count; expand it to inspect nested child sessions, live or terminal status, and runtime without leaving the sidebar. Selecting a child opens its chat and automatically reveals its ancestor path. Child rows stay outside root grouping, pinning, dragging, multi-select, and pagination; collapsed zones do not consume the visible page budget. Sessions with new activity since they were last read show an unread dot, and opening one marks it read. An agent can also publish a short expiring status line and optionally request attention with a curated amber icon; that declaration clears when you open the session, send the next message, clear it explicitly, or its TTL expires. Cloud-worker lifecycle states use a globe badge; local and reclaimed sessions omit a placement badge because local execution is the default. Each root session row has a context menu (kebab button or right-click) with Pin/Unpin, Mark as unread/read, Rename, Fork, Move to group (including New group and Remove from group), Archive or Unarchive, and Delete; touch layouts keep the direct pin and menu controls visible. Cmd/Ctrl-click toggles root rows into a multi-select and Shift-click extends it across the visible order; opening the menu on a selected row then offers batch actions (Mark N as unread/read, Move N to group, Archive N, Delete N) that apply to every selected session, with a single confirmation for batch delete. Drag a root session onto Pinned to pin it, or onto a custom group to move it. Custom group headers can be collapsed, expanded, or dragged to reorder them; group names and their order live in the gateway (sessions.groups.*), so they follow you across browsers, while collapsed state stays in the browser profile. Group headers also have a menu (kebab button or right-click) with Rename group, New group, and Delete group; renaming or deleting a group updates every member session server-side, including archived ones, and deleting a group keeps its sessions and moves them back to Threads.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
New session page
The + in the sidebar session-list header opens a full-page draft at /new: nothing is created until you send the first message. A unified Place picker chooses the working folder and, for admin operators, the execution destination: Gateway · local, a paired node that exposes system.run, or an available cloud profile. The folder defaults to the agent workspace; another absolute Gateway path requires operator.admin but can run directly without being a Git checkout. When the selected Gateway folder is a Git checkout, the same picker offers optional Worktree isolation with a base-branch picker backed by worktrees.branches (no fetch) and an optional worktree name (the branch becomes openclaw/). Cloud workers require that managed-worktree path; paired nodes never expose it. The composer footer chooses the new session's model and reasoning level. Its Incognito toggle creates a web-only thread whose session entry, transcript, and compaction state stay in memory until the Gateway restarts; OpenClaw also skips its automatic memory flush. The agent keeps its normal tools, so an explicit save request or tool-driven file write can still persist data. The model provider still processes messages, and content-free audit metadata is still recorded. Cloud starts persist their model and reasoning choices before dispatching the session to its worker.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
What it can do (today)
주요 항목:
- Chat with the model via Gateway WS (
chat.history,chat.send,chat.abort,chat.inject). Archived sessions keep the composer disabled and show a banner with an Unarchive action before the conversation can continue. - Chat history refreshes request a bounded recent window with per-message text caps, so large sessions do not force the browser to render a full transcript payload before chat becomes usable.
- Hovering or keyboard-focusing a public GitHub issue or pull request link shows its state, title, author, recent activity, comments, and change statistics. The connected Gateway fetches and caches public metadata without changing the link target, including when the UI uses a remote Gateway. The Gateway uses
GH_TOKENorGITHUB_TOKENwhen available, after confirming the repository is public; otherwise it uses GitHub's anonymous API with a longer cache. - Talk through browser realtime sessions. OpenAI uses direct WebRTC, Google Live uses a constrained one-use browser token over WebSocket, and backend-only realtime voice plugins use the Gateway relay transport. Video-capable browser sessions can choose a device-local camera in Settings or flip cameras from the live preview; the browser captures JPEG frames for the realtime provider without streaming camera video through the Gateway. Client-owned provider sessions start with
talk.client.create; Gateway relay sessions start withtalk.session.create. The relay keeps provider credentials on the Gateway while the browser streams microphone PCM throughtalk.session.appendAudio, forwardsopenclaw_agent_consultprovider tool calls throughtalk.client.toolCallfor Gateway policy and the larger configured OpenClaw model, and routes active-run voice steering throughtalk.client.steerortalk.session.steer. - Stream tool calls and live tool output cards in Chat (agent events). Tool activity renders as kind-aware rows: shell commands show the syntax-highlighted command with terminal-style output; supported edit and write calls show bounded inline diffs, line numbers when available, and
+added -removedstats; and consecutive calls collapse into a summary such as "Ran 13 commands, read 6 files, edited 9 files". While a run is live, the newest running call names the group header. Expand a row to inspect its remaining arguments and raw output. - Optional AI purpose titles for complex tool calls (long shell commands, argument-heavy plugin tools), enabled with
gateway.controlUi.toolTitles: true(default off). Titles come from the batchedchat.toolTitlesmethod through standard utility-model routing — an explicitutilityModel(operator-chosen provider, like other utility tasks), else the session provider's declared small-model default — and cache gateway-side per agent. When the opt-in is off or no cheap model is usable, rows keep their deterministic labels and no model call happens. - Start or dismiss ephemeral model-suggested follow-up tasks; accepted suggestions open a fresh managed-worktree session with the proposed prompt.
- Activity tab with browser-local, redaction-first summaries of live tool activity from existing
session.tool/ tool event delivery. - Channels: built-in plus bundled/external plugin channels status, QR login, and per-channel config (
channels.status,web.login.*,config.patch). - Channel probe refreshes keep the previous snapshot visible while slow provider checks finish, and label partial snapshots when a probe or audit exceeds its UI budget.
- Threads (a workspace page at
/sessions, with a Worktrees tab alongside it): list configured-agent sessions by default, pin frequent sessions, rename them, archive or restore inactive sessions, fall back from stale unconfigured agent session keys, and apply per-session model/thinking/fast/verbose/trace/reasoning overrides (sessions.list,sessions.patch). A three-way Active / Archived / All filter controls both this page and the sidebar; All dims archived rows and labels them explicitly. Archived sessions keep their transcripts, are never auto-pruned, and remain shelved until explicitly unarchived or deleted. Rows show an unread dot for active sessions with activity since they were last read, with mark-unread/mark-read actions (sessions.patch { unread }), and a Fork action that branches the transcript into a new session (sessions.create { parentSessionKey, fork: true }). Overview tiles above the table summarize the loaded roster (session count, live runs, unread sessions, total tokens, and archived count when available), each row carries a kind glyph with a live-run dot, status renders as a plain dot plus label, and the Tokens column shows a context-window usage meter when the session reports token and context sizes. Row management actions live in a per-row menu (kebab button or right-click) mirroring the sidebar's session menu, and the row drawer carries the agent runtime and run duration alongside the other session details. - Native Claude and Codex sidebar catalogs stream one host at a time, then reconcile after node connectivity changes, on page focus, and at most every 30 seconds while visible. Catalog changes trigger a faster follow-up pass, so sessions created in the native tools appear without reloading the Control UI. Claude Desktop rows also retain their local custom-group label when present; OpenClaw reads that mapping from Desktop's local store and never writes it.
- Session grouping: a Group by control organizes the sessions table into sections by custom groups, channel, kind, agent, or date. Custom groups persist per session via
sessions.patch(category), so sessions started from message channels (Discord, Telegram, WhatsApp, ...) can be categorized too; assign groups by dragging rows onto a section, or with the per-row group selector, and create groups with the New group action. - Memory (a tab on the Agents page, scoped to the selected agent): dreaming status, enable/disable toggle, and Dream Diary reader (
doctor.memory.status,doctor.memory.dreamDiary,config.patch). - Import Memory (
/memory-import, reached from the Agents page's Memory tab): preview and copy local Claude Code auto-memory, Codex consolidated memory, or Hermes memory files into the selected agent workspace (migrations.memory.plan,migrations.memory.apply). - Onboarding memory offer: when the Control UI opens in onboarding mode (
?onboarding=1, used by the Linux companion app after its first-run install), a one-page dialog offers to import detected memories with the same plan/apply flow; skipping leaves the settings page as the later entry point. - Automations (cron jobs): stat cards (automation count, failing count, scheduler state, next wake) above an Automations/Run history tab switch; the Automations tab lists jobs in a filterable table (All/Active/Paused, search, schedule and last-run filters, per-row action menu) with starter suggestions below, and the Run history tab shows recent runs across all automations (
cron.*). - Tasks: live active and recent background task ledger with linked sessions and cancellation (
tasks.*). Chat's Background tasks rail groups running and finished work; select a row to inspect its bounded prompt and output or error summary. - Plugins: browse the installed inventory and curated store, search ClawHub, install and remove plugin code, and enable or disable installed plugins (
plugins.*); MCP server rows editmcp.serversthrough the config methods. - Skills: status, enable/disable, install, API key updates (
skills.*). - Devices: one inventory joins paired device records, the node catalog, and live presence (
device.pair.list,node.list,system-presence). The Gateway host is pinned first; paired clients show connection status, roles, tokens, capabilities, and commands. Duplicate pairings collapse into an expandable group, and Clean up N stale bulk-removes admin-confirmed offline duplicates that were auto-approved (silent local, trusted-CIDR, or SSH-verified) or predate approval provenance. Entries can be removed (node.pair.remove,device.pair.remove), device pairing and node re-approvals handled inline (device.pair.*,node.pair.approve/reject), and mobile setup codes created from the same card. - Exec approvals: edit gateway or node allowlists and ask policy for
exec host=gateway/node(exec.approvals.*). - View/edit
~/.openclaw/openclaw.json(config.get,config.set). - Settings navigation starts with Ask OpenClaw, then groups pages by attention: General, Appearance, and Notifications up top; Connections (Connection, Channels, Communications, Devices); Agents & Tools (Agents, AI & Agents, Model Providers, MCP, Automation, Labs); Privacy & Security (Security, Approvals); and System (Infrastructure, Advanced, Debug, Logs, About). General is a slim hub with model defaults, language, and gateway host stats; every other setting lives on exactly one page.
- Privacy & Security: curated rows for gateway auth, exec policy, browser enablement, tool profile, device auth, and mobile pairing, above the schema-backed
security/approvalssections.
Import assistant memory
Open Settings → Import Memory to bring local Codex or Claude Code memory into an OpenClaw agent. The Gateway discovers supported local memory on its own host, so a remote Control UI imports from the Gateway computer rather than the browser computer.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
MCP page
The dedicated MCP page is an operator view for OpenClaw-managed MCP servers under mcp.servers. It does not start MCP transports by itself; use it to inspect and edit saved config, then use openclaw mcp doctor --probe when you need live server proof.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Activity tab
The Activity tab lives in Settings › System, next to Logs and Debug. It is an ephemeral browser-local observer for live tool activity, derived from the same Gateway session.tool / tool event stream that powers Chat tool cards. It does not add another Gateway event family, endpoint, durable activity store, metrics feed, or external observer stream.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Operator terminal
The dockable operator terminal is disabled by default. To enable it, set gateway.terminal.enabled: true and restart the Gateway. The terminal requires an operator.admin connection and opens a host PTY in the active agent workspace. New tabs follow the currently selected chat agent.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Browser panel
The Control UI ships a dockable browser panel that renders the Gateway-controlled browser (the same one agents drive through the browser tool) in any regular web browser - no native webview required. It appears when the connected Gateway advertises browser.request to an operator.admin connection; the globe button in the thread workspace rail toggles it. The panel shows a live page snapshot with tabs, an editable URL bar, back/forward/reload, and open-in-your-browser, docks right or bottom, and forwards clicks, wheel scrolling, and basic typing to the remote page.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Annotate (pencil): draw freehand markup over the page. Send to chat composites the strokes into the screenshot, attaches the image to the active chat composer, and prefills a prompt describing the page URL, title, and each marked region so the agent knows exactly what you circled.
- Inspect (pointer): hover to see the element under the cursor (selector, accessible name, role, size); click to send that element's details plus a highlighted screenshot through the same composer flow. Inspect, wheel scrolling, and back/forward need
browser.evaluateEnabled(on by default).
Chat behavior
Talk mode uses a registered realtime voice provider. Configure OpenAI with talk.realtime.provider: "openai" plus an openai API-key profile, talk.realtime.providers.openai.apiKey, or OPENAI_API_KEY. OpenAI Realtime uses the public Platform API and requires a Platform API key; a Codex OAuth login does not satisfy this surface. Configure Google with talk.realtime.provider: "google" plus talk.realtime.providers.google.apiKey. The browser never receives a standard provider API key: OpenAI receives an ephemeral Realtime client secret for WebRTC, and Google Live receives a one-use constrained Live API auth token for a browser WebSocket session, with instructions and tool declarations locked into the token by the Gateway. Providers that only expose a backend realtime bridge run through the Gateway relay transport, so credentials and vendor sockets stay server-side while browser audio moves through authenticated Gateway RPCs. The Realtime session prompt is assembled by the Gateway; talk.client.create does not accept caller-provided instruction overrides.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
chat.sendis non-blocking: it acks immediately with{ runId, status: "started" }and the response streams viachatevents. Trusted Control UI clients may also receive optional ACK timing metadata for local diagnostics.- Chat uploads accept images plus non-video files. Images keep the native image path; other files are stored as managed media and shown in history as attachment links.
- Re-sending with the same
idempotencyKeyreturns{ status: "in_flight" }while running, and{ status: "ok" }after completion. chat.historyresponses are size-bounded for UI safety. When transcript entries are too large, Gateway may truncate long text fields, omit heavy metadata blocks, and replace oversized messages with a placeholder ([chat.history omitted: message too large]).- When a visible assistant message was truncated in
chat.history, the side reader can fetch the full display-normalized transcript entry on demand throughchat.message.getbysessionKey, activeagentIdwhen needed, and transcriptmessageId. If the Gateway still cannot return more, the reader shows an explicit unavailable state instead of silently repeating the truncated preview. - Assistant/generated images are persisted as managed media references and served back through authenticated Gateway media URLs, so reloads do not depend on raw base64 image payloads staying in the chat history response.
- When rendering
chat.history, the Control UI strips display-only inline directive tags from visible assistant text (for example[[reply_to_*]]and[[audio_as_voice]]), plain-text tool-call XML payloads (including<tool_call>...</tool_call>,<function_call>...</function_call>,<tool_calls>...</tool_calls>,<function_calls>...</function_calls>, and truncated tool-call blocks), and leaked ASCII/full-width model control tokens. It omits assistant entries whose whole visible text is only the exact silent tokenNO_REPLY/no_replyor the heartbeat acknowledgement tokenHEARTBEAT_OK. - During an active send and the final history refresh, the chat view keeps local optimistic user/assistant messages visible if
chat.historybriefly returns an older snapshot; the canonical transcript replaces those local messages once the Gateway history catches up. - Live
chatevents are delivery state, whilechat.historyis rebuilt from the durable session transcript. After tool-final events the Control UI reloads history and merges only a small optimistic tail; the transcript boundary is documented in WebChat. chat.injectappends an assistant note to the session transcript and broadcasts achatevent for UI-only updates (no agent run, no channel delivery).- The sidebar lists every loaded active session by agent section and pinned/channel/work/custom/Chats buckets with a single New Session action that opens the draft dialog. Opening a visible row moves only the highlight. Sessions can be dropped onto Pinned to pin them, or onto a custom group or Chats to move them; custom groups are collapsible and drag-reorderable, group names and order sync through the gateway, and collapsed state stays in the browser. A new dashboard session asynchronously gets a concise generated title from its first non-command message; explicit names and authenticated sender identity remain separate, so account names are never used as generated titles. Set
agents.defaults.utilityModel(oragents.entries.*.utilityModel) to route this separate model call to a lower-cost model; if that distinct model fails, title generation retries once with the primary model. Expanding another agent section browses that agent's sessions without leaving the open chat. - Thread search lives in the command palette (⌘K, or the search button in the top-left control cluster): typing a query follows a bounded number of matching pages across agents, filters internal child/cron rows, and lists visible matches next to navigation commands. The Threads page keeps the exhaustive searchable list with filters.
- Each sidebar row keeps direct pin access plus a full context menu for unread state, rename, fork, grouping, archive, and delete. Multi-selected rows (Cmd/Ctrl-click, Shift-click for ranges) get a batch menu covering unread state, grouping, archive, and delete; batch archive/delete stays disabled unless every selected session is archivable. An active run and an agent's main session cannot be archived. Archiving or deleting the currently selected session switches Chat back to that agent's main session.
- In the macOS app, the OpenClaw mark uses the otherwise-empty native titlebar strip next to the window controls instead of consuming a sidebar row.
- On desktop widths, chat controls stay on one compact row and collapse while scrolling down the transcript; scrolling up, returning to the top, or reaching the bottom restores the controls.
- The session header shows a small facepile beside the workspace chip when other people are viewing the same session; it lists up to four viewer avatars with an overflow count and disappears when you are alone.
- Consecutive duplicate text-only messages render as one bubble with a count badge. Messages that carry images, attachments, tool output, or canvas previews are left uncollapsed.
- User-message bubbles carry transcript actions: a hover rewind button (confirm popover with a "Don't ask again" option) plus right-click Rewind to here and Fork from here. Rewind repoints the session to the state just before that message and returns its text to the composer for edit and resend (
sessions.rewind,operator.admin); fork creates a new session from the active-path prefix before the message, opens it, and seeds its composer with the same text (sessions.fork,operator.write). Both actions disable with an explanatory tooltip while the agent is working, apply only to persisted user messages, and are rejected for sessions whose conversation is owned by an external agent harness. Rewind moves chat context only — files and other tool side effects are not reverted — and the pre-rewind transcript remains preserved in the append-only session store. When that store contains multiple transcript branches, the chat title bar shows a branch menu with each branch's latest message, message count, and recency; selecting an inactive branch switches the current session back to that preserved path (sessions.branches.list,operator.read;sessions.branches.switch,operator.admin). Branch switching is also unavailable while the agent is working, and selecting the already-active branch is a typed no-op error at the RPC boundary. The separate hide action on user bubbles hides a message in the current browser only; the message stays in the transcript and the agent still sees it. - When a session's checkout sits on a non-default branch of a GitHub repository, the chat view pins pull request chips above the composer: PR number, repo, branch, diff counts, a CI pill, and draft/merged/closed state, each linking to the PR. The row shows at most two chips — live (open/draft) PRs first — and a "Show more" button reveals collapsed merged/closed history. The CI pill opens a small CI monitoring popover with passed/failed/running/skipped check counts and a link to the PR's checks page. Detection runs server-side through
controlUi.sessionPullRequests, which reuses the Gateway'sGH_TOKEN/GITHUB_TOKENwhen set. When the GitHub API rate limit is hit, chips keep the last known status and show a warning that the status may be out of date; dismissing a chip hides it for that session in the current browser profile. Before any PR exists, the row shows the branch itself — repo, branch name, and the +/− size of the diff against the default-branch merge base (committed and uncommitted work). Once the pushed branch has commits to compare, the row adds a Create PR button that opens GitHub's new-pull-request page; before that, a session with changed files (committed, uncommitted, or untracked) still gets the row without the button. The row hides itself while an open or draft PR exists. The branch row comes from local git only, so it stays available while GitHub is rate limited and carries the same stale-status warning, since "no PR found" cannot be trusted until the limit resets. - The session diff panel shows what a session's checkout actually changed: the branch button in the workspace rail or chat title bar opens the detail panel with a per-file diff of branch, uncommitted, and untracked work against the checkout's default-branch merge base — status dot, rename arrow, per-file +/− counts, collapsible files, and "N unmodified lines" markers between hunks. Diffs are computed server-side through the
sessions.diffGateway method (operator.readscope); binary and oversized files degrade to stats-only entries, and the button only appears when the connected Gateway advertisessessions.diff. - Every Chat pane has a title bar. Click the session title to rename it; the workspace chip copies the checkout path or branch and can reveal local Gateway workspaces in the host file manager. Remote and exec-node sessions keep copy actions but hide reveal.
- The thread workspace rail in each Chat pane lists thread files, project files, and artifacts. It docks to the pane's right edge by default; drag its header (or use the dock button) to move it to the bottom, and the choice is stored in the current browser profile. A collapsed rail takes no space at all: reopen it with ⇧⌘B or the files toggle in the title bar, which carries a changed-file count badge. The separate file, tool, and Canvas detail panel is unaffected.
- Clicking a file reference in chat, a file path in an expanded read/edit/write tool card, or a file row in the workspace rail opens the file detail panel: a CodeMirror-based code view with syntax highlighting, line numbers, jump-to-line, in-file search, copy actions, and an open-in-external-editor menu. When the Gateway advertises
sessions.files.setto anoperator.adminconnection, the panel adds an Edit mode with dirty tracking and Cmd/Ctrl-S save; unsaved drafts survive file, panel, and session navigation in the current browser tab until explicitly saved or discarded. Saves are compare-and-swap on a content hash returned bysessions.files.get: if the file changed on disk since it was loaded (for example because the agent kept working), the panel shows a conflict notice with Reload (take the latest content) and Overwrite (keep the local edit) actions. Writes go through the same fs-safe workspace guards as reads — path containment, symlink/hardlink rejection, and a 256 KB UTF-8 cap — and only overwrite existing files; the editor never creates or deletes them. - The background tasks rail in each Chat pane lists the current agent's background tasks and subagents (
tasks.listscoped by agent, kept live bytaskevents): running work shows a live elapsed timer, tool-use count, the tool currently in use, and a stop control; the collapsible finished section adds run durations; and a View transcript link opens the task's child session in the pane. Open it with the title-bar activity toggle; the task snapshot loads eagerly, so it carries a running-count badge without opening the rail first. The Tasks page remains the full cross-agent ledger. - The workspace rail, background tasks rail, and detail panel adapt to each pane's own width rather than the window: in a narrow pane or compact window both rails present as bottom strips (side-dock controls hide until the pane widens; the workspace rail keeps first claim on the side slot when only one column fits), and the detail panel stacks below the thread with a horizontal resize handle instead of sharing the row with it. Phone-sized viewports still open the detail panel full-screen.
Connection loss and reconnect
Once a session is established, a dropped Gateway connection does not log you out. The dashboard stays visible with a floating amber "Gateway connection lost — Reconnecting…" pill under the top bar while the client retries automatically with backoff (800 ms up to 15 s). Live updates and realtime/session actions pause until the connection returns; Retry now in the pill forces an immediate attempt. Chat remains editable: ordinary text and attachment sends are kept in the current tab's gateway/session-scoped browser storage, shown as waiting for reconnect, and sent automatically when the Gateway returns. Live controls and slash commands remain unavailable while offline, except that Stop can queue an exact local run ID for replay. A session-only stop is not replayed because newer work may start in that session before the connection returns.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
PWA install and web push
The Control UI ships a manifest.webmanifest and a service worker, so modern browsers can install it as a standalone PWA. Web Push lets the Gateway wake the installed PWA with notifications even when the tab or browser window is not open.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
OPENCLAW_VAPID_PUBLIC_KEYOPENCLAW_VAPID_PRIVATE_KEYOPENCLAW_VAPID_SUBJECT(defaults tohttps://openclaw.ai)push.web.vapidPublicKeyfetches the active VAPID public key.push.web.subscriberegisters anendpointpluskeys.p256dh/keys.auth.push.web.unsubscriberemoves a registered endpoint.push.web.testsends a test notification to the caller's subscription.
| Surface | What it does |
|---|---|
ui/public/manifest.webmanifest |
PWA manifest. Browsers offer "Install app" once it is reachable. |
ui/public/sw.js |
Service worker that handles push events and notification clicks. |
state/openclaw.sqlite → web_push_vapid_keys |
Auto-generated VAPID keypair used to sign Web Push payloads. |
state/openclaw.sqlite → web_push_subscriptions |
Persisted browser subscription endpoints, keys, and registration timestamps. |
Hosted embeds
Assistant messages can render hosted web content inline with the [embed ...] shortcode. The iframe sandbox policy is controlled by gateway.controlUi.embedSandbox:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
{
gateway: {
controlUi: {
embedSandbox: "scripts",
},
},
}
Chat transcript layout
The chat transcript uses a centered readable frame aligned with the composer. Assistant and tool output stay left-aligned while your own messages stay right-aligned inside that frame. In multi-user sessions (for example a group chat relayed from a channel plugin), messages from other attributed participants render left-aligned with the author's avatar, name, and a stable per-identity color, so only the signed-in viewer's messages read as "mine". When two or more attributed participants are present, assistant replies carry a small "Replying to name" marker naming the participant whose message triggered the turn. System entries such as local slash-command output render as centered notice rows without an avatar.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Chat message width
Wide-monitor users can override the transcript width under Settings → Chat → Message width. The preference stays in that browser's local storage. Supported forms include plain lengths and percentages such as 960px or 82%, plus constrained min(...), max(...), clamp(...), calc(...), and fit-content(...) width expressions.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Tailnet access (recommended)
Keep the Gateway on loopback and let Tailscale Serve proxy it with HTTPS:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
openclaw gateway --tailscale serve
openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
Insecure HTTP
If you open the dashboard over plain HTTP (http:// or http://), the browser runs in a non-secure context and blocks WebCrypto. By default, OpenClaw blocks Control UI connections without device identity.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Successful trusted-proxy auth can admit operator Control UI sessions without device identity.
- This does not extend to node-role Control UI sessions.
- Same-host loopback reverse proxies still do not satisfy trusted-proxy auth; see Trusted proxy auth.
Content security policy
The Control UI ships a tight img-src policy: only same-origin assets, data: URLs, and locally generated blob: URLs are allowed. Remote http(s) and protocol-relative image URLs are rejected by the browser and never issue network fetches.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Avatars and images served under relative paths (for example
/avatars/<id>) still render, including authenticated avatar routes the UI fetches and converts into localblob:URLs. - Inline
data:image/...URLs still render. - Local
blob:URLs created by the Control UI still render. - GitHub link preview avatars are fetched by the Gateway from GitHub's fixed avatar host and returned as bounded
data:URLs; the operator browser never contacts the remote avatar host. - Remote avatar URLs emitted by channel metadata are stripped at the Control UI's avatar helpers and replaced with the built-in logo/badge, so a compromised or malicious channel cannot force arbitrary remote image fetches from an operator browser.
Avatar route auth
When gateway auth is configured, the Control UI avatar endpoint requires the same gateway token as the rest of the API:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
GET /avatar/<agentId>returns the avatar image only to authenticated callers.GET /avatar/<agentId>?meta=1returns the avatar metadata under the same rule.- Unauthenticated requests to either route are rejected (matching the sibling assistant-media route), so the avatar route cannot leak agent identity on hosts that are otherwise protected.
- The Control UI forwards the gateway token as a bearer header when fetching avatars, and uses authenticated blob URLs so the image still renders in dashboards.
Assistant media route auth
When gateway auth is configured, assistant local-media previews use a two-step route:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
GET /__openclaw__/assistant-media?meta=1&source=<path>requires the normal Control UI operator auth; the browser sends the gateway token as a bearer header when checking availability.- Successful metadata responses include a short-lived
mediaTicketscoped to that exact source path. - Browser-rendered image, audio, video, and document URLs use
mediaTicket=<ticket>instead of the active gateway token or password. The ticket expires quickly and cannot authorize a different source.
Approval links
Operator approval notifications can deep-link to a standalone approval document served under the reserved ${controlUiBasePath}/approve/{approvalId} namespace (for example /approve/, or /openclaw/approve/ with a configured base path). The URL is stable for the lifetime of the approval and safe to forward between your own devices: it identifies the approval, never authorizes it.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- The one-segment
/approve/<approvalId>namespace is reserved by the Gateway ahead of plugin HTTP routes for all HTTP methods, so a plugin route can never shadow or intercept an approval document. - Opening an approval document requires the same gateway auth as the rest of the Control UI (token/password, Tailscale Serve identity, or trusted-proxy identity); credentials are never part of the approval URL.
- When Control UI serving is disabled, requests to the namespace return
404instead of falling through to plugin handlers. - Signing in on an approval document is ephemeral for that page: it does not overwrite the gateway selection or settings saved by the full Control UI in the same browser.
pnpm ui:build
OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build
pnpm ui:dev
Blank Control UI page
If the browser loads a blank dashboard and DevTools shows no useful error, an extension or early content script may have prevented the JavaScript module app from evaluating. The static page includes a plain HTML recovery panel that appears when `` is not registered after startup.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Disable extensions that inject into all pages, especially extensions with
<all_urls>content scripts. - Try a private window, a clean browser profile, or another browser.
- Keep the Gateway running and verify the same dashboard URL after the browser change.
Debugging/testing: dev server + remote Gateway
The Control UI is static files; the WebSocket target is configurable and can differ from the HTTP origin. This is handy when you want the Vite dev server locally but the Gateway runs elsewhere.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
gatewayUrlis stored in localStorage after load and removed from the URL.- If you pass a full
ws://orwss://endpoint viagatewayUrl, URL-encode the value so the browser parses the query string correctly. tokenshould be passed via the URL fragment (#token=...) whenever possible. Fragments are not sent to the server, which avoids request-log and Referer leakage. Legacy?token=query params are still imported once for compatibility, but only as a fallback, and are stripped immediately after bootstrap.passwordis kept in memory only.- When
gatewayUrlis set, the UI does not fall back to config or environment credentials. Providetoken(orpassword) explicitly; missing explicit credentials is an error. - Use
wss://when the Gateway is behind TLS (Tailscale Serve, HTTPS proxy, etc.). gatewayUrlis only accepted in a top-level window (not embedded), to prevent clickjacking.- Public non-loopback Control UI deployments must set
gateway.controlUi.allowedOriginsexplicitly (full origins). Private same-origin LAN/Tailnet loads from loopback, RFC1918/link-local,.local,.ts.net, or Tailscale CGNAT hosts are accepted without enabling Host-header fallback. - Gateway startup may seed local origins such as
http://localhost:<port>andhttp://127.0.0.1:<port>from the effective runtime bind and port, but remote browser origins still need explicit entries. - Do not use
gateway.controlUi.allowedOrigins: ["*"]except for tightly controlled local testing; it means allow any browser origin, not "match whatever host I am using." gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=trueenables Host-header origin fallback mode, but it is a dangerous security mode.
pnpm ui:dev
http://localhost:5173/?gatewayUrl=ws%3A%2F%2F<gateway-host>%3A18789
http://localhost:5173/?gatewayUrl=wss%3A%2F%2F<gateway-host>%3A18789#token=<gateway-token>
{
gateway: {
controlUi: {
allowedOrigins: ["http://localhost:5173"],
},
},
}
관련 문서
주요 항목:
- Dashboard — gateway dashboard
- Health Checks — gateway health monitoring
- TUI — terminal user interface
- WebChat — browser-based chat interface
실습 체크리스트
- 공식 문서와 로컬 버전을 대조합니다:
https://docs.openclaw.ai/web/control-ui - 관련 CLI는
openclaw --help및 하위 명령--help로 옵션을 확인합니다. - 설정 변경 시
openclaw config/openclaw doctor로 유효성을 검사합니다. - Gateway·채널·플러그인 변경 후에는 필요 시 Gateway를 재시작합니다.
자주 쓰는 명령·설정 예시
openclaw devices list
openclaw devices approve <requestId>
{
gateway: {
controlUi: {
embedSandbox: "scripts",
},
},
}
openclaw gateway --tailscale serve
openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
pnpm ui:build
관련 링크
- 공식 원문: web/control-ui
- OpenClaw 문서 홈
이 가이드는 공식 문서를 한국어 학습용으로 재구성한 것입니다. 옵션 기본값·플래그 이름은 설치 버전에 따라 달라질 수 있습니다.