Skip to content

VM Agent Reference

The VM Agent is a Go binary (packages/vm-agent/) that runs on each Hetzner node. It listens on port 8080 and provides HTTP/WebSocket endpoints for terminal sessions, container management, and Claude Code agent sessions.

GET /health

Returns agent health status, version, uptime, and system information.

POST /auth/token

Exchange credentials for a session cookie. Used by the browser after obtaining a workspace JWT from the API.

WebSocket /workspaces/:id/shell

Opens a PTY terminal session inside the workspace container. Supports:

  • Binary and text frames
  • Terminal resize events
  • Ring buffer replay on reconnect (catches up missed output)
WebSocket /workspaces/:id/agent

Opens a Claude Code agent session using the Agent Communication Protocol (ACP). Messages are JSON-encoded with types:

  • session/prompt — send a user prompt
  • session/update — streaming agent output
  • session/complete — agent finished
GET /workspaces/:id/tabs

Returns the list of open tabs (shell and agent sessions) for a workspace. Used to restore tabs on page refresh.

POST /workspaces

Create a new workspace container. Called by the API Worker during workspace provisioning.

DELETE /workspaces/:id

Delete a workspace container and clean up resources.

Manages terminal sessions with:

  • Session multiplexing — multiple terminals per workspace
  • Ring buffer — stores recent output for replay on reconnect
  • Lifecycle management — automatic cleanup on disconnect

Handles Docker operations:

  • devcontainer up — build and start devcontainer from repo config
  • docker exec — execute commands inside containers
  • Git credential injection — injects GitHub tokens for push access
  • Named volume management — persistent storage across container restarts

Implements the Agent Communication Protocol for Claude Code:

  1. Initialize — establish protocol version and capabilities
  2. NewSession — create a session with working directory and MCP servers
  3. Prompt — send user prompts, receive streaming responses

Responses are serialized via orderedPipe to prevent token reordering from concurrent notification dispatch.

Validates workspace JWTs using the API’s JWKS endpoint:

  • Fetches public keys from /.well-known/jwks.json
  • Caches keys with periodic refresh
  • Extracts workspace ID and user ID from claims

Environment variables set by the cloud-init template:

VariableDefaultDescription
NODE_IDUnique node identifier
CONTROL_PLANE_URLAPI Worker URL for callbacks
CALLBACK_TOKENJWT for authenticating callbacks
LOG_LEVELinfoLog level: debug, info, warn, error
LOG_FORMATjsonOutput format: json or text
ACP_NOTIF_SERIALIZE_TIMEOUT5sTimeout for ACP notification serialization
VariableDefaultDescription
LOG_RETRIEVAL_DEFAULT_LIMIT200Default entries per log page
LOG_RETRIEVAL_MAX_LIMIT1000Max entries per log page
LOG_STREAM_BUFFER_SIZE100Catch-up entries on stream connect
LOG_READER_TIMEOUT30sTimeout for journalctl reads
LOG_STREAM_PING_INTERVAL30sWebSocket ping interval
LOG_STREAM_PONG_TIMEOUT90sWebSocket pong deadline
Terminal window
cd packages/vm-agent
# Build all platforms
make build-all
# Build for specific platform
GOOS=linux GOARCH=amd64 go build -o bin/vm-agent-linux-amd64 .

Output binaries:

  • vm-agent-linux-amd64 — production (x86)
  • vm-agent-linux-arm64 — production (ARM)
  • vm-agent-darwin-amd64 — local testing (Intel Mac)
  • vm-agent-darwin-arm64 — local testing (Apple Silicon)