mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-06 12:03:07 +08:00
979e64fe19
* feat: add Docker CI to build all-in-one image with agent-server + automation + frontend
Adds a GitHub Actions workflow (.github/workflows/docker.yml) that builds and
publishes ghcr.io/openhands/agent-canvas — a single Docker image combining:
1. Agent Server (ghcr.io/openhands/agent-server base image from SDK repo)
2. Automation server (pip-installed from openhands-automation)
3. agent-canvas frontend (static build from this repo)
The automation server is pip-installed rather than copied from its Docker image
because both services share openhands-sdk, fastapi, uvicorn, pydantic, httpx
etc. — installing into the agent-server's Python 3.13 deduplicates all shared
packages. Only automation-specific deps (asyncpg, sqlalchemy, boto3, …) are
added on top.
An entrypoint script starts all three services and a static-server proxy that
unifies them behind a single port (default 8000):
/api/automation/* → automation backend (:18001)
/api/* → agent-server (:18000)
/* → static frontend + SPA fallback
Workflow triggers:
- Push to main: builds and pushes with branch + SHA tags
- v* tags (releases): also pushes semver tags (1.2.3, 1.2, 1, latest)
- PRs: builds, pushes SHA-tagged image, updates PR description with
pull/run instructions (same pattern as the SDK repo)
- workflow_dispatch: supports overriding base image and automation version
Files added:
- docker/Dockerfile (multi-stage: frontend build + agent-server base)
- docker/entrypoint.sh (process manager for all three services)
- .dockerignore
- .github/workflows/docker.yml
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: build multi-arch Docker images (amd64 + arm64)
Adds QEMU setup for cross-compilation and defaults the platform matrix
to linux/amd64,linux/arm64 so the image works on both Intel and Apple
Silicon machines.
Co-authored-by: openhands <openhands@all-hands.dev>
* refactor: rewrite Docker workflow to match SDK repo structure
Replace the single-job QEMU approach with the same architecture-matrix
pattern used by the SDK repo's server.yml:
1. build-and-push-image — matrix over {amd64, arm64} with native runners
(ubuntu-24.04 for amd64, ubuntu-24.04-arm for arm64). Each job pushes
arch-suffixed tags (e.g. sha-abc1234-amd64) and uploads build-info
artifacts.
2. merge-manifests — downloads both arch build-infos, strips the -amd64
suffix from amd64 tags to derive manifest tags, and creates multi-arch
manifests via `docker buildx imagetools create`.
3. consolidate-build-info — aggregates all build-info and manifest-info
artifacts into a single JSON summary (PR-only).
4. update-pr-description — renders the summary into the PR body between
AGENT_CANVAS_DOCKER_START/END markers.
Native runners avoid the 3-5× slowdown of QEMU emulation for arm64
builds.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: sanitize branch names in Docker tags (/ is not allowed)
Branch names like 'feat/docker-ci' produce invalid Docker tags because
'/' is forbidden in tag names. Replace '/' with '-' so the tag becomes
'feat-docker-ci-amd64'.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: default automation to SQLite and fix wait blocking proxy startup
Two bugs:
1. The automation server defaults to PostgreSQL on localhost, which
doesn't exist in the all-in-one container. Default AUTOMATION_DB_URL
to sqlite+aiosqlite:// so it works out of the box. Users can override
with a real Postgres URL for production.
2. The bare 'wait' command waited for ALL background children — including
the long-running agent-server and automation processes — so the
static-server/proxy on port 8000 never started. Fix by waiting only
for the wait_for_port subshell PIDs.
Verified locally: all three services start, endpoints respond correctly,
no more scheduler ConnectionRefusedError.
Co-authored-by: openhands <openhands@all-hands.dev>
* feat: add VOLUME directives for persistence and project mounts
Declare /home/openhands/.openhands (settings, secrets, conversations,
automation SQLite DB) and /projects (user code) as Docker volumes so
data survives container restarts by default. Users should bind-mount
these for durable persistence:
docker run -v ~/.openhands:/home/openhands/.openhands \
-v ~/projects:/projects \
-p 8000:8000 ghcr.io/openhands/agent-canvas
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: set OH_SECRET_KEY default and pre-create persistence dirs
Three issues fixed:
1. OH_SECRET_KEY was not set → agent-server refused to return encrypted
secrets → conversation creation failed with 503. Set the same static
default used by dev-safe.mjs / dev-docker.mjs.
2. Persistence dirs (conversations, bash_events, automation DB) were not
pre-created → the openhands user got PermissionError when the VOLUME
directive created them as root. Pre-create with correct ownership
before the USER switch in the Dockerfile.
3. Set OH_PERSISTENCE_DIR, OH_CONVERSATIONS_PATH, OH_BASH_EVENTS_DIR
defaults in the entrypoint (matching dev-docker.mjs) so data lands
under the well-known ~/.openhands tree.
Verified locally: all three services start clean, no warnings about
OH_SECRET_KEY, SQLite migrations apply successfully.
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: merge main and remove stale dev-docker.mjs references
Main removed scripts/dev-docker.mjs (Docker is no longer a dependency of
the npm package flow). Update comments in docker.yml, entrypoint.sh, and
AGENTS.md that referenced the deleted file.
Co-authored-by: openhands <openhands@all-hands.dev>
* feat: centralize config into config/defaults.json (single source of truth)
All version pins, port defaults, persistence paths, package names, and
the dev secret key now live in config/defaults.json. Consumers read from
it instead of hardcoding values:
- scripts/dev-safe.mjs: reads via JSON.parse(readFileSync(...))
- scripts/dev-with-automation.mjs: same
- scripts/check-sdk-version-sync.mjs: same (no longer regex-parses JS)
- docker/Dockerfile: config-gen build stage converts JSON to
/opt/agent-canvas/defaults.env (shell-sourceable)
- docker/entrypoint.sh: sources defaults.env at startup; also adds
session API key auto-generation so the image doesn't run wide-open
- .github/workflows/docker.yml: reads versions from JSON in a setup
step (no more hardcoded env vars)
To bump a version, edit config/defaults.json only.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: address PR review feedback (#634)
- Fix PID tracking bug: move PIDS+=($!) inside if/elif branches so the
else (automation-not-found) path doesn't add a stale PID
- chmod 600 session API key file to prevent credential leak
- Warn when using insecure default OH_SECRET_KEY in Docker entrypoint
- Add try/catch + field validation for config/defaults.json loading in
check-sdk-version-sync.mjs
- Fix semver tag parsing: strip pre-release/build metadata, only create
abbreviated tags (major.minor, major, latest) for stable releases
- Sanitize branch names for Docker tags (tr invalid chars, strip leading
dot/dash) to handle branches with #, @, spaces, etc.
- Add arch validation before manifest merge (assert both amd64.json and
arm64.json exist)
- Remove $schema reference to non-existent defaults.schema.json
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: remove hardcoded version defaults from Dockerfile
Replace hardcoded ARG defaults (AGENT_SERVER_IMAGE, AUTOMATION_VERSION)
with empty ARGs. Values are always derived from config/defaults.json:
- CI: reads JSON in the workflow config step, passes --build-arg
- Local: new scripts/docker-build.mjs helper reads JSON and invokes
docker build with the correct --build-arg values
Added npm run build:docker convenience script.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: stabilize snapshot tests and auto-generate Docker secret key
Two fixes:
1. **Flaky snapshot tests**: The 'Local pagination fixture' mock conversation
used a fixed absolute timestamp (PAGINATION_BASE_TIME = May 13, 2026) for
its created_at/updated_at, while 'Errored Project' used a relative
timestamp (now - 7d). As real time progressed past the crossover point,
their sort order in the sidebar flipped, causing 30/73 snapshot diffs on
every PR. Fix: use relative timestamps (now - 6d) for the pagination
fixture's conversation listing fields. The internal event timestamps
(used by pagination tests) still use PAGINATION_BASE_TIME — only the
sidebar ordering is affected.
2. **Docker OH_SECRET_KEY**: The entrypoint used a static insecure default
for OH_SECRET_KEY and warned about it. Now mirrors the session API key
pattern: auto-generate a cryptographic random key on first run, persist
it to ~/.openhands/agent-canvas/secret-key.txt, and reuse on restart.
Users can still override via the OH_SECRET_KEY env var. Removed the
now-unused CONFIG_SECRET_KEY from the Docker defaults.env generation.
Also deduped STATE_DIR computation (was repeated for session key path).
Co-authored-by: openhands <openhands@all-hands.dev>
* docs: update AGENTS.md with mock timestamp and Docker secret key notes
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: include canvas_ui tool in Docker image
The Docker image was missing the tools/ directory and OH_EXTRA_PYTHON_PATH,
so the agent-server couldn't import canvas_ui_tool.py when the frontend
sent canvas_ui in the conversation tools list. This caused:
HTTP 500: ToolDefinition 'canvas_ui' is not registered
Fix: COPY tools/ into the image and set OH_EXTRA_PYTHON_PATH in the
entrypoint, matching what scripts/dev-safe.mjs already does for local dev.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
40 lines
359 B
Plaintext
40 lines
359 B
Plaintext
# Dependencies
|
|
node_modules/
|
|
|
|
# Build outputs (rebuilt in Docker)
|
|
build/
|
|
dist/
|
|
|
|
# Development files
|
|
.git/
|
|
.github/
|
|
.openhands/
|
|
.agents/
|
|
.pr/
|
|
|
|
# Test files
|
|
__tests__/
|
|
tests/
|
|
__mocks__/
|
|
test-results/
|
|
playwright-report*/
|
|
coverage/
|
|
|
|
# IDE / OS
|
|
.vscode/
|
|
.idea/
|
|
*.swp
|
|
*.swo
|
|
.DS_Store
|
|
Thumbs.db
|
|
|
|
# Environment
|
|
.env
|
|
.env.*
|
|
!.env.sample
|
|
|
|
# Misc
|
|
artifacts/
|
|
*.tgz
|
|
*.log
|