Hotline Computer v0.11.0

Hotline Computer

A Linux desktop for your coding agent, in a rootless container on your machine. It has a screen, a browser, a shell and a home directory, and one MCP server that lets the agent see the screen, act on it and check what happened.

Claude Code, Codex, ChatGPT desktop or any client that speaks MCP over HTTP can drive it. You watch the same desktop from your browser and take the mouse when it needs you.

The computer's desktop: Chromium on the left showing a site served at 127.0.0.1:4321, the job log on the right with two jobs finished and one running, and the top bar reading agent at work, 2 running, 43 done.
Claude serving a site on its own computer, every job it ran logged on the right. 1920 by 1080.
Install
$ export TOKEN=$(openssl rand -hex 24)
$ docker run -d --name computer \
    --cap-drop=ALL --security-opt no-new-privileges \
    --pids-limit 1024 --memory 4g --shm-size 1g \
    -p 127.0.0.1:8787:8787 -e HOTLINE_COMPUTER_TOKEN="$TOKEN" \
    -v computer-home:/home/agent \
    ghcr.io/1broseidon/hotline-computer:0.11.0
For your agent
Install Hotline Computer for me and connect it to this client.
1. Check that Docker, Podman or Apple container is running.
2. Generate a token with `openssl rand -hex 24` and start
   ghcr.io/1broseidon/hotline-computer:0.11.0 with the run command at
   https://computer.hotline.dev/#install, published on 127.0.0.1 only.
3. Add it as an HTTP MCP server at http://127.0.0.1:8787/mcp with the
   header `Authorization: Bearer <token>`.
4. Call `state info`, then `state guide`, and follow the guide.
5. Give me the viewer link, http://127.0.0.1:8787/#<token>, and no one else.

Overview

One container is one machine. Inside it:

PartRole
Xvfb and MesaThe X11 display and software OpenGL. No GPU needed
ChromiumThe visible browser, driven over its DevTools protocol
D-Bus and AT-SPIThe accessibility tree the agent reads native apps by
gnome-keyringThe Secret Service that apps and CLIs keep passwords in
NixToolchains a project needs, prepared per workspace
hotline-computerPID 1: supervisor, window manager, top bar and MCP server

The agent connects straight to the container. There is no gateway, no account and no cloud service in between.

The image is a contract, not a binary: anything that serves the same eight tools over streamable HTTP at /mcp, with /health open, is a valid computer.

Install

You need Docker, Podman or Apple container 1.5+, and 4 GB of memory for the container. The image ships for arm64 and amd64.

Docker
$ export TOKEN=$(openssl rand -hex 24)
$ docker run -d --name computer \
    --cap-drop=ALL --security-opt no-new-privileges \
    --pids-limit 1024 --memory 4g --shm-size 1g \
    -p 127.0.0.1:8787:8787 -e HOTLINE_COMPUTER_TOKEN="$TOKEN" \
    -v computer-home:/home/agent \
    ghcr.io/1broseidon/hotline-computer:0.11.0

Every flag is there on purpose:

FlagWhy
--cap-drop=ALLThe computer needs no Linux capabilities
--security-opt no-new-privilegesNothing inside can gain privileges it did not start with
--pids-limit 1024 --memory 4gA runaway job stops at the container, not your machine
--shm-size 1gChromium needs a sized /dev/shm
-p 127.0.0.1:8787:8787Loopback only. Never publish it on every interface
-e HOTLINE_COMPUTER_TOKENWithout a token, every route is open
-v computer-home:/home/agentThe home survives an upgrade or a recreate

To share a project, add -v "$PWD:/home/agent/workspace". Mount the project, never your whole home and never the container runtime's socket.

Quickstart

Point your agent at the MCP endpoint with the same token.

Claude Code
$ claude mcp add --transport http computer \
    http://127.0.0.1:8787/mcp \
    --header "Authorization: Bearer $TOKEN"

Codex, ChatGPT desktop and other HTTP MCP clients take the same URL and Authorization header in their own config.

The agent's first two calls are state info, which names the running release, and state guide, which returns the guide that ships inside that release. The guide comes from the running binary, so it always matches the image.

Open the desktop in your browser:

Viewer
$ open "http://127.0.0.1:8787/#$TOKEN"

Tools

capture screenshots

A scaled PNG of the screen plus the AT-SPI accessibility tree: windows, elements, roles, coordinates, values and states. Pass a window to read one app, or a region to see part of the screen at full size. mode=png writes the original instead.

input mouse and keyboard

Clicks, moves, drags, scrolls, types, presses keys and pastes, through XTEST. batch runs up to ten steps under one lock.

browser Chromium

Navigates, snapshots the page as text with element refs, and acts on those refs: click, fill, select, check, hover, upload, tabs, dialogs and downloads. fill types text, or one of your stored secrets by name. No action runs longer than a minute.

shell jobs

Starts jobs with a label you can read, keeps 4 MiB of output each, and lets the agent read, wait on, write to or cancel them. Up to 16 run at once and the newest 64 are kept. run starts a named entry from the workspace manifest.

files file transfer

Gets, puts and lists paths under the home. Downloads URLs and GitHub release assets with optional SHA-256 checks, extracts archives safely, and runs scripts as managed jobs.

windows window layout

Lists, focuses, closes, maximizes and tiles windows, and verifies the result.

wait text polling

Polls the accessibility tree and the browser's page text for a phrase.

state machine state

The running version, your stored secrets by name, the release guide, workspace manifests and Nix preparation, desktop leases, browser logins and snapshots of the home.

Viewer

The computer serves its own screen. / is a page with one canvas, and /ws is the socket behind it. The page reads the token from the URL fragment, which never leaves your browser.

The viewer opens watch-only. Nothing you do moves the machine until you press Take control. While you drive, the agent's tools that change the screen are refused, and the desktop hands itself back when you press Give it back, close the page or stop for ten seconds.

The Activity window: timestamped tool calls, among them Started Clone the Hotline site, a failed Opened 127.0.0.1/ and then a successful one, and Started Check the page answers.
The Activity window, failures included.

The top bar shows who is working and what is running: agent at work, 2 running · 5 done, or amber you're driving. The jobs observer on the right shows every job by its label, with its output and a ✓ or ✗ when it ends. The Activity window lists the last 500 tool calls, failures included.

Files in the viewer opens the home: download anything from it, or drop a file on the page to upload it.

Workspaces

The image has the desktop, the browser and Nix, and no language toolchains. A project describes what it needs once, in .hotline/manifest.json, and the agent prepares it:

{
  "packages": ["nodejs", "pnpm"],
  "runs": {
    "test": { "command": ["pnpm", "test"] },
    "web": { "command": ["pnpm", "dev"], "kind": "web" }
  }
}

Packages are Nixpkgs names, or the repository's own flake. Jobs started inside the workspace get the prepared environment. A web run gets a free $PORT and answers with its URL once it listens; a desktop run answers once its window is up, with a screenshot.

The prepared environment, its cache, the job history and the browser profile all live in the home, so they survive an upgrade when the home is a volume.

Security

The container is the boundary. Inside it, the agent can do anything the container's user can do.

Holds

  • Nothing runs as root. The image has no sudo and no apt, and with --cap-drop=ALL and no-new-privileges nothing can elevate.
  • The MCP endpoint, the viewer's socket and its file routes all require the token. Only /health and the viewer page itself are open.
  • A job never inherits HOTLINE_COMPUTER_TOKEN.
  • Stored secrets are sent by name. A variable reaches jobs as an environment variable. A login is typed only on its own sites. A passkey's private key is never put in the browser.

Gaps

  • Redaction replaces secret values in tool output with [redacted NAME]. That keeps them out of the agent's context. It does not stop code written to get them out, in pieces or encoded, and the screen is never redacted.
  • Jobs and Chromium run as the same user, so a job can reach the browser's DevTools port inside the container.
  • The keyring's password is empty. Its file in the home is not encrypted, so the home volume is the boundary around what is kept there.
  • Chromium runs with --no-sandbox; the container is its sandbox.

Limits

  • No GPU. Graphics render on Mesa in software.
  • X11 only. No Wayland.
  • Linux apps only.
  • One desktop per container. A second agent gets a second container.
  • A workspace's first prepare downloads its Nix packages, which takes a while.
  • Tk and Fyne apps have no accessibility tree; the agent sees them as pixels.

Configuration

VariableDefault
HOTLINE_COMPUTER_TOKENunsetThe bearer for /mcp, the viewer and its files. Unset means open
HOTLINE_COMPUTER_ADDR0.0.0.0:8787Where the server listens inside the container
HOTLINE_COMPUTER_SCREEN1920x1080The display's size
HOTLINE_COMPUTER_HOME/home/agentThe directory files is confined to
HOTLINE_COMPUTER_GUTTER16Space around app windows; 0 for edge to edge
TZUTCThe clock in the top bar

For agents

Start every session with state info and state guide, and follow the guide that comes back: it is the one for the release that is actually running.

Prefer browser text and refs for web pages, and capture with a window for native apps. Give every job a label in plain words, because that is what the person watching reads. When a step needs the person, such as a sign-in or a 2FA tap, say so and wait; they can take control from the viewer.

Never ask the person to paste a secret. If a task needs one that state info does not list, ask them to store it.

Notes

Hotline Computer is the desktop each teammate gets in Hotline, released on its own. Hotline starts one container per teammate and gives it the token; everything on this page works without it.

The guides go further: the viewer and its protocol, the desktop, workspaces, secrets, passkeys, every HTTP route, the contract and building from source.