Running OpenHands Agent Canvas with Podman (and Claude Code)
OpenHands is a self-hosted control panel for running coding agents against your own repos. Most guides assume Docker, so here’s what it takes to run it under Podman instead.
The project has changed shape recently #
If you find an older guide referencing a command like this, it’s out of date:
podman run -it --rm \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.43-nikolaik \
... \
docker.all-hands.dev/all-hands-ai/openhands:0.43
That’s the pre-rewrite architecture. Two things changed:
- The GitHub org renamed from
All-Hands-AItoOpenHandsin October 2025, moving image paths fromdocker.all-hands.dev/ghcr.io/all-hands-ai/...toghcr.io/openhands/.... - OpenHands 1.0 was a re-architecture, not a version bump. The old pattern — a main
openhandscontainer spinning up a separateruntime:*-nikolaiksandbox container per conversation — is gone. The current product is Agent Canvas: a single container, no separate sandbox image, noSANDBOX_RUNTIME_CONTAINER_IMAGEenv var.
The Podman setup #
Agent Canvas mounts two things: a folder for its own settings/state, and a folder containing the repos you want to work on.
Fish #
# openhands-create.fish
# Run this ONCE to create the named container. After that, use
# `podman start openhands-agent-canvas` / `podman stop openhands-agent-canvas`.
set -x AGENT_CANVAS_IMAGE ghcr.io/openhands/agent-canvas:latest
set -x PROJECTS_PATH ~/code
mkdir -p $PROJECTS_PATH ~/.openhands
set FLAGS \
-p 8000:8000 \
-v ~/.openhands:/home/openhands/.openhands:Z \
-v "$PROJECTS_PATH:/projects:Z" \
--security-opt label=disable \
--userns=keep-id \
--name openhands-agent-canvas \
--restart unless-stopped
podman pull "$AGENT_CANVAS_IMAGE"
podman create $FLAGS "$AGENT_CANVAS_IMAGE"
Bash #
#!/usr/bin/env bash
# openhands-create.sh
# Run this ONCE to create the named container. After that, use
# `podman start openhands-agent-canvas` / `podman stop openhands-agent-canvas`.
export AGENT_CANVAS_IMAGE=ghcr.io/openhands/agent-canvas:latest
export PROJECTS_PATH=~/code
mkdir -p "$PROJECTS_PATH" ~/.openhands
FLAGS=(
-p 8000:8000
-v ~/.openhands:/home/openhands/.openhands:Z
-v "$PROJECTS_PATH:/projects:Z"
--security-opt label=disable
--userns=keep-id
--name openhands-agent-canvas
--restart unless-stopped
)
podman pull "$AGENT_CANVAS_IMAGE"
podman create "${FLAGS[@]}" "$AGENT_CANVAS_IMAGE"
Either way, day to day it’s the same regardless of shell:
podman start openhands-agent-canvas
podman stop openhands-agent-canvas
podman logs -f openhands-agent-canvas
A few details worth calling out:
podman create, notpodman run --rm. Without--rm, and usingcreateinstead ofrun, the container persists between sessions rather than being thrown away on exit.--userns=keep-idavoids rootless permission errors. Rootless Podman maps container users to unprivileged host UIDs by default, which can leave mounted folders like~/.openhandslooking like they belong to someone else from inside the container. This flag keeps the container’s user matched to yours, so the mounted folders stay writable.:Zon the volume mounts relabels them for SELinux. Harmless if you’re not on an SELinux-enforcing distro; necessary if you are.Point
PROJECTS_PATHat wherever your repos actually live. The container-side path (/projects) is just an internal convention and doesn’t need to match your host folder name.
Wiring up Claude Code as the agent #
Agent Canvas doesn’t call an LLM directly — it talks to coding agents through the Agent Client Protocol (ACP). That means you can point it at Claude Code, Codex, or Gemini CLI instead of the built-in agent, and it’ll use whatever authentication that tool already has — including an existing subscription, rather than a separate API key.
For Claude Code specifically, the Agent Canvas settings page (Settings → Agent → Edit agent profile) has a CLAUDE_CODE_OAUTH_TOKEN field with a note: “Subscription OAuth token for Claude Pro/Max. Run claude setup-token in your terminal to get it.”
On a machine where Claude Code is already installed and logged into your subscription:
claude setup-token
Paste the resulting token into that field in Agent Canvas. This uses your existing Claude Pro/Max subscription for the agent’s inference cost rather than metering separately against an API key — worth knowing if you’re already paying for a plan.