Big picture
- MCP client — Open WebUI, Claude Desktop, LiteLLM, n8n, or anything that speaks MCP over Streamable HTTP.
- Computer Use Server (the orchestrator) — stateless HTTP service that routes MCP requests to per-chat sandbox containers, serves the system prompt, exposes the live browser/terminal, and hosts file previews.
- Sandbox container — one Docker container per
X-Chat-Id. Full Ubuntu userspace with the tools listed in Introduction.
Data flow
X-Chat-Id (mandatory in strict multi-user mode). The orchestrator creates the sandbox lazily on first use and tears it down after CONTAINER_MAX_AGE_HOURS. Everything is isolated — the AI can install packages, create files, run servers, and nothing leaks between users.
Sandbox contents
The live browser
The terminal tab
ttyd + tmux. The sub-agent tool launches Claude Code CLI inside a named tmux session — you can attach, watch, or take over. See Terminal.
File pipeline
/home/assistant/uploads/{chat_id}/ inside the sandbox, and are re-exposed as MCP resources/list entries. Files the model creates are served back through the same public endpoint (cu.yambr.com/files/... in managed Yambr; http://localhost:8081/files/... self-hosted) and auto-previewed in Open WebUI’s artifacts panel. See File preview.
The system prompt — six redundant channels
The per-chat system prompt isn’t just pasted into a single field. It’s delivered through six MCP-native and HTTP channels so the model can recover its environment even if a client strips one of them:- Tool descriptions (every MCP tool includes context)
/home/assistant/README.mdinside the sandbox (readable by theviewtool)InitializeResult.instructions(MCP handshake)resources/list+resources/read(uploaded files)- HTTP
GET /system-prompt(legacy integrations) - HTTP
GET /skill-list(for sub-agent delegation)
Session isolation
Controlled bySINGLE_USER_MODE:
| Mode | X-Chat-Id | Behavior |
|---|---|---|
| unset | Yes | Isolated container per chat ID |
| unset | No | Shared default container + warning in every tool response |
true | any | Always one default container; header ignored |
false | Yes | Strict: isolated container per chat ID |
false | No | Rejected with error |
