CodeWorlds
Back to collections
Guide15 min readCodeWorlds Team

OpenHands, a coding agent running unattended in a container

OpenHands runs a coding agent in a container, formerly OpenDevin. Version, licence from three sources, confirmation policies, token cost, and cloud pricing.

OpenHands, a coding agent running unattended in a container

OpenHands is an open source coding agent that takes a task description, starts in its own environment, and then writes code, runs shell commands, reads test output, and fixes its own mistakes. The difference against an editor assistant is fundamental: nobody approves the individual steps until you configure that yourself.

How it differs from an editor assistant

An editor assistant works in a rhythm of proposal, human glance, acceptance. You see every file change before it lands on disk and every shell command before it runs. That rhythm costs your attention, but it gives you a stopping point ahead of each irreversible step.

OpenHands moves that stopping point to the very end. You send a task, the agent enters a loop: pick a tool, run it, look at the result, pick the next one. The loop turns until the job is done or a limit is hit, and you watch the event log if you feel like it. The output is often a finished branch with a change set and a description of what was done.

There are two consequences and you need both before the first run. The first concerns safety. An agent that runs commands itself will also run a destructive command if it judges it a step towards the goal. The blunt instruction in the README says as much: starting the agent server without a sandbox gives it full access to the file system of the machine you installed it on. That is not defensive boilerplate, it is a description of the actual state.

The second concerns money. Every turn of the loop is a model call carrying the whole history so far in context. A session running a hundred steps sends the context a hundred times, and the context grows with every file read and every command result. An editor assistant burns tokens too, but at a pace you set, because a human stands between the turns.

There is a third difference, less obvious and often decisive. An agent in a container can be triggered from code, from a schedule, or from a hook in an issue tracker, because it needs no editor window open. For repeatable work such as dependency updates or triaging an issue, that is a different class of tool from Cursor or Cline.

Names, versions, and a licence from three sources

The project changed its name twice, and that is the only reason older guides lead nowhere. It started as OpenDevin, was renamed OpenHands, and the GitHub organisation went from All-Hands-AI to OpenHands. Every old address redirects: github.com/OpenDevin/OpenDevin and github.com/All-Hands-AI/OpenHands both end at github.com/OpenHands/OpenHands, and the all-hands.dev domain lands on openhands.dev. When digging through an archived thread, search under both names.

The repository was created on 13 March 2024 and as of 21 August 2026 holds 84,668 stars, 11,037 forks, and 523 open issues. It is not archived, and the last change on the main branch dates from the same day. The project site states 80.8 thousand stars in its header, a lower figure than the GitHub programming interface reports, and that discrepancy cannot be settled from outside. I give both.

The code is in the middle of moving, and that is a transitional state rather than the destination. The README in the main repository says outright that the agent engine and the agent server now live in OpenHands/software-agent-sdk, and the browser console, named Agent Canvas, in OpenHands/agent-canvas. The console itself carries a beta status badge. That matters when planning a rollout, because documentation and package names have shifted faster than usual over recent months.

The versions look like this. The openhands-ai package in the PyPI registry sits at 1.11.0 from 9 July 2026, requires Python from 3.12 up to and including 3.13, and pulls in among others litellm 1.84.1, docker 7.1.0, and browsergym-core 0.13.3. The release pace this year was steady: 1.3.0 in February, 1.5.0 in March, 1.7.0 in May, 1.9.0 in early July, with five releases in a row between 6 and 9 July. The @openhands/agent-canvas package in the npm registry is at 1.14.0 from 17 August 2026. The SDK family, meaning openhands-sdk, openhands-tools, and openhands-workspace, sits at 1.42.1 from 12 August 2026.

The licence checked against three sources comes out mostly clean, with one exception worth recording in a dependency register. The LICENSE file in the OpenHands/OpenHands repository is plain MIT text with a "Copyright 2025 OpenHands contributors" notice. The PyPI metadata field for openhands-ai reads License-Expression: MIT, and the published source archive contains a LICENSE file. The npm registry reports MIT for @openhands/agent-canvas, and the package carries a package/LICENSE file. Up to that point everything agrees.

The divergence starts at two points. First, the LICENSE file inside the openhands-ai 1.11.0 archive opens with a preamble stating that content in the enterprise/ directory falls under the licence defined in enterprise/LICENSE. That directory exists neither in the archive nor on the repository main branch, and the referenced file returns a 404. The clause is therefore dead, but a licence scanner will see a conditional restriction and flag it for clarification. Second, and more serious, the openhands-sdk, openhands-tools, and openhands-workspace packages at version 1.42.1 carry no license field, no license_expression, and no licence classifier in PyPI, and their source archives contain no licence file at all. The OpenHands/software-agent-sdk repository is meanwhile marked as MIT. If you embed the SDK in a commercial product, the package itself carries no evidence of the terms you received it under.

Running it and the limits of the sandbox

The shortest route goes through the npm registry and runs everything on your machine. It needs Node 22.12 or newer plus the uv tool.

Code
Bash
npm install -g @openhands/agent-canvas
agent-canvas

# splitting the layers when the backend belongs on another machine
agent-canvas --frontend-only
agent-canvas --backend-only

That variant has no sandbox. The agent server runs directly on the host, so the agent sees your whole home directory, SSH keys, .env files, and shell history. For playing with a toy project that is fine, for work on a real repository it is not.

The container variant narrows visibility down to a single directory you nominate.

Code
Bash
export PROJECTS_PATH="$HOME/projects"
mkdir -p "$PROJECTS_PATH" "$HOME/.openhands"

docker run -it --rm \
  -p 8000:8000 \
  -v "$HOME/.openhands:/home/openhands/.openhands" \
  -v "${PROJECTS_PATH}:/projects" \
  ghcr.io/openhands/agent-canvas:1.14.0

The interface sits at http://localhost:8000. The PROJECTS_PATH variable draws the boundary: the agent reaches any project inside that directory and nothing outside it. The .openhands directory holds settings and conversation history, so mounting it preserves state across container restarts.

The boundary is narrower than it looks, though. A container protects the host file system, but it protects neither the network it can reach, nor the secrets you hand it yourself, nor the remote repository you gave it a write-scoped token for. An agent holding a GitHub token can push a branch, open a merge request, and close somebody else's issue, and no container stops that. If what you want is isolation in the sense of a separate short-lived virtual machine, that is a job for E2B rather than a local container.

The third variant is an agent server standing on a separate cloud machine that the console connects to remotely. That arrangement makes sense when agents should work while your laptop is shut, or when tasks fire from hooks in external services.

The SDK and steering the agent loop

A separate route is embedding the agent in your own code. The openhands-sdk package offers three concepts: a model, an agent, and a conversation. The field names below come straight from version 1.42.1.

Code
Python
from pydantic import SecretStr

from openhands.sdk import LLM, Agent, Conversation
from openhands.tools.preset.default import get_default_tools

model = LLM(
    model="anthropic/claude-sonnet-5",
    api_key=SecretStr(api_key_value),
    num_retries=5,
    max_output_tokens=16000,
    caching_prompt=True,
)

agent = Agent(
    llm=model,
    tools=get_default_tools(enable_browser=False),
)

conversation = Conversation(
    agent=agent,
    workspace="/projects/shop",
    persistence_dir="/projects/.state",
    max_iteration_per_run=120,
    stuck_detection=True,
    max_budget_per_run=3.0,
)

conversation.send_message("Fix the failing test in tests/test_cart.py and leave the rest alone.")
conversation.run()
conversation.close()

The model field takes an identifier in the LiteLLM convention, because the call layer rests on LiteLLM and therefore handles aggregators such as OpenRouter. The agent receives a tool list, and the default set is a terminal, a file editor, and a task tracker, optionally with a browser. Turning the browser off shortens the tool description in the prompt and thereby lowers the cost of every turn.

Three conversation fields make sure the loop stops. max_iteration_per_run caps the number of steps and defaults to 500, which on a failing task is a great deal. stuck_detection spots looping, including a repeating action and observation pair, a repeating error, and an agent monologue with no action at all. max_budget_per_run aborts the run once a given dollar amount is exceeded, counting every model used in that run together, including the one summarising history.

There are also work environments other than a local directory. The DockerWorkspace class from the openhands-workspace package starts a container by itself and accepts among others working_dir, server_image, host_port, volumes, forward_env, network, and health_check_timeout. Alongside it stand APIRemoteWorkspace, ApptainerWorkspace, and OpenHandsCloudWorkspace.

Human in the loop, confirmations, and risk

Working with no human in the loop is the default mode, but not the only one. The SDK offers three confirmation policies and a risk scale with four levels.

Code
Python
from openhands.sdk.security import (
    AlwaysConfirm,
    ConfirmRisky,
    NeverConfirm,
    SecurityRisk,
)

# every action waits for human approval
conversation.set_confirmation_policy(AlwaysConfirm())

# approval only for actions rated as risky
conversation.set_confirmation_policy(ConfirmRisky(threshold=SecurityRisk.MEDIUM))

# full autonomy, no stopping points
conversation.set_confirmation_policy(NeverConfirm())

The SecurityRisk enumeration holds UNKNOWN, LOW, MEDIUM, and HIGH, with comparisons involving UNKNOWN raising an exception, since unknown risk cannot be placed on the scale. The ConfirmRisky policy defaults its threshold to HIGH and asks for approval on actions at that level and above.

The risk rating comes from an analyzer, and there are several kinds: LLMSecurityAnalyzer asks a model, PatternSecurityAnalyzer matches patterns, PolicyRailSecurityAnalyzer checks rules, and EnsembleSecurityAnalyzer combines several sources of judgement. In the application layer settings the security_analyzer field takes the value llm or none and defaults to llm, tied to the confirmation mode.

A sensible arrangement for real work looks like this. For tasks on a repository copy, inside a container, with no write-scoped token, NeverConfirm is fine, because the worst outcome is wasted tokens. For tasks touching a remote branch or an environment holding data, ConfirmRisky with a MEDIUM threshold is a reasonable compromise. AlwaysConfirm reduces the tool to an assistant, and at that point Aider in a terminal is usually more comfortable.

Token cost and the cloud variant

A long agent session costs more than intuition suggests, because history grows and every turn sends all of it. Measuring it takes one line off the conversation.

Code
Python
metrics = conversation.conversation_stats.get_combined_metrics()

print(metrics.accumulated_cost)
print(metrics.accumulated_token_usage.prompt_tokens)
print(metrics.accumulated_token_usage.completion_tokens)
print(metrics.accumulated_token_usage.cache_read_tokens)
print(metrics.accumulated_token_usage.reasoning_tokens)

The cache_read_tokens field is the important one here. If it stays at zero with caching_prompt enabled, the prompt cache is not working and you pay full rate for repeated context, which across a hundred turns makes an enormous difference. I covered the provider side caching mechanism at more length alongside the Claude models.

The second brake on cost is summarising history. A condenser swaps an old stretch of conversation for a summary instead of resending it over and over.

Code
Python
from openhands.sdk.context.condenser import LLMSummarizingCondenser

agent = Agent(
    llm=model,
    tools=get_default_tools(enable_browser=False),
    condenser=LLMSummarizingCondenser(
        llm=model,
        max_size=120,
        keep_first=2,
    ),
)

By default max_size is 240 events and keep_first is two, so the first two events stay untouched, since the task description lives in them. Lowering max_size trims the bill but raises the chance the agent forgets a decision made early in the session and starts going in circles.

A cloud variant exists and has a price list, though without a stated figure on the commercial side. The pricing page lists three plans. The local open source plan is free with no cap on daily conversations. The cloud Individual plan is free, supports one user, and limits conversations to ten a day, with the model connected through your own key or through the OpenHands provider billed, as the vendor states, at cost with no markup on a pay as you go basis. The Enterprise plan is custom priced and adds deployment inside your own virtual private cloud, SAML and SSO sign-in, unlimited users and concurrent conversations, priority support, and a shared Slack channel. No Enterprise figure appears anywhere in public material, so I do not quote one.

OpenHands against the alternatives

FeatureOpenHandsClineAiderCursor
Form factoragent server and browser consoleextension, CLI and SDKcommand line toolseparate editor
Client code licenceMITApache 2.0Apache 2.0closed
Inference billingown key or provider at costown key or creditsown keysubscription
Public repositoryOpenHands/OpenHandscline/clineAider-AI/aidernone
GitHub stars84.7k66.6k48.4knot applicable

The choice comes down to one question: does the task need to run while you are not there. If yes, meaning an overnight dependency update, an issue triage pass, or a job fired from a schedule, OpenHands does something the other three either do not do at all or do through a side door. If no, meaning ordinary code writing with every change in view, an editor tool is faster, cheaper, and less risky.

Vendor lock-in risk is low on the model side, since the key is yours and switching providers is a one string change. It is higher on the project side, for a specific reason: the code is moving between repositories right now, the console is in beta, and the whole construction rests on one company and the community around it. For a multi-year rollout, pin exact package versions and expect module names to shift.

Common mistakes

The first is running without a sandbox on your working machine. The npm variant puts the agent server directly on the host, so the agent sees SSH keys and files holding secrets. If you are not doing this in a container, at least do it under a separate system account.

The second is leaving the default step limit. The max_iteration_per_run value is 500, and a failing task can consume that entire budget and deliver nothing. On first runs set a few dozen and raise it afterwards.

The third is having no spending cap. Without max_budget_per_run the only boundary is the step count, and the cost of a step grows with history, so a two hundred step session often costs several times a hundred step one.

The fourth is handing over a write-scoped repository token at the start. The agent will use it as it sees fit. A safer arrangement is a read-only token with you pushing the branch by hand after reviewing the result.

The fifth is copying the image tag out of the README. The documentation there carries a release candidate tag while the npm registry shows a distinctly higher current version. Check the number in the registry before typing it into a command.

The sixth is hunting for documentation under the old name. Material describing OpenDevin or the All-Hands-AI organisation covers the same project, but from before the restructuring, and the package names and directory layout no longer match.

The seventh is treating the SDK as a package with a clear legal status. The openhands-sdk, openhands-tools, and openhands-workspace archives at version 1.42.1 contain no licence file and no licence field in their metadata. During a dependency audit, record where the determination came from, meaning the repository, because the package alone does not tell you.

FAQ

Are OpenHands and OpenDevin the same project?

Yes. OpenDevin was the original name, changed to OpenHands, and the GitHub organisation moved from All-Hands-AI to OpenHands. The old addresses redirect to github.com/OpenHands/OpenHands, and the all-hands.dev domain to openhands.dev.

What licence is OpenHands under?

The main repository and the openhands-ai package are MIT, confirmed in the LICENSE file, in the PyPI metadata, and in the published archive. The SDK packages at 1.42.1 are the exception: they carry no licence field in the registry and no licence file in the archive, although their repository is marked MIT.

What does the cloud variant cost?

The local plan and the cloud Individual plan are free, with Individual limiting conversations to ten a day and supporting one user. You connect a model through your own key or use the OpenHands provider billed, per the vendor's statement, at cost. The Enterprise plan is custom priced and not published.

Can I force human approval of actions?

Yes. The set_confirmation_policy method on the conversation object accepts AlwaysConfirm, NeverConfirm, or ConfirmRisky with a threshold on the SecurityRisk scale, where the available levels are LOW, MEDIUM, and HIGH.

How do I cap the cost of a long session?

With three dials at once: a step limit through max_iteration_per_run, a spending limit through max_budget_per_run, and history summarising through LLMSummarizingCondenser with a lowered max_size. Check the cache_read_tokens field in the metrics as well, because a working prompt cache cuts the bill hardest.

Will OpenHands replace an editor assistant?

Not for daily code writing, where you want to see every change. It replaces one for tasks meant to run without you: dependency updates, preparing a branch with a fix, triaging an issue. Many teams find it worthwhile to keep both tools and use them for different things.

The documentation lives on the OpenHands documentation site, the source code in the GitHub repository, and the plans and limits on the pricing page.

Read next

We use cookies to enhance your experience on the site