Guide

Linux, WSL and Docker

Run the Helmlane agent on any Linux box, on Windows through WSL 2, or in a container — a machine that never sleeps is the cleanest answer to a laptop that does.

Install in one line

In the Helmlane app open Computers → Add computer → Linux, server or container, name the computer, and copy the command it shows. It looks like this:

Terminal
curl -fsSL https://helmlane.com/downloads/install.sh \
  | sh -s -- --token hl_XXXXXXXXXXXXXXXXXXXXXXXXXX --origin https://api.helmlane.com

Paste it into a terminal on the box as your normal user — not root. In about half a minute it:

  1. downloads the Helmlane runtime for your processor (x86-64 or arm64) and verifies its checksum — Node.js is included;
  2. installs it under ~/.local/share/helmlane and the helmlane-agent command under ~/.local/bin;
  3. enrolls the computer with the token and stores its credential;
  4. starts the agent and its sentinel as systemd --user services that start at boot, with lingering so they keep running after you log out;
  5. waits until the agent is online and tells you so.

The token is single-use and expires within fifteen minutes. Its last character is a checksum, so a typo is caught before anything is sent.

Prefer to read before you pipe? Read install.sh, download it, and run sh install.sh --token hl_… --origin https://….sh install.sh --help lists every option.

Share a project folder

The app can only open folders you share from the box itself:

Terminal
helmlane-agent folders add ~/code/my-app
helmlane-agent folders            # list
helmlane-agent folders remove ~/code/my-app

Sharing takes a second — the agent restarts briefly to record it — and the folder then appears when you add a project. Helmlane refuses / and any folder that contains its own private state, such as your whole home directory, because that would let a phone read the computer’s credential. Share the project folders inside it instead. You can also share folders while enrolling: install.sh --token hl_… --folder ~/code/my-app.

Everyday commands

Terminal
helmlane-agent status            # enrolled? online? services? credential store? folders?
helmlane-agent logs -f           # follow the agent's log (also: sentinel, update)
helmlane-agent restart           # restart the agent
helmlane-agent stop | start      # stop or start it
helmlane-agent update            # install the latest release
helmlane-agent help              # everything else

status shows exactly what the app sees: whether the computer is enrolled and connected, how its credential is stored, whether it can sleep, and which folders are shared. The same logs are readable in the app underComputers → this computer → Logs.

Windows (WSL 2)

Helmlane runs on Windows inside WSL 2. Keep your projects in the Linux file system (~/code/…), not under /mnt/c/…, which is much slower for coding agents.

  1. In PowerShell run wsl --install -d Ubuntu, then open Ubuntu.
  2. Turn on systemd once, so the agent can run as a service:
    Terminal
    printf '[boot]\nsystemd=true\n' | sudo tee -a /etc/wsl.conf
    Then run wsl --shutdown in PowerShell and open Ubuntu again.
  3. In the app choose Windows when adding the computer and paste the command into the Ubuntu terminal.

Without systemd everything still works: the installer notices and Helmlane supervises itself (helmlane-agent up starts it,down stops it). Nothing starts it when WSL starts, so add it to your shell profile:

Terminal
echo 'helmlane-agent up >/dev/null 2>&1' >> ~/.profile

Keeping it running. WSL can stop a distribution shortly after its last terminal closes, taking the agent with it. To keep it available, start WSL at Windows sign-in with a scheduled task that runswsl.exe -d Ubuntu --exec sleep infinity (Task Scheduler → Create Task → trigger “At log on”, “Run whether user is logged on or not”). The PC itself can still sleep; the app then shows it as offline.

Docker

The agent image is the cleanest way to run Helmlane on a VPS: nothing to install on the host, a box that never sleeps, and all state in one volume. Choosing container in the app gives you this command with your token:

Terminal
docker run -d --name helmlane-agent --restart unless-stopped \
  -v helmlane-agent:/var/lib/helmlane \
  -v "$PWD":/workspace \
  -e HELMLANE_ORIGIN=https://api.helmlane.com \
  -e HELMLANE_ENROLLMENT_TOKEN=hl_XXXXXXXXXXXXXXXXXXXXXXXXXX \
  ghcr.io/relicdragon/helmlane-agent:latest
  • The container enrolls on first start and shares /workspace.HELMLANE_APPROVE_FOLDERS (colon-separated) changes which folders; set it empty to share none. The token is spent on first start and can be removed afterwards.
  • /var/lib/helmlane holds the enrollment, the encrypted credential, the journal and the logs. Keep the volume, or the container has to be enrolled again.
  • It runs as an unprivileged user (uid 10001); bind-mounted project folders must be writable by that uid.
  • Without a token it waits. Enroll it later without a restart:docker exec -it helmlane-agent helmlane-agent enroll --token hl_…
  • The container reports healthy only while the agent is connected to the server; an unenrolled container is unhealthy on purpose.

Add your coding agents

The image contains the Helmlane agent and git, not the coding agents. Build on it:

Dockerfile
FROM ghcr.io/relicdragon/helmlane-agent:latest
USER root
RUN npm install -g @anthropic-ai/claude-code @openai/codex
USER helmlane

Sign each tool in once (docker exec -it helmlane-agent claude), or later from the app when it asks. Their credentials live in the container user’s home, so mount a volume at /home/helmlane if they should survive a re-created container.

Compose

compose.yaml
services:
  helmlane-agent:
    image: ghcr.io/relicdragon/helmlane-agent:latest
    restart: unless-stopped
    environment:
      HELMLANE_ORIGIN: https://api.helmlane.com
      HELMLANE_ENROLLMENT_TOKEN_FILE: /run/secrets/helmlane_token   # optional
    volumes:
      - helmlane-agent:/var/lib/helmlane
      - ./projects:/workspace
volumes:
  helmlane-agent:

Updating a container means pulling a new image and re-creating it:docker pull ghcr.io/relicdragon/helmlane-agent:latest && docker compose up -d. The app does not offer “Update now” for containers, because the image is what you update.

Devcontainers and Codespaces

Copy the helmlane-agent featureinto .devcontainer/ and reference it:

.devcontainer/devcontainer.json
{
  "features": {
    "./helmlane-agent": {}
  }
}

Rebuild the container, then once, in its terminal:

Terminal
helmlane-agent enroll --token hl_…          # token from the app
helmlane-agent folders add /workspaces/my-repo

The enrollment lives in a named volume, so it survives rebuilds, and the feature starts the agent on every container start. Codespaces stop after a period of inactivity (30 minutes by default, up to 4 hours in your GitHub settings); while stopped, the computer shows as offline.

How it runs

Services

With systemd, the installer writes three user units in ~/.config/systemd/user/:

UnitWhat it does
helmlane-agent.serviceThe agent. Restarts on any exit.
helmlane-sentinel.serviceA small supervisor: restarts an agent that has lost its connection for ten minutes, applies updates and restarts on request from the app.
helmlane-logrotate.timerKeeps each log under 10 MB, with one previous file.

They are user units, not system units: coding tools run as you, with your PATH, git identity and credentials. Lingering (loginctl enable-linger) keeps them running without a login session; the installer enables it and prints the sudo command if it could not. Without systemd — WSL without systemd, containers, devcontainers — Helmlane’s own supervisor does the same job.

Credential storage

The computer’s credential never lives in plain text:

  • Desktop with a keyring (GNOME Keyring, KWallet via the Secret Service): stored in your keyring through secret-tool, locked with it.
  • Server, container, WSL: an encrypted file (AES-256-GCM) under~/.local/share/helmlane/agent/vault/. Where the host has a machine id, the key is bound to it, so a copy restored on another machine does not decrypt. This protects against stray backups, snapshots and other users on the box — not against root on the box.

Power

On a box that can suspend, the app’s keep-awake control holds it awake through systemd-inhibit for the time you pick and releases it on its own. If the system refuses a background sleep lock, the app says so. Servers, VMs and containers report never sleeps and the control is not shown. A Linux laptop that goes to sleep shows as offlinerather than asleep, because the agent cannot announce sleep beforehand on Linux; it reports back within seconds of waking.

Telemetry

Battery, power, disk space, thermal pressure, uptime and load come from the kernel (/sys, /proc). Whatever the machine does not expose — a VPS has no battery — shows as unknown, never as a made-up value.

Updating and removing

Terminal
helmlane-agent update                    # latest release; the app's "Update now" does the same
helmlane-agent update --version 0.3.0    # a specific release

Updates download and verify the new runtime, switch to it and restart the services. The previous runtime is kept in ~/.local/share/helmlane/runtime/for a manual rollback.

Terminal
helmlane-agent uninstall            # remove the services and the runtime; keep the enrollment
helmlane-agent uninstall --purge    # also erase the enrollment, credential, folders and logs

Then remove the computer under Computers in the app. If the command is already gone, the installer can clean up:curl -fsSL …/install.sh | sh -s -- --uninstall --purge.

Troubleshooting

You seeWhat to do
status says it cannot reach the serverCheck the network and the origin you enrolled with (status shows it). Firewalls must allow outbound HTTPS.
systemd --user is not available after su or sudo -uLog in as the user directly (SSH), or run sudo loginctl enable-linger USER and export XDG_RUNTIME_DIR=/run/user/$(id -u).
The agent stops when you log outLingering is off: sudo loginctl enable-linger $USER.
“That token has a typo”Retype it from the app; nothing was sent.
“That token expired”Tokens last up to fifteen minutes. Create a new one in the app.
The credential store did not accept the credentialOn a desktop, unlock your keyring and retry. On a server, check that ~/.local/share/helmlane/agent/vault is writable.
“This agent directory was created on a different machine identity”The state directory was copied from another OS or user. Run the agent as the original user, or set HELMLANE_ACCEPT_PLATFORM_REBIND=1 once to drop the old folder approvals and share them again.
An agent shows as unavailable in the appInstall and sign in to that tool as the same user the agent runs as, then helmlane-agent restart.
Anything elsehelmlane-agent logs -n 300 and helmlane-agent status --json.

Reference

Files

PathContents
~/.local/share/helmlane/runtime/<version>/, currentThe runtime, Node.js included
~/.local/bin/helmlane-agentThe command
~/.local/share/helmlane/agent/Enrollment journal and encrypted credential (private, 0700)
~/.local/state/helmlane/logs/agent, sentinel, supervise and update logs
~/.config/systemd/user/helmlane-*The services

All of them honour XDG_DATA_HOME, XDG_STATE_HOME and XDG_CONFIG_HOME.

Environment variables

VariableMeaning
HELMLANE_ORIGINServer to enroll with (default https://api.helmlane.com)
HELMLANE_ENROLLMENT_TOKEN, …_FILEToken for unattended enrollment (installer, container)
HELMLANE_APPROVE_FOLDERSColon-separated folders to share when enrolling (container default /workspace)
HELMLANE_AGENT_DIRECTORYState directory
HELMLANE_LOG_DIRECTORYLog directory
HELMLANE_AGENT_HEALTH_PORTLoopback health port (default 4793)
HELMLANE_VAULT_BACKEND=file_encryptedSkip the keyring even when one is available
HELMLANE_VERSION, HELMLANE_BUNDLEInstaller: a specific release, or a local bundle file

Building from source is described in therepository’s Linux notes.