---
title: OpenClaw Agent
description: Install the ggui skill in OpenClaw and let any agent push interactive UIs on demand.
---

:::caution[Placeholder integration]
**OpenClaw** and **ClawHub** are placeholder brand names for an upcoming launch partner — the `clawhub` CLI and the `mcporter.json` skill manifest referenced below do **not** exist as a shipping product yet. The rest of the page (tool catalogue, handshake-first flow, auth headers, MCP config JSON) is canonical and works against any MCP-compatible host today; once OpenClaw ships, only the install command on this page changes. If you're integrating right now, follow [Generic MCP / Raw HTTP](/examples/generic-mcp/) instead.
:::

:::note[Works on OSS today; hosted coming soon]
The ggui skill is protocol-only — the same wire surface works against a local **`ggui serve`** (`127.0.0.1:6781/mcp`) today and against **hosted ggui** (`mcp.ggui.ai/apps/<appId>`, coming soon). Pick the variant that matches your endpoint in steps 2 and 3.
:::

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.

## Setup

### 1. Install the skill

```bash
clawhub install ggui
```

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

### 2. Pick an endpoint

**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](/oss-quickstart/)); any bearer — use `Bearer dev` — authenticates in this mode. Local development only; default `ggui serve` requires a paired bearer.

:::note[Hosted ggui — coming soon]
The hosted endpoint isn't live yet. When it ships you'll sign up at console.ggui.ai, create an app, and mint a `ggui_user_…` key under **Agent Connectors**:

```bash
export GGUI_API_KEY="ggui_user_..."
```

:::

### 3. Configure MCP

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

**OSS `ggui serve`**

```json
{
  "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:

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

## Tool catalogue

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**

| Tool             | Purpose                                                                    |
| ---------------- | -------------------------------------------------------------------------- |
| `ggui_handshake` | Negotiate the wire surface for the next UI (returns a `handshakeId`).      |
| `ggui_render`    | Materialize the UI (mints `sessionId`; accept the suggestion or override). |
| `ggui_consume`   | Long-poll for user gestures (form submits, button clicks).                 |
| `ggui_update`    | Patch a delivered render's props without re-rendering.                     |
| `ggui_emit`      | Push frames onto a declared `streamSpec` channel (optional).               |

**Inspection**

| Tool                 | Purpose                                                                     |
| -------------------- | --------------------------------------------------------------------------- |
| `ggui_get_session`   | Inspect render state.                                                       |
| `ggui_list_sessions` | Enumerate this conversation's sessions for resume (keyed by host-session).  |
| `ggui_list_gadgets`  | Enumerate renderer-side capabilities (map tiles, charts, editors).          |
| `ggui_list_themes`   | List theme presets the agent may apply via `ggui_render({themeId})`.        |

**Blueprint registry (optional)**

| Tool                            | Purpose                                              |
| ------------------------------- | ---------------------------------------------------- |
| `ggui_list_featured_blueprints` | Browse curated blueprints the provider has featured. |
| `ggui_search_blueprints`        | Search the blueprint registry by keyword / intent.   |
| `ggui_render_blueprint`         | Render a manifest-declared blueprint directly by id. |

## Usage

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.

### Multi-step wizard

> "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](/cookbook/multi-step-wizard/) for back-navigation patterns.

### Live patches without a re-render

> "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.

## How it works

```
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.

## Patterns

- **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"`.

## Troubleshooting

| Symptom              | Fix                                                                                              |
| -------------------- | ------------------------------------------------------------------------------------------------ |
| `Unauthorized`       | Local: run `ggui serve --dev-allow-all` (or pair a bearer). Hosted (coming soon): set `GGUI_API_KEY`. |
| `Session not found`  | Session expired (TTL elapsed) — re-handshake to mint a fresh one.                                |
| `Handshake required` | You called `ggui_render` without a `handshakeId` — handshake first.                              |
| Empty `consume`      | User hasn't interacted yet. Keep polling (long-poll up to ~20s).                                 |
| Generation failed    | Simplify the prompt. (Hosted only, coming soon: check your account has credits.)                 |

## Next steps

- **[MCP Protocol Reference](/api/mcp-protocol/)** — wire-level tool catalogue
- **[Claude Agent](/examples/claude-agent/)** — same flow, Claude SDK in TypeScript
- **[Generic MCP / Raw HTTP](/examples/generic-mcp/)** — language-agnostic version
- **[Feedback Form cookbook](/cookbook/feedback-form/)** — end-to-end recipe with code
- **[Glossary](/glossary/)** — gadget vs tool vs blueprint