Skip to content

OpenClaw Agent

read as .md

Install the ggui skill from ClawHub and any OpenClaw agent can generate interactive UIs from a natural-language prompt — forms, dashboards, wizards, anything the model can describe.

Terminal window
clawhub install ggui

This drops the ggui MCP tool catalogue and skill prompt into your agent’s context.

OSS / self-hosted — no signup. Run ggui serve --dev-allow-all locally (defaults to http://127.0.0.1:6781/mcp; see the OSS Quick Start); any bearer — use Bearer dev — authenticates in this mode. Local development only; default ggui serve requires a paired bearer.

The skill ships an mcporter.json that wires this up automatically. For manual setup:

OSS ggui serve

{
"mcpServers": {
"ggui": {
"type": "http",
"url": "http://127.0.0.1:6781/mcp",
"headers": { "Authorization": "Bearer dev" }
}
}
}

Hosted ggui (coming soon) — the cloud endpoint is per-app, no /mcp suffix:

{
"mcpServers": {
"ggui": {
"type": "http",
"url": "https://mcp.ggui.ai/apps/<appId>",
"headers": { "Authorization": "Bearer ${GGUI_API_KEY}" }
}
}
}

The skill exposes the ggui MCP tools — the agent never picks a blueprint by hand, the server’s matcher does that under the hood during handshake.

Core render loop

ToolPurpose
ggui_handshakeNegotiate the wire surface for the next UI (returns a handshakeId).
ggui_renderMaterialize the UI (mints sessionId; accept the suggestion or override).
ggui_consumeLong-poll for user gestures (form submits, button clicks).
ggui_updatePatch a delivered render’s props without re-rendering.
ggui_emitPush frames onto a declared streamSpec channel (optional).

Inspection

ToolPurpose
ggui_get_sessionInspect render state.
ggui_list_sessionsEnumerate this conversation’s sessions for resume (keyed by host-session).
ggui_list_gadgetsEnumerate renderer-side capabilities (map tiles, charts, editors).
ggui_list_themesList theme presets the agent may apply via ggui_render({themeId}).

Blueprint registry (optional)

ToolPurpose
ggui_list_featured_blueprintsBrowse curated blueprints the provider has featured.
ggui_search_blueprintsSearch the blueprint registry by keyword / intent.
ggui_render_blueprintRender a manifest-declared blueprint directly by id.

The canonical flow is handshake → render → consume. Ask your OpenClaw agent:

“Collect feedback about the user’s recent purchase. Ask for a star rating and free-form comments.”

The agent will:

  1. ggui_handshake({ intent, blueprintDraft }) — get a handshakeId + a routed suggestion (origin: cache / agent / synth).
  2. ggui_render({ handshakeId, props }) — accept the suggestion as-is (or pass override: { contract } / { variance } to re-aim). Returns { sessionId, resourceUri } — the render is an MCP-Apps resource a host mounts, not a URL.
  3. ggui_consume({ sessionId, timeout: 20 }) — long-poll until the user submits; events arrive keyed by intent (your actionSpec key).

Renders decay implicitly via TTL — there is no explicit close ceremony.

“Walk the user through a 3-step onboarding: personal info, preferences, confirmation.”

Each step is its own fresh ggui_handshake + ggui_render pair (each minting a new sessionId). Carry earlier answers forward by passing them as props on the next step’s ggui_render (declare the matching propsSpec entries in that step’s blueprintDraft) so the next prompt can prefill. See the Multi-step wizard cookbook for back-navigation patterns.

“While the form is open, refresh the available time-slot list every 10s.”

Loop ggui_update({ sessionId, kind: "merge", patch: { slots } }) to mutate props in place (RFC 7396 JSON Merge Patch — null deletes a key). Use { kind: "replace", props } for a full props swap. No new render, no flicker.

OpenClaw Agent ggui server User browser
| | |
|-- ggui_handshake ------->| |
| (matcher picks cached | |
| blueprint OR fires | |
| synth — invisible) | |
|<-- { handshakeId, -------| |
| suggestion } | |
|-- ggui_render({ -------->| |
| handshakeId, props }) | |
|<-- { sessionId, ---------| |
| resourceUri } | |
| |-- mounts resource ---->|
| |---- render UI -------->|
|-- ggui_consume --------->| |
| |<--- submit form -------|
|<-- { events } -----------| |
| (render decays via TTL) | |

Blueprints are an internal cache: the matcher checks them on every handshake. A cache hit returns near-instantly; a miss generates fresh React (expect seconds to ~a minute depending on model). The agent doesn’t pick — it just describes intent.

  • Describe intent, not markup. “A 3-question NPS survey” beats “a form with a slider, a textarea, and a submit button.”
  • Pass data as props, declared in the contract. Lists of options, prefilled values, the current user — declare them in blueprintDraft’s propsSpec and pass the values as props on ggui_render, not in the intent string.
  • Fresh render per step. Each new screen is a fresh handshake → render pair with its own sessionId. Prior renders decay via TTL.
  • Drain ggui_consume in a loop. Events are cleared after consumption. Match on each event’s intent (your actionSpec key, e.g. submit); react, then re-call. Exit when status: "expired".
SymptomFix
UnauthorizedLocal: run ggui serve --dev-allow-all (or pair a bearer). Hosted (coming soon): set GGUI_API_KEY.
Session not foundSession expired (TTL elapsed) — re-handshake to mint a fresh one.
Handshake requiredYou called ggui_render without a handshakeId — handshake first.
Empty consumeUser hasn’t interacted yet. Keep polling (long-poll up to ~20s).
Generation failedSimplify the prompt. (Hosted only, coming soon: check your account has credits.)