Give your agent a real computer.
A lightweight Linux desktop that runs entirely inside Docker — with an HTTP daemon and TypeScript SDK so any model can drive it: shell, GUI apps, browser, keyboard, mouse, screen.
$ git clone
https://github.com/tanav29/desktop && cd desktop
$ docker compose up -d --build
# wait for healthy…
$ open http://localhost:6080/vnc.html:6080 noVNC viewer · :8095 HTTP daemon · :8090 live stream
A real desktop
Debian 13 + XFCE + Chromium in one container, capped at 2 CPU / 3 GB. Xvfb on :99, noVNC in your browser.
One HTTP daemon
xdotool, ImageMagick and bash behind a clean API on port 8095. Shell quoting and process cleanup handled for you.
TypeScript SDK
actions, cmd, create, kill, screenshot, live, frames — every call is one millisecond-level round-trip.
Watch it work
noVNC viewer for humans, MJPEG stream + JPEG frame generator for agents and vision models.
Disposable by design
Boot with one command, reset with docker compose down. Only ./workspace persists — nothing to clean up.
Model-agnostic
Plain HTTP end to end. Claude, GPT, Gemini, GLM or a bash script — if it can call an API, it can drive the computer.
Architecture
Three layers, each replaceable.
Every control surface is one HTTP round-trip to a process inside the container — milliseconds per call instead of ~150 ms+ spawning docker exec per action. And each computer is just a port.
Container
Real GUI desktop: Xvfb → XFCE → x11vnc → noVNC. — Swap with any X11 desktop.
Daemon
Python-stdlib HTTP API over xdotool / ImageMagick / bash. — Swap with anything that speaks HTTP.
SDK
Thin TS client: actions, cmd, create, kill, screenshot, live, frames. — Swap with raw fetch() calls.
┌──────────────────── your machine ────────────────────┐ │ │ │ web UI (Next.js) ────── eve agent │ │ (chat + live (tools + loop) │ │ desktop pane) │ │ │ │ │ computer-use-sdk │ │ │ HTTP │ │ ▼ │ │ ┌──────────── Docker container ─────────────┐ │ │ │ daemon :8095 every call = 1 round-trip │ │ │ │ │ │ │ │ │ XFCE on Xvfb :99 · xdotool │ │ │ │ x11vnc → websockify → noVNC :6080 │ │ │ │ Chromium · xterm · ImageMagick │ │ │ └───────────────────────────────────────────┘ │ │ │ │ │ ./workspace persists on host │ └──────────────────────────────────────────────────────┘
import { computer } from "computer-use-sdk";
// launch an app with a unique title
await computer.create("chromium https://example.com", {
title: "web-1",
});
// a whole input sequence in ONE round-trip
await computer.actions([
{ do: "wait_for", window: "Chromium", timeoutMs: 45_000 },
{ do: "focus", window: "Chromium" },
{ do: "key", keys: "ctrl+l" },
{ do: "paste", text: "https://news.ycombinator.com" },
{ do: "key", keys: "Return" },
]);
await computer.screenshot("state.png"); // → workspace/state.png
const feed = await computer.live(); // watch it move
await computer.kill("web-1"); // disposeDrive it from code
Batched actions. One round-trip.
Wait for a window, focus it, paste a URL, hit enter — in a single request. When a language model is the caller, one call per task beats one call per keystroke every time.
Boot your first computer.
One command, two minutes, zero host dependencies beyond Docker. Reset whenever you like.