LocalRuntime — Browser, Jupyter, VSCode, and served-app tabs in a self-hosted OpenHands 0.44 deployment
Hi all, looking for guidance on getting all four runtime tabs (Browser, Jupyter, VSCode, Served Apps) fully functional
in a self-hosted setup.
Environment
- OpenHands 0.44 (
ghcr.io/all-hands-ai/openhands:0.44)
- Two deployment shapes side by side:
a.
Admin server: vanilla compose, uses DockerRuntime spinning up
ghcr.io/all-hands-ai/runtime:0.44-nikolaik per
conversation. All four tabs work out of the box here.
b.
Per-developer sandbox: container built FROM
ghcr.io/all-hands-ai/openhands:0.44, runs LocalRuntime
(RUNTIME=local, LOCAL_RUNTIME_MODE=1, OPENHANDS_REPO_PATH=/app) so we avoid nested docker. This is the one I have
questions about.
- LiteLLM in front of vLLM serving Qwen3-Coder-30B for the LLM.
Sandbox image extras already installed for LocalRuntime to come up cleanly
# poetry "runtime" group deps OH server image doesn't bundle
RUN /app/.venv/bin/pip install --no-cache-dir \
jupyterlab notebook jupyter_kernel_gateway memory-profiler flake8
# bash sessions
RUN apt-get install -y tmux
# browser plugin
RUN /app/.venv/bin/playwright install --with-deps chromium
# real openvscode-server (98 MB), multi-staged in from the official runtime image
FROM
ghcr.io/all-hands-ai/runtime:0.44-nikolaik AS oh-runtime
# ...
COPY --from=oh-runtime /openhands/.openvscode-server /openhands/.openvscode-server
Without each of these, agent_session start either errors (tmux not on path, No module named memory_profiler,
BrowserType.launch: Executable doesn't exist) or hangs (VSCode plugin's stdout-wait loop, until the wait_all plugin
timeout fires).
What now works in the sandbox
- execute_bash via tmux ✓
- browser plugin: browser_env.py: Successfully called env.reset and Browser env started. in logs ✓
- execute_ipython_cell: jupyter-kernelgateway process spawns, ipykernel_launcher is a child ✓
- str_replace_editor: writes files to /workspace ✓
- VSCode: tab loads in the UI, GET /vscode/connection_token returns 200 (just installed the real binary, untested
end-to-end)
- Served-Apps tab: file_viewer_server starts at localhost:<port> per startup log
Specific questions I'd love help on
1.
Is there a canonical list of dependencies LocalRuntime requires? I peeled them off one stack trace at a time (tmux
→ memory_profiler → playwright → jupyter group → openvscode-server). A reference list would be great for anyone else
building a custom sandbox image off the OH server image.
2.
VSCode plugin under LocalRuntime: is copying /openhands/.openvscode-server/ from the nikolaik image the supported
approach, or is there an official install path? My current Dockerfile uses a multi-stage COPY
--from=
ghcr.io/all-hands-ai/runtime:0.44-nikolaik. Works, but feels brittle.
3.
Jupyter plugin in LocalRuntime mode specifically needs LOCAL_RUNTIME_MODE=1 and OPENHANDS_REPO_PATH=/app env vars
to look in the local .venv instead of nikolaik's /openhands/poetry/... path. Is that documented anywhere, or did I
figure that out by reading the source?
4.
Served-Apps tab discovery: how does the UI know which ports inside the runtime container are "apps the agent has
served"? I see file_viewer_server listening on a random high port; does the UI pick up any listener, or does the agent
need to call a specific tool to register the app?
5.
MCP tools create_pr and create_mr appear in every conversation's tool list unconditionally (loaded from
openhands/server/routes/mcp.py). They fail when no GitHub token is set (LocalProtocolError: Illegal header value
b'Bearer '). What's the supported way to disable them at server-config time without forking? I haven't found a config
flag.
6.
Microagent reload semantics: When I edit a file in the mounted microagents folder, current conversations don't pick
it up. I believe agent_session.start() caches the prompt at init, and only new conversations see edits. Is that
correct? Is there a hot-reload endpoint or pattern others use during microagent development?