Agent UI
Build a visual interface for each agent, connect it to live agent state, and preview it inside xCloud.
Agent UI is the visual layer for an agent. Instead of every agent being only a chat thread, an agent can own a small web app that shows its state, tools, workflow, and domain-specific controls.
This is one of the main differences between xCloud and a normal web chat: the agent still runs on OpenClaw, but xCloud gives it a product-like interface.
How It Works
Each agent can have its own UI project.
~/.openclaw/workspace/<agent-id>/
IDENTITY.md
SOUL.md
AGENTS.md
ui-config.json
ui/
package.json
src/The ui-config.json file tells xCloud where the UI project lives and which port to use for preview.
For local engines, the UI normally lives on your computer. For remote engines, the UI can be stored on the remote engine and optionally synced from a local source folder.
Create An Agent UI
- Open an agent.
- Open the right preview panel.
- Choose Create UI or connect an existing UI folder.
- xCloud creates context files for the UI project.
- Build the UI with your preferred editor or coding agent.
xCloud writes helper files such as:
| File | Purpose |
|---|---|
AGENT-CONTEXT.md | Explains the agent identity, personality, tools, and UI goal |
CLAUDE.md | Instructions for Claude Code |
.cursorrules | Instructions for Cursor |
XCLOUD-UI.md | Guide for the xCloud runtime bridge |
xcloud-runtime.js | Runtime injected into the preview |
xcloud-ag-ui.js | Helper for AG-UI events |
Supported Editors
xCloud can open the UI folder in common local tools:
- Cursor
- VS Code
- Windsurf
- Claude Code
- Codex
- OpenCode
- Zed
- Terminal
- iTerm
The editor is only for building the UI. The actual agent still runs in the active OpenClaw engine.
Preview Rules
The preview expects a normal web project.
For React/Vite/Next projects:
- Include a
package.json. - Include a
devorstartscript. - Respect the
PORTenvironment variable. - Bind to
127.0.0.1locally or0.0.0.0on remote engines.
For simple HTML projects:
- Include an
index.html. - xCloud can serve it with a static HTTP server.
If the project has a dev server, xCloud starts it and embeds the URL in the preview.
Live Agent Bridge
xCloud injects a runtime into the UI. The UI can read live agent state from:
const state = window.xcloud.agent.getState();Useful state fields:
| Field | Meaning |
|---|---|
status | idle, running, responding, tool, or error |
messages | Recent user and assistant messages |
activeTools | Tools currently being called |
lastEvent | Last raw AG-UI event |
lastToolResult | Last finished tool result |
Subscribe to changes:
window.xcloud.agent.onStateChange((state) => {
console.log(state.status, state.messages);
});UI Tools
The UI can register tools that the agent can call.
window.xcloud.agent.registerTool({
name: "selectWorkout",
description: "Select a workout in the UI.",
parameters: {
type: "object",
properties: {
workoutId: { type: "string" }
},
required: ["workoutId"]
},
async execute(args) {
return { selected: args.workoutId };
}
});When the agent calls that tool, xCloud forwards the request into the iframe and returns the UI result to OpenClaw.
Remote Engine Notes
When the active engine is a VPS or another PC:
- The UI project can be copied to the remote engine.
- xCloud starts the dev server on the remote host.
- The preview loads from that host and port.
- If a local source path is configured, xCloud can sync between local files and the remote UI folder.
Remote previews are more sensitive to firewall, host binding, npm install time, and port conflicts.
Common Problems
| Problem | Fix |
|---|---|
| Preview stays loading | Confirm the project has package.json with dev or start, or an index.html |
| Port opens but page is blank | Check the dev server logs and browser console |
| UI works locally but not on VPS | Make sure the remote dev server binds to 0.0.0.0 |
| Runtime state is missing | Confirm xcloud-runtime.js was injected or imported |
| Agent cannot call UI tool | Keep the preview open and make sure the tool is registered after load |
| Imported UI does not appear | Check that the package included a ui/ folder and ui-config.json points to it |