The open-source, self-hosted AI software engineer: Docker and CLI quickstarts, LLM config, the skills/microagents system, and a safety guide for autonomous coding in a sandbox.
Docker quickstart — the standard way to run it
This single container is both the web UI and the orchestrator; it spins up a separate sandbox container per session to actually execute the agent's commands, which is why it needs the Docker socket mounted.
Open http://localhost:3000, pick an LLM provider and paste an API key, then open or clone a repo from the UI.
CLI quickstart — no Docker, runs in your terminal
The CLI installs via uv (the fast Python package manager) and talks to the same agent-server underneath, but without the web UI — good for scripting, CI, or working entirely in a terminal.
System requirements
A modern processor with at least 4 GB RAM. Docker Desktop on macOS/Windows, Docker Engine on Linux, or WSL2 + Docker Desktop on Windows.
Getting an LLM API key
Any provider works. Anthropic (Claude) and OpenAI keys are the most common; OpenHands also has its own hosted credits if you'd rather not manage a separate provider account. A local model via Ollama or LM Studio works too, just point the base URL at it.
The sandbox container
A separate, disposable container per session where the agent actually executes code — never your host shell directly. This is the entire safety boundary; see the Safety tab.
PROJECTS_PATH
The one host directory mounted into the agent's reach. Nothing outside it is visible to the sandbox, which is why scoping it matters more than any other setting.
Confirmation modes
Default asks before every action; --always-approve runs unattended; --llm-approve has a second, cheaper model gate risky actions. Covered in the CLI tab.
Skills / microagents
Markdown files that teach the agent repo-specific context, loaded automatically or triggered by keyword. Covered in its own tab.
| Command | What it does |
|---|---|
openhands | Interactive default mode — asks for confirmation before every action the agent takes. |
openhands -t "task description" | Start immediately with a task instead of typing it into the prompt. |
openhands -f requirements.txt | Read the task description from a file — useful for a long spec or a task generated by another tool. |
openhands --always-approve | Never pause for confirmation. Fast, but the agent can run any command in the sandbox unattended — scope PROJECTS_PATH tightly first (Safety tab). |
openhands --llm-approve | A second, usually cheaper LLM call reviews each action for risk before it runs — a middle ground between manual approval and full autonomy. |
openhands --resume | Lists previous conversations to pick up where you left off. |
openhands --resume --last | Resumes the most recent conversation with no picker. |
openhands --resume abc123def456 | Resumes a specific conversation by its ID. |
openhands --gpu --mount-cwd | Passes a GPU through to the sandbox and mounts the current working directory — for local-model inference or GPU-dependent build steps. |
uv tool upgrade openhands --python 3.12 | Updates the CLI to the latest release. Run this before filing a bug — many "broken" reports turn out to be an old build. |
| Key | Function |
|---|---|
Ctrl+P | Opens the command palette — settings, MCP server status, and other in-session controls. |
Esc | Pauses the agent mid-task. Useful the moment you see it heading somewhere you didn't intend. |
Ctrl+Q / /exit | Exits the CLI cleanly. |
| Variable / setting | Example | Notes |
|---|---|---|
| LLM_MODEL | -e LLM_MODEL=claude-sonnet-5-20260929 | The model string your provider expects. Set from the UI's Settings panel on first launch, or as an env var for headless/CI use. |
| LLM_API_KEY | -e LLM_API_KEY=sk-… | Your provider's API key. Never bake this into a committed Dockerfile or script — pass it at runtime. |
| SANDBOX_VOLUMES | -e SANDBOX_VOLUMES=/Users/tyler/acme:/workspace:rw | Replaces the older, now-deprecated WORKSPACE_* path options. Format is host_path:container_path[:mode]; comma-separate multiple mounts. This is the actual boundary of what the agent can touch — see the Safety tab. |
| SANDBOX_RUNTIME_CONTAINER_IMAGE | -e SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.38-nikolaik | The image used for the per-session sandbox container — separate from the main app image. Pin a version if you need reproducible sandbox behavior across runs. |
| LOG_ALL_EVENTS | -e LOG_ALL_EVENTS=true | Verbose event logging — the first thing to enable when a run behaves unexpectedly and you need to see every step the agent took. |
| AGENT_SERVER_IMAGE_TAG | -e AGENT_SERVER_IMAGE_TAG=1.26.0-python | Pins the agent-server image version independently of the main app tag — useful when a release note calls out a specific server fix. |
| Tavily API key (web search) | Settings → LLM tab → Search API Key | Optional. Without it the agent can't search the web for up-to-date library docs or error messages — worth adding for anything touching a fast-moving dependency. |
| --add-host host.docker.internal:host-gateway | docker run … --add-host host.docker.internal:host-gateway | Lets the container reach services running on your host machine (a local dev server, a database) by that hostname. |
| ~/.openhands mount | -v ~/.openhands:/.openhands | Persists settings, conversation history, and credentials across container restarts — without it, every docker run starts from a blank slate. |
--always-approve running unattended.
Where they live
repo.md — loaded on every task
The main agent reads this automatically at the start of a session. Put here anything that's true for every task in the repo: how to run tests, the build command, coding conventions, which directories are generated and shouldn't be hand-edited.
Triggered skills — loaded only when relevant
A skill other than repo.md can declare trigger keywords in its frontmatter; the agent only loads it when those words show up in the conversation. This keeps narrow domain knowledge (a specific migration tool, a legacy subsystem) out of every prompt's context until it's actually needed.
- Running the agent-server directly (no Docker sandbox) gives it full filesystem access on your machine. That's an explicit, documented mode for advanced use — not the default, and not what you want for a first run.
- The Docker-sandboxed path restricts the agent to
SANDBOX_VOLUMES/PROJECTS_PATHand nothing else — scope that mount to exactly the project you're working on, not your entire home directory. - Never point it at a repo with production credentials in plaintext (a checked-in
.env, cloud CLI credentials cached in the mounted path) — the agent can read anything inside the mount and may include it in tool calls sent to the LLM provider. - Treat
--always-approveas a deliberate choice, not a default habit. Confirmation mode exists specifically to catch a plan going sideways before it runs a destructive command. - Give it a scratch branch, not
main. Autonomous multi-step edits are exactly the case where an easy revert matters most. - The Docker socket mount (
/var/run/docker.sock) is powerful. It lets the main container spin up sandbox containers, but it also means that container effectively has Docker-level access to the host — standard for this architecture, still worth knowing rather than assuming it's fully contained.
| Symptom | Likely cause / fix |
|---|---|
| "Cannot connect to the Docker daemon" | Docker Desktop (or Engine) isn't running, or the socket path differs on your OS/setup — confirm docker ps works outside OpenHands first. |
| Agent can't see files you expect it to | SANDBOX_VOLUMES doesn't include that path. It only sees what's explicitly mounted — this is a feature, not a bug, see the Safety notes above. |
| Agent stalls or loops on the same failing step | Pause with Esc, add a note to repo.md about the specific gotcha it's hitting, and resume — this is exactly what the skills system is for. |
| Old/unexpected behavior after an update | Run with --pull=always on the Docker command, or uv tool upgrade openhands for the CLI, before assuming it's a real bug. |
| Confusing "OpenHands" search results | The org renamed and also ships Agent Canvas, a separate broader product. If a result mentions Slack/Linear automations or "agent-canvas," it's describing that product, not the coding agent this page covers. |
Official docs & further reading
OpenHands moves fast and the org renamed mid-2026 — when this page and the docs disagree, the docs win.