From 274ab318a567612aa7a44535572b1c45b6c09e2a Mon Sep 17 00:00:00 2001
From: enyst <6080905+enyst@users.noreply.github.com>
Date: Mon, 14 Sep 2026 03:10:16 +0000
Subject: [PATCH] docs: sync llms context files
---
llms-full.txt | 5753 ++++++++++++++++++++++++++++++++++++++++++++++---
llms.txt | 37 +-
2 files changed, 5505 insertions(+), 285 deletions(-)
diff --git a/llms-full.txt b/llms-full.txt
index 32c7d659..03396b24 100644
--- a/llms-full.txt
+++ b/llms-full.txt
@@ -37,7 +37,7 @@ Get started with some examples or keep reading to learn more.
icon="plug"
href="/sdk/guides/agent-server/openai-gateway"
>
- Access the OpenHands agent via an OpenAI-compatible endpoint for chat UIs, IDEs, voice platforms, and other OpenAI-style clients.
+ Access the OpenHands agent via OpenAI-compatible Chat Completions and Responses endpoints for chat UIs, IDEs, voice platforms, and other OpenAI-style clients.
@@ -6311,7 +6311,7 @@ For full list of implemented workspaces, see the [source code](https://github.co
**Features:**
- REST API & WebSocket endpoints for conversations, bash, files, events, desktop, and VSCode
-- [OpenAI-compatible `/v1/chat/completions` endpoint](/sdk/guides/agent-server/openai-gateway) for clients that expect an OpenAI-style backend
+- [OpenAI-compatible `/v1/chat/completions` and `/v1/responses` endpoints](/sdk/guides/agent-server/openai-gateway) for clients that expect an OpenAI-style backend
- Service management with isolated per-user sessions
- API key authentication and health checking
@@ -9216,6 +9216,185 @@ On the agent-server side, the ACP-capable REST surface lives under `/api/acp/con
- **[TaskToolSet](/sdk/guides/task-tool-set)** — Compose multiple agents for complex workflows
- **[LLM Metrics](/sdk/guides/metrics)** — Track token usage and costs across models
+### Ask Oracle
+Source: https://docs.openhands.dev/sdk/guides/agent-ask-oracle.md
+
+import RunExampleCode from "/sdk/shared-snippets/how-to-run-example.mdx";
+
+> A ready-to-run example is available [here](#ready-to-run-example)!
+
+Use `ask_oracle` when an agent should consult a stronger or more specialized
+model for a second opinion without switching its active model.
+
+## When to Use It
+
+`ask_oracle` is useful when an agent is:
+
+- Stuck or uncertain about its next step
+- Comparing implementation approaches
+- Reviewing a risky or difficult decision
+- Asked by the user to get a second opinion
+
+## How It Works
+
+When the agent calls `ask_oracle`:
+
+1. The tool loads the saved LLM profile named `oracle`.
+2. The Oracle receives a dedicated system prompt and a user message containing
+ the agent's question and optional context.
+3. The Oracle returns a text recommendation to the original agent.
+4. The original agent continues the conversation with its existing model.
+
+The Oracle does not receive the conversation history or any tools. It cannot
+modify the workspace directly. Its token usage and cost are included in the
+conversation's combined metrics.
+
+
+ The tool does not fall back to the agent's active model. If the `oracle`
+ profile is missing or cannot be loaded, the tool returns an error observation
+ telling the agent that the Oracle is unavailable.
+
+
+## Configure the Oracle Profile
+
+The tool resolves its model by convention from a saved LLM profile named
+`oracle`. There is no dedicated agent setting for selecting another profile.
+
+To enable it:
+
+1. Save a usable LLM configuration under the name `oracle`. See
+ [LLM Profile Store](/sdk/guides/llm-profile-store).
+2. Add `AskOracleTool` to the agent's tools:
+
+```python icon="python" wrap focus={2, 5}
+from openhands.sdk import Agent, Tool
+from openhands.tools.ask_oracle import AskOracleTool
+
+agent = Agent(
+ llm=primary_llm,
+ tools=[Tool(name=AskOracleTool.name)],
+)
+```
+
+By default, `LocalConversation` reads profiles from
+`~/.openhands/profiles`. If you use a custom profile directory, pass the same
+directory to both `LLMProfileStore` and `LocalConversation` through
+`profile_store_dir`.
+
+
+ Do not place literal API keys in source code. The ready-to-run example reads
+ its key from the environment and stores the Oracle profile in a temporary
+ directory, which is removed after the example exits. Follow the
+ [LLM Profile Store](/sdk/guides/llm-profile-store) guidance when creating a
+ persistent profile.
+
+
+## Ask Oracle vs. Switch LLM
+
+`ask_oracle` makes one stateless call to another model and then returns control
+to the original agent. It never changes the active conversation model.
+
+Use `switch_profile()` or the `switch_llm` tool instead when subsequent agent
+turns should run on a different saved profile. See
+[LLM Profile Store](/sdk/guides/llm-profile-store#mid-conversation-model-switching).
+
+## Ready-to-run Example
+
+
+This example is available on GitHub: [examples/01_standalone_sdk/58_ask_oracle_tool/main.py](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/58_ask_oracle_tool/main.py)
+
+
+```python icon="python" expandable examples/01_standalone_sdk/58_ask_oracle_tool/main.py
+"""Consult the Oracle end-to-end with the ask_oracle tool.
+
+The Oracle is a saved LLM profile resolved by convention under the name
+``oracle``. This example wires two profiles — the agent's primary model and a
+separate ``oracle`` model — adds ``Tool(name="ask_oracle")`` to the agent, then
+drives a normal conversation: the agent decides to call ``ask_oracle``, the tool
+consults the ``oracle`` profile, and the agent uses the Oracle's answer to reply.
+
+Usage:
+ LLM_API_KEY=... LLM_BASE_URL=https://llm-proxy.app.all-hands.dev \
+ uv run python examples/01_standalone_sdk/58_ask_oracle_tool/main.py
+
+Note:
+ The example saves the ``oracle`` profile in a temporary directory so it
+ does not modify the user's default profile store.
+"""
+
+import os
+import tempfile
+
+from pydantic import SecretStr
+
+from openhands.sdk import LLM, Agent, LocalConversation, Tool
+from openhands.sdk.llm.llm_profile_store import LLMProfileStore
+from openhands.tools.ask_oracle import ORACLE_PROFILE_NAME, AskOracleTool
+
+
+DEFAULT_BASE_URL = "https://llm-proxy.app.all-hands.dev"
+# The agent's primary model (follows the standard LLM_MODEL env like other
+# examples). The Oracle defaults to the same model; override ASK_ORACLE_MODEL to
+# point the "oracle" profile at a different/stronger model.
+PRIMARY_MODEL = os.getenv("ASK_ORACLE_PRIMARY_MODEL") or os.getenv(
+ "LLM_MODEL", "openai/gpt-5.5"
+)
+ORACLE_MODEL = os.getenv("ASK_ORACLE_MODEL", PRIMARY_MODEL)
+
+api_key = os.getenv("LLM_API_KEY")
+assert api_key is not None, "LLM_API_KEY environment variable is not set."
+base_url = os.getenv("LLM_BASE_URL", DEFAULT_BASE_URL)
+
+with tempfile.TemporaryDirectory() as profile_store_dir:
+ store = LLMProfileStore(profile_store_dir)
+ store.save(
+ ORACLE_PROFILE_NAME,
+ LLM(
+ model=ORACLE_MODEL,
+ api_key=SecretStr(api_key),
+ base_url=base_url,
+ usage_id="oracle",
+ ),
+ include_secrets=True,
+ )
+
+ primary_llm = LLM(
+ model=PRIMARY_MODEL,
+ api_key=SecretStr(api_key),
+ base_url=base_url,
+ usage_id="primary",
+ )
+ agent = Agent(llm=primary_llm, tools=[Tool(name=AskOracleTool.name)])
+ conversation = LocalConversation(
+ agent=agent,
+ workspace=os.getcwd(),
+ profile_store_dir=profile_store_dir,
+ )
+
+ print(f"Primary model: {conversation.agent.llm.model}")
+ print(f"Oracle model: {ORACLE_MODEL}")
+ conversation.send_message(
+ "Call the oracle to ask it for its opinion on the weather today, "
+ "then just tell me in two words how it's like."
+ )
+ conversation.run()
+
+ cost = conversation.conversation_stats.get_combined_metrics().accumulated_cost
+ print(f"Total cost: ${cost:.6f}")
+ print(f"EXAMPLE_COST: {cost}")
+```
+
+
+
+## Next Steps
+
+- **[LLM Profile Store](/sdk/guides/llm-profile-store)** - Create and manage
+ reusable LLM configurations
+- **[LLM Metrics](/sdk/guides/metrics)** - Track usage and cost across the
+ primary and Oracle models
+- **[Custom Tools](/sdk/guides/custom-tools)** - Build tools with custom
+ behavior
+
### Browser Use
Source: https://docs.openhands.dev/sdk/guides/agent-browser-use.md
@@ -12628,10 +12807,24 @@ Source: https://docs.openhands.dev/sdk/guides/agent-server/openai-gateway.md
import RunExampleCode from "/sdk/shared-snippets/how-to-run-example.mdx";
-The agent-server exposes an OpenAI-compatible `/v1/chat/completions` endpoint so clients that already speak the OpenAI protocol can call an OpenHands agent.
+The agent-server exposes an OpenAI-compatible API surface under `/v1` with two endpoints:
+
+- `POST /v1/chat/completions` — the OpenAI Chat Completions protocol.
+- `POST /v1/responses` — the OpenAI Responses protocol.
Use this when you want an existing chat UI, IDE integration, evaluation harness, voice platform, or another agent to treat OpenHands as an OpenAI-style backend while still getting the full agent runtime behind the request.
+## How It Works
+
+Both endpoints are protocol adapters over the **same full OpenHands agent**, not a thin wrapper around a raw LLM call. Each request:
+
+1. Loads the OpenHands agent configured by the named profile.
+2. Starts (or, for Chat Completions, optionally reuses) an OpenHands conversation.
+3. Runs the agent's complete internal tool loop to completion.
+4. Returns only the final assistant text as an OpenAI-shaped response.
+
+The mental model is **"access an agent conversation as if it were a model"**: you send a prompt, the agent does its work (including executing tools in its workspace), and you receive one response when it finishes. Internal tool activity is not exposed as OpenAI tool calls.
+
## What to Configure
Most OpenAI-compatible clients ask for the same three fields:
@@ -12644,11 +12837,13 @@ Most OpenAI-compatible clients ask for the same three fields:
For example, a saved LLM profile named `gateway_demo` appears as the OpenAI model `openhands_gateway_demo`.
-The gateway accepts the same session key in either OpenHands or OpenAI-compatible form:
+Authentication maps OpenAI-style bearer tokens onto the agent-server's existing session key mechanism. The gateway accepts the same session key in either form:
- `X-Session-API-Key: `
- `Authorization: Bearer `
+Both are validated against the configured session API keys — there is no second credential system. When the server is configured without session keys, it remains unauthenticated just like the native agent-server API.
+
## Prepare a Profile
OpenAI-compatible traffic is backed by an agent-server LLM profile. Create one with the native profile API first:
@@ -12678,7 +12873,19 @@ curl "$AGENT_SERVER_URL/v1/models" \
-H "Authorization: Bearer $SESSION_API_KEY"
```
-## Client Recipes
+## Chat Completions (`POST /v1/chat/completions`)
+
+Each request runs a full OpenHands agent to completion and returns the final assistant text in a standard Chat Completions shape.
+
+Supported request fields:
+
+- `model` — required; must be an `openhands_` exposed via `GET /v1/models`.
+- `messages` — a standard list. The last `user` message becomes the agent's task; `system` and `developer` messages are folded into the agent's system context.
+- `stream` — `true` returns a server-sent events stream; `false` (default) returns a single response.
+
+The response includes a `X-OpenHands-ServerConversation-ID` header. Send that header on a follow-up request to continue the same server-side OpenHands conversation instead of starting a new one.
+
+### Client Recipes
@@ -12780,7 +12987,6 @@ For Open WebUI, LibreChat, Chatbot UI, and similar OpenAI-compatible frontends,
- **Base URL**: `https://YOUR_AGENT_SERVER/v1`
- **API key**: your agent-server session API key
- **Model**: `openhands_`
-- **Streaming**: disabled for now
If the UI can store a response header and send a custom request header, persist `X-OpenHands-ServerConversation-ID` per chat thread and send it on follow-up turns. If it cannot, each request starts a new OpenHands conversation and works best for one-shot tasks.
@@ -12817,9 +13023,9 @@ Return `reply_text` to the voice or webhook platform. Keep the mapping for as lo
-## Conversation State
+### Conversation State
-The OpenAI Chat Completions protocol usually sends full message history on every request. The OpenHands gateway does not reconstruct agent history from prior assistant messages. Instead:
+The Chat Completions protocol usually sends full message history on every request, but the gateway does **not** reconstruct agent history from prior assistant messages. Instead:
- Omit `X-OpenHands-ServerConversation-ID` to start a new OpenHands conversation.
- Read `X-OpenHands-ServerConversation-ID` from the response.
@@ -12827,11 +13033,128 @@ The OpenAI Chat Completions protocol usually sends full message history on every
When reusing a conversation, send the newest user turn in `messages`. The server-side OpenHands conversation owns the previous agent state, tool activity, and workspace context.
-## Current Limitations
+## Responses (`POST /v1/responses`)
+
+The Responses endpoint targets the OpenAI Responses API — a better fit for agent-shaped traffic, with typed input/output items. It is **stateless-first** by design.
+
+### Mental Model
+
+Every request starts a **fresh** OpenHands conversation and runs the full agent to completion. There is no server-side continuation handle: to carry context forward, clients replay prior input and output items into the next request's `input`.
+
+```bash
+curl "$AGENT_SERVER_URL/v1/responses" \
+ -H "Authorization: Bearer $SESSION_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d "{
+ \"model\": \"$OPENHANDS_MODEL\",
+ \"instructions\": \"Answer briefly.\",
+ \"input\": \"Summarize this repository in one sentence.\",
+ \"store\": false
+ }"
+```
+
+Response:
+
+```json
+{
+ "id": "resp_…",
+ "object": "response",
+ "created_at": 1726000000.0,
+ "completed_at": 1726000120.0,
+ "model": "openhands_gateway_demo",
+ "instructions": "Answer briefly.",
+ "output": [
+ {
+ "id": "msg_…",
+ "type": "message",
+ "role": "assistant",
+ "status": "completed",
+ "content": [
+ { "type": "output_text", "text": "This repository is …", "annotations": [] }
+ ]
+ }
+ ],
+ "parallel_tool_calls": false,
+ "previous_response_id": null,
+ "status": "completed",
+ "tool_choice": "none",
+ "tools": [],
+ "usage": {
+ "input_tokens": 123,
+ "input_tokens_details": { "cached_tokens": 0 },
+ "output_tokens": 45,
+ "output_tokens_details": { "reasoning_tokens": 0 },
+ "total_tokens": 168
+ }
+}
+```
+
+The response also carries the `X-OpenHands-ServerConversation-ID` header, but unlike Chat Completions you **cannot** pass it back to continue that conversation — the Responses surface ignores it. Use the header only to correlate the response with the underlying OpenHands conversation through the native agent-server API.
+
+### Replaying Context
+
+To maintain context across Responses calls, replay the previous assistant output items (and any system/developer context) into the next request's `input`:
-- Only non-streaming Chat Completions requests are supported. Requests with `stream: true` return `400` until streaming support is added.
-- The response contains the final assistant text only. Internal OpenHands tool activity is not exposed as OpenAI tool calls.
-- OpenAI request fields that are not needed by the gateway are ignored or rejected intentionally by the server implementation.
+```python
+import os
+from typing import cast
+
+from openai import OpenAI
+from openai.types.responses import ResponseInputItemParam
+
+client = OpenAI(
+ api_key=os.environ["SESSION_API_KEY"],
+ base_url=f"{os.environ['AGENT_SERVER_URL']}/v1",
+)
+
+first = client.responses.create(
+ model=os.environ["OPENHANDS_MODEL"],
+ instructions="You are reviewing this repository.",
+ input="Summarize the project structure.",
+ store=False,
+)
+
+second = client.responses.create(
+ model=os.environ["OPENHANDS_MODEL"],
+ input=[
+ {"role": "developer", "content": "You are reviewing this repository."},
+ {"role": "user", "content": "Summarize the project structure."},
+ *[
+ item.model_dump(mode="json", exclude_none=True)
+ for item in cast(list[ResponseInputItemParam], first.output)
+ ],
+ {"role": "user", "content": "Now list the main packages."},
+ ],
+ store=False,
+)
+```
+
+### How Input Is Interpreted
+
+- Top-level `instructions` and any `system`/`developer` input items become the agent's **system context**.
+- The remaining input items become the agent's user prompt. A single `user` item is sent as-is; multiple non-system items are wrapped in `` tags so their roles are preserved.
+- `model` must be an `openhands_` exposed via `GET /v1/models`.
+
+### Not Supported Yet
+
+The following OpenAI Responses features are intentionally rejected or ignored. Status codes and wording are exact.
+
+| Feature | Behavior |
+| --- | --- |
+| `previous_response_id` | Rejected with `400` — `"previous_response_id is not supported; replay input items instead"`. |
+| `store: true` | Rejected with `400` — `"Persistent response storage (store=True) is not supported yet"`. There is no retrievable Responses object and no `GET /v1/responses/{id}`. |
+| `stream: true` | Rejected with `400` — `"Streaming responses are not supported yet"`. |
+| `tools`, `tool_choice`, `parallel_tool_calls` | Accepted but **ignored** — the caller's declared tools do not replace OpenHands' internal tool loop. |
+| `temperature` and other generation-tuning fields | Accepted but **ignored**. |
+
+
+Setting `store: false` (the default) is **not** a data-retention control. It only signals that no Responses object is retained. The backing OpenHands conversation still follows the agent-server's normal persistence policy.
+
+
+## Current Limitations (Both Endpoints)
+
+- The response contains the final assistant text only. Internal OpenHands tool activity is not exposed as OpenAI tool calls or Responses output items.
+- OpenAI request fields the gateway does not need are either ignored or rejected intentionally by the server implementation. Declared tools and generation-tuning fields do not change agent behavior.
## Ready-to-run example
@@ -13031,7 +13354,7 @@ A Remote Agent Server is an HTTP/WebSocket server that:
- **Manages workspaces** (Docker containers or remote sandboxes)
- **Streams events** to clients via WebSocket
- **Handles command and file operations** (execute command, upload, download), check [base class](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/base.py) for more details
-- **Accepts OpenAI-compatible Chat Completions requests** through the [OpenAI-compatible endpoint](/sdk/guides/agent-server/openai-gateway)
+- **Accepts OpenAI-compatible Chat Completions and Responses requests** through the [OpenAI-compatible endpoint](/sdk/guides/agent-server/openai-gateway)
- **Provides isolation** between different agent executions
Think of it as the "backend" for your agent, while your Python code acts as the "frontend" client.
@@ -13210,6 +13533,39 @@ This is useful when:
- Letting users edit agent configuration in a form-based UI
- Rehydrating the same agent setup in another process
+## Load Persisted Settings
+
+`model_validate` only accepts payloads that already match the current schema. Use `from_persisted` for data written by an older SDK version: it applies the registered schema migrations first, then validates the migrated payload against the class you call it on.
+
+```python icon="python" focus={1}
+restored = OpenHandsAgentSettings.from_persisted(payload)
+```
+
+`from_persisted` is defined on `AgentSettingsBase`, so it is a concrete-variant loader: `OpenHandsAgentSettings.from_persisted()` returns an `OpenHandsAgentSettings` and `ACPAgentSettings.from_persisted()` returns an `ACPAgentSettings`. When you do not know which variant a payload holds, use `validate_agent_settings` (also in `openhands.sdk.settings`) instead — it dispatches across the settings union.
+
+Passing an already-validated instance of that variant returns it unchanged, so its secrets are preserved without a lossy serialization round trip.
+
+
+The deprecated `agent_kind="llm"` discriminator is only rewritten while migrating between schema versions. A payload that is already at the current schema version but still carries `agent_kind="llm"` is therefore rejected by `OpenHandsAgentSettings.from_persisted`. Load those payloads with `validate_agent_settings`, which canonicalizes the discriminator unconditionally.
+
+
+### Encrypted Payloads
+
+Secret-bearing fields only decrypt when you pass the same validation context that was used to write them.
+
+```python icon="python" focus={2}
+persisted = settings.model_dump(mode="json", context={"cipher": cipher})
+restored = OpenHandsAgentSettings.from_persisted(persisted, context={"cipher": cipher})
+```
+
+### Errors
+
+| Exception | Raised when |
+|-----------|-------------|
+| `TypeError` | The payload is not a mapping or `BaseModel`, or its `schema_version` is not an integer. |
+| `ValueError` | `schema_version` is negative, newer than the supported version, or has no registered migration. |
+| `pydantic.ValidationError` | The migrated payload is invalid for the class you called `from_persisted` on. |
+
## Create an Agent from Settings
Once validated, create a working agent directly from the settings object.
@@ -18191,9 +18547,9 @@ Hooks let you observe and customize key lifecycle moments in the SDK without for
## Exit Codes
-Command hooks (shell scripts) signal their result through their exit code —
-[agent-based hooks](#agent-based-hooks) return a JSON decision instead. The SDK
-matches the
+Command hooks (shell scripts) signal their result through their exit code.
+[Prompt-based hooks](#prompt-based-hooks) and
+[agent-based hooks](#agent-based-hooks) return a JSON decision instead. The SDK matches the
[Claude Code hook contract](https://docs.claude.com/en/docs/claude-code/hooks):
- **`0` — success.** The operation proceeds. `stdout` is parsed as JSON for
@@ -18218,6 +18574,20 @@ policy must exit with `2`.
- Isolation: hooks run outside the agent loop logic, avoiding core modifications
- Composition: enable or disable hooks per environment (local vs. prod)
+## Execution Modes
+
+Hook definitions support three execution modes:
+
+| `type` | Evaluator | Tool access | Best for |
+|--------|-----------|-------------|----------|
+| `command` (default) | Shell command | Through the script | Deterministic checks and integrations |
+| `prompt` | One LLM completion | No | Semantic decisions based only on the hook event |
+| `agent` | Short-lived sub-agent | Optional allowlist | Decisions that require workspace investigation |
+
+Use the least powerful mode that can make the decision. Command hooks are the
+most deterministic. Prompt hooks add model judgment with one completion. Agent
+hooks add an agent loop and tools when the event payload is not enough.
+
## Ready-to-run Example
@@ -18458,6 +18828,149 @@ exit 0
+## Prompt-based Hooks
+
+Set `type="prompt"` to evaluate a hook event with one LLM completion. Prompt
+hooks are useful when a decision needs semantic judgment but all required
+context is already present in the `HookEvent` payload. For example, a
+`PreToolUse` policy can evaluate the intent of a terminal command without
+starting a tool-using sub-agent.
+
+```python
+HookDefinition(
+ type=HookType.PROMPT,
+ name="terminal-safety",
+ prompt="Deny terminal commands that recursively delete files ...",
+ timeout=30,
+)
+```
+
+Key fields on a prompt `HookDefinition`:
+
+- `name` — identifies the hook in logs, events, and its stable
+ `prompt-hook:` metrics bucket.
+- `prompt` — the trusted policy used to evaluate each matching event.
+- `timeout` — the timeout applied to the copied hook LLM.
+
+The hook uses the conversation's current LLM, including changes made through
+model or profile switching. The executor copies that LLM so the hook has an
+isolated timeout, usage ID, and metrics. Hook spend is merged back into the
+parent conversation's metrics. The SDK selects Chat Completions or the Responses
+API from the model's capabilities. Prompt hooks are single-shot and non-streaming,
+regardless of the parent LLM's streaming setting.
+
+The policy is placed in system context. The serialized event is sent in a
+separate user message and marked as untrusted data, so instructions embedded in
+tool input or output are not treated as hook policy. The model is asked to
+return the shared hook result contract:
+
+```json
+{"decision": "allow" | "deny", "reason": ""}
+```
+
+If the conversation has no LLM, the provider call fails, or the response does
+not contain a valid decision, the hook falls open with `decision="allow"` and
+`success=False`. This lets consumers distinguish an execution failure from a
+deliberate allow verdict.
+
+
+Prompt hooks cannot inspect files, run commands, or access conversation history
+beyond data included in the hook event. Use an [agent-based hook](#agent-based-hooks)
+when the evaluator must gather more context before deciding.
+
+
+
+This example is available on GitHub: [examples/01_standalone_sdk/57_prompt_hooks](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/57_prompt_hooks/)
+
+
+```python icon="python" expandable examples/01_standalone_sdk/57_prompt_hooks/main.py
+"""OpenHands Agent SDK - prompt-based hooks example.
+
+Evaluates two synthetic PreToolUse events with one LLM completion each. The
+commands are only event data: this example never executes them.
+"""
+
+import os
+import tempfile
+from pathlib import Path
+
+from pydantic import SecretStr
+
+from openhands.sdk import LLM
+from openhands.sdk.conversation.conversation_stats import ConversationStats
+from openhands.sdk.hooks import (
+ HookConfig,
+ HookDefinition,
+ HookManager,
+ HookMatcher,
+ HookType,
+)
+
+
+api_key = os.getenv("LLM_API_KEY")
+assert api_key is not None, "LLM_API_KEY environment variable is not set."
+
+llm = LLM(
+ usage_id="agent",
+ model=os.getenv("LLM_MODEL", "anthropic/claude-sonnet-4-5-20250929"),
+ base_url=os.getenv("LLM_BASE_URL"),
+ api_key=SecretStr(api_key),
+)
+
+TERMINAL_POLICY = """Evaluate the semantic intent of a terminal command.
+Deny commands that recursively delete files, read credentials or sensitive
+system files, modify the host system, or exfiltrate data. Allow read-only
+workspace inspection, builds, and test commands. When uncertain, deny and give
+a concise reason."""
+
+hook_config = HookConfig(
+ pre_tool_use=[
+ HookMatcher(
+ matcher="terminal",
+ hooks=[
+ HookDefinition(
+ type=HookType.PROMPT,
+ name="terminal-safety",
+ prompt=TERMINAL_POLICY,
+ timeout=30,
+ )
+ ],
+ )
+ ]
+)
+
+cases = [
+ ("python -m pytest -q", True),
+ ("find / -type f -delete", False),
+]
+
+with tempfile.TemporaryDirectory() as tmpdir:
+ stats = ConversationStats()
+ manager = HookManager(
+ config=hook_config,
+ working_dir=str(Path(tmpdir)),
+ session_id="prompt-hook-example",
+ llm=llm,
+ conversation_stats=stats,
+ )
+
+ for command, expected_to_continue in cases:
+ should_continue, results = manager.run_pre_tool_use(
+ tool_name="terminal",
+ tool_input={"command": command},
+ )
+ result = results[0]
+ verdict = "ALLOW" if should_continue else "DENY"
+ print(f"{verdict:5} {command}")
+ print(f" {result.reason}")
+ assert should_continue is expected_to_continue
+
+ cost = stats.get_combined_metrics().accumulated_cost
+ print(f"\nEXAMPLE_COST: {cost}")
+```
+
+
+
## Agent-based Hooks
Besides shell scripts, a hook can delegate its decision to an LLM-driven
@@ -25801,6 +26314,56 @@ agent_context = AgentContext(skills=list(skills.values()))
- **[MCP Integration](/sdk/guides/mcp)** - Connect external tool servers
- **[Confirmation Mode](/sdk/guides/security)** - Add execution approval
+### Structured Output
+Source: https://docs.openhands.dev/sdk/guides/structured-output.md
+
+import RunExampleCode from "/sdk/shared-snippets/how-to-run-example.mdx";
+
+Pass a Pydantic model (or a JSON Schema dict) as a tool's `response_schema`. Its fields are merged into the schema the LLM sees, so the model must populate them when it calls that tool, and the reply is validated on receipt — no prompting for a format, no output parsing.
+
+```python
+class ProjectFacts(BaseModel):
+ description: str = Field(description="One-paragraph description of the project.")
+ facts: list[str] = Field(description="Three concise, distinct facts.")
+
+
+agent = Agent(
+ llm=llm,
+ tools=[Tool(name="FinishTool", params={"response_schema": ProjectFacts})],
+)
+```
+
+The tool keeps its own arguments — `FinishTool` still takes `message`, now alongside `description` and `facts`. This works on any tool, including [custom](/sdk/guides/custom-tools) and [MCP](/sdk/guides/mcp) tools.
+
+## Reading results
+
+Resolved tools live on `agent.tools_map`. Use `parse_last_response()` for the most recent call, or `parse_response(action)` for a specific one:
+
+```python
+finish_tool = agent.tools_map["finish"]
+facts = cast(ProjectFacts | None, finish_tool.parse_last_response(conversation.state.events))
+```
+
+`parse_last_response()` returns `None` if the tool has not been called. With a JSON Schema dict instead of a model, both methods return a validated `dict`.
+
+
+`parse_last_response()` re-reads the tool call, so it works after a conversation is persisted and reloaded. `action.structured_output` is in-memory only — it is not serialized with the event and comes back `None` after a round-trip, so prefer the parse methods.
+
+
+## Constraints
+
+- **Reserved names.** A schema may not declare `kind`, `security_risk`, `structured_output`, or `summary`, nor reuse one of the tool's own field names (e.g. `message` on `FinishTool`). Both raise a `ValueError` when the tool is resolved.
+- **One tool per spec.** A spec that resolves to a tool set is rejected; attach the schema to the individual tool instead.
+- **Scoped to its tool.** A model may try to send the schema fields when calling *other* tools; those calls are rejected as unexpected arguments and the agent retries.
+
+## Ready-to-run Example
+
+```python icon="python" expandable examples/01_standalone_sdk/56_structured_output.py
+# content is auto-synced
+```
+
+
+
### Task Tool Set
Source: https://docs.openhands.dev/sdk/guides/task-tool-set.md
@@ -29002,6 +29565,12 @@ Use an OpenHands profile when you want Agent Canvas to run the built-in OpenHand
An OpenHands profile references an LLM profile, so model and credential changes are managed in `Settings > LLM`. Use this when you want Agent Canvas to own both the agent behavior and the model configuration.
+### Let the Agent Switch LLM Profiles
+
+The OpenHands profile editor includes a **"Let the agent switch LLM profiles"** toggle. When enabled, the agent is given the `SwitchLLMTool`, which lets it switch between available LLM profiles during a conversation. When disabled, the tool is removed from the agent's toolset.
+
+This toggle is version-gated: it appears only when the connected backend reports agent-server `1.31.0` or later. On older backends (for example, agent-server `1.29.0`–`1.30.x`) the toggle is hidden.
+
## ACP Profiles
Use an ACP profile when you want Agent Canvas to drive an external coding agent through the Agent Client Protocol.
@@ -29030,7 +29599,7 @@ If you choose OpenHands, the setup flow also configures the LLM profile that the
### Agent Canvas Architecture
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/architecture.md
-Agent Canvas is the open-source browser client and control center for OpenHands conversations and automations. It presents backend state and sends requests to backend services; it is not an agent runtime or sandbox. Agent Server or an ACP agent process executes tools, and the selected workspace or sandbox provides the execution boundary.
+Agent Canvas is the open-source browser client and control center for OpenHands conversations and automations. It presents backend state and sends requests to backend services; it is not an agent runtime or sandbox. Agent Server or an ACP agent CLI executes tools, and the selected workspace or sandbox provides the execution boundary.
## Core Components
@@ -29041,39 +29610,10 @@ Agent Canvas is the open-source browser client and control center for OpenHands
| **Automation Server** | Stores schedules and event triggers, tracks runs, and dispatches conversations | [`OpenHands/automation`](https://github.com/OpenHands/automation) |
| **Workspace or sandbox** | Defines which files, processes, credentials, and networks an agent can access | Deployment-specific |
-Sandbox Server is a community-driven standalone API and sandbox control plane. It is not a core Agent Canvas backend or a supported deployment option. [Learn more about Sandbox Server](https://github.com/OpenHands/sandbox-server).
+Sandbox Server is a community-driven standalone API and sandbox control plane. [Learn more about Sandbox Server](https://github.com/OpenHands/sandbox-server).
## Service Relationships
-```mermaid
-%%{init: {"theme": "default", "flowchart": {"nodeSpacing": 30, "rankSpacing": 45}} }%%
-flowchart TB
- Browser["Browser"] --> Canvas["Agent Canvas browser client"]
-
- subgraph Backend["Selected backend"]
- AgentServer["Agent Server"] -->|execute agent and tools| Workspace["Workspace or sandbox"]
- Automation["Automation Server"] -->|dispatch conversation| AgentServer
- end
-
- Canvas -->|conversations and settings| AgentServer
- Canvas -->|schedules, events, and runs| Automation
-
- subgraph Platform["OpenHands Cloud or Enterprise"]
- ControlPlane["Platform control plane"] -->|create and manage| Sandbox["Conversation sandbox"]
- Sandbox -->|hosts| PlatformAgentServer["Agent Server"]
- end
-
- Canvas -.->|managed backend| PlatformAgentServer
-
- classDef primary fill:#f3e8ff,stroke:#7c3aed,stroke-width:2px
- classDef secondary fill:#e8f3ff,stroke:#2b6cb0,stroke-width:2px
- classDef tertiary fill:#fff4df,stroke:#b7791f,stroke-width:2px
- classDef service fill:#e9f9ef,stroke:#2f855a,stroke-width:2px
- class Canvas primary
- class AgentServer,Automation,PlatformAgentServer secondary
- class Workspace,Sandbox tertiary
- class ControlPlane service
-```
The normal browser path is **Browser → Agent Canvas → selected backend**. Agent Server owns conversation execution. Automation Server owns scheduled and event-driven run lifecycle. A backend distribution can expose both services behind one URL, but they remain separate responsibilities.
@@ -29096,17 +29636,16 @@ The launcher supports split modes:
Docker and Helm packages can also bundle the client and backend services. A bundled deployment changes how services are installed, not which component owns execution or isolation.
-## Execution And Isolation
+## Execution and Isolation
When you send a message, Agent Canvas sends it to the selected backend. Agent Server starts or resumes the conversation, runs the selected agent, invokes tools, updates backend state, and streams events to Canvas.
The workspace determines the execution boundary:
-| Workspace type | Execution and isolation boundary |
-|----------------|----------------------------------|
-| **Local process** | Agent Server and tools run directly on the backend host without container isolation. |
+| Execution environment | Execution and isolation boundary |
+|-----------------------|----------------------------------|
+| **Host process** | Agent Server and tools run directly on the backend host without container isolation. If the backend is remote, that host—not the browser's machine—is the execution boundary. |
| **Docker or Kubernetes** | Agent Server and tools run inside the configured container or pod with its mounts and network policy. |
-| **Remote Agent Server** | Agent Server runs on another machine or in a separate container, with the workspace boundary configured there. |
| **OpenHands Cloud or Enterprise** | The managed platform creates and operates the conversation sandbox that hosts Agent Server. |
Connecting Canvas to a remote backend does not grant the browser direct access to that backend's filesystem. Canvas displays files and terminal output returned by Agent Server.
@@ -29127,14 +29666,14 @@ Switching backends changes which backend-managed conversations, settings, automa
| Pattern | Relationship |
|---------|--------------|
| **Local all-in-one** | The launcher starts Canvas and local backend services on one machine. |
-| **Remote Agent Server** | Canvas connects to an Agent Server running on another machine or in a separate container on the same machine. |
-| **Self-hosted backend services** | You deploy Agent Server, and optionally Automation Server, on a VM, Docker host, Kubernetes cluster, or Modal. |
+| **Self-hosted backend services** | You deploy Agent Server, and optionally Automation Server, in another process, on a VM, in Docker or Kubernetes, or on Modal. Canvas connects to the deployment as a remote backend. |
| **Managed platform** | Canvas connects to OpenHands Cloud or OpenHands Enterprise, which operate their backend and sandbox infrastructure. |
## Next Steps
- [Install Agent Canvas](/openhands/usage/agent-canvas/setup)
- [Connect And Manage Backends](/openhands/usage/agent-canvas/backends)
+- [Connect To A Remote Backend](/openhands/usage/agent-canvas/backend-setup/remote)
- [Self-Host On A VM](/openhands/usage/agent-canvas/backend-setup/vm)
- [Use Docker](/openhands/usage/agent-canvas/backend-setup/docker)
- [Agent Server Overview](/sdk/guides/agent-server/overview)
@@ -29151,6 +29690,7 @@ A Cloud backend is a good fit when you want to:
- Run agents without tying up local resources
- Use OpenHands Cloud's managed sandboxes and integrations
- Keep your local machine for development while offloading agent work
+- Easy Phone & Tablet Access so you can code on the go
## Prerequisites
@@ -29237,11 +29777,60 @@ Configuration is passed via `-e` flags on `docker run`:
| `PORT` | Ingress port inside the container (default `8000`). Map it with `-p :`. |
| `LOCAL_BACKEND_API_KEY` | API key for the server. Auto-generated and persisted if not set. |
| `OH_SECRET_KEY` | Secret used to protect stored settings and secrets. |
+| `AGENT_CANVAS_DISABLE_TELEMETRY` | Set to `1` or `true` to disable Agent Canvas product telemetry. |
+
+You can also pass `--disable-telemetry` to the Agent Canvas runtime. Use the environment variable for deployment configuration because older images ignore an unknown environment variable but reject an unknown runtime flag.
The agent server can execute arbitrary shell commands inside the container. If exposing it beyond localhost, set `LOCAL_BACKEND_API_KEY` to a strong secret.
+## Let the Agent Use Docker
+
+By default the agent cannot run containers: `docker` is installed in the image, but the
+daemon cannot start inside an unprivileged container. If the agent tries, it fails with
+`error creating default "bridge" network: operation not permitted`.
+
+That matters for tasks where a container is part of the workflow — building a `Dockerfile`
+and running it to confirm the change works, bringing up a `docker compose` stack to
+reproduce a bug, or using a toolchain that is only published as an image. Without a
+daemon the agent can edit those files but cannot verify them.
+
+To enable it, start the container with `--privileged`:
+
+```bash
+docker run -it --rm \
+ --privileged \
+ -p 8000:8000 \
+ -v ~/.openhands:/home/openhands/.openhands \
+ -v ~/projects:/projects \
+ ghcr.io/openhands/agent-canvas:latest
+```
+
+
+ `--privileged` gives the container broad access to the host kernel, which substantially
+ weakens the isolation between the agent and your machine. The agent can execute
+ arbitrary shell commands, so grant this only on a host you are willing to expose and
+ only when the agent genuinely needs to run containers.
+
+
+Verify from inside the container:
+
+```bash
+docker exec -it docker info
+```
+
+
+ There is no safer middle ground. The Docker daemon needs kernel capabilities that are
+ granted by the host when the container starts, so they cannot be acquired later — and
+ rootless Docker does not avoid this: the daemon starts, but containers it creates fail
+ to launch (`error mounting "proc" to rootfs: operation not permitted`).
+
+ OpenHands Enterprise solves this differently, running each sandbox under a hardened
+ runtime that provides kernel-level isolation so nested containers run unprivileged. See
+ [Running Docker in the Agent Sandbox](/enterprise/docker-in-sandbox).
+
+
## Connect from the Frontend
Start the frontend separately and point it at the container:
@@ -29265,6 +29854,120 @@ Then add the Docker backend:
- [Local Backend](/openhands/usage/agent-canvas/backend-setup/local)
- [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm)
- [Kubernetes (Helm)](/openhands/usage/agent-canvas/backend-setup/kubernetes)
+- [Running Docker in the Agent Sandbox](/enterprise/docker-in-sandbox) — how Enterprise does this without `--privileged`
+
+### Isolate Tool Execution with Docker
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/docker-execution.md
+
+Use Docker execution mode when you want Agent Canvas and Agent Server to remain trusted host processes while isolating filesystem and process tools in a separate container for each conversation.
+
+This mode differs from [running the entire Agent Canvas distribution in Docker](/openhands/usage/agent-canvas/backend-setup/docker). The outer Agent Server retains conversation state, LLM calls, credentials, policy, persistence, and orchestration. Supported tool actions run inside an ephemeral execution container.
+
+## Prerequisites
+
+- Docker installed and running on the Agent Server host
+- Permission for the user running `agent-canvas` to invoke Docker
+- An Agent Server image compatible with the installed Agent Server version
+
+## Start Agent Canvas
+
+Set the execution runtime and image before starting Agent Canvas:
+
+```bash
+export OH_EXECUTION_RUNTIME=docker
+export OH_EXECUTION_IMAGE=ghcr.io/openhands/agent-server:latest-python
+export OH_EXECUTION_PLATFORM=linux/amd64
+agent-canvas
+```
+
+Use `linux/arm64` for an ARM host such as Apple Silicon.
+
+You can combine these variables with other launcher options. For example, to use another port:
+
+```bash
+OH_EXECUTION_RUNTIME=docker \
+OH_EXECUTION_IMAGE=ghcr.io/openhands/agent-server:latest-python \
+OH_EXECUTION_PLATFORM=linux/amd64 \
+agent-canvas --port 9000
+```
+
+The launcher forwards the variables to the local Agent Server. No separate frontend configuration is required.
+
+## How Isolation Works
+
+For each local conversation, Agent Server creates a `DockerExecutionWorkspace` with `/workspace` as its working directory. The container starts lazily when the conversation first invokes a supported tool.
+
+The following built-in tools execute in the container:
+
+- `terminal`
+- `file_editor`
+- `grep`
+- `glob`
+- `apply_patch`
+
+The outer Agent Server continues to run the agent loop and all LLM requests. It sends supported tool actions to an authenticated execution-only endpoint in the container. The inner server does not expose conversation, profile, settings, LLM, persistence, or WebSocket APIs.
+
+
+ Tools without a Docker execution adapter continue to run in the outer Agent Server process. Review custom and additional tools before treating the container as their security boundary.
+
+
+## Keep the Sandbox Ephemeral
+
+By default, the execution container has no host filesystem mounts. Leave `OH_EXECUTION_VOLUMES` unset to keep the workspace ephemeral and prevent host files from appearing under `/workspace`.
+
+To mount data deliberately, provide a JSON array of Docker volume specifications:
+
+```bash
+export OH_EXECUTION_VOLUMES='["/path/on/host:/workspace/project"]'
+```
+
+
+ A volume gives tools in the container access to the mounted host path. Do not configure volumes when you require a disposable sandbox with no host filesystem access.
+
+
+The execution container:
+
+- Publishes its API only on host loopback.
+- Receives a generated per-workspace capability instead of the outer server's credentials.
+- Is removed when its workspace closes.
+- Does not store the outer conversation state or LLM configuration.
+
+Conversation history persists in the outer Agent Server according to its normal persistence configuration. Files created only inside an unmounted execution container do not persist after that container is removed.
+
+## Verify Isolation
+
+Create a new conversation and ask the agent to run:
+
+```bash
+printf 'PWD=%s\nHOME=%s\n' "$PWD" "$HOME"
+find "$HOME" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort
+```
+
+A default execution image should report `/workspace` as `PWD` and a container-local home directory such as `/home/openhands`. It must not display the Agent Server host's home-directory contents.
+
+On the host, inspect the active execution container:
+
+```bash
+docker ps --filter name=openhands-execution-
+docker inspect --format '{{json .Mounts}}'
+```
+
+For an ephemeral configuration, the mounts output should be `[]`.
+
+## Configuration Reference
+
+| Variable | Default | Purpose |
+|----------|---------|---------|
+| `OH_EXECUTION_RUNTIME` | `local` | Set to `docker` to enable one execution container per local conversation. |
+| `OH_EXECUTION_IMAGE` | `ghcr.io/openhands/agent-server:latest-python` | Agent Server image used for execution containers. |
+| `OH_EXECUTION_PLATFORM` | `linux/amd64` | Docker platform for execution containers. |
+| `OH_EXECUTION_VOLUMES` | `[]` | Optional JSON array of Docker volume specifications. |
+
+## Related Guides
+
+- [Use Docker with Agent Canvas](/openhands/usage/agent-canvas/backend-setup/docker) — run the entire Canvas distribution and backend in one container
+- [Agent Canvas Architecture](/openhands/usage/agent-canvas/architecture)
+- [Docker Sandbox](/sdk/guides/agent-server/docker-sandbox) — run the entire conversation through a remote Agent Server container
### Kubernetes (Helm)
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/kubernetes.md
@@ -29847,7 +30550,7 @@ Switch between them from the backend selector depending on what you're working o
### Modal Backend
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/modal.md
-Deploy [Agent Server](https://github.com/OpenHands/software-agent-sdk/tree/main/openhands-agent-server) on [Modal](https://modal.com) as a remote backend for Agent Canvas. Canvas runs locally on your machine while Agent Server runs on Modal and executes code inside the container—the same execution model as the backend started by `npx @openhands/agent-canvas`.
+Deploy [OpenHands](https://github.com/OpenHands/OpenHands) on [Modal](https://modal.com) as a remote backend for Agent Canvas. Canvas runs locally on your machine while the Agent Canvas Backend runs on Modal and executes code inside the container—the same execution model as the backend started by `npx @openhands/agent-canvas`.
The agent server runs with full access to the container's filesystem, environment, and network. Anyone with the API key can execute arbitrary code on your Modal container. Keep the API key secret and rotate it if it's ever exposed.
@@ -30204,10 +30907,10 @@ Agent Canvas does not distinguish a remote backend by where it runs. It connects
A remote backend must provide:
- An accessible Agent Server URL.
-- An API key when the backend requires authentication.
+- An API key.
- A workspace or sandbox where Agent Server can execute tools.
-To use scheduled or event-driven automations, the backend must also provide Automation Server.
+To use scheduled or event-driven automations, the backend must also provide an Automation Server.
## Connect To A Remote Backend
@@ -30582,28 +31285,220 @@ Before exposing Agent Canvas beyond an SSH tunnel:
### Backends
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/backends.md
-A **backend** provides Agent Server and, when automations are enabled, Automation Server. Agent Server runs conversations and tools in a workspace: the folder, mounted project directory, container, or cloud sandbox where the agent reads and writes files. Automation Server manages schedules, events, and run lifecycle. Agent Canvas connects to these services and displays the state of whichever backend is selected.
+A **backend** provides [Agent Server](/sdk/guides/agent-server/overview#what-is-a-remote-agent-server) and, when automations are enabled, Automation Server. Agent Server runs conversations and tools in a workspace: the folder, mounted project directory, container, or cloud sandbox where the agent reads and writes files. Automation Server manages schedules, events, and run lifecycle. Agent Canvas connects to these services and displays the state of whichever backend is selected.
## Connecting to a Backend
Any Agent Canvas frontend can connect to any Agent Canvas backend. Use the backend switcher in the UI to open **Manage Backends**, where you can add, edit, or remove entries. Each entry stores a display name, host URL, and an API key for authentication.
+
+
Settings, LLM configuration, MCP servers, and automations are all scoped to the active backend — switching backends switches all of these.
+"Remote" describes how Canvas connects to a backend, not where that backend runs. A remote backend can be a separate process on the same machine, a self-hosted deployment on a VM or container platform, or a managed Cloud or Enterprise service.
+
## Recommended Setups
| Setup | When to use | How |
|-------|-------------|-----|
| **Default local** | Quick local work on your machine | Run `agent-canvas`—a local backend is created automatically. |
-| **Remote Agent Server** | An Agent Server on another machine or in a separate local container | Add its host URL and API key in `Manage Backends`. See [Remote Backend](/openhands/usage/agent-canvas/backend-setup/remote). |
-| **Self-hosted VM** | Always-on server, more powerful hardware, team-shared access, or a full self-hosted Canvas | Run `agent-canvas --backend-only --public` for backend-only mode, or `agent-canvas --public` for the full UI and backend. See [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm). |
+| **Self-hosted backend** | A separate local process or container, an always-on VM, more powerful hardware, or team-shared access | Deploy the backend services, then add their host URL and API key in `Manage Backends`. See [Remote Backend](/openhands/usage/agent-canvas/backend-setup/remote) and [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm). |
| **Cloud or Enterprise** | Managed backend and sandbox infrastructure | Connect from `Manage Backends`. See [Cloud Backend](/openhands/usage/agent-canvas/backend-setup/cloud). |
+### Apps (Beta)
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/canvas-extensions.md
+
+Apps let you add custom pages to Agent Canvas without changing the Agent Canvas source code. An app can provide an integrated dashboard, project tool, or other browser interface that connects to the active Agent Server.
+
+
+ Apps are a beta feature. The name and app API may change as the feature develops.
+
+
+## What Apps Add
+
+The initial beta supports **custom pages**. When you enable an app, its pages appear in the Agent Canvas sidebar and open inside the application.
+
+An app page can:
+
+- Render a browser-based interface inside Agent Canvas
+- Add nested routes below its declared page path
+- Navigate to other Agent Canvas pages
+- Make authenticated HTTP requests to the active Agent Server
+- Read metadata about the app and active backend
+
+The current beta does not support conversation tabs, arbitrary interface slots, themes, visualizer replacement, or direct Agent Server WebSocket connections.
+
+Apps change the Agent Canvas interface. They are different from [skills](/overview/skills), which give agents instructions and knowledge, and [plugins](/openhands/usage/agent-canvas/plugins), which package agent capabilities and configuration.
+
+## Availability
+
+Apps are managed by the active Agent Server and are currently available with supported local backends. They are not available when an OpenHands Cloud backend is active.
+
+Each backend has its own installed apps, files, versions, and enabled states. Switching backends replaces the apps shown in Agent Canvas.
+
+If `Customize > Apps` reports that the feature is unavailable, update the Agent Server connected to Agent Canvas. A backend without the Canvas Extensions API cannot install or run apps.
+
+## Install an App
+
+Open `Customize > Apps`, then select `Add app`.
+
+
+
+ 1. Enter the Git source, such as `github:owner/repository`.
+ 2. Optionally enter a branch, tag, or commit in `Ref`.
+ 3. If the app is not at the repository root, enter its directory in `Repo path`.
+ 4. Select `Add app`.
+
+
+ 1. Enter the absolute path to the app directory.
+ 2. Select `Add app`.
+
+ The path is resolved on the Agent Server machine. A path on the computer running your browser will not work unless that computer also runs the Agent Server and exposes the same path.
+
+
+
+One Add app operation installs one app package. If a repository contains several apps, add each manifest directory separately with its own `Repo path`.
+
+New apps are installed **disabled**. Review the source, resolved revision, manifest details, and contributed pages before enabling one.
+
+## Enable and Manage Apps
+
+To run an installed app:
+
+1. Open `Customize > Apps`.
+2. Find the installed app and enable it.
+3. Review and accept the trusted-code notice.
+4. Open its new item in the Agent Canvas sidebar.
+
+You can disable an app without restarting Agent Canvas. Its navigation items and mounted pages are removed immediately. Re-enable it to load the app again, or uninstall it to remove the installation from the active backend.
+
+### Trust Model
+
+Enabling an app runs its JavaScript in the same browser context as Agent Canvas. The beta does not isolate apps in an iframe or worker and does not enforce fine-grained permissions.
+
+Only enable apps whose code and resolved revision you trust. An enabled app has the browser authority available to Agent Canvas and can use an authenticated helper to call the active Agent Server.
+
+## Build an App
+
+An app is a directory containing:
+
+- `canvas-extension.json` at the app root
+- One self-contained browser ESM entrypoint inside that root
+- Any source files or build configuration needed to produce the entrypoint
+
+The current package format uses manifest schema `1` and host API `1`.
+
+### Create the Manifest
+
+```json canvas-extension.json
+{
+ "schema_version": 1,
+ "name": "example-dashboard",
+ "display_name": "Example dashboard",
+ "version": "0.1.0",
+ "description": "A project dashboard for Agent Canvas.",
+ "entrypoint": "extension.js",
+ "contributes": {
+ "pages": [
+ {
+ "id": "dashboard",
+ "title": "Dashboard",
+ "path": "/dashboard",
+ "nav_label": "Dashboard"
+ }
+ ]
+ }
+}
+```
+
+Use lowercase letters, numbers, and hyphens for app names and page IDs. Page paths must start with `/`, and every page ID and path must be unique within the app.
+
+The `entrypoint` must stay inside the app root. Bundle dependencies, CSS, and required assets into one browser ESM file; unresolved package imports and external runtime chunks cannot be loaded.
+
+### Register the Page
+
+Export an `activate` function from the entrypoint and register each page declared in the manifest:
+
+```js extension.js
+export function activate(host) {
+ if (host.apiVersion !== "1") {
+ throw new Error("This extension requires host API 1.");
+ }
+
+ return host.registerPage("dashboard", ({ container, path }) => {
+ const page = document.createElement("section");
+ page.setAttribute("aria-label", "Example dashboard");
+ page.textContent = path ? `Dashboard route: ${path}` : "Dashboard";
+ container.append(page);
+
+ return () => page.remove();
+ });
+}
+```
+
+The page ID passed to `registerPage` must match a page declared in `canvas-extension.json`. Return cleanup functions for registered pages, DOM nodes, timers, listeners, and other effects so the app can be disabled or reloaded safely.
+
+Agent Canvas mounts this example at:
+
+```text
+/extensions/example-dashboard/dashboard
+```
+
+For a nested URL such as `/extensions/example-dashboard/dashboard/services`, the page receives `services` as its relative `path`.
+
+### Connect to the Agent Server
+
+Use `host.agentServer.request` for authenticated requests to the backend that owns the app:
+
+```js
+const serverInfo = await host.agentServer.request({
+ method: "GET",
+ path: "/server_info",
+});
+```
+
+Request paths must be root-relative, begin with exactly one `/`, and must not be full URLs. Do not derive backend URLs or authentication credentials from Agent Canvas internals.
+
+The beta host API does not expose the backend origin or a WebSocket authentication capability. Use the authenticated HTTP helper, polling where appropriate, or a backend-owned bridge instead of opening a direct Agent Server WebSocket.
+
+## Design for the Beta Lifecycle
+
+Agent Canvas may activate, mount, and dispose an app repeatedly when you enable or disable it, update it, reconnect, or switch backends. App pages should:
+
+- Render only inside the supplied page container
+- Scope styles to an app-specific root element
+- Clean up all DOM nodes, styles, timers, listeners, observers, and subscriptions
+- Prevent late asynchronous responses from updating an unmounted page
+- Handle loading, empty, malformed-response, and error states
+- Remain keyboard accessible and usable on narrow screens
+
+## Learn More
+
+- [Canvas Extensions API specification](https://github.com/OpenHands/OpenHands/blob/main/specs/canvas-extensions.md)
+- [Minimal app fixture](https://github.com/OpenHands/OpenHands/tree/main/src/fixtures/canvas-extensions/demo-page)
+- [Customize and Settings](/openhands/usage/agent-canvas/customize-and-settings)
+
### Conversations
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/conversations.md
A conversation is a single agent session on the active backend. It has its own message history, tool calls, file changes, selected agent profile, and conversation-specific plugins.
+## Child Conversations
+
+When an agent uses `launch_child_conversation`, Agent Canvas can launch a child conversation on a local or Cloud target. Local children can use either an isolated worktree or the parent's shared workspace. Cloud children use the repository and branch selected for the launch.
+
+The child remains linked to its parent, and its result is returned to the parent conversation. Agent Canvas validates the launch inputs before creating the child conversation.
+
+## Conversation List Controls
+
+Use the conversation list controls to manage automation runs and visible tags:
+
+- Choose `All`, `Hide`, or `Only` to include, exclude, or show only automation-run conversations. You can further select individual automation names, including unnamed automations.
+- Pinned conversations remain visible when automation-run filtering would otherwise hide them.
+- Enable the `Tags` preference to show conversation tag chips. Tags are off by default; when there are more tags than fit, Agent Canvas shows a `+N` chip with the remaining count.
+
+Agent Canvas omits reserved tags and raw automation IDs from the chips. LLM metadata is also hidden by default.
+
## Follow Agent Activity
While an agent is running, the composer shows a live activity chip for its current unresolved action, such as reading a file or running a command. If no action-specific label is available, it shows `Thinking`. The chip disappears when the agent pauses or completes its work.
@@ -30612,6 +31507,45 @@ While an agent is running, the composer shows a live activity chip for its curre
If a message fails to send, select `Retry` to send it again or `Dismiss` to remove the failed message bubble. Dismissing a message does not restore its text to the composer.
+## Inline Markdown Artifact Previews
+
+When an agent creates a Markdown file, Agent Canvas renders it inline as a height-limited rich preview with an internal scrollbar instead of showing only the raw file content. Select `View` to open the full file in the Files drawer.
+
+## Conversation Overview Panel
+
+The conversation overview panel displays project context for the active conversation, including workspace information, git state, and loaded resources such as skills, MCP servers, and automations.
+
+Toggle the overview using the info control in the conversation header. The panel peeks beside the chat area and closes when you open the Files drawer.
+
+### Unified Commits Drawer
+
+From the overview panel, open the **Commits** drawer to see a unified view of git activity:
+
+- The commit list shows recent commits alongside any uncommitted changes
+- A header git-actions control lets you send commit, pull, push, and pull-request prompts to the agent
+
+The Commits tab combines the commit history with uncommitted changes in a single view, so you no longer need to switch between separate Diff and Commits surfaces.
+
+### Files View
+
+The **Files** tab is a focused file browser with open-file tabs and close controls. The file tree is resizable and persists its state across refreshes.
+
+Above the file tree, the active workspace path is displayed with a copy button. Hover the truncated path to see the full value in a tooltip, then click to copy it.
+
+
+ The workspace path row is hidden when the conversation has no working directory.
+
+
+## Context Window Usage and Manual Compaction
+
+Agent Canvas shows a context-window meter in the composer that visualizes how much of the model's available context is in use. The meter fills as the conversation grows.
+
+Click the meter to open the usage preview, then click "Usage" to see the full usage panel which shows token usage and provider balance details. You can manually compact the conversation to reduce context by selecting "Compact context" in the usage preview or usage panel.
+
+
+ The meter only appears for models that report a context window size. Models that do not report one will not show a meter.
+
+
## Branch From a Message
Use `Branch from here` on a message when you want to explore a different path without changing the original conversation.
@@ -30726,6 +31660,29 @@ The export is generated locally in your browser from the events Agent Canvas alr
For very large conversations, Agent Canvas loads the full event history before generating the file. This may take a moment. On cloud backends, the export uses the events the app currently has loaded.
+## Archive a Conversation
+
+Archiving a conversation hides it from the sidebar list without deleting it. The conversation's full history stays on the backend, and you can unarchive it at any time.
+
+**To archive a conversation:**
+
+1. Open the conversation card menu in the sidebar.
+2. Select `Archive`.
+3. Confirm in the dialog that appears.
+
+The conversation disappears from the default sidebar list. An archived conversation shows an `Archived` chip when revealed.
+
+**To view or restore archived conversations:**
+
+1. Open the panel filter menu in the sidebar.
+2. Enable `Show archived`.
+3. Archived conversations reappear with an `Archived` chip.
+4. Open an archived conversation's menu and select `Unarchive` to restore it to the default list.
+
+
+ Archive state is stored per backend in your browser's local storage. It does not sync across browsers or machines. The `Delete all` action still deletes archived conversations, including hidden ones. Archiving is non-destructive, but deleting is permanent.
+
+
## Related Guides
- [Fork a Conversation](/sdk/guides/convo-fork)
@@ -30877,11 +31834,12 @@ Agent Canvas separates **Customize** from **Settings**.
Open the top-level `Customize` area to manage:
-- [Skills](/overview/skills)
- [MCP Servers](/openhands/usage/settings/mcp-settings)
+- [Skills](/overview/skills)
- [Plugins](/openhands/usage/agent-canvas/plugins)
+- [Apps (Beta)](/openhands/usage/agent-canvas/canvas-extensions)
-Use the section navigation inside `Customize` to switch between these pages.
+Use the section navigation inside `Customize` to switch between these pages. Apps add trusted custom pages to Agent Canvas, while skills and plugins change agent behavior.
MCP Server configuration lives under `Customize > MCP Servers`, not under `Settings`.
@@ -30915,15 +31873,16 @@ The `Settings` area currently includes the following sections:
| Section | Purpose |
|---------|---------|
| `Agent` | Agent Profile library and agent-specific capabilities |
-| `LLM` | Provider, model, API key, and profile configuration |
+| `LLM` | Provider, model, API key, profile configuration, and provider connections |
| `Condenser` | Context compression and summarization behavior |
| `Verification` | Approval, critic evaluation, and verification-related behavior |
| `Application` | UI-level preferences and app behavior |
| `Secrets` | Stored secrets used by the active backend |
-On local backends, the `LLM` page also includes an `Available Profiles` area for saved profiles.
-In `Settings > Application`, the **Conversation titles** setting selects the LLM profile used to generate conversation titles. **Automatic** uses the active local LLM profile; you can choose another saved profile, like a small, cheap LLM, when you want titles generated independently from the model selected for agent work. The same page shows the installed Agent Canvas version, update availability, and a **Check for updates** button.
+In `Settings > Application`, the **Conversation titles** setting selects the LLM profile used to generate conversation titles. **Automatic** uses the active local LLM profile; you can choose another saved profile, like a small, cheap LLM, when you want titles generated independently from the model selected for agent work.
+
+The main settings nav also shows the installed version of Agent Canvas with a manual **Check for updates** button. When an update is available click on the tile to view details and update information.
Use `Settings > Agent` to choose the active Agent Profile for new conversations. OpenHands profiles reference LLM profiles from `Settings > LLM`; ACP profiles use the external agent's own model configuration.
@@ -31032,6 +31991,8 @@ Available options:
The setup screen defaults to `OpenHands` as the provider and pre-selects a recommended model. Switch the `LLM Provider` dropdown to choose a different provider.
+The default model is **OpenAI GPT-5.6 Sol**, and **DeepSeek V4 Flash** is the free OpenHands-routed model. When adding an OpenHands provider connection, the provider field is a searchable supported-provider selector rather than free text.
+
For OpenHands Agent Profiles, this LLM setup becomes the model profile the agent uses. ACP agents such as Claude Code, Codex, and Gemini CLI use their own authentication and model configuration.
## Step 4: Start From a Proven Workflow
@@ -31051,12 +32012,152 @@ Other available templates include:
You can browse all pre-built automations from the `Automate` view at any time. See [Pre-built Automations](/openhands/usage/agent-canvas/prebuilt-automations) for the full list.
+## Getting Started Checklist
+
+After completing the setup wizard, a **Getting Started** checklist appears in the sidebar. It guides you through the core first actions:
+
+1. **Set up your LLM** — links to `Settings > LLM`
+2. **Connect MCP servers** — links to `Customize > MCP`
+3. **Start a conversation** — links to `Conversations`
+4. **Explore automations** — links to `Automate`
+5. **Customize your agent** — links to `Customize`
+6. **Review settings** — links to `Settings`
+
+Each item links directly to the relevant page. The checklist tracks your progress and minimizes to stay out of the way. When all items are complete, the checklist auto-hides.
+
+
+ Toggle the checklist from `Settings > Application` using the **Show getting started checklist** switch. The setting persists across sessions.
+
+
+## Customize your Agent Canvas
+
+When you are ready to go beyond the default setup, choose the mechanism that fits the task:
+
+- Add repository-wide guidance with [`AGENTS.md`](/overview/skills/repo) for each Workspace.
+- Add reusable task instructions with [Skills](/overview/skills).
+- Connect external tools through [MCP](/openhands/usage/settings/mcp-settings).
+- Add packaged capabilities with [Plugins](/openhands/usage/agent-canvas/plugins).
+- Automate repeated work with [Automations](/openhands/usage/agent-canvas/managing-automations).
+
## After Your First Session
Keep the terminal or Docker container that runs Agent Canvas active while you use the browser. When you are done, [stop Agent Canvas](/openhands/usage/agent-canvas/setup#stop-agent-canvas). Start it again with the same command when you return.
For routine maintenance, see [update and uninstall](/openhands/usage/agent-canvas/setup#update-agent-canvas). If the UI, backend, or model does not work as expected, start with [Troubleshooting](/openhands/usage/agent-canvas/troubleshooting).
+### Sync Automations with Git
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/git-sync.md
+
+Git Sync keeps the automations on an Agent Canvas backend synchronized with a Git repository. It gives you version history, an off-host backup, and a reviewable workflow for changing automations through pull requests.
+
+
+ Automation definitions can contain prompts, repository names, scripts, and other sensitive configuration. Use a private repository unless you are certain every synchronized file is safe to publish.
+
+
+## How Git Sync Works
+
+Each sync cycle pulls the configured branch, imports changes from Git into the Automation Server, exports local automation changes, and pushes a commit when the synchronized files changed.
+
+By default, each automation is stored in its own directory under the configured path:
+
+```text
+automations/
+└── daily-code-review/
+ ├── automation.yaml
+ └── tarball/
+ └── ...
+```
+
+The `automation.yaml` file stores the automation configuration. Files from an uploaded automation bundle are expanded under `tarball/` so Git can show meaningful diffs.
+
+
+ Git Sync is bidirectional. A change made in Agent Canvas is exported to Git, while a change merged into the synchronized branch is imported into Agent Canvas during the next cycle. If the same automation has pending local changes, the local version takes precedence for that cycle.
+
+
+## Requirements
+
+Before configuring Git Sync, make sure you have:
+
+- A healthy Agent Canvas backend with a version of Automation Server that supports Git Sync
+- Permission to manage automations on that backend
+- A Git repository and branch dedicated to the synchronized automation files
+- An HTTPS access token with read and write access when the repository is private
+
+Git Sync is not available for cloud backends. If the page reports that the backend does not support Git Sync, [update Agent Canvas](/openhands/usage/agent-canvas/setup#update-agent-canvas) and restart it.
+
+## Configure Git Sync
+
+1. Open the `Automate` view in Agent Canvas.
+2. Select `Git Sync` near the top of the automation list.
+3. Configure the repository:
+ - `Repository URL`: The HTTPS clone URL, such as `https://github.com/example/automation-backup.git`.
+ - `Branch`: The branch Git Sync pulls from and pushes to. The default is `main`. Git Sync creates the branch during the first cycle if it does not exist.
+ - `Path`: The repository-relative directory that holds automation files. The default is `automations`.
+ - `Access token`: Required for private repositories. The token needs permission to read and push repository contents.
+4. Set `Sync every (seconds)`:
+ - Enter `0` to sync only when you select `Sync now`.
+ - Enter a positive number to run automatic sync cycles at that interval.
+5. Optionally set the commit author name and email. Leave these fields blank to use the backend defaults.
+6. Optionally enter an encryption key. See [Encrypt Synchronized Files](#encrypt-synchronized-files) before enabling this option.
+7. Turn on `Enable Git Sync`.
+8. Select `Save and sync now`.
+
+Before saving a changed repository URL, branch, or token, Agent Canvas checks whether it can reach the repository. This check does not verify push permission, so the first sync can still fail if the token is read-only. If the check cannot reach the repository, correct the settings or select the save action again to store them anyway.
+
+After the cycle completes, the **Sync Status** section shows the latest commit, last sync time, pending local changes, and any error returned by Git.
+
+## Encrypt Synchronized Files
+
+An encryption key encrypts each automation file before it is committed. The repository then contains ciphertext instead of readable YAML and script content.
+
+
+ Store the encryption key in a password manager or another secure location. Agent Canvas cannot read or restore encrypted automation files without the same key.
+
+
+Encryption protects the contents stored in Git, but it also prevents normal code review and meaningful diffs. Use it when repository-level access controls are not sufficient for the sensitivity of your automation definitions.
+
+The access token and encryption key entered in Agent Canvas are encrypted before the Automation Server stores them. Leaving either secret field blank keeps its current value. Use the corresponding clear option when you intend to remove a stored secret.
+
+## Edit Automations Through Git
+
+Use a pull request when you want to review automation changes before Agent Canvas imports them:
+
+1. Create a branch from the synchronized branch.
+2. Edit the automation's `automation.yaml` or files under `tarball/`.
+3. Open and review a pull request.
+4. Merge the pull request into the synchronized branch.
+5. Wait for the next automatic cycle or select `Sync now`.
+6. Open the automation in Agent Canvas and confirm the imported configuration before running it.
+
+Git Sync validates imported automation fields. It skips an invalid automation directory and reports the problem in Automation Server logs rather than applying a partial configuration.
+
+
+ If file encryption is enabled, edit automations in Agent Canvas instead. Encrypted repository files are not directly editable or reviewable.
+
+
+## Pause or Run Sync Manually
+
+Turn off `Enable Git Sync` and save to pause synchronization without deleting the repository configuration. Turn it on again to resume.
+
+Select `Sync now` to start a cycle immediately. The request schedules the cycle in the background, and the activity row follows it until it succeeds or fails. If another cycle is already running, Agent Canvas follows that cycle instead of starting a duplicate.
+
+## Troubleshooting
+
+| Problem | What to Check |
+|---------|---------------|
+| Git Sync is not available | Confirm the active backend is local, healthy, and running a current Automation Server version. |
+| Repository check fails | Confirm the HTTPS URL, branch name, network access, and token. Select save again only if you intentionally want to keep settings that the check cannot verify. |
+| Repository check passes but push fails | Give the access token write permission for repository contents and confirm branch protection permits the configured workflow. |
+| Sync reports a non-fast-forward or divergence error | Update the synchronized branch through reviewed pull requests and avoid another process writing directly to it while Agent Canvas has an unpushed commit. |
+| Encrypted files cannot be imported | Restore the exact encryption key used to write them. A different or missing key cannot decrypt the repository contents. |
+| Changes do not sync automatically | Confirm Git Sync is enabled and `Sync every (seconds)` is greater than `0`, or use `Sync now`. |
+
+## Related Guides
+
+- [Manage Automations](/openhands/usage/agent-canvas/managing-automations)
+- [Install Agent Canvas](/openhands/usage/agent-canvas/setup)
+- [Connect and Manage Backends](/openhands/usage/agent-canvas/backends)
+
### Manage LLM Profiles
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/llm-profiles.md
@@ -31068,6 +32169,8 @@ LLM profiles can also generate conversation titles. In `Settings > Application >
Open `Settings > LLM` to add a reusable LLM profile. Use the **Basic** tab for a provider and model available in the dropdowns. Use the **Advanced** tab when you need to enter a model name and base URL directly. Use the **All** tab to view and customize the full set of model configuration fields.
+If you are deciding between a provider key, local endpoint, LiteLLM proxy, OpenRouter, or ACP agent, start with [Configure a Model](/openhands/usage/agent-canvas/model-configuration).
+
ACP agents such as Claude Code, Codex, and Gemini CLI manage their own model access. See [ACP Agents](/openhands/usage/agent-canvas/acp-agents) instead.
@@ -31076,14 +32179,14 @@ ACP agents such as Claude Code, Codex, and Gemini CLI manage their own model acc
| I have | Profile tab | Configure |
|---|---|---|
-| An API key from Anthropic, OpenAI, Google, or another provider | **Basic** | Select the provider and model, then add its API key. |
-| An OpenHands LLM API key | **Basic** | Select `OpenHands`, choose a model, and add your OpenHands LLM API key. |
-| A local OpenAI-compatible server | **Advanced** | Enter the provider, exact model ID, base URL, and any required API key. |
-| A LiteLLM proxy | **Advanced** | Use the `litellm_proxy/` model prefix, proxy base URL, and proxy API key. |
+| An API key from Anthropic, OpenAI, Google, or another provider | **Basic** | Select the provider and model, then add its API key or reuse a Provider Connection. |
+| An OpenHands LLM API key | **Basic** | Select `OpenHands`, choose a model, then add the key or reuse a Provider Connection. |
+| A local OpenAI-compatible server | **Advanced** | Enter the provider and exact model ID, then add its base URL/key or reuse a Provider Connection. |
+| A LiteLLM proxy | **Advanced** | Use the `litellm_proxy/` model prefix, then add its proxy URL/key or reuse a Provider Connection. |
### Direct Provider
-In the **Basic** tab, select your provider and model, add the API key issued by that provider, and save the profile. Use a new conversation to test the change; an existing conversation continues with the agent and model it started with.
+In the **Basic** tab, select your provider and model. Select a **Provider Connection** to reuse its API key, or add an API key directly when it belongs only to this profile. Save the profile, then use a new conversation to test the change; an existing conversation continues with the agent and model it started with.
For provider and model recommendations, see [LLM Configuration](/openhands/usage/llms/llms).
@@ -31095,8 +32198,20 @@ Use an OpenHands LLM API key when you want Agent Canvas to access models through
2. In the **Basic** tab, select `OpenHands`, choose a model, and add the key.
3. Save the profile and start a new conversation.
+While using OpenHands as your LLM provider you will see OpenHands-routed model IDs marked as `Free`. These models change as we have promotional periods where we can offer them without any additional token cost. Currently **DeepSeek V4 Flash** is the free OpenHands-routed model.
+
+The `Free` label applies only to those full `openhands/` routes. Endpoints from other providers with similar model names may have separate billing. The label remains visible after you select one of these models.
+
+When you create a local LLM profile, the form initially selects **OpenAI GPT-5.6 Sol** (the default model) and derives the profile name from it. You can change either value before saving.
+
For key details and available models, see [OpenHands LLM Provider](/openhands/usage/llms/openhands-llms).
+### Pre-Save Validation
+
+When you save an LLM profile, the configuration is validated against the backend before it is persisted. If validation fails — for example, because the API key is rejected or the model is unavailable — the save is blocked and the backend error is shown. The save button displays a validating state while the check runs.
+
+Older backends that do not support validation (they return a `404` for the validation endpoint) skip this check and save normally.
+
### Local OpenAI-Compatible Endpoint
A local server can be LM Studio, Ollama, vLLM, SGLang, or another service that exposes an OpenAI-compatible API. In the **Advanced** tab, enter the provider, exact model ID, endpoint base URL, and the required API key or a placeholder value when the server does not require one.
@@ -31117,6 +32232,32 @@ In the **Advanced** tab, use the model name format `litellm_proxy/`,
See [LiteLLM Proxy](/openhands/usage/llms/litellm-proxy) for the complete configuration.
+## Provider Connections
+
+
+ Provider Connections are available on **local agent-server backends only**. The panel is hidden when using an OpenHands Cloud backend.
+
+
+When you want multiple LLM profiles to share the same provider credentials, use **Provider Connections** to store a provider, API key, and optional base URL once and reference it across profiles. This avoids pasting the same key into every profile and lets you rotate credentials in one place. Linked profiles keep their own model selection while using the shared connection for credentials.
+
+### Create a Provider Connection
+
+1. Open `Settings > LLM`.
+2. In the **Provider Connections** panel, add a new connection.
+3. Enter a name, then select a provider from the searchable supported-provider selector, and add the API key and an optional base URL.
+
+The provider field in the **create** connection flow is a searchable selector backed by the supported-provider catalog. You must select a supported provider before the connection can be saved. Existing connections retain free-text editing, so legacy or custom provider identifiers remain maintainable.
+
+### Link a Profile to a Provider Connection
+
+When you add or edit an LLM profile, choose a saved connection in the **Provider Connection** selector. Select **None** to use credentials specific to that profile instead. When a profile is linked, its inline API key and base URL fields are hidden — the profile uses the connection's credentials instead.
+
+Linked profiles are grouped under their Provider Connection name in the profile list for readability. To use another model with the same API key, add another LLM profile, select the same connection, choose that model, and save.
+
+### Update or Delete a Connection
+
+Edit a Provider Connection to rename it, rotate its API key, or change its base URL. The update applies to every linked profile. Before deleting a connection, re-link or change every profile that uses it; Agent Canvas prevents deleting a connection while profiles still reference it.
+
## Working with LLM Profiles
LLM profiles are useful when you want different model setups for different tasks, such as:
@@ -31131,6 +32272,8 @@ LLM profiles are separate from [Agent Profiles](/openhands/usage/agent-canvas/ag
The available profiles list shows each profile's name, configured model, and whether it is active. Use a profile's menu to edit or rename it, set it as the active profile for new conversations, or delete it when you no longer need it.
+
+
## Switching Profiles in a Conversation
You can switch profiles from the profile selector in the chat input or with the `/model` command:
@@ -31183,7 +32326,7 @@ The **Automate** view in Agent Canvas is the in-app control center for your auto
## Browse and inspect automations
-Open the **Automate** tab in the sidebar to see all automations on the active backend. Each row shows the automation name, trigger type, and enabled state.
+Open the **Automate** tab in the sidebar to see all automations on the active backend. Each row shows the automation name, trigger type, and enabled state. When the active backend is healthy but has no automations, the Automate pane remains available and includes an option to add one.
Click an automation to open its detail view. The detail view shows:
@@ -31196,6 +32339,16 @@ Click an automation to open its detail view. The detail view shows:
A run can be `PENDING`, `RUNNING`, `COMPLETED`, `FAILED`, `CANCELLED`, or `SKIPPED`. A `SKIPPED` run can occur when the backend reaches its concurrency limit. Future backend statuses appear as a neutral status badge so they do not prevent you from viewing the automation.
+### Run Phase
+
+Automation runs surface a live **phase** that reflects a run's current state: `PENDING`, `RUNNING`, or `FAILED`. The phase appears on automation cards, in the Activity Log, and on the home screen, and updates live as a run progresses. A failed run retains its last phase after it stops.
+
+### Activity Log Costs and Exports
+
+The Activity Log displays a completed run's reported LLM cost in USD to four decimal places. A measured zero cost appears as `$0.0000`; when the backend does not report a cost, no cost appears in the log.
+
+Use the Activity Log export controls to download run data as CSV or JSON. Both formats include a raw numeric `cost` field for every run, as well as the run's `phase`. An unavailable cost is exported as `null`.
+
## Enable and disable automations
Toggle an automation on or off from the kebab menu (⋮) on the automation row, or from the detail view. Disabled automations do not fire on their scheduled trigger or in response to events, but their configuration is preserved.
@@ -31256,12 +32409,16 @@ You can import an automation from a JSON file previously exported by Agent Canva
2. Click **Import automation** at the top of the list.
3. Pick the `.json` file to import.
4. Review the preview — it shows the automation's name, trigger type, and prompt.
+
+
+
5. Confirm to create the automation.
Imported automations are created **disabled**. After importing, open the automation from the list, review its configuration, and enable it when ready.
## Related guides
+- [Sync automations with Git](/openhands/usage/agent-canvas/git-sync)
- [Creating automations](/openhands/usage/automations/creating-automations)
- [Managing automations (CLI-style)](/openhands/usage/automations/managing-automations)
- [Pre-built automations](/openhands/usage/agent-canvas/prebuilt-automations)
@@ -31318,6 +32475,105 @@ Open the ngrok forwarding URL in your phone or tablet browser.
ngrok also supports OAuth, IP allowlists, and other access controls for additional protection.
+### Configure a Model
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/model-configuration.md
+
+Use this guide to choose a model configuration path in Agent Canvas. Start with the credentials or endpoint you have, then save the profile and test it in a new conversation.
+
+
+ACP agents such as Claude Code, Codex, and Gemini CLI manage their own model access. Use [ACP Agents](/openhands/usage/agent-canvas/acp-agents) instead of creating an LLM profile for those agents.
+
+
+## Choose a Configuration Path
+
+| I have | Use | Configure in |
+|---|---|---|
+| An API key from a model provider | A direct provider profile | `Settings > LLM` → `Basic` |
+| An OpenHands LLM API key | An OpenHands provider profile | `Settings > LLM` → `Basic` |
+| A local OpenAI-compatible server | A local endpoint profile | `Settings > LLM` → `Advanced` |
+| A LiteLLM proxy | A proxy profile | `Settings > LLM` → `Advanced` |
+| A signed-in Claude Code, Codex, or Gemini CLI subscription | An ACP agent | `Settings > Agent` |
+
+## Provider Connection for Reusable API Credentials
+
+Create a **Provider Connection** when you expect to use the same provider API key for more than one model or LLM profile. A connection stores the provider, API key, and optional base URL once; each linked profile supplies its own model configuration and uses the connection's credentials.
+
+1. Open `Settings > LLM`.
+2. In **Provider Connections**, select **Add provider connection**.
+3. Enter a recognizable name, such as `Personal OpenHands API` or `Team OpenAI`.
+4. Choose the provider from the searchable provider list.
+5. Enter the API key and, if needed, the provider base URL.
+6. Save the connection.
+7. Add or edit an LLM profile, select the connection in **Provider Connection**, then select the model and save the profile.
+
+When a profile uses a Provider Connection, its API key and base URL come from the connection rather than the profile. Reuse that connection for additional models from the same provider. Update the connection once to rotate its key or change its base URL for every linked profile.
+
+
+Provider Connections are available on local agent-server backends. The panel is hidden when using an OpenHands Cloud backend.
+
+
+## Direct Provider or OpenHands Profile
+
+Use the `Basic` tab when you have an API key from Anthropic, OpenAI, Google, OpenHands, or another provider in the selector.
+
+1. If you will reuse the key, create or choose a [Provider Connection](#provider-connection-for-reusable-api-credentials).
+2. Select the provider and model.
+3. Select the Provider Connection, or enter the API key directly for a profile-specific credential.
+4. Save the profile.
+5. Start a new conversation and send a short message to confirm the model responds.
+
+For model recommendations and provider references, see [LLM Configuration](/openhands/usage/llms/llms). For the OpenHands provider, see [OpenHands LLM Provider](/openhands/usage/llms/openhands-llms).
+
+## Local OpenAI-Compatible Server
+
+Use the `Advanced` tab for LM Studio, Ollama, vLLM, SGLang, or another server that exposes an OpenAI-compatible API.
+
+1. Find the exact model ID served by your server, usually from its `GET /v1/models` endpoint.
+2. Enter `openai/` as the model.
+3. If the server needs an API key or a reusable base URL, create a [Provider Connection](#provider-connection-for-reusable-api-credentials) with those values and select it for the profile. Otherwise, enter them directly in the profile.
+4. Make sure the base URL is reachable from the **backend**.
+5. Save the profile and start a new conversation to verify it.
+
+If Agent Canvas runs in Docker while the model server runs on the host, `127.0.0.1` points to the container, not the host. Use the host address appropriate for your platform, such as `http://host.docker.internal:/v1` where supported.
+
+See [Run Local LLMs with OpenHands](/openhands/usage/llms/local-llms) for server-specific examples.
+
+## LiteLLM Proxy
+
+Use the `Advanced` tab when you use a LiteLLM proxy.
+
+1. Enter `litellm_proxy/` as the model.
+2. Create or select a [Provider Connection](#provider-connection-for-reusable-api-credentials) for the proxy URL and API key. You can instead enter those values directly when they are specific to one profile.
+3. Make sure `` exactly matches a model configured on the proxy.
+4. Save the profile and start a new conversation to verify it.
+
+See [LiteLLM Proxy](/openhands/usage/llms/litellm-proxy) for the complete proxy configuration.
+
+## OpenRouter
+
+Use OpenRouter when you have an OpenRouter API key and want to access a model through its catalog. Create an `OpenRouter` Provider Connection to reuse the key, then in the `Basic` tab select `OpenRouter`, choose a model, select the connection, and save the profile. Use the `Advanced` tab only when you need to enter a model ID that is not available in the selector.
+
+See [OpenRouter](/openhands/usage/llms/openrouter) for model-ID and recovery guidance.
+
+## Fix a Failed Configuration
+
+| Symptom | Check first | Next step |
+|---|---|---|
+| Provider is not recognized | The profile path and provider/model prefix | Choose the matching path above. |
+| Model ID or format error | The exact model ID from the provider or proxy inventory | Update the model ID or prefix. |
+| Local endpoint cannot be reached | The base URL from the backend | Check host, port, bind address, and container networking. |
+| Authentication or permission error | Key type and provider account access | Re-enter the key and check the provider requirements. |
+| The model cannot complete agent tasks | Context length and tool-use support | Use a more capable model or supported runtime. |
+
+For additional error-specific guidance, see [Troubleshooting](/openhands/usage/agent-canvas/troubleshooting#model-or-api-key-errors).
+
+## Next Steps
+
+- [Manage LLM Profiles](/openhands/usage/agent-canvas/llm-profiles)
+- [Run Local LLMs with OpenHands](/openhands/usage/llms/local-llms)
+- [LiteLLM Proxy](/openhands/usage/llms/litellm-proxy)
+- [Troubleshooting](/openhands/usage/agent-canvas/troubleshooting)
+
### Agent Canvas Overview
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/overview.md
@@ -31343,16 +32599,27 @@ You can also test a preview build of the native desktop app. [Try the desktop pr
Agent Canvas is the browser client. It connects to backend services that own execution and persistent state:
-| Component | Responsibility |
-|-----------|----------------|
-| **Agent Canvas** | Displays conversations, files, terminals, settings, backends, and automations. |
-| **Agent Server** | Runs conversations, agents, tools, and workspace operations. |
-| **Automation Server** | Manages schedules, event triggers, dispatch, and run history. |
-| **Workspace or sandbox** | Defines which files, processes, credentials, and networks the agent can access. |
+| Concept | What It Means | Why It Matters |
+|-------|---------------|----------------|
+| **Browser UI** | The web interface you open in your browser. | This is where you chat, inspect files, manage settings, and configure automations. |
+| **Backend** | The agent server that runs conversations, tools, settings, secrets, and automations. | This determines where the agent runs and what machine or sandbox it can access. |
+| **Workspace** | The folder, repository, container mount, or cloud sandbox the agent works in. | This determines which files the agent can read and write. |
+| **Agent and model** | The OpenHands agent or an ACP agent, plus the model credentials it uses. | This determines which LLM or provider receives conversation context and powers the agent. |
+
+```mermaid
+flowchart LR
+ browser["Browser UI"] --> backend["Selected backend"]
+ backend --> conversation["Conversation and agent"]
+ conversation --> model["Model access"]
+ conversation --> workspace["Workspace and tools"]
-
- Agent Canvas does not execute tools or provide sandbox isolation. Agent Server or an ACP process executes tools, and the selected workspace or sandbox provides the execution boundary.
-
+ classDef primary fill:#f3e8ff,stroke:#7c3aed,stroke-width:2px
+ classDef secondary fill:#e8f3ff,stroke:#2b6cb0,stroke-width:2px
+ classDef tertiary fill:#fff4df,stroke:#b7791f,stroke-width:2px
+ class browser primary
+ class backend,conversation secondary
+ class model,workspace tertiary
+```
The `agent-canvas` launcher can package the client and backend services into one local stack. You can also run the client separately and connect it to services on a VM, in Docker or Kubernetes, or through OpenHands Cloud or OpenHands Enterprise.
@@ -31392,7 +32659,19 @@ Agent Canvas supports several model access patterns:
- **ACP agent subscription login** — use a signed-in provider, such as Claude Code, Codex, or Gemini, when the backend runs on the same machine as that login.
- **Local or OpenAI-compatible provider** — connect providers such as Ollama, LM Studio, LiteLLM, or a compatible gateway through model settings.
-See [Manage LLM Profiles](/openhands/usage/agent-canvas/llm-profiles) and [ACP Agents](/openhands/usage/agent-canvas/acp-agents) for details.
+See [Configure a Model](/openhands/usage/agent-canvas/model-configuration), [Manage LLM Profiles](/openhands/usage/agent-canvas/llm-profiles), and [ACP Agents](/openhands/usage/agent-canvas/acp-agents) for details.
+
+## Customize Your Agent
+
+After the first conversation, choose the extension point that matches your need:
+
+| If you want to... | Start here |
+|---|---|
+| Add always-on repository guidance | [Repository Context and `AGENTS.md`](/overview/skills/repo) |
+| Add reusable task-specific instructions | [Skills Overview](/overview/skills) |
+| Connect external tools or services | [MCP Settings](/openhands/usage/settings/mcp-settings) |
+| Extend the agent with packaged capabilities | [Plugins](/openhands/usage/agent-canvas/plugins) |
+| Run work on a schedule or in response to events | [Automations](/openhands/usage/agent-canvas/managing-automations) |
## How It Fits With Other OpenHands Products
@@ -31532,7 +32811,7 @@ Agent Canvas ships with a set of pre-built automations for the most common agent
---
-Backends created by the `agent-canvas` launcher include Automation Server, so they can run agents on a schedule or in response to external events. Other backends must provide a compatible automation service for these features.
+Backends created by the `agent-canvas` launcher include Automation Server, so they can run agents on a schedule or in response to external events.
## What You Can Do
@@ -31555,8 +32834,16 @@ In practice, new automation setup starts in one of two ways:
For recommended automations that support a direct form setup, Agent Canvas checks the active backend's capabilities and any prerequisites, then guides you through the required input fields, a review step, and creation. If direct form setup is unavailable, it offers a conversation-assisted setup instead. Review the proposed configuration before creating an automation.
+Some catalog entries ship a **script bundle** — a packaged set of files that install as a deterministic automation — rather than a prompt-based preset. Script-bundle entries run their own logic for tasks like polling, deduplication, and fixed API calls, using the agent only for the parts that genuinely require judgment. When a catalog entry supports a bundle install, the setup form handles packaging and upload automatically; you just fill in the required fields.
+
+Catalog entries that accept repositories can also collect multiple repositories in a single field, so one automation can monitor several repos at once.
+
For a detailed walkthrough, see [Creating Automations](/openhands/usage/automations/creating-automations).
+
+ Some recommended automations depend on integrations that cannot be auto-installed as MCP servers on this backend (for example, Jira's HTTP/OpenAPI-only integration). These appear on the recommendation card with a `Needs external setup` label. The `MCPs to connect` count only covers integrations the install flow can connect automatically. You must configure externally-hosted integrations yourself before the automation can use them.
+
+
Automations run against the active backend. Use [Manage Backends](/openhands/usage/agent-canvas/backends) to see and switch which backend your automations run on.
## Edit an Automation's LLM Profile
@@ -31916,13 +33203,252 @@ After the automation is created:
- [Setup a Pre-built Automation](/openhands/usage/agent-canvas/prebuilt-automations)
- [Customize and Settings](/openhands/usage/agent-canvas/customize-and-settings)
+### Agent Canvas 1.10.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.10.0.md
+
+# Agent Canvas 1.10.0
+
+Released August 5, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.10.0).
+
+## Highlights
+
+- **Canvas default model set to GLM 5.2** — New conversations now use GLM 5.2 as the default model, providing a better out-of-the-box experience without requiring manual model selection.
+- **Activity Log export** — Users can export the full Activity Log for a conversation, making it easier to share agent trajectories and audit work outside of Canvas.
+- **Featured Automations dashboard** — A new landing dashboard surfaces featured automations, helping users discover and set up prebuilt workflows directly from the home screen.
+- **Faceted skills filter** — The skills page now includes a faceted filter rail, letting users quickly narrow down skills by category, source, or status.
+- **Manifest-driven automation sub-pages** — Automations can now define their own sub-pages via a manifest, enabling richer configuration UIs without custom frontend code.
+
+## Improvements and fixes
+
+- Automation timeout cap is now derived from the deployment configuration, preventing runs from being silently capped by stale defaults.
+- Sidebar conversation links are pinned to the correct backend identity, fixing broken navigation when multiple backends are connected.
+- Local proxy targets now use IPv4 loopback addresses, resolving connection failures on systems where IPv6 loopback is not configured.
+- Resolved all npm audit vulnerabilities reported in the frontend dependency tree.
+- MCP server credentials are preserved during Canvas settings mutations, preventing credential loss when toggling or editing other settings.
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.10.0)
+- [Compare v1.9.0 to v1.10.0](https://github.com/OpenHands/OpenHands/compare/v1.9.0...v1.10.0)
+
+### Agent Canvas 1.11.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.11.0.md
+
+# Agent Canvas 1.11.0
+
+Released August 7, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.11.0).
+
+## Highlights
+
+- **Per-run LLM cost in Activity Log** — Each Activity Log entry and CSV export now includes the LLM cost for that run, giving users visibility into spending at the conversation level.
+- **Typed agent action for child conversations** — A new typed action lets agents programmatically launch local or Cloud child conversations, enabling structured delegation workflows.
+- **Automation tag filter and recognition** — Automations can now be tagged, and the UI supports filtering by tags so users can organize and find automations faster.
+- **Conversation tag chips** — Conversations display tag chips with overflow and hovercard labels, making it easier to identify and group conversations by category.
+- **Customize navigation reordered** — The Customize page navigation has been reorganized for a more logical flow between settings sections.
+- **Version update UI polished** — The Agent Canvas version update experience has been refined with clearer status indicators and smoother transitions.
+- **Automations pane always visible** — The home screen Automations pane now stays visible even when no automations are installed, guiding users toward setup.
+
+## Improvements and fixes
+
+- Multi-size application icons are now shipped for both Windows and macOS, eliminating blurry or missing icons in taskbars and docks.
+- The desktop app has been renamed to "OpenHands Agent Canvas" for consistency across platforms.
+- Runtime metrics now fetch the conversation directly instead of going through a removed cloud-proxy endpoint, fixing a broken metrics path.
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.11.0)
+- [Compare v1.10.0 to v1.11.0](https://github.com/OpenHands/OpenHands/compare/v1.10.0...v1.11.0)
+
+### Agent Canvas 1.12.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.12.0.md
+
+# Agent Canvas 1.12.0
+
+Released August 7, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.12.0).
+
+## Highlights
+
+- **Clarified free OpenHands model endpoints** — The free OpenHands model offerings now have clearer endpoint labeling, helping users understand which models are available at no cost and how to select them.
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.12.0)
+- [Compare v1.11.0 to v1.12.0](https://github.com/OpenHands/OpenHands/compare/v1.11.0...v1.12.0)
+
+### Agent Canvas 1.13.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.13.0.md
+
+# Agent Canvas 1.13.0
+
+Released August 13, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.13.0).
+
+## Highlights
+
+- **Context window usage meter and manual compaction** — A new context-window usage meter, usage drawer, and manual compaction control let users monitor and manage token consumption in real time, preventing unexpected context overflow.
+- **Client-side conversation archive** — Users can archive conversations directly from the sidebar, keeping the active conversation list clean without permanently deleting work.
+- **Inline markdown artifact previews** — Markdown artifacts rendered in chat now show inline previews, reducing the need to open a separate viewer for common output formats.
+- **Ready-for-dev issue readiness gate** — A new readiness gate enforces type-specific criteria before issues are marked ready for development, improving workflow discipline.
+
+## Improvements and fixes
+
+- A postinstall message now explains how to start Agent Canvas after installation.
+- Agent-server telemetry is now correctly configured when launched from Canvas.
+- Overflow menus are now usable on touch devices, fixing a long-standing mobile interaction issue.
+- The sidebar "Load more" button now correctly discovers folders rather than expanding folder contents prematurely.
+- Chat input drag-resize is disabled when the input is not bottom-anchored, preventing unexpected layout shifts.
+- Non-MCP-installable automation integrations are now surfaced instead of being silently dropped.
+- A flaky `ProgressEvent` unhandled rejection in CI has been resolved.
+- Launcher services are spawned without an implicit shell, improving reliability across environments.
+- The Basic LLM provider list no longer truncates at 100 entries, ensuring all available providers are visible.
+- The context meter ring track is now drawn from the foreground color instead of a border token, fixing visual inconsistency.
+- Pending MSW callbacks are drained before jsdom teardown, eliminating a `ProgressEvent` `ReferenceError` in tests.
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.13.0)
+- [Compare v1.12.0 to v1.13.0](https://github.com/OpenHands/OpenHands/compare/v1.12.0...v1.13.0)
+
+### Agent Canvas 1.14.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.14.0.md
+
+# Agent Canvas 1.14.0
+
+Released August 17, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.14.0).
+
+## Highlights
+
+- **Structured error outcomes** — Agent errors are now presented as structured outcomes in the UI, making it easier to understand what went wrong and what action to take next.
+- **LLM pre-flight validation** — A pre-flight check validates LLM configuration before saving a profile, preventing misconfigured profiles from being saved and causing failures at run time.
+- **Git Sync page for automations** — A new Git Sync page lets automation authors manage how their automation repositories stay in sync, streamlining the automation development lifecycle.
+- **Canvas default model set to Kimi K3** — New conversations now default to Kimi K3, which is tagged as free, lowering the barrier to entry for new users.
+
+## Improvements and fixes
+
+- Onboarding now preselects the OpenHands LLM provider after picking the OpenHands agent, reducing friction during first-time setup.
+- Backend scope is preserved in conversation links, fixing broken navigation when switching between multiple backends.
+- The `VITE_BACKEND_BASE_URL` is no longer baked at build time during `npm run dev`, allowing developers to point at different backends without rebuilding.
+- Automation local responder URLs are now set from the browser origin, fixing webhook delivery in behind-proxy deployments.
+- The full workspace file tree is now shown in the Files tab on cloud backends, restoring visibility into nested directories.
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.14.0)
+- [Compare v1.13.0 to v1.14.0](https://github.com/OpenHands/OpenHands/compare/v1.13.0...v1.14.0)
+
+### Agent Canvas 1.15.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.15.0.md
+
+# Agent Canvas 1.15.0
+
+Released August 21, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.15.0).
+
+## Highlights
+
+- **Getting started checklist** — A new checklist in the sidebar helps users complete initial setup. Its visibility can be controlled in settings.
+- **Workspace paths in Files** — The Files view now shows the workspace path, making it easier to identify the folder currently being explored.
+- **Script-bundle automation installs** — Automation catalog entries can now install a bundled script along with the automation, supporting more complete automation setups.
+- **LLM provider connections** — Local agent-server users can manage LLM provider connections from a dedicated interface.
+- **Automation dashboard and discovery** — The automations dashboard, recommendations rail, and Add/Import flow have been updated to make finding and adding automations easier.
+- **Conversation overview and commits** — Conversations now include an overview panel and a unified commits drawer, bringing key conversation information and Git commits together.
+
+## Improvements and fixes
+
+- Agent profiles are no longer silently downgraded.
+- Grouped workspace views now show all folders even when pagination is in use.
+- The LLM selected from the home dropdown now takes precedence over an agent profile's pinned LLM.
+- The `Cmd`+`Enter` build shortcut now applies only in plan mode.
+- Long skill descriptions no longer hide modal actions.
+- PDF previews now render in the built-in viewer.
+- Agent Canvas no longer persists ACP model selections to agent settings when profile discovery fails.
+- The events socket stays alive across refetches and has a bounded handshake, improving connection reliability.
+- Streaming deltas are batched so the UI can keep up with faster models.
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.15.0)
+- [Compare v1.14.0 to v1.15.0](https://github.com/OpenHands/OpenHands/compare/v1.14.0...v1.15.0)
+
+### Agent Canvas 1.16.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.16.0.md
+
+# Agent Canvas 1.16.0
+
+Released August 27, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.16.0).
+
+## Highlights
+
+- **Supported-provider selector** — The "Add provider" connection flow now uses a searchable supported-provider selector instead of free text. Existing connections keep free-text editing.
+- **Linux desktop installer** — New Linux desktop installer artifacts (AppImage and deb) for the Agent Canvas desktop app.
+- **Live run phase for automations** — Automation runs now surface a live phase (PENDING/RUNNING/FAILED) on cards, the activity log, and home; the phase is exported in CSV/JSON activity logs.
+- **LLM-switching toggle in Agent settings** — A new "Let the agent switch LLM profiles" toggle in the Agent profile editor controls whether the `SwitchLLMTool` is available to the agent.
+- **Explicit skill allow-list** — The skill catalog now defaults to an 11-skill allow-list instead of enabling all ~59 catalog skills; Customize gains a "Recommended" badge/facet.
+- **Canvas Extensions beta** — Add trusted custom pages and integrated tools to Agent Canvas without forking the application. Install and manage extensions in `Customize > Extensions`; see [Canvas Extensions (Beta)](/openhands/usage/agent-canvas/canvas-extensions).
+
+## Improvements and fixes
+
+- File paths in chat are now clickable and link to the Files drawer.
+- Onboarding is skipped when a user-added Local backend already has a usable LLM.
+- The default model is now OpenAI GPT-5.6 Sol, and DeepSeek V4 Flash is the sole free OpenHands-routed model.
+- The VSCode button now renders on self-hosted (local) backends, gated on editor capability.
+- The API key for the OpenHands provider is hidden on cloud.
+- The home screen remembers local workspace mode selection.
+- Conversation titles can be renamed on cloud backends.
+- The API key is validated before advancing the backend connection step.
+- Routine dependency bumps (software-agent-sdk 1.44.0, automation 1.9.0, extensions 0.19.0).
+
+## Full changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.16.0)
+- [Compare v1.15.0 to v1.16.0](https://github.com/OpenHands/OpenHands/compare/v1.15.0...v1.16.0)
+
+### Agent Canvas 1.17.0
+Source: https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.17.0.md
+
+# Agent Canvas 1.17.0
+
+Released September 9, 2026.
+
+[View the full release on GitHub](https://github.com/OpenHands/OpenHands/releases/tag/v1.17.0).
+
+## Highlights
+
+- **Apps beta** — Canvas Extensions is now called Apps in Agent Canvas. Manage trusted custom pages in `Customize > Apps`; the Canvas Extensions API and `canvas-extension.json` format remain unchanged. See [Apps (Beta)](/openhands/usage/agent-canvas/canvas-extensions).
+- **Local Plan Mode Enabled** — Plan, refine, and build from a plan on a self-hosted or local Agent Server backend.
+- **Conversation tags and filtering** — Add tags from a conversation row menu, show tag chips, and filter the conversation list by tags or automation name. See [Conversations](/openhands/usage/agent-canvas/conversations).
+- **Cloud LLM provider connections** — Cloud backends with an organization can manage and select shared provider connections in LLM settings.
+
+## Improvements and Fixes
+
+- Workspace hooks in `.openhands/hooks.json` now load automatically when you start a local Agent Canvas conversation. See [Hooks](/openhands/usage/customization/hooks).
+- Self-hosted deployments can opt out of product telemetry with `AGENT_CANVAS_DISABLE_TELEMETRY=1` (or `true`) or the `--disable-telemetry` runtime flag.
+- Automation permissions now distinguish viewing from managing automations. Users with view-only access can still manage automations they created.
+
+## Full Changelog
+
+- [GitHub release notes](https://github.com/OpenHands/OpenHands/releases/tag/v1.17.0)
+- [Compare v1.16.0 to v1.17.0](https://github.com/OpenHands/OpenHands/compare/v1.16.0...v1.17.0)
+
### Install Agent Canvas
Source: https://docs.openhands.dev/openhands/usage/agent-canvas/setup.md
The `agent-canvas` launcher can run the Canvas client with Agent Server, Automation Server, and ingress as an all-in-one local stack. Use npm or npx for direct local execution, or Docker for a containerized stack with explicit project mounts. You can also run the client separately and connect it to an existing backend.
- Agent Server and ACP processes can run shell commands, read files, write files, and use connected tools. Agent Canvas is the client and does not provide isolation. Treat the machine, container, or sandbox where the backend runs as trusted infrastructure. Before exposing backend services to a network you do not control, review [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm).
+ Treat agents and ACP processes as untrusted: they can run shell commands, read files, write files, and use connected tools within their execution environment. Agent Canvas is the client and does not provide isolation. If the backend runs directly on your machine, the agent can act with your user account's permissions. Use a container, sandbox, or VM to define a tighter boundary. Before exposing backend services to a network you do not control, review [VM / Self-Hosted Installation](/openhands/usage/agent-canvas/backend-setup/vm).
## Choose An Install Method
@@ -32224,7 +33750,7 @@ Uninstalling the package or image does not automatically remove your persisted d
## Desktop App (Preview Build)
-The Agent Canvas desktop app for macOS and Windows is an early preview build ready for user testing. It bundles the Node.js and `uv` runtimes, so you do not need to install prerequisites or keep a terminal open.
+The Agent Canvas desktop app for macOS, Windows, and Linux is an early preview build ready for user testing. It bundles the Node.js and `uv` runtimes, so you do not need to install prerequisites or keep a terminal open.
Please [join the OpenHands Slack community](https://openhands.dev/joinslack) to share feedback and [open an issue](https://github.com/OpenHands/OpenHands/issues) for problems you find while testing the preview.
@@ -32248,6 +33774,12 @@ Pre-built desktop releases support Apple silicon Macs. On an Intel Mac, use the
2. Run the installer. If Windows SmartScreen prompts you, confirm that you want to continue.
3. Launch Agent Canvas from the Start menu.
+**Linux**
+
+1. Download the `Agent-Canvas-.AppImage` or `Agent-Canvas-.deb` installer.
+2. For the AppImage, make the file executable and run it. For the deb, install it with your package manager (for example, `sudo apt install ./Agent-Canvas-.deb`).
+3. Launch Agent Canvas from your applications menu.
+
The desktop app starts its local backend automatically. During startup, select **Show details** to view and copy the live startup log. This is useful if startup takes longer than expected or fails.
### Troubleshooting and Lifecycle
@@ -32505,7 +34037,7 @@ If you changed the port with `--port`, use the port you selected.
## Model Or API Key Errors
-If a conversation fails before the agent responds, check `Settings > LLM`.
+If a conversation fails before the agent responds, check `Settings > LLM`. To choose the right provider, local endpoint, LiteLLM proxy, OpenRouter, or ACP path, start with [Configure a Model](/openhands/usage/agent-canvas/model-configuration).
Common causes:
@@ -32515,6 +34047,11 @@ Common causes:
- A LiteLLM proxy token is invalid.
- An OpenAI-compatible provider needs the provider, model, base URL, and key to line up.
+Agent Canvas classifies conversation errors and presents them with distinct banner variants:
+
+- **Recoverable errors** (such as authentication failures) are shown with a warning banner, indicating you can take action — for example, updating an API key or switching models.
+- **Internal errors** are shown with an error banner, indicating a problem that may require restarting the conversation or backend.
+
For model setup details, see:
- [Manage LLM Profiles](/openhands/usage/agent-canvas/llm-profiles)
@@ -32660,7 +34197,7 @@ https://github.com/OpenHands/OpenHands/assets/38853559/f592a192-e86c-4f48-ad31-d
_Example of CodeActAgent with `gpt-4-turbo-2024-04-09` performing a data science task (linear regression)_.
-### Sandbox Server REST API (V1)
+### REST API (V1)
Source: https://docs.openhands.dev/openhands/usage/api/v1.md
The [OpenHands Sandbox Server](https://github.com/OpenHands/sandbox-server) is the standalone API and sandbox control plane extracted from the former OpenHands monorepo. It exposes conversation and sandbox resources without bundling a frontend.
@@ -32675,7 +34212,7 @@ Sandbox Server V1 REST endpoints are mounted under:
- /api/v1
-Use these endpoints to integrate with the Sandbox Server control plane. Agent Canvas is the browser client for compatible deployments; Sandbox Server itself does not include a frontend.
+Use these endpoints to integrate with the Sandbox Server control plane. Sandbox Server itself does not include a frontend.
## Key resources
@@ -32741,7 +34278,7 @@ When asking OpenHands to create an automation, include:
- **What it should do**: Describe the task clearly
- **When it should run**: Daily, weekly, every hour, etc.
- **Timezone** (optional): Defaults to UTC if not specified
-- **Run timeout** (optional): Defaults to 10 minutes; maximum 30 minutes
+- **Run timeout** (optional): Defaults to 10 minutes; the maximum depends on your deployment
- **Name** (optional): The agent can suggest one based on your description
- **Plugins** (optional): Mention specific plugins if you need extended capabilities
@@ -33166,7 +34703,7 @@ Update the "Weekly Cleanup" automation to run on Sundays at 2 AM UTC
Set the "Weekly Cleanup" automation timeout to 20 minutes
```
-Timeouts can be up to 30 minutes. Runs that exceed their timeout fail automatically.
+The maximum timeout depends on your deployment. Runs that exceed their timeout fail automatically.
## Running Manually
@@ -33196,6 +34733,8 @@ Each run creates a conversation that automatically appears in your conversations
- **Continue** if you want to interact with the sandbox
- **Debug** if something went wrong
+In an automation's `Activity Log`, use `Export JSON` or `Export CSV` to download its complete run history.
+
Automations are user-scoped, so all your automation runs appear alongside your regular conversations. Look for them in your conversations list after each scheduled run.
@@ -36393,74 +37932,97 @@ AWS Bedrock provides access to foundation models from Amazon and third-party pro
### Environment Variables
-When running OpenHands with Docker, set the following environment variables using `-e`:
+When running Agent Canvas with the [official Docker image](/openhands/usage/agent-canvas/backend-setup/docker), add these options to the documented `docker run` command:
```bash
-docker run -it --pull=always \
- -e LLM_AWS_ACCESS_KEY_ID="your-access-key-id" \
- -e LLM_AWS_SECRET_ACCESS_KEY="your-secret-access-key" \
- -e LLM_AWS_REGION_NAME="us-east-1" \
- ...
+--env LLM_AWS_ACCESS_KEY_ID="your-access-key-id" \
+--env LLM_AWS_SECRET_ACCESS_KEY="your-secret-access-key" \
+--env LLM_AWS_REGION_NAME="us-east-1"
```
+The official `ghcr.io/openhands/agent-canvas:latest` image includes the AWS SDK for Python (`boto3`).
+
Make sure you have enabled the Bedrock models you want to use in the AWS Console. Go to **Amazon Bedrock** → **Model access** and request access to the models you need.
### UI Configuration
-In the OpenHands UI Settings under the `LLM` tab:
+In Agent Canvas:
-1. Enable `Advanced` options
-2. Set the following:
- - `Custom Model` to the Bedrock model ID (see [Model IDs](#model-ids))
- - Leave `Base URL` empty (Bedrock uses AWS endpoints automatically)
- - Leave `API Key` empty (authentication is handled via AWS credentials)
+1. Open `Settings > LLM` and enable the `Advanced` options.
+2. Set `Custom Model` to the Bedrock model or inference profile ID. See [Model IDs](#model-ids).
+3. Leave `Base URL` empty because Bedrock uses AWS endpoints automatically.
+4. Leave `API Key` empty because authentication is handled through your AWS credentials.
+5. Save the profile and start a new conversation to test it.
+
+See [Manage LLM Profiles](/openhands/usage/agent-canvas/llm-profiles) for more information about profile settings.
### Model IDs
Bedrock model IDs are managed by AWS and may change over time. Use the exact **Model ID** from the AWS Console or the AWS documentation (no `bedrock/` prefix).
Example format:
+
- `Custom Model`: `anthropic.claude-3-5-sonnet-20241022-v2:0`
For a complete list of available models, see the [AWS Bedrock documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html).
### Cross-Region Inference
-Some Bedrock models can be invoked across regions by prefixing the model ID with the target region (for example, `us.`):
+Some models must be invoked through a cross-region inference profile rather than their direct foundation model ID. Inference profile IDs include a geographic prefix such as `us.`.
+
+For example, use:
+
+- `Custom Model`: `us.anthropic.claude-sonnet-4-5-20250929-v1:0`
+
+instead of the direct model ID:
-- `Custom Model`: `.`
+- `anthropic.claude-sonnet-4-5-20250929-v1:0`
-No additional environment variable configuration is needed—keep using your normal Bedrock setup and credentials.
+No additional environment variables are required. Keep using the AWS region where you configured Bedrock access and your existing credentials. See [Increase throughput with cross-region inference](https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html) for supported profiles and regions.
### Using IAM Roles (Alternative to Access Keys)
-If running OpenHands on AWS infrastructure (EC2, ECS, Lambda), you can use IAM roles instead of access keys:
+If running OpenHands on AWS infrastructure such as EC2, ECS, or Lambda, you can use IAM roles instead of access keys:
-1. Attach an IAM role with Bedrock permissions to your compute resource
-2. Omit the `LLM_AWS_ACCESS_KEY_ID` and `LLM_AWS_SECRET_ACCESS_KEY` environment variables
-3. The AWS SDK will automatically use the instance role credentials
+1. Attach an IAM role with Bedrock permissions to your compute resource.
+2. Omit the `LLM_AWS_ACCESS_KEY_ID` and `LLM_AWS_SECRET_ACCESS_KEY` environment variables.
+3. The AWS SDK automatically uses the instance role credentials.
### Troubleshooting
#### "No module named 'boto3'" Error
If you encounter this error:
-```
+
+```text
litellm.APIConnectionError: No module named 'boto3'
ModuleNotFoundError: No module named 'boto3'
```
-This means you're using an older version of the OpenHands Docker image that doesn't include the AWS SDK. Update to the latest version:
+First identify how you installed Agent Canvas:
-```bash
-docker pull docker.openhands.dev/openhands/openhands:latest
+- **Docker:** The current `ghcr.io/openhands/agent-canvas:latest` image includes `boto3`. Pull the latest image and recreate the container:
+
+ ```bash
+ docker pull ghcr.io/openhands/agent-canvas:latest
+ ```
+
+- **npm or npx:** The Python environment managed by the npm distribution may not include the optional Bedrock dependency. Follow [OpenHands issue #16578](https://github.com/OpenHands/OpenHands/issues/16578) for the package fix. Use the official Agent Canvas Docker image if you need Bedrock while that issue remains open.
+
+Do not install `boto3` into a temporary uv archive environment because Agent Canvas may recreate that environment.
+
+#### On-Demand Throughput Is Not Supported
+
+Some foundation model IDs cannot be invoked directly and return an error similar to:
+
+```text
+Invocation of model ID ... with on-demand throughput isn't supported.
+Retry your request with the ID or ARN of an inference profile that contains this model.
```
-
-This issue is resolved in recent OpenHands releases. If you still see it, upgrade to `latest` (or a recent release tag).
-
+Use the corresponding inference profile ID or ARN, such as `us.anthropic.claude-sonnet-4-5-20250929-v1:0`. This error does not indicate a credential, model access, or `boto3` problem.
#### Access Denied Errors
@@ -36819,6 +38381,20 @@ page focuses on how the OpenHands interfaces surface those capabilities. When in
for the canonical list of supported parameters.
+## Choose a Model Configuration Path
+
+Choose the path that matches the access you have:
+
+| I have | Start here |
+|---|---|
+| An API key from a model provider or OpenHands | [Configure a Model in Agent Canvas](/openhands/usage/agent-canvas/model-configuration) |
+| A local model server such as Ollama, LM Studio, vLLM, or SGLang | [Run Local LLMs with OpenHands](/openhands/usage/llms/local-llms) |
+| A LiteLLM proxy | [LiteLLM Proxy](/openhands/usage/llms/litellm-proxy) |
+| An OpenRouter API key | [Use OpenRouter with OpenHands](/openhands/usage/llms/openrouter) |
+| Claude Code, Codex, or Gemini CLI credentials | [ACP Agents](/openhands/usage/agent-canvas/acp-agents) |
+
+For model-ID, endpoint, API-key, and recovery checks, use [Configure a Model](/openhands/usage/agent-canvas/model-configuration) before changing advanced settings.
+
## Model Recommendations
Model quality for coding agents changes quickly. These recommendations are based on current
@@ -36955,6 +38531,17 @@ Source: https://docs.openhands.dev/openhands/usage/llms/local-llms.md
Use this guide when you want a local model, rather than a local Agent Canvas backend or local project files. Local LLMs can have limited functionality; use a capable model and GPU-backed server for the best experience.
+## Choose What You Mean by Local
+
+| If you want... | Start here |
+|---|---|
+| A model server on your computer or network | Continue with this guide. |
+| Agent Canvas itself to run on your computer | [Install Agent Canvas](/openhands/usage/agent-canvas/setup) |
+| A containerized Agent Canvas backend | [Use Docker with Agent Canvas](/openhands/usage/agent-canvas/backend-setup/docker) |
+| The agent to work with local files | [Connect and Manage Backends](/openhands/usage/agent-canvas/backends) |
+
+For the model ID, base URL, and recovery checks that connect a local server to Agent Canvas, see [Configure a Model](/openhands/usage/agent-canvas/model-configuration).
+
## News
- 2026/05/21: We now recommend [Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwen3.6-35B-A3B) as the first local model to try with OpenHands. It is an open-weight MoE model built for agentic coding, supports a large context window, and is available through LM Studio, Ollama, vLLM, and SGLang.
@@ -37401,18 +38988,36 @@ Pricing follows official API provider rates. Below are the current pricing detai
**Note:** Prices listed reflect provider rates with no markup, sourced via LiteLLM’s model price database and provider pricing pages. Cached input tokens are charged at a reduced rate when the same content is reused across requests. Models that don't support prompt caching show "N/A" for cached input cost.
-### OpenRouter
+### Use OpenRouter with OpenHands
Source: https://docs.openhands.dev/openhands/usage/llms/openrouter.md
-## Configuration
+Use OpenRouter when you have an OpenRouter API key and want to access a model from its [model catalog](https://openrouter.ai/models).
-When running OpenHands, you'll need to set the following in the OpenHands UI through the Settings under the `LLM` tab:
-* `LLM Provider` to `OpenRouter`
-* `LLM Model` to the model you will be using.
-[Visit here to see a full list of OpenRouter models](https://openrouter.ai/models).
-If the model is not in the list, enable `Advanced` options, and enter it in
-`Custom Model` (e.g. openrouter/<model-name> like `openrouter/anthropic/claude-3.5-sonnet`).
-* `API Key` to your OpenRouter API key.
+## Configure Agent Canvas
+
+1. Open `Settings > LLM`.
+2. In the `Basic` tab, select `OpenRouter` as the provider.
+3. Select a model, enter your OpenRouter API key, and save the profile.
+4. Start a new conversation and send a short message to verify the model responds.
+
+If the model is not in the selector, use the `Advanced` tab and enter its model ID with the `openrouter/` prefix. For example, OpenRouter model ID `anthropic/claude-3.5-sonnet` becomes:
+
+```text
+openrouter/anthropic/claude-3.5-sonnet
+```
+
+Copy the current model ID from the [OpenRouter model catalog](https://openrouter.ai/models). Model availability and IDs can change, so do not rely on a previously saved identifier without checking it.
+
+## Fix Common Problems
+
+| Problem | Check | Next step |
+|---|---|---|
+| Model is not found | The exact OpenRouter model ID | Copy the ID from the model catalog and add the `openrouter/` prefix in `Advanced`. |
+| Authentication fails | The API key | Create or copy an active OpenRouter API key, then save the profile again. |
+| The model is unavailable | The selected model in the catalog | Choose an available model or check your OpenRouter account and model access. |
+| The model does not complete agent tasks reliably | Model context and tool-use support | Choose a more capable model that supports the features required for your task. |
+
+For the broader configuration decision and local/proxy recovery paths, see [Configure a Model](/openhands/usage/agent-canvas/model-configuration). For LiteLLM's provider behavior, see [LiteLLM's OpenRouter documentation](https://docs.litellm.ai/docs/providers/openrouter).
### Configure
Source: https://docs.openhands.dev/openhands/usage/run-openhands/gui-mode.md
@@ -38052,6 +39657,10 @@ To override the defaults:
for commits and pull requests. OpenHands will remain as a co-author.
+## Getting Started Checklist
+
+The sidebar shows a **Getting Started** checklist after first-run onboarding. Toggle `Show getting started checklist` in `Settings > Application` to hide or show it. The setting persists across sessions. See [First Time Setup](/openhands/usage/agent-canvas/first-time-setup#getting-started-checklist) for details.
+
## Sandbox Grouping Strategy
The `Sandbox Grouping Strategy` setting controls where OpenHands places new
@@ -38285,6 +39894,12 @@ for new conversations.
Alternatively, you can click the `Add LLM Profile` button in the Available Profiles section to create a new profile
directly.
+
+When saving a local LLM profile, the configuration is validated against the backend before it is persisted. If validation
+fails (for example, an invalid API key or unavailable model), the save is blocked and the error is shown. Older backends
+that do not support validation skip this check and save normally.
+
+
### Managing LLM Profiles
You can manage your saved profiles in the `Available Profiles` section of the LLM settings page. Each profile shows:
@@ -38618,7 +40233,7 @@ Other options include:
In Agent Canvas, open `Customize > MCP Servers` to manage installed MCP servers. Use the control on an installed server card to disable it without deleting its configuration or saved credentials. Disabled servers are unavailable to new conversations until you enable them again.
-Use the editor's delete action only when you want to remove the server configuration. Editing a disabled server does not enable it.
+Adding, editing, renaming, or deleting one server does not remove saved credentials for your other servers. Use the editor's delete action only when you want to remove that server configuration. Editing a disabled server does not enable it.
## OAuth Authentication
@@ -39647,6 +41262,251 @@ After creating the automation:
- [GitHub Integration](/openhands/usage/cloud/github-installation) - Set up GitHub integration for OpenHands Cloud
- [Skills Documentation](/overview/skills) - Learn more about OpenHands skills
+### Agent-Driven Daily Workflow
+Source: https://docs.openhands.dev/openhands/usage/use-cases/daily-workflow.md
+
+
+
+This guide shows how to use the OpenHands Agent Canvas as a daily development work queue. The agent gathers work from GitHub and Slack, organizes it by urgency, gives you one task at a time, and can dispatch separate agents for work that can happen in parallel.
+
+The video above demonstrates the same workflow for readers who prefer a video walkthrough. You do not need to watch it to follow this guide.
+
+## What you will build
+
+At the end of this guide, one Agent Canvas conversation will:
+
+1. Collect pull requests, issues, notifications, and relevant Slack activity.
+2. Produce a prioritized report with links and a recommended first task.
+3. Help you complete that task or start a separate agent to work on another task.
+4. Continue with the next task when you are ready.
+
+## Prerequisites
+
+
+- [Install and start Agent Canvas](/openhands/usage/agent-canvas/setup).
+- Complete [first-time setup](/openhands/usage/agent-canvas/first-time-setup), including an OpenHands agent profile, a connected backend, and an LLM.
+- A GitHub account with access to the repositories you want to review.
+- A Slack workspace and permission to create or install a Slack app.
+
+
+
+The MCP library lists built-in integrations, including GitHub and Slack. Choose the HTTP Slack integration shown here when following this guide.
+The workflow can use other MCP integrations, such as Linear or Jira, but the examples below use GitHub and Slack.
+
+
+
+## Step 1: Connect GitHub
+
+The agent needs GitHub access to find assigned issues, pull requests that need your attention, review requests, notifications, and CI results.
+
+### Create a GitHub token
+
+1. Open [GitHub Developer Settings](https://github.com/settings/tokens).
+2. Select **Fine-grained tokens** and choose **Generate new token**.
+3. Give the token a name, select **Only select repositories** when possible, and set an expiration date.
+4. Grant the minimum permissions for the work you want the agent to do:
+
+| Purpose | Permissions |
+|---|---|
+| Gather and report work | `Metadata: read`, `Contents: read`, `Issues: read`, `Pull requests: read`, `Actions: read`, `Checks: read` |
+| Work on code or issues | Add `Contents: write` and `Issues: write` |
+| Update pull requests or post reviews | Add `Pull requests: write` |
+
+5. Generate the token and copy it. GitHub shows it only once.
+
+
+
+The GitHub server dialog shows where to enter the server token and save it as a backend secret.
+### Add the GitHub MCP server
+
+Use the backend where this conversation will run. The MCP server and its saved secret belong to that backend.
+
+1. In Agent Canvas, confirm the correct backend in the backend switcher.
+2. Open **Customize** in the left navigation.
+3. Open **MCP Servers**.
+4. Select **GitHub** from the MCP library.
+5. Paste the token into the token field.
+6. Leave the option to create a secret enabled, then save the server.
+7. Wait for the server card to report a healthy connection.
+
+See [MCP server settings](/openhands/usage/settings/mcp-settings) for general configuration and troubleshooting details. Do not paste tokens into the conversation itself.
+
+## Step 2: Connect Slack
+
+Slack access lets the agent find mentions, threads, and messages that need your response. The bot can read only channels it can access.
+
+### Create and install a Slack app
+
+1. Open the [Slack API dashboard](https://api.slack.com/apps) and select **Create New App** → **From scratch**.
+2. Choose the workspace where the app will read messages.
+3. In **OAuth & Permissions**, add these bot scopes:
+
+| Scope | Purpose |
+|---|---|
+| `channels:read` | List public channels |
+| `channels:history` | Read public-channel messages |
+| `groups:history` | Read private-channel messages where the bot is a member |
+| `users:read` | Resolve people mentioned in messages |
+| `chat:write` | Allow the agent to post replies when you explicitly ask it to |
+
+4. Select **Install to Workspace**, approve the permissions, and copy the **Bot User OAuth Token**.
+5. Invite the bot to each channel it should monitor. The bot cannot read channels it has not joined.
+6. Find your workspace ID from your Slack workspace URL or [Slack's workspace-ID guide](https://slack.com/help/articles/221769328-Locate-your-Slack-URL-or-ID).
+
+
+
+The built-in Slack integration dialog shows the workspace ID and bot-token fields, along with the option to save each value as a secret.
+### Add the Slack MCP server
+
+The same **Customize → MCP Servers** screen is used for Slack.
+
+1. In Agent Canvas, open **Customize** → **MCP Servers**.
+2. Select **Slack** from the MCP library.
+3. Paste the bot token and enter the workspace ID.
+4. Keep secret creation enabled and save the server.
+5. Wait for a healthy connection, then verify that the bot can access the channels you want to search.
+
+## Step 3: Start the daily workflow conversation
+
+
+Create a new conversation in Agent Canvas and send this prompt:
+
+
+
+```
+Do my daily workflow using the connected GitHub and Slack MCP servers.
+
+Gather:
+- pull requests that need my attention or review
+- assigned issues
+- GitHub notifications and failing CI
+- Slack mentions, threads, and messages that need a response
+
+Group the results by urgency. For every item, include its title, why it matters,
+and a direct link. End with the single highest-priority task for me to start.
+Do not make changes or send messages without asking me first.
+```
+
+
+
+If you use Linear, Jira, or another connected service, add it explicitly to the prompt. For example:
+
+```
+Also check my assigned Linear issues and current cycle.
+```
+
+The agent may ask clarifying questions, such as which repositories or Slack channels to include. Answer those questions before asking it to produce the final report.
+
+## Step 4: Read the prioritized report
+
+Ask for a report in this format if the first response is not organized clearly:
+
+```
+Organize the results into:
+1. Immediate action
+2. PRs waiting for my response
+3. PRs requesting my review
+4. Assigned issues
+5. Slack highlights
+6. GitHub notifications
+
+Sort each section by urgency. Include direct links and finish by recommending one first task.
+```
+
+A useful report looks like this:
+
+```text
+## Immediate action
+- Fix failing CI on PR #123 — blocking the release —
+
+## PRs waiting for my response
+- Address requested changes on PR #456 —
+
+## PRs requesting my review
+- Review PR #789 — changes authentication behavior —
+
+## Assigned issues
+- Document the new API behavior —
+
+## Slack highlights
+- Reply to the deployment question in #engineering —
+
+## GitHub notifications
+- Workflow failure on repository-name —
+
+## First task
+Fix the failing CI on PR #123.
+```
+
+The report is a starting point, not a guarantee that every source contains actionable work. Ask the agent to search a specific repository, channel, or date range when an important item is missing.
+
+## Step 5: Work through one task at a time
+
+When the agent recommends a task:
+
+1. Ask for links if the report does not include them: `Give me the links for that task.`
+2. Tell the agent whether you want investigation, implementation, or only a summary.
+3. Set the safety boundary before it changes anything. For example:
+
+```
+Inspect the failing CI on PR #123, explain the root cause, and propose a fix.
+Do not edit files, push changes, or comment on GitHub until I approve the plan.
+```
+
+4. After reviewing the result, ask it to implement the approved change, run the relevant checks, and report what changed.
+5. When the task is complete, ask:
+
+```
+I finished that task. Re-check the remaining work and give me the next highest-priority item.
+```
+
+The agent can inspect and edit files in its configured workspace, but its ability to push code, update GitHub, or post to Slack depends on the permissions granted to the MCP servers and the confirmation policy you use.
+
+## Step 6: Dispatch parallel work
+
+Use a separate agent only for work that is independent of the task you are handling. For example:
+
+```
+Start a separate agent to inspect the failing CI and unaddressed review comments
+on my other open pull requests. It may modify files in its own workspace and
+run tests, but it must not push, merge, or post comments. Return a summary and
+proposed changes when finished.
+```
+
+Before dispatching, specify:
+
+- Which repositories, pull requests, or issues it may access
+- Whether it may edit files
+- Which tests it should run
+- Whether it may push branches or post comments
+- What it should return when finished
+
+Keep related changes in separate workspaces or branches to avoid overwriting your active work. Review a subagent's summary and diff before asking it to push or make external changes. You can continue the original conversation while the separate agent runs, then inspect its conversation from the Agent Canvas conversation list.
+
+## Troubleshooting
+
+- **The agent cannot find GitHub work:** confirm the GitHub MCP server is healthy, the token includes the required repositories, and the token has not expired.
+- **Slack results are empty:** confirm the bot is installed in the workspace and invited to each channel you want to search.
+- **The agent reports no tools:** start a new conversation after adding or changing an MCP server; MCP configuration is loaded when a conversation starts.
+- **The report is too broad:** name the repositories, Slack channels, date range, or task categories to include.
+- **The agent tries to act too early:** state that it must ask for approval before editing files, pushing, or posting messages.
+
+## Reference
+
+- [Daily workflow video](https://youtu.be/S_wap45Iq8U) — optional video walkthrough
+- [Agent Canvas overview](/openhands/usage/agent-canvas/overview)
+- [Agent Canvas first-time setup](/openhands/usage/agent-canvas/first-time-setup)
+- [MCP server settings](/openhands/usage/settings/mcp-settings)
+- [Agent Canvas configuration](/openhands/usage/agent-canvas/customize-and-settings)
+
### Dependency Upgrades
Source: https://docs.openhands.dev/openhands/usage/use-cases/dependency-upgrades.md
@@ -40278,6 +42138,13 @@ Each use case can be implemented in different ways—as a one-off conversation,
>
Automate dependency updates, handle breaking changes, and validate applications.
+
+ Orchestrate your entire daily development routine through AI agents — from triage to task execution to parallel remediation.
+
- The V0 API is deprecated since version 1.0.0 and will be removed on **April 1, 2026**.
- New integrations should use the V1 API documented above.
-
-
-### Starting a New Conversation (V0)
-
-
-
- ```bash
- curl -X POST "https://app.all-hands.dev/api/conversations" \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "initial_user_msg": "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so.",
- "repository": "yourusername/your-repo"
- }'
- ```
-
-
- ```python
- import requests
-
- api_key = "YOUR_API_KEY"
- url = "https://app.all-hands.dev/api/conversations"
-
- headers = {
- "Authorization": f"Bearer {api_key}",
- "Content-Type": "application/json"
- }
-
- data = {
- "initial_user_msg": "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so.",
- "repository": "yourusername/your-repo"
- }
-
- response = requests.post(url, headers=headers, json=data)
- conversation = response.json()
-
- print(f"Conversation Link: https://app.all-hands.dev/conversations/{conversation['conversation_id']}")
- print(f"Status: {conversation['status']}")
- ```
-
-
- ```typescript
- const apiKey = "YOUR_API_KEY";
- const url = "https://app.all-hands.dev/api/conversations";
-
- const headers = {
- "Authorization": `Bearer ${apiKey}`,
- "Content-Type": "application/json"
- };
-
- const data = {
- initial_user_msg: "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so.",
- repository: "yourusername/your-repo"
- };
-
- async function startConversation() {
- try {
- const response = await fetch(url, {
- method: "POST",
- headers: headers,
- body: JSON.stringify(data)
- });
-
- const conversation = await response.json();
-
- console.log(`Conversation Link: https://app.all-hands.dev/conversations/${conversation.conversation_id}`);
- console.log(`Status: ${conversation.status}`);
-
- return conversation;
- } catch (error) {
- console.error("Error starting conversation:", error);
- }
- }
-
- startConversation();
- ```
-
-
-
-#### Response (V0)
-
-```json
-{
- "status": "ok",
- "conversation_id": "abc1234"
-}
-```
-
### Cloud UI
Source: https://docs.openhands.dev/openhands/usage/cloud/cloud-ui.md
@@ -43061,59 +44833,193 @@ At some point, we may transfer custody of OpenHands to an open source foundation
### Contributing
Source: https://docs.openhands.dev/overview/contributing.md
-# Contributing To OpenHands
+# Contributing to OpenHands
-OpenHands is developed across several repositories. Choose the repository that owns the component you want to change, then follow that repository's setup and contribution guidance.
+Welcome to the OpenHands community! We're building the future of AI-powered software development, and we'd love for you to be part of this journey.
-## Find The Right Repository
+## Our Vision: Free as in Freedom
-| Area | Repository | Guidance | Issues | License |
-|------|------------|----------|--------|---------|
-| **Agent Canvas** | [`OpenHands/OpenHands`](https://github.com/OpenHands/OpenHands) | [README](https://github.com/OpenHands/OpenHands#quickstart) and [development docs](https://github.com/OpenHands/OpenHands/tree/main/docs) | [Issues](https://github.com/OpenHands/OpenHands/issues) | [License](https://github.com/OpenHands/OpenHands/blob/main/LICENSE) |
-| **Software Agent SDK and Agent Server** | [`OpenHands/software-agent-sdk`](https://github.com/OpenHands/software-agent-sdk) | [Development guide](https://github.com/OpenHands/software-agent-sdk/blob/main/DEVELOPMENT.md) and [contribution guide](https://github.com/OpenHands/software-agent-sdk/blob/main/CONTRIBUTING.md) | [Issues](https://github.com/OpenHands/software-agent-sdk/issues) | [License](https://github.com/OpenHands/software-agent-sdk/blob/main/LICENSE) |
-| **Sandbox Server** | [`OpenHands/sandbox-server`](https://github.com/OpenHands/sandbox-server) | [README](https://github.com/OpenHands/sandbox-server#local-development) | [Issues](https://github.com/OpenHands/sandbox-server/issues) | [License](https://github.com/OpenHands/sandbox-server/blob/main/LICENSE) |
-| **OpenHands CLI** | [`OpenHands/OpenHands-CLI`](https://github.com/OpenHands/OpenHands-CLI) | [Contribution guide](https://github.com/OpenHands/OpenHands-CLI/blob/main/CONTRIBUTING.md) | [Issues](https://github.com/OpenHands/OpenHands-CLI/issues) | [License](https://github.com/OpenHands/OpenHands-CLI/blob/main/LICENSE) |
-| **Documentation** | [`OpenHands/docs`](https://github.com/OpenHands/docs) | [Repository guide](https://github.com/OpenHands/docs/blob/main/AGENTS.md) | [Issues](https://github.com/OpenHands/docs/issues) | Check the repository before reuse |
-| **Evaluations and benchmarks** | [`OpenHands/benchmarks`](https://github.com/OpenHands/benchmarks) | [Contribution guide](https://github.com/OpenHands/benchmarks/blob/main/CONTRIBUTING.md) | [Issues](https://github.com/OpenHands/benchmarks/issues) | [License](https://github.com/OpenHands/benchmarks/blob/main/LICENSE) |
+The OpenHands community is built around the belief that **AI and AI agents are going to fundamentally change the way we build software**, and if this is true, we should do everything we can to make sure that the benefits provided by such powerful technology are **accessible to everyone**.
-OpenHands Enterprise development is maintained privately. For an Enterprise support request or product question, use your support channel or [contact the OpenHands team](https://openhands.dev/enterprise).
+We believe in the power of open source to democratize access to cutting-edge AI technology. Just as the internet transformed how we share information, we envision a world where AI-powered development tools are available to every developer, regardless of their background or resources.
-
- The former OpenHands monorepo is preserved in the read-only [`OpenHands/legacy`](https://github.com/OpenHands/legacy) repository. Route active Canvas, SDK, Agent Server, Sandbox Server, CLI, and evaluation work to the repositories above.
-
+If this resonates with you, we'd love to have you join us in our quest!
+
+## 🚀 Getting Started
+
+Ready to contribute? Here's your path to making an impact:
-## Start Contributing
+### 1. Quick Wins
+Start with these easy contributions:
+- **Use OpenHands** and [report issues](https://github.com/OpenHands/OpenHands/issues) you encounter
+- **Give feedback** using the thumbs-up/thumbs-down buttons after each session
+- **Star our repository** on [GitHub](https://github.com/OpenHands/OpenHands)
+- **Share OpenHands** with other developers
-1. Open the repository that owns your change.
-2. Read its `README`, `AGENTS.md`, and contribution or development guide when present.
-3. Search the repository's existing issues and pull requests.
-4. For a substantial change, open or join an issue before implementation so maintainers can confirm the direction.
-5. Run the repository's required formatting, linting, and tests before opening a pull request.
+### 2. Set Up Your Development Environment
+Follow our setup guide:
+- **Requirements**: Node.js 22+, uv
+- **Quick setup**:
+```
+git clone https://github.com/OpenHands/OpenHands.git
+cd OpenHands
+npm install
+```
+- **Run locally**: `npm run dev` to start the application
+
+*Full details in [Development Guide](https://github.com/OpenHands/OpenHands/blob/main/docs/DEVELOPMENT.md)*
+
+### 3. Find Your First Issue
+Look for beginner-friendly opportunities:
+- Browse [good first issues](https://github.com/OpenHands/OpenHands/labels/good%20first%20issue)
+- Ask in [Slack](https://openhands.dev/joinslack) what needs help
+
+Issues labeled `ready-for-dev` meet the automated readiness criteria (clear reproduction, acceptance criteria) for development work — see [Issue Triage and the ready-for-dev Gate](/overview/issue-lifecycle) for how issues get labeled and what the pull request description check requires.
+
+### 4. Join the Community
+Connect with other contributors in our [Slack Community](https://openhands.dev/joinslack). You can connect with OpenHands contributors, maintainers, and more!
+
+## 📋 How to Contribute Code
+
+### Pull Request Process
+We welcome pull requests across our public repositories! Here's how we evaluate them:
+
+#### Small Improvements
+- Quick review and approval for obvious improvements
+- Make sure CI tests pass
+- Include clear description of changes
+
+#### Core Agent Changes
+We're more careful with agent changes since they affect user experience:
+- **Accuracy** - Does it make the agent better at solving problems?
+- **Efficiency** - Does it improve speed or reduce resource usage?
+- **Code Quality** - Is the code maintainable and well-tested?
+
+*Discuss major changes in [GitHub issues](https://github.com/OpenHands/OpenHands/issues) or [Slack](https://openhands.dev/joinslack) first!*
+
+### Pull Request Guidelines
+We recommend the following for smooth reviews but they're not required. Just know that the more you follow these guidelines, the more likely you'll get your PR reviewed faster and reduce the quantity of revisions.
+
+**Title Format:**
+- `feat: Add new agent capability`
+- `fix: Resolve memory leak in runtime`
+- `docs: Update installation guide`
+- `style: Fix code formatting`
+- `refactor: Simplify authentication logic`
+- `test: Add unit tests for parser`
+
+**Description:**
+- Explain what the PR does and why
+- Link to related issues
+- Include screenshots for UI changes
+- Add changelog entry for user-facing changes
+
+## What Can You Build?
+
+There are countless ways to contribute to OpenHands. Whether you're a seasoned developer, a researcher, a designer, or someone just getting started, there's a place for you in our community.
+
+*Small fixes are always welcome! For bigger changes, join our [Slack](https://openhands.dev/joinslack) first.*
+
+### Frontend & UI/UX
+Make OpenHands more beautiful and user-friendly:
+React & TypeScript Development - Improve the web interface
+UI/UX Design - Enhance user experience and accessibility
+Mobile Responsiveness - Make OpenHands work great on all devices
+Component Libraries - Build reusable UI components
-Good first issues are labeled per repository. Browse the [OpenHands organization repositories](https://github.com/orgs/OpenHands/repositories), or ask in the [OpenHands Slack community](https://openhands.dev/joinslack) if you are unsure where a change belongs.
+*Small fixes are always welcome! For bigger changes, join our `#agent-canvas` channel in [Slack](https://openhands.dev/joinslack) first.
-## Pull Request Guidance
-Keep pull requests focused on one component and explain:
+### Agent Development
+Help make our AI agents smarter and more capable:
+- **Prompt Engineering** - Improve how agents understand and respond
+- **New Agent Types** - Create specialized agents for different tasks
+- **Agent Evaluation** - Develop better ways to measure agent performance
+- **Multi-Agent Systems** - Enable agents to work together
-- What changed and why
-- Which issue the change addresses
-- How you tested it
-- Any user-facing behavior or compatibility impact
-- Screenshots for visible Agent Canvas changes
+*We use [SWE-bench](https://www.swebench.com/) to evaluate our agents. Join our [Slack](https://openhands.dev/joinslack) to learn more.*
-Follow the target repository's title, changelog, and review requirements. Architecture and agent-behavior changes usually need more design discussion than small bug fixes or documentation corrections.
+### Backend & Infrastructure
+Build the foundation that powers OpenHands:
+- **Python Development** - Core functionality and APIs
+- **Runtime Systems** - Docker containers and sandboxes
+- **Cloud Integrations** - Support for different cloud providers
+- **Performance Optimization** - Make everything faster and more efficient
-## Other Ways To Contribute
+### Testing & Quality Assurance
+Help us maintain high quality:
+- **Unit Testing** - Write tests for new features
+- **Integration Testing** - Ensure components work together
+- **Bug Hunting** - Find and report issues
+- **Performance Testing** - Identify bottlenecks and optimization opportunities
-- Report reproducible issues in the repository that owns the affected component.
-- Improve guides and API documentation in [`OpenHands/docs`](https://github.com/OpenHands/docs).
-- Add or improve evaluations in [`OpenHands/benchmarks`](https://github.com/OpenHands/benchmarks).
-- Answer questions and share feedback in the [OpenHands Slack community](https://openhands.dev/joinslack).
+### Documentation & Education
+Help others learn and contribute:
+- **Technical Documentation** - API docs, guides, and tutorials
+- **Video Tutorials** - Create learning content
+- **Translation** - Make OpenHands accessible in more languages
+- **Community Support** - Help other users and contributors
-## Community Standards
+### Research & Innovation
+Push the boundaries of what's possible:
+- **Academic Research** - Publish papers using OpenHands
+- **Benchmarking** - Develop new evaluation methods
+- **Experimental Features** - Try cutting-edge AI techniques
+- **Data Analysis** - Study how developers use AI tools
-Follow the community and contribution guidance in the repository you are changing. Be respectful, provide enough context for maintainers to reproduce problems, and keep technical discussion focused on the proposed change.
+## Becoming a Maintainer
+
+For contributors who have made significant and sustained contributions to the project, there is a possibility of joining the maintainer team.
+The process for this is as follows:
+
+1. Any contributor who has made sustained and high-quality contributions to the codebase can be nominated by any maintainer. If you feel that you may qualify you can reach out to any of the maintainers that have reviewed your PRs and ask if you can be nominated.
+2. Once a maintainer nominates a new maintainer, there will be a discussion period among the maintainers for at least 3 days.
+3. If no concerns are raised the nomination will be accepted by acclamation, and if concerns are raised there will be a discussion and possible vote.
+
+Note that just making many PRs does not immediately imply that you will become a maintainer. We will be looking at sustained high-quality contributions over a period of time, as well as good teamwork and adherence to our [Code of Conduct](https://github.com/OpenHands/OpenHands/blob/main/CODE_OF_CONDUCT.md).
+
+## License
+
+OpenHands is released under the **MIT License**, which means:
+
+### You Can:
+- **Use** OpenHands for any purpose, including commercial projects
+- **Modify** the code to fit your needs
+- **Share** your modifications
+- **Distribute** or sell copies of OpenHands
+
+### You Must:
+- **Include** the original copyright notice and license text
+- **Preserve** the license in any substantial portions you use
+
+### No Warranty:
+- OpenHands is provided "as is" without warranty
+- Contributors are not liable for any damages
+
+*Full license text: [LICENSE](https://github.com/OpenHands/OpenHands/blob/main/LICENSE)*
+
+**Special Note:** Content in the `enterprise/` directory has a separate license, and we cannot accept external pull requests for changes to this directory at this time. See `enterprise/LICENSE` for details.
+
+## Ready to make your first contribution?
+
+1. **⭐ Star** our [GitHub repository](https://github.com/OpenHands/OpenHands)
+2. **🔧 Set up** your development environment using our [Development Guide](https://github.com/OpenHands/OpenHands/blob/main/Development.md)
+3. **💬 Join** our [Slack community](https://openhands.dev/joinslack) to meet other contributors
+4. **🎯 Find** a [good first issue](https://github.com/OpenHands/OpenHands/labels/good%20first%20issue) to work on
+5. **📝 Read** our [Code of Conduct](https://github.com/OpenHands/OpenHands/blob/main/CODE_OF_CONDUCT.md)
+
+## Need Help?
+
+Don't hesitate to ask for help:
+- **Slack**: [Join our community](https://openhands.dev/joinslack) for real-time support
+- **GitHub Issues**: [Open an issue](https://github.com/OpenHands/OpenHands/issues) for bugs or feature requests
+- **Email**: Contact us at [contact@openhands.dev](mailto:contact@openhands.dev)
+
+---
+
+Thank you for considering contributing to OpenHands! Together, we're building tools that will democratize AI-powered software development and make it accessible to developers everywhere. Every contribution, no matter how small, helps us move closer to that vision.
+
+Welcome to the community! 🎉
### FAQs
Source: https://docs.openhands.dev/overview/faqs.md
@@ -43355,32 +45261,32 @@ The [Software Agent SDK](/sdk) is a composable Python library for building agent
[OpenHands Cloud](/openhands/usage/cloud/openhands-cloud) is the managed commercial service for running OpenHands without operating your own backend and sandbox infrastructure. It provides hosted execution, integrations, collaboration, access controls, usage reporting, and budget management.
-[Sign in with your GitHub account](https://app.all-hands.dev) to try it.
+[Open Agent Canvas](https://app.all-hands.dev/canvas) to sign in and try it.
## OpenHands Enterprise
-[OpenHands Enterprise](/enterprise) provides commercial capabilities and support for organizations that need licensed self-hosting or managed deployment options. Enterprise development lives in a private repository rather than a public `enterprise/` directory.
+[OpenHands Enterprise](/enterprise) provides commercial capabilities and support for organizations that need licensed self-hosting or managed deployment options.
Learn more at [openhands.dev/enterprise](https://openhands.dev/enterprise).
## Sandbox Server
-[Sandbox Server](https://github.com/OpenHands/sandbox-server) is the community supported standalone OpenHands API and sandbox control plane. It creates and manages sandboxed environments that host Agent Server. It does not bundle a frontend but can be configured to use Agent Canvas as its browser client.
-
+[Sandbox Server](https://github.com/OpenHands/sandbox-server) is the community-supported standalone OpenHands API and sandbox control plane. It creates and manages sandboxed environments that host Agent Server. It can be configured to use Agent Canvas as its browser client.
## Component And Repository Map
| Component | Responsibility | Source |
|-----------|----------------|--------|
| **Agent Canvas** | Browser client and control center | [`OpenHands/OpenHands`](https://github.com/OpenHands/OpenHands) |
-| **Software Agent SDK and Agent Server** | Agent framework and remote execution API | [`OpenHands/software-agent-sdk`](https://github.com/OpenHands/software-agent-sdk) |
+| **Software Agent SDK** | Agent framework, tools, conversations, and workspaces | [`OpenHands/software-agent-sdk`](https://github.com/OpenHands/software-agent-sdk) |
+| **Agent Server** | Remote agent execution API | [`OpenHands/software-agent-sdk`](https://github.com/OpenHands/software-agent-sdk/tree/main/openhands-agent-server) |
| **Automation Server** | Scheduled and event-driven automation lifecycle | [`OpenHands/automation`](https://github.com/OpenHands/automation) |
+| **Sandbox Server** | Standalone API and sandbox control plane | [`OpenHands/sandbox-server`](https://github.com/OpenHands/sandbox-server) |
| **Documentation** | Documentation for the OpenHands ecosystem | [`OpenHands/docs`](https://github.com/OpenHands/docs) |
| **Evaluations** | Benchmark and evaluation infrastructure | [`OpenHands/benchmarks`](https://github.com/OpenHands/benchmarks) |
Each public repository includes its own license. Check the repository you use or modify instead of assuming one license applies to the entire ecosystem.
-
## Legacy
The archived [`OpenHands/legacy`](https://github.com/OpenHands/legacy) snapshot also preserves the previous backend and runtime architecture for historical reference.
@@ -43403,6 +45309,118 @@ The archived [`OpenHands/legacy`](https://github.com/OpenHands/legacy) snapshot
Explore all [OpenHands repositories](https://github.com/orgs/OpenHands/repositories) and [join us on Slack](https://openhands.dev/joinslack).
+### Issue Triage and the ready-for-dev Gate
+Source: https://docs.openhands.dev/overview/issue-lifecycle.md
+
+# Issue Triage and the ready-for-dev Gate
+
+OpenHands uses automated labeling and readiness checks to route issues toward development. Understanding this lifecycle helps you file issues that are picked up quickly and open pull requests that pass validation on the first try.
+
+Two repositories are covered here:
+
+- **OpenHands/OpenHands** (the monorepo: app, CLI, and Agent Canvas frontend)
+- **OpenHands/software-agent-sdk** (the Agent SDK)
+
+## What Happens After You File an Issue
+
+The labeling pipeline differs between the two repositories, but both converge on the same readiness check.
+
+
+
+ 1. **Type label at creation.** The issue form templates apply the type label (`bug` or `enhancement`) when the issue is created.
+ 2. **Topic and priority labels.** The all-hands-bot app adds topic and priority labels later.
+ 3. **Readiness check.** Once a type label is present, the issue readiness workflow evaluates the body against the type-specific criteria below and applies the `ready-for-dev` label within about a minute if they are met.
+
+
+ When your agent files an issue, it might forget to check the templates, in which case the issue will have no labels. The all-hands-bot app usually adds a type label within about an hour here too — but if it abstains, the issue waits for a human triager. Only once a type label is present does the readiness check run.
+
+
+
+ 1. **Type, topic, and priority labels.** The all-hands-bot app applies a type label (`bug` or `enhancement`) plus topic and priority labels, typically within about an hour of filing.
+ 2. **Readiness check.** As soon as the type label lands, the issue readiness workflow evaluates the body and applies `ready-for-dev` within about a minute if the criteria below are met.
+
+
+ The bot can abstain from assigning a type label when it cannot classify the issue confidently. If your issue sits with no type label, the reliable remedy is to recreate it through the web issue form, which sets the type label at creation.
+
+
+
+
+### Filing Tips
+
+- **File through the web form when you can.** It is the deterministic path: the type label is set at creation and the readiness check runs within about a minute.
+- **SDK issues filed via CLI or API** usually still get labeled by the bot within about an hour, with the abstention risk noted above.
+- **Monorepo issues filed via CLI or API** start unlabeled; the triage bot usually types them within about an hour, and only an abstention waits on a human.
+
+## Readiness Criteria
+
+The readiness check parses the issue body into sections using `###` (h3) headings — the same headings the issue forms render for each field — and evaluates the sections for the issue's type.
+
+
+ Only `###` headings are parsed. If you write the sections as `##` (h2) headings, every section parses as empty and the issue never gets `ready-for-dev` — with no hint that the heading level is the reason. Keep the `###` headings exactly as the form renders them.
+
+
+### Bug Reports
+
+The bug criteria differ between the two repositories:
+
+**OpenHands/OpenHands (monorepo)** — all three must hold:
+
+1. **`### Steps to Reproduce`** is filled in and references a supported run method: `agent-canvas`, `npm run`, or `app.all-hands.dev/canvas`.
+2. **`### Actual Behavior`** contains an embedded screenshot or video of the bug (a dragged-in file, a GitHub attachment, or a video link). A screenshot attached to a different field does not count — the evidence must be inside the Actual Behavior section.
+3. **`### Acceptance Criteria`** contains at least one checklist item (`- [ ] …`) so the fix is verifiable.
+
+**OpenHands/software-agent-sdk** — both must hold:
+
+1. **`### Actual Behavior`** shows the problem as a runnable command or snippet referencing `python`, `pytest`, `uv`, or `pip`.
+2. **`### Acceptance Criteria`** contains at least one checklist item (`- [ ] …`).
+
+### Enhancements
+
+An issue labeled `enhancement` is ready for development when both of the following hold:
+
+1. **`### Desired Behavior`** is filled in.
+2. **`### Acceptance Criteria`** contains at least one checklist item (`- [ ] …`).
+
+
+ An empty optional form field renders as `_No response_`, which the check treats as empty.
+
+
+You can run the same check locally against a draft body before filing, using the script in each repository:
+
+```bash
+python .github/scripts/check_issue_readiness.py --body-file /tmp/issue.md --labels bug
+```
+
+## The Pull Request Description Gate
+
+In the monorepo, a workflow validates the PR description before review. It enforces the PR template plus a link back to a ready issue:
+
+- **First line is `HUMAN:`.** The first visible line of the description must be `HUMAN:` alone on the line, followed by a short human-written note (at least 20 characters), followed by the `AGENT:` marker from the template. Both markers must be present.
+- **Template sections are filled in.** The `## Why`, `## Summary`, and `## How to Test` sections must be kept and contain content.
+- **The human-tested checkbox.** If the `A human has tested these changes` checkbox is present, it must be checked.
+- **Frontend changes need visual evidence.** If the PR touches frontend code, the description must include a screenshot or video.
+- **Bug fixes need reproduction evidence.** If the PR is marked as a Bug fix, the description must include a screenshot or video showing the bug before the fix and the result after — this applies even when no frontend code was touched (a terminal capture is fine).
+- **A linked issue with `ready-for-dev`.** The body must reference at least one issue (for example `Fixes #123`), and at least one referenced issue must carry the `ready-for-dev` label.
+- **The PR type must match the linked issue.** A "Bug fix" PR must link an issue labeled `bug`; a "Feature" PR must link one labeled `enhancement`.
+
+You can run the same validation locally before opening the PR:
+
+```bash
+python .github/scripts/check_pr_description.py --body-file /tmp/pr-body.md --files-file /tmp/pr-files.txt
+```
+
+## Common Pitfalls
+
+- **Using `##` instead of `###` headings in an issue.** The readiness parser only reads `###` headings; `##` sections parse as empty and the sections read as missing with no hint of the real cause. See [Readiness Criteria](#readiness-criteria).
+- **Putting the screenshot in the wrong field.** For bug reports, the screenshot or video must be embedded in `### Actual Behavior`. Attaching it elsewhere in the issue does not satisfy the check.
+- **Skipping reproduction evidence on a non-frontend bug fix.** The before/after evidence requirement for Bug fix PRs applies regardless of which files changed.
+- **Filing a monorepo issue via CLI or API.** It starts unlabeled and the readiness check cannot run until a human triager adds a type label. Use the web form for the deterministic path.
+- **Waiting on a stuck SDK issue.** If the triage bot abstains from assigning a type, recreate the issue through the web form rather than waiting.
+
+## Related
+
+- [Contributing](/overview/contributing) — how to get started contributing to OpenHands
+
### Model Context Protocol (MCP)
Source: https://docs.openhands.dev/overview/model-context-protocol.md
@@ -44173,6 +46191,8 @@ In the SDK, explicitly supplied skills override automatically loaded user and pu
In Agent Canvas, disabling a bundled or custom skill prevents it from being included in the agent context for new OpenHands and ACP conversations. Enabled skills remain available to new conversations.
+The skill catalog defaults to an **explicit allow-list** of recommended skills rather than enabling every available skill. The `Customize > Skills` page shows the full catalog with a **Recommended** badge and facet; only the recommended skills are enabled by default. You can enable any additional skill individually. An existing deny-list still takes precedence over the default allow-list.
+
See [Customize and Settings](/openhands/usage/agent-canvas/customize-and-settings) for Agent Canvas and [Plugin Launcher](/openhands/usage/cloud/plugin-launcher) for loading a Git-hosted skill into an OpenHands Cloud conversation.
@@ -45573,6 +47593,7 @@ Enterprise customers receive:
## Additional Resources
+- [Sizing Guide](/enterprise/sizing-guide) — Size a deployment from peak concurrent sandboxes
- [OpenHands Documentation](/overview/introduction) — Learn how to use OpenHands
- [SDK Documentation](/sdk/index) — Build custom agents with the OpenHands SDK
- [Pricing](https://openhands.dev/pricing) — Compare all OpenHands plans
@@ -45633,6 +47654,23 @@ Before you begin, complete the [Quick Start guide](/enterprise/quick-start).
tls:
enabled: true
secretName: "laminar-frontend-tls"
+ env:
+ # Must equal the frontend hostname above; the Keycloak callback URL is derived from it.
+ nextauthUrl: "https://analytics."
+ nextPublicUrl: "https://analytics."
+ extraEnv:
+ - name: AUTH_KEYCLOAK_ID
+ valueFrom:
+ secretKeyRef:
+ name: keycloak-realm
+ key: client-id
+ - name: AUTH_KEYCLOAK_SECRET
+ valueFrom:
+ secretKeyRef:
+ name: keycloak-realm
+ key: client-secret
+ - name: AUTH_KEYCLOAK_ISSUER
+ value: "https://auth./realms/allhands"
appServer:
# Use an app-server ingress on GCP or other L7 ingress setups.
@@ -45689,6 +47727,12 @@ Click the **Continue with Keycloak** button:

+
+ For the **Continue with Keycloak** flow to succeed, the Keycloak client referenced by the `keycloak-realm` Secret must allow the Laminar callback. Its **Valid Redirect URIs** must include `https://analytics./api/auth/callback/keycloak` and its **Web Origins** must include `https://analytics.`.
+
+ These must match the hostname in `laminar.frontend.ingress.hostname`. If your DNS uses the simple (single-level) layout — for example `analytics.` rather than a nested `analytics.app.` — confirm the redirect URI matches that hostname exactly, otherwise Keycloak rejects the login with an `Invalid parameter: redirect_uri` error.
+
+
If you want more background on Laminar Cloud versus self-hosting outside OHE, see Laminar's official [hosting options](https://laminar.sh/docs/hosting-options).
## Create a Laminar Project
@@ -46175,6 +48219,32 @@ is `RUNNING`:
| `ERROR` | Task encountered an error |
| `STUCK` | Agent appears to be stuck |
+## Conversation Lifecycle Limits
+
+Running conversations are subject to time-based limits that free up cluster
+resources. Two of these are configurable in the admin console under
+**Sandbox Configuration** (see
+[Admin Console Configuration](/enterprise/vm-install/admin-console-configuration)):
+
+- **Idle Time (seconds)** — After a conversation has been idle (no agent or user
+ activity) for this long, its sandbox is **paused**, releasing CPU and memory.
+ Activity resets the idle timer, so an actively-working agent is not paused for
+ idleness. A paused conversation is resumed automatically on next access.
+- **Deletion Time (seconds)** — After a conversation has been **paused** for this
+ long, it and its storage are permanently deleted and can no longer be resumed.
+
+
+ Separately from the idle timeout, a single running session is capped at a
+ maximum of **12 hours**. This cap applies even to a continuously-active
+ conversation: once a session has been running for 12 hours it is force-paused.
+ Resuming the conversation starts a new 12-hour window. This maximum session
+ duration is not currently configurable.
+
+
+Because these limits are deployment-wide, they cannot be set per conversation or
+per Agent Profile. Agent Profiles configure the agent's model, tools, and
+behavior, not sandbox lifetime.
+
## Read-Only Conversations
When `sandbox_status` is `ERROR` or `MISSING`, the conversation becomes
@@ -46233,12 +48303,24 @@ Custom sandbox images let you prebake the repository, dependencies, compiled out
your agents need. Instead of spending minutes provisioning a workspace on every run, your agents start
on the actual task immediately.
+This page covers two levels of customization:
+
+1. **[A single custom image](#configure-a-single-custom-image-admin-console)** that replaces the default
+ sandbox image for the whole installation. Configured in the Replicated Admin Console; no cluster access needed.
+2. **[Multiple custom images](#run-multiple-custom-images-with-warm-runtime-pools)** running side by side,
+ each with its own warm pool, selectable per user. Configured through the Runtime API; requires `kubectl` access.
+
## Why Use a Custom Image
Custom images eliminate cold-start setup work (clone, install, transpile, and bootstrap) so agents
spend their time on the actual task. They also reduce setup variance and lower sandbox memory requirements
by keeping only what the agent needs.
+With **multiple** custom images, different teams get different environments: a PHP image with Composer and
+MySQL client for the web team, a JDK and Maven image for the Java services team, a data science image with
+pinned Python packages for the analytics team. Each image is kept ready in its own warm pool so conversations
+start in seconds regardless of which environment they use.
+
## Build Your Own Custom Image
The [OpenHands agent-server sandbox guide](https://docs.openhands.dev/sdk/guides/agent-server/docker-sandbox)
@@ -46251,7 +48333,7 @@ Replicated VM deployment.
2. Keep the normal OpenHands entrypoint intact: extend the image, do not replace the entrypoint.
3. Add your repo, docs, tools, and verification wrappers.
4. Pre-run the expensive setup you do not want to repeat at task time.
-5. Publish the image to a registry and point the Replicated installer at it.
+5. Publish the image to a registry reachable from your OpenHands cluster.
Do not override the entrypoint or replace the runtime contract of the base image. The installer
@@ -46261,15 +48343,31 @@ Replicated VM deployment.
### Base Image
```dockerfile
-FROM ghcr.io/openhands/agent-server:1.23.0-python
+FROM ghcr.io/openhands/agent-server:1.46.0-python
```
-Pin a specific version tag to ensure reproducible builds. Check
+This example matches OpenHands Enterprise 0.64.0. Pin a specific version tag to ensure reproducible
+builds, and replace it with the tag expected by your installed release. Check
[ghcr.io/openhands/agent-server](https://github.com/OpenHands/OpenHands/pkgs/container/agent-server)
-for the latest available tags.
+for available tags.
+
+### Version Compatibility
+
+Each OpenHands Enterprise release expects a specific agent-server version. The base image tag you
+build from must match the release you run: the `openhands-sdk` inside the sandbox and the one inside
+the OpenHands application must agree on major and minor version.
+
+To find the expected tag, enable **Use a Custom Sandbox Image** in the Admin Console. The
+**Sandbox Image Tag** field defaults to the tag the current release expects.
+
+When a conversation starts on a custom image, OpenHands checks the sandbox's agent-server version.
+If it does not match the release, the conversation fails with an error naming the expected and
+actual versions. Rebuild your image from the expected tag and update the **Sandbox Image Tag**
+field to fix it.
- To get the latest features of OpenHands Enterprise, rebuild your custom image before each upgrade. The agent server base image is updated with every OHE release.
+ Rebuild your custom image before each upgrade. The agent-server base image changes with every
+ OHE release, and an image built for an older release will be rejected by the version check.
### Example: Build and Push
@@ -46310,12 +48408,12 @@ Good candidates for prebaking:
If the repository or dependencies change frequently, include a `prepare-*` script in the image
so the agent can refresh only the parts that need updating without a full rebuild.
-## Configure the Replicated VM Installer
+## Configure a Single Custom Image (Admin Console)
Once your image is built and pushed to a registry, point the Replicated Admin Console at it.
1. Open the **Admin Console** at `https://admin.:30000`.
-2. Navigate to **Config** and find the **Sandbox Image** section.
+2. Navigate to **Config** and find the **Sandbox Configuration** section.
3. Set the following fields:
| Field | Value |
@@ -46329,15 +48427,354 @@ Once your image is built and pushed to a registry, point the Replicated Admin Co
4. Click **Save config** and then **Deploy** to apply the change.
+This single image becomes both the default image for new conversations and the image kept ready in the
+installer-managed warm pool.
+
This setting applies to the **sandbox / agent-server image** only (the image that runs inside each
agent's isolated workspace). It does not replace the other OpenHands service images.
+## Run Multiple Custom Images with Warm Runtime Pools
+
+To offer several sandbox images at once, configure **warm runtime pools** through the Runtime API.
+Each configuration names one image and keeps a pool of pre-started sandbox pods ready for it. The
+OpenHands application automatically exposes every configuration as a selectable sandbox, so users can
+pick their environment without any redeployment.
+
+**Requirements:**
+
+- OpenHands Enterprise **0.64.0 or later**.
+- `kubectl` access to the cluster. On a Replicated VM install, get a shell with
+ `sudo /var/lib/embedded-cluster/bin/openhands shell`; on a Helm install, use your normal kubeconfig.
+- Custom images built and pushed as described above (all on the agent-server version your release expects).
+
+### How It Works
+
+- The installer-managed configuration remains the base configuration. Configurations saved through the
+ Runtime API are overlaid by name: a new name adds a pool, while an existing name overrides that
+ installer-managed entry.
+- You manage database configurations with the admin REST endpoints
+ (`PUT` / `DELETE /api/admin/warm-runtime-configs/{name}`). Deleting an override reveals the
+ installer-managed entry again.
+- A reconciler job runs **every minute** and creates or removes warm sandbox pods so each
+ configuration has `count` unclaimed pods ready.
+- The OpenHands application polls the configuration list (cached for 60 seconds) and exposes each
+ configuration as a **sandbox spec**. Users choose their default in **Settings → Application → Default Sandbox**.
+- When a conversation starts, the Runtime API hands it a matching warm pod in a few seconds. If no
+ warm pod is available, the sandbox cold-starts from the image instead (20+ seconds), and the
+ reconciler replenishes the pool.
+
+Changes take effect within about a minute, with no application restarts and no redeployments.
+
+
+ The installer-managed `v1_current` pool remains active when you add API-managed configurations. Do
+ not save a `v1_current` configuration unless you intentionally want to override the installer default.
+
+
+### Step 1: Confirm the Admin Password
+
+The Runtime API's admin endpoints authenticate with an admin password. Replicated generates a durable
+password, stores it in the `admin-password` secret, and injects it into the runtime-api pod. The helper
+script in Step 2 uses that pod environment. If the value is empty, the script reports an error before a
+save or delete.
+
+To set or rotate the password:
+
+1. Open the `Admin Console` and select `Config`.
+2. In `Sandbox Configuration`, set `Runtime API Admin Password`.
+3. Select `Save config`, then deploy the new configuration.
+
+The value persists across later deploys. Changing it automatically restarts runtime-api so the new
+password takes effect. For a Helm installation, populate the chart's `admin-password` Secret before
+using the admin endpoints and restart runtime-api after changing it.
+
+### Step 2: Save the Helper Script
+
+The Runtime API is not exposed outside the cluster by default. Download the maintained
+[`warm-runtime-configs.sh`](https://github.com/OpenHands/runtime-api/blob/main/scripts/warm-runtime-configs.sh)
+helper, which runs each API call inside the runtime-api pod with `kubectl exec`:
+
+```bash
+curl -fsSLo warm-runtime-configs.sh \
+ https://raw.githubusercontent.com/OpenHands/runtime-api/main/scripts/warm-runtime-configs.sh
+chmod +x warm-runtime-configs.sh
+./warm-runtime-configs.sh list
+```
+
+
+ The helper uses `DEFAULT_API_KEY` and `ADMIN_PASSWORD` from the runtime-api pod without printing or
+ copying either value. Listing authenticates with the regular API key. Saving and deleting use the
+ admin password via a challenge-response login that returns a 24-hour JWT.
+
+
+List responses identify each configuration's `source`. When `v1_current` is not overridden, it appears
+with `"source": "file"`.
+
+### Step 3: Start From the Installer's Default Configuration
+
+Do not write configurations from scratch. The environment in a warm runtime configuration is what its
+sandbox pods actually boot with; the default configuration contains install-specific values (webhook
+callback URL, CA bundles, workspace paths) that sandboxes need to function. Export the default from the
+installer-managed ConfigMap and use it as your template:
+
+```bash
+kubectl -n openhands get configmap warm-runtimes-config \
+ -o jsonpath='{.data.warm-runtimes\.json}' \
+ | jq '.configs[] | select(.name == "v1_current") | del(.name)' > default-config.json
+```
+
+(If the ConfigMap has a different name in your install, find it with
+`kubectl -n openhands get configmap | grep warm-runtimes`.)
+
+The installer-managed `v1_current` entry remains live and follows Admin Console changes. Derive each
+custom image configuration from the exported template, changing only the image and pool size:
+
+```bash
+jq '.image = "ghcr.io/your-org/openhands-php:8.4-v1" | .count = 1' \
+ default-config.json > php-web.json
+./warm-runtime-configs.sh save php-web php-web.json
+
+./warm-runtime-configs.sh list
+```
+
+### Configuration Format
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `image` | string | Yes | Full image reference (e.g. `ghcr.io/your-org/openhands-php:8.4-v1`) |
+| `working_dir` | string | Yes | Working directory inside the sandbox (copy from the default) |
+| `command` | array | Yes | Agent-server start command (copy from the default) |
+| `environment` | object | Yes | Environment variables the sandbox boots with (copy from the default) |
+| `count` | integer | No | Warm pods to keep ready for this image. When omitted, uses the installer-wide **Warm Runtime Count** (default: `1` on Replicated installs) |
+| `run_as_user` | integer | No | Copy from the installer default (currently `10001`) so warm pods match application start requests |
+| `run_as_group` | integer | No | Copy from the installer default (currently `10001`) so warm pods match application start requests |
+| `fs_group` | integer | No | Copy from the installer default (currently `10001`) so warm pods match application start requests |
+
+The configuration name comes from the URL path (the `save ` argument), not the body. Saving
+creates or replaces a database entry. If an installer-managed entry has the same name, the database
+entry overrides it. List responses also include a read-only `source` field: `file` for installer-managed
+entries and `db` for API-managed entries and overrides. Do not add `source` to a saved configuration.
+
+The application uses the image reference as the sandbox spec ID. Give every selectable configuration a
+distinct image reference; configurations that share an image reference cannot be selected independently,
+even if their commands or environments differ.
+
+
+ Set `count` explicitly. Every warm pod reserves the full sandbox resource envelope (including 10Gi of
+ ephemeral storage by default) whether or not it is in use, so the sum of all pool sizes must fit your
+ node capacity. Pools that exceed capacity show up as `Pending` pods. Start with `count: 1` per image
+ and grow the pools that see real traffic.
+
+
+### Step 4: Verify the Warm Pools
+
+The reconciler runs every minute. Watch it create the pods:
+
+```bash
+# Warm (unclaimed) sandboxes: runtime deployments with no session_id label yet
+kubectl -n openhands get deploy -l 'runtime_id,!session_id' \
+ -o custom-columns='NAME:.metadata.name,READY:.status.readyReplicas,IMAGE:.spec.template.spec.containers[0].image'
+```
+
+You should see one `runtime-` deployment per warm pod, with your configured images. To see
+the reconciler's own view (per-pool counts, pull failures, culling decisions), read the latest
+reconciler job log:
+
+```bash
+JOB=$(kubectl -n openhands get jobs --sort-by=.metadata.creationTimestamp -o name \
+ | grep warm-runtimes | tail -1)
+kubectl -n openhands logs "$JOB"
+```
+
+If a pod is stuck pulling your image, `kubectl -n openhands describe pod ` shows the pull
+error. For private registries, either fill in the **Registry Server / Username / Password** fields in
+the Admin Console's **Sandbox Configuration** section (they render an image pull secret that runtime
+pods use), or add your own secret name to the runtime-api `RUNTIME_IMAGE_PULL_SECRETS` setting.
+
+### Step 5: Pick an Image and Start a Conversation
+
+Within a minute of saving configurations (the application caches the list for 60 seconds):
+
+- **Per user**: each user opens **Settings → Application** and picks an image in the **Default Sandbox**
+ dropdown (entries are the image references). Before a user picks an image, the application uses the
+ configuration named `v1_current`, or the first configuration if no `v1_current` exists. All of the
+ user's new conversations use their selected image.
+- **Per conversation (API)**: start a sandbox for a specific image, then attach a conversation to it:
+
+ ```bash
+ # 1. Start a sandbox from a specific spec (the spec id is the image reference)
+ curl -X POST "https://app./api/v1/sandboxes?sandbox_spec_id=ghcr.io/your-org/openhands-php:8.4-v1" \
+ -H "Authorization: Bearer $API_KEY"
+ # 2. Create the conversation on that sandbox, using "id" from the response
+ curl -X POST "https://app./api/v1/app-conversations" \
+ -H "Authorization: Bearer $API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"sandbox_id": ""}'
+ ```
+
+To confirm a conversation claimed a warm pod rather than cold-starting, note that its sandbox was
+ready in a few seconds, or check the cluster: the claimed runtime deployment now carries a
+`session_id` label, and the reconciler creates a fresh warm pod to replace it within a minute.
+
+### How Warm Pods Are Claimed
+
+A conversation claims a warm pod only when the pod **exactly matches** the requested image, command,
+working directory, environment (ignoring a fixed set of session-specific variables), and
+`run_as_user` / `run_as_group` / `fs_group`. Because the application requests exactly what the
+selected configuration declares, conversations started through OpenHands match automatically.
+
+Cold starts still happen when:
+
+- All warm pods for the image are already claimed (`count` too low for the traffic).
+- The configuration changed in the last minute, so the old pods no longer match and replacements are
+ still starting.
+- Warm pods cannot become ready (image pull failures, insufficient node resources).
+
+Cold-started conversations run the same image and work normally; they just take 20+ seconds to begin.
+
+### Updating and Deleting Configurations
+
+Update by saving the same name again. To roll out a new image version:
+
+```bash
+jq '.image = "ghcr.io/your-org/openhands-php:8.4-v2"' php-web.json > php-web-v2.json
+./warm-runtime-configs.sh save php-web php-web-v2.json
+```
+
+Within a minute the reconciler stops the old pods and starts pods on the new image. Delete a
+database-only configuration to remove its pool:
+
+```bash
+./warm-runtime-configs.sh delete php-web
+```
+
+If the deleted name overrides an installer-managed entry, the underlying entry becomes effective again
+instead of disappearing. Confirm the result with `./warm-runtime-configs.sh list`; its `source` changes
+from `db` to `file`.
+
+Keep superseded image tags available in your registry while conversations that used them can still
+resume: a paused conversation resumes on its **original** image. Delete old tags only after the
+conversations that used them are gone (by default, stopped sandboxes are cleaned up after 10 days).
+
+### After Upgrading OpenHands Enterprise
+
+
+ API-managed configurations are **frozen snapshots**; upgrades do not touch them. The installer-managed
+ `v1_current` entry updates automatically unless a database entry with that name overrides it. Each
+ release expects a specific agent-server version and may add or change sandbox environment variables.
+ After every OpenHands Enterprise upgrade:
+
+ 1. Rebuild your custom images on the release's new agent-server base version.
+ 2. Re-export the default template (Step 3) from the refreshed ConfigMap.
+ 3. Re-derive and save each API-managed custom configuration from the new template.
+ 4. If you intentionally override `v1_current`, refresh or delete that override so the new
+ installer-managed entry can take effect.
+
+ Skipping this leaves configurations pointing at the previous agent-server version, and new
+ conversations fail with a version mismatch error until the configurations are updated.
+
+
+### Return an Entry to Installer Management
+
+Delete a same-named database override to restore the installer-managed entry on the next reconciler
+cycle. For example, if `v1_current` was intentionally overridden:
+
+```bash
+./warm-runtime-configs.sh delete v1_current
+./warm-runtime-configs.sh list # v1_current now reports "source": "file"
+```
+
+Other API-managed configurations continue running. Delete them individually when you no longer want
+their pools or images in the application's selector.
+
+### Troubleshooting
+
+| Symptom | Cause and fix |
+|---|---|
+| `HTTP 403: Admin functionality is disabled` | The runtime-api deployment has no admin password, or the configured value is empty. On Replicated installs, set `Runtime API Admin Password` per Step 1 and deploy. |
+| `HTTP 401` on login | Wrong password, or the challenge expired. Challenges are single-use and expire after 5 minutes; the script fetches a fresh one per call. |
+| `HTTP 401: ...provide a valid API key...` on list | The list endpoint authenticates with `X-API-Key`, not the admin JWT. Use the helper script. |
+| Installer-managed default is missing from the list | The release does not include overlay support, or the overlay is not enabled. Upgrade OpenHands Enterprise and confirm that the list reports `source` before saving configurations. |
+| Saved a config but the dropdown does not show it | The application caches the list for 60 seconds; wait a minute and reload. Also confirm with `./warm-runtime-configs.sh list`. |
+| No warm pods appear | Read the latest reconciler job log (Step 4). Look for image pull errors or scheduling failures. |
+| Warm pods `Pending` | Insufficient node resources. Every warm pod reserves the full sandbox resource envelope; lower the pool `count`s or add capacity. |
+| Conversations cold-start despite warm pods | Pool exhausted or configuration recently changed; see [How Warm Pods Are Claimed](#how-warm-pods-are-claimed). |
+| Sandbox fails at start with an agent-server version error | The custom image's base version does not match the release. Rebuild on the expected agent-server version (see [Base Image](#base-image)). |
+| Conversations on a custom image start but never show agent output | The configuration's `environment` is missing install-specific values (webhook callback URL, CA bundles). Rebuild the configuration from the default template (Step 3). |
+
+### API Reference
+
+The endpoints below are served by the runtime-api service (in-cluster: `http://:5000`).
+
+**Admin authentication** (for save and delete):
+
+1. `GET /api/admin/challenge` returns `{challenge, salt, iterations}`. Challenges are single-use and
+ expire after 5 minutes.
+2. Compute `PBKDF2-HMAC-SHA256(password, salt + challenge, iterations, dklen=32)` and hex-encode it.
+3. `POST /api/admin/login` with `{"challenge": ..., "hash": ...}` returns `{"token": ...}`, a JWT
+ valid for 24 hours.
+4. Send `Authorization: Bearer ` on admin requests.
+
+**List configurations** (regular API key, not admin):
+
+```http
+GET /api/warm-runtime-configs
+X-API-Key: {api-key}
+```
+
+Returns `200` with the effective configuration set:
+
+```json
+{
+ "configs": [
+ {"name": "v1_current", "image": "...", "source": "file"},
+ {"name": "php-web", "image": "...", "source": "db"}
+ ]
+}
+```
+
+Installer-managed entries have `source: "file"`. API-managed entries have `source: "db"`; a database
+entry with the same name replaces the file entry in this effective list.
+
+**Create or update a configuration** (admin):
+
+```http
+PUT /api/admin/warm-runtime-configs/{name}
+Authorization: Bearer {admin-jwt}
+Content-Type: application/json
+
+{"image": "...", "working_dir": "...", "command": [...], "environment": {...}, "count": 1}
+```
+
+Returns `200` with the saved configuration. Creates or overwrites; the name in the URL is the identity.
+
+**Delete a configuration** (admin):
+
+```http
+DELETE /api/admin/warm-runtime-configs/{name}
+Authorization: Bearer {admin-jwt}
+```
+
+Returns `200` with a confirmation message, or `404` if no database configuration has that name. When
+the deleted name also exists in the installer-managed file, that file entry becomes effective again.
+
## Reference
-- [OpenHands custom image example repo](https://github.com/OpenHands/openhands-custom-image): Dockerfile, benchmark scripts, and analysis tooling for the VS Code custom image example.
-- [Agent-server sandbox guide](https://docs.openhands.dev/sdk/guides/agent-server/docker-sandbox): full SDK documentation on building and configuring custom sandbox images.
+
+
+ Full SDK documentation on building custom sandbox images
+
+
+ Dockerfile, benchmark scripts, and analysis tooling for the VS Code custom image example
+
+
+ How conversations, sandboxes, and their lifecycle fit together
+
+
+ Capacity planning, including headroom for warm pools
+
+
### Running Docker in the Agent Sandbox
Source: https://docs.openhands.dev/enterprise/docker-in-sandbox.md
@@ -46520,6 +48957,13 @@ first time it needs it. You don't have to run anything yourself—just give the
preinstalled. If you use a [custom sandbox image](/enterprise/custom-sandbox-image), extend the
standard base image so this tooling remains available.
+
+ **Self-hosting Agent Canvas instead?** The same capability is available, but without the
+ hardened runtime it requires starting the container with `--privileged`, which weakens
+ isolation between the agent and the host. See
+ [Let the Agent Use Docker](/openhands/usage/agent-canvas/backend-setup/docker#let-the-agent-use-docker).
+
+
Prebake repositories, dependencies, and tooling—including your own container images—into the
sandbox your agents start from.
@@ -47090,6 +49534,1084 @@ when the job starts and when it completes.
| Bitbucket webhook deliveries do not reach OpenHands | Confirm the Bitbucket Data Center network can reach the OpenHands app URL. |
| Bitbucket API calls fail with TLS errors | Upload the Bitbucket Data Center CA certificate in **Additional Trusted CA Certificates** and redeploy. |
+### External LLM Gateways
+Source: https://docs.openhands.dev/enterprise/integrations/external-llm-gateways.md
+
+Many organizations already run an LLM gateway (LiteLLM, Bifrost, or a similar
+OpenAI-compatible proxy) to route, rate-limit, audit, and track cost across
+multiple LLM providers. OpenHands Enterprise (OHE) ships with its own built-in
+LiteLLM instance, and that built-in instance can forward requests to your
+existing gateway instead of calling LLM providers directly.
+
+This guide walks an operator through configuring the built-in LiteLLM to
+forward to an external gateway, for both single-model and multi-model setups.
+
+
+ This guide is for **OpenHands Enterprise** operators who want to chain the
+ built-in LiteLLM to an external gateway. If you are using OpenHands Cloud or
+ the OSS build and want to point OpenHands at your own LiteLLM proxy directly,
+ see [LiteLLM Proxy](/openhands/usage/llms/litellm-proxy) instead. That path
+ does not involve the built-in LiteLLM.
+
+
+## Overview
+
+OHE does not point the OpenHands runtime directly at an external gateway. Instead,
+the built-in LiteLLM forwards requests to the external gateway, which in turn
+forwards to the actual LLM provider:
+
+```text
+OpenHands Runtime
+ │
+ ▼
+Built-in LiteLLM (runs inside the OHE cluster)
+ │
+ ▼ (forwards as OpenAI-compatible HTTP)
+External Gateway (your LiteLLM or Bifrost)
+ │
+ ▼
+LLM Provider (Anthropic, OpenAI, Bedrock, Azure, etc.)
+```
+
+This design means:
+
+- OHE never needs credentials for the underlying LLM providers.
+- Your gateway keeps full control of provider keys, routing rules, cost tracking,
+ and audit logs.
+- Only one secret is exchanged: an API key or virtual key for your gateway, which
+ the built-in LiteLLM uses to authenticate.
+
+## What you need from the gateway owner
+
+For each model you want to expose to OHE, you need three pieces of information
+from whoever administers the external gateway:
+
+| Field | Description | Example |
+|-------|-------------|---------|
+| **Gateway URL** | Base URL of the gateway, reachable from the OHE cluster | `http://litellm.internal:4000` or `https://bifrost.corp.example.com:8080` |
+| **Gateway Key** | An API key or virtual key on the gateway that authorizes chat/completions calls | `sk-litellm-vk-abc123...` |
+| **Model Name** | The model name as the gateway expects it in the `model` field of the request body | `claude-sonnet-4-5-20250929` (LiteLLM) or `anthropic/claude-sonnet-4-5-20250929` (Bifrost) |
+
+No provider credentials, AWS keys, or Azure endpoints are needed on the OHE
+side. Those all stay on the external gateway.
+
+## Prerequisites
+
+Before you start, confirm:
+
+- **OHE is installed and reachable.** You can sign in at
+ `https://app.`.
+- **The external gateway is reachable from the OHE cluster.** The built-in
+ LiteLLM pod makes outbound HTTP/S calls to the gateway, so DNS and network
+ paths must resolve from inside the `openhands` namespace.
+- **You have the built-in LiteLLM master key.** This is needed for the admin
+ API path (testing only) and for verifying the config. Retrieve it with:
+
+ ```bash
+ kubectl -n openhands exec deploy/openhands-litellm -- printenv PROXY_MASTER_KEY
+ ```
+
+- **You have cluster access** to edit Helm values or apply config changes, and
+ can restart the LiteLLM pod.
+
+## Configure the built-in LiteLLM
+
+There are two ways to add gateway-forwarding models to the built-in LiteLLM.
+For production, use the **Helm values**. Use the **admin API** only for light
+testing. It does not survive pod restarts or upgrades and is not recommended
+for regular use.
+
+### Option 1: Admin API (testing only)
+
+
+ Models added via the admin API are stored in the LiteLLM database and take
+ effect immediately, but **they are lost when the LiteLLM pod restarts or the
+ cluster is upgraded**. Use this path only to test that a gateway connection
+ works, then move validated models to the Helm values (Option 2) for
+ production.
+
+
+```bash
+# Add a model that forwards to an external LiteLLM gateway
+curl -X POST http://:4000/model/new \
+ -H "Authorization: Bearer $PROXY_MASTER_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model_name": "claude-sonnet-4-5-via-gateway",
+ "litellm_params": {
+ "model": "litellm_proxy/claude-sonnet-4-5-20250929",
+ "api_base": "http://:4000",
+ "api_key": ""
+ }
+ }'
+```
+
+Models added this way appear immediately in `GET /v1/models` and are usable
+right away. No pod restart is needed.
+
+### Option 2: Helm values (production)
+
+For production, add model entries to the OpenHands Helm chart's
+`proxy_config.model_list`. These survive pod restarts and cluster upgrades.
+
+
+
+ 1. Open the Replicated admin console at `https://:30000`.
+ 2. Navigate to the LiteLLM config section and edit the `model_list` YAML.
+ 3. Add one entry per model (see the config snippets in
+ [Gateway-specific configuration](#gateway-specific-configuration) below).
+ 4. Save and deploy. Replicated will roll the LiteLLM pod with the new config.
+
+
+ Edit `values.yaml` for the `openhands` chart:
+
+ ```yaml
+ proxy_config:
+ model_list:
+ # ... existing models ...
+
+ # Forward to an external LiteLLM gateway
+ - model_name: claude-sonnet-4-5-via-gateway
+ litellm_params:
+ model: litellm_proxy/claude-sonnet-4-5-20250929
+ api_base: http://:4000
+ api_key: os.environ/EXTERNAL_GATEWAY_KEY
+
+ # Forward to an external Bifrost gateway
+ - model_name: claude-sonnet-4-5-via-bifrost
+ litellm_params:
+ model: openai/anthropic/claude-sonnet-4-5-20250929
+ api_base: http://:8080/v1
+ api_key: os.environ/BIFROST_KEY
+ ```
+
+ Then supply the keys as a Kubernetes secret and redeploy:
+
+ ```bash
+ kubectl -n openhands create secret generic external-gw-keys \
+ --from-literal=EXTERNAL_GATEWAY_KEY='' \
+ --from-literal=BIFROST_KEY=''
+
+ helm upgrade openhands ./charts/openhands -f values.yaml -n openhands
+ ```
+
+
+
+## Gateway-specific configuration
+
+The `model` and `api_base` fields differ depending on whether the external
+gateway is LiteLLM or Bifrost.
+
+### LiteLLM as the external gateway
+
+Use the `litellm_proxy/` model prefix. This tells the built-in LiteLLM to
+forward to another LiteLLM instance and preserve LiteLLM-specific features
+(virtual key headers, spend tracking, team/org metadata).
+
+```yaml
+- model_name:
+ litellm_params:
+ model: litellm_proxy/
+ api_base: http://:4000 # no /v1 suffix
+ api_key:
+```
+
+
+ The `api_base` should **not** include `/v1`. LiteLLM appends the
+ `/v1/chat/completions` path automatically.
+
+
+### Bifrost as the external gateway
+
+Use the `openai/` model prefix. Bifrost is OpenAI-compatible, so the built-in
+LiteLLM treats it as an OpenAI-compatible endpoint.
+
+```yaml
+- model_name:
+ litellm_params:
+ model: openai//
+ api_base: http://:8080/v1 # include /v1
+ api_key:
+```
+
+Key differences from LiteLLM:
+
+- `api_base` **must** include `/v1`. Bifrost does not auto-append it.
+- The model name on Bifrost uses the `provider/model` convention (for example,
+ `anthropic/claude-sonnet-4-5-20250929`), so the full `model` field becomes
+ `openai/anthropic/claude-sonnet-4-5-20250929`.
+
+## Multi-model gateways
+
+Gateways typically host many models across different providers, sizes, and
+routing rules. There are two patterns for exposing them to OHE.
+
+### Pattern A: Explicit per-model entries (recommended)
+
+Add one `model_list` entry per model you want to expose. Each entry maps a
+friendly name (what OHE users see in the dropdown) to a model on the external
+gateway. This works identically for LiteLLM and Bifrost gateways.
+
+```yaml
+proxy_config:
+ model_list:
+ - model_name: claude-sonnet-4-5
+ litellm_params:
+ model: litellm_proxy/claude-sonnet-4-5-20250929
+ api_base: http://:4000
+ api_key: os.environ/EXTERNAL_GW_KEY
+
+ - model_name: claude-haiku-4-5
+ litellm_params:
+ model: litellm_proxy/claude-haiku-4-5-20251001
+ api_base: http://:4000
+ api_key: os.environ/EXTERNAL_GW_KEY
+
+ - model_name: gpt-4o
+ litellm_params:
+ model: litellm_proxy/gpt-4o
+ api_base: http://:4000
+ api_key: os.environ/EXTERNAL_GW_KEY
+```
+
+All three entries point at the same `api_base` and use the same `api_key`.
+Only the upstream model name differs. OHE users see three models in the
+dropdown: `claude-sonnet-4-5`, `claude-haiku-4-5`, `gpt-4o`.
+
+This pattern is explicit, easy to audit, and gives you control over which
+models are exposed and what they are named.
+
+### Pattern B: Wildcard passthrough (not recommended)
+
+
+ Pattern B is **not recommended** for production. It floods the OHE model
+ dropdown with hundreds of models that do not exist on the external gateway,
+ and it requires users to type exact model names in a specific format. Use
+ Pattern A unless you have a specific reason to allow arbitrary model names.
+
+
+LiteLLM supports a wildcard model entry that forwards any model name to the
+upstream gateway without pre-declaring each one:
+
+```yaml
+proxy_config:
+ model_list:
+ - model_name: "*"
+ litellm_params:
+ model: openai/*
+ api_base: http://:8080/v1
+ api_key: os.environ/BIFROST_KEY
+```
+
+Tested behavior of this pattern:
+
+- **The OHE model dropdown becomes unusable.** `GET /v1/models` on the built-in
+ LiteLLM returns 200+ entries: the explicitly configured models, a literal
+ `*`, and the entire LiteLLM internal OpenAI model registry (models like
+ `openai/gpt-4o`, `openai/gpt-5`, and so on). These OpenAI models do **not**
+ exist on the external gateway. They are LiteLLM's known model names,
+ auto-populated because of the `openai/*` prefix. Users see a flooded
+ dropdown where most entries fail when selected.
+- **Users must type the exact `provider/model` format.** A call to
+ `claude-opus-4-8` fails with a 400 error. A call to
+ `anthropic/claude-opus-4-8` succeeds and is forwarded to the gateway. The
+ user must know the gateway's model naming convention in advance.
+- **Typo protection moves to the gateway.** Unknown model names are forwarded
+ verbatim and rejected by the external gateway, not by the built-in LiteLLM.
+
+The one advantage of Pattern B is that when the external gateway adds a new
+model, it works immediately without a config change on the OHE side. That
+convenience rarely outweighs the cost of a broken dropdown and the need for
+users to know exact model strings.
+
+## Model discovery
+
+OHE discovers available models by calling `GET /v1/models` on the built-in
+LiteLLM. This endpoint returns every model in the `model_list`, both those in
+the Helm config and any added via the admin API for testing.
+
+```bash
+curl http://:4000/v1/models \
+ -H "Authorization: Bearer $PROXY_MASTER_KEY"
+```
+
+For production, models should be in the Helm config so they survive pod
+restarts and cluster upgrades. Models added via the admin API appear
+immediately but are lost on restart. Use that path only for testing.
+
+## Verified capabilities
+
+The following OHE agent capabilities have been tested and confirmed working
+through both LiteLLM and Bifrost external gateways:
+
+| Capability | LiteLLM gateway | Bifrost gateway |
+|-----------|-----------------|-----------------|
+| Basic chat completions | Yes | Yes |
+| Tool and function calling | Yes | Yes |
+| Streaming responses | Yes | Yes |
+| Multi-step agent loops (tool call, result, next response) | Yes | Yes |
+| Token usage tracking | Yes | Yes |
+| Multiple models on same gateway | Yes | Yes |
+
+## Identity and cost attribution
+
+A common reason to chain through an external gateway is cost attribution
+and audit: the gateway owner needs to know which OpenHands user,
+team, or project generated each LLM call so they can route spend to
+the right cost center. This section is a set of recipes. Pick the one
+that matches your scenario.
+
+### What the OpenHands runtime sends by default
+
+The runtime calls the built-in LiteLLM using the OpenAI Python SDK.
+By default the request carries:
+
+- Standard OpenAI SDK headers (`x-stainless-*`, `authorization`).
+- An OpenAI `user` field in the request body, set to the OpenHands
+ user identifier. The built-in LiteLLM records this in its own spend
+ logs but does not forward it to the upstream gateway in the request
+ body.
+
+No `X-OpenHands-User-Id` or similar identity header is attached
+automatically. Everything below adds attribution to that baseline.
+
+### Recipe 1: Per-team attribution with per-key model entries
+
+**Use when** you have a small number of teams or projects and want
+the external gateway to attribute spend by API key.
+
+**How.** Create one API key per team on the external gateway. Add one
+model entry per key in the built-in LiteLLM config:
+
+```yaml
+proxy_config:
+ model_list:
+ - model_name: claude-sonnet-4-5-team-alpha
+ litellm_params:
+ model: litellm_proxy/claude-sonnet-4-5-20250929
+ api_base: http://:4000
+ api_key: os.environ/TEAM_ALPHA_KEY
+
+ - model_name: claude-sonnet-4-5-team-beta
+ litellm_params:
+ model: litellm_proxy/claude-sonnet-4-5-20250929
+ api_base: http://:4000
+ api_key: os.environ/TEAM_BETA_KEY
+```
+
+Users on each team select their model in the OHE model dropdown. The
+gateway sees the team's key and attributes spend accordingly.
+
+**What appears at the gateway.** The team's `Authorization: Bearer
+` header. Standard gateway spend reporting by key.
+
+**Limits.**
+
+- No header forwarding or runtime changes needed.
+- Does not scale to many users because each user needs their own
+ entry and key. Best for a small number of teams or projects.
+
+### Recipe 2: Per-user or per-profile attribution with `extra_headers`
+
+**Use when** you want each LLM call from a specific OpenHands user
+or team to carry identity headers the gateway can read. Works for
+both web UI and API conversations.
+
+**How.** Two steps.
+
+1. Enable header forwarding on the built-in LiteLLM. In your Helm
+ values or Replicated config:
+
+ ```yaml
+ proxy_config:
+ general_settings:
+ forward_client_headers_to_llm_api: true
+ ```
+
+ In the Replicated admin console this is the **Enable Forwarding
+ Client Headers Through LiteLLM to LLM Providers** checkbox under
+ Advanced Options.
+
+2. Set `extra_headers` on the LLM profile. In the OpenHands web UI,
+ open Settings, LLM, Advanced Options, and edit the **Extra
+ Headers** field. Or POST to the profile API:
+
+ ```bash
+ curl -X POST "https://app./api/v1/settings/profiles/Default" \
+ -H "X-Session-API-Key: $OH_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "preserve_existing_api_key": true,
+ "llm": {
+ "model": "openai/claude-sonnet-4-5-via-gateway",
+ "base_url": "http://openhands-litellm:4000/v1",
+ "extra_headers": {
+ "X-OpenHands-User-Id": "alice",
+ "X-OpenHands-Project": "trade-confirm-demo"
+ }
+ }
+ }'
+ ```
+
+For per-user attribution today, create one LLM profile per user and
+set that user's identifier in the profile's `extra_headers`. Users
+select their own profile from the profile dropdown.
+
+**What appears at the gateway.** Every LLM call from a conversation
+using this profile arrives with the headers you set. The gateway
+reads them and attributes spend accordingly.
+
+**Verified.**
+
+- The `extra_headers` field is exposed on the LLM profile schema in
+ the OHE app and persists through the profile API round-trip.
+- The SDK forwards `llm.extra_headers` to LiteLLM on every call.
+- The built-in LiteLLM forwards headers starting with `x-` (and
+ `anthropic-*`, excluding `x-stainless-*`) to the upstream gateway
+ when `forward_client_headers_to_llm_api: true`. Tested end-to-end
+ with a capture service standing in for the upstream gateway.
+
+**Limits.**
+
+- Headers are static per profile, not per user, so per-user
+ attribution scales with the number of profiles.
+- The header name `x-litellm-session-id` is reserved by the SDK for
+ conversation tracing (see [Trace calls back to a conversation](#trace-calls-back-to-a-conversation)).
+ Setting that key in `extra_headers` is overwritten at call time.
+
+### Recipe 3: Static gateway auth headers with `custom_llm_extra_headers`
+
+**Use when** the external gateway requires a static auth or routing
+header on every request, and your LLM provider setting is Custom LLM.
+
+**How.**
+
+1. In the Replicated admin console, set LLM Provider to **Custom LLM**.
+2. Under Advanced Options, enable **Custom LLM Extra HTTP Headers**.
+3. Enter a JSON object mapping header names to values:
+
+ ```json
+ {"Ocp-Apim-Subscription-Key": "abc123", "X-Tenant-Id": "prod"}
+ ```
+
+4. Deploy. The built-in LiteLLM injects these headers on every
+ outbound request to the gateway.
+
+**What appears at the gateway.** The headers you configured, on every
+outbound request, identical for every user.
+
+**Limits.**
+
+- Gated on the Custom LLM provider. Not available for Anthropic,
+ OpenAI, Bedrock, Azure, or Vertex provider settings.
+- Static values, same for every user. Not a per-user attribution
+ mechanism.
+- Values are rendered as plaintext in the LiteLLM ConfigMap.
+
+### Recipe 4: LiteLLM spend log metadata
+
+**Use when** the external gateway is also LiteLLM and you want
+structured metadata (user, project, cost center) captured on both the
+built-in and upstream LiteLLM spend logs, so you can query and join
+them.
+
+**How.** Enable header forwarding as in Recipe 2. Then set the
+`x-litellm-spend-logs-metadata` header on the LLM profile's
+`extra_headers`. LiteLLM parses this header as a JSON string and
+stores it in the spend log row:
+
+```bash
+curl -X POST "https://app./api/v1/settings/profiles/Default" \
+ -H "X-Session-API-Key: $OH_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "preserve_existing_api_key": true,
+ "llm": {
+ "model": "openai/claude-sonnet-4-5-via-gateway",
+ "base_url": "http://openhands-litellm:4000/v1",
+ "extra_headers": {
+ "x-litellm-spend-logs-metadata": "{\"openhands_user_id\":\"alice\",\"project\":\"trade-confirm-demo\"}"
+ }
+ }
+ }'
+```
+
+**What appears at the gateway.** The header on every request, and
+the parsed metadata in LiteLLM's spend database on both sides of the
+chain.
+
+**Limits.**
+
+- Only LiteLLM gateways interpret the JSON natively. Bifrost sees the
+ header but does not parse it.
+- The value is a JSON string, not a nested object. Serialize before
+ putting it in `extra_headers`.
+
+### Recipe 5: Batch reconciliation with conversation tags
+
+**Use when** you can reconcile gateway spend with OpenHands
+conversations after the fact and do not need per-call attribution
+visible at the gateway.
+
+**How.** Tag conversations with your external identifiers when you
+start them via the API. Tag keys must be lowercase alphanumeric (no
+underscores or hyphens); values are strings up to 256 characters:
+
+```bash
+curl -X PATCH "$CONVERSATION_URL" \
+ -H "X-Session-API-Key: $SESSION_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"tags": {"costcenter": "trade-confirm-demo", "externalproject": "proj-42"}}'
+```
+
+Export gateway spend logs filtered by time and model. Export the
+OpenHands conversation list filtered by tag. Join by timestamp and
+model. See the
+[conversation-tags example](https://github.com/jpshackelford/oh-examples/tree/main/conversation-tags)
+for a working round-trip.
+
+**What appears at the gateway.** Nothing. Tags live on the OpenHands
+conversation record and never touch the LLM request.
+
+**Limits.** Not real-time. Reconciliation is a batch job.
+
+### Choosing a recipe
+
+| Scenario | Recipe |
+|----------|--------|
+| Per-team attribution, few teams | Recipe 1 |
+| Per-user attribution, small number of users | Recipe 2 |
+| Static gateway auth header, Custom LLM provider | Recipe 3 |
+| Metadata in LiteLLM spend logs on both sides of the chain | Recipe 4 |
+| Batch reconciliation after the fact | Recipe 5 |
+
+Recipes are not mutually exclusive. A common combination is Recipe 1
+(per-team keys) plus Recipe 2 (per-user headers within a team).
+
+### Trace calls back to a conversation
+
+Independent of attribution, the SDK stamps every LLM request with
+`x-litellm-session-id: `. When
+`forward_client_headers_to_llm_api: true`, this header reaches the
+external gateway. It is useful for:
+
+- Correlating a spend log row on the gateway to the OpenHands
+ conversation that produced it.
+- Joining logs across the built-in and external LiteLLM instances.
+- Debugging which conversation is generating traffic.
+
+It is not an attribution mechanism. The value is a conversation ID,
+not a user ID. Use it together with one of the recipes above when you
+need both attribution and traceability.
+
+## Security notes
+
+- The external gateway key is stored as a Kubernetes secret in the OHE cluster.
+ Limit access to that secret to the LiteLLM pod's service account.
+- The built-in LiteLLM logs request and response metadata (model, token counts,
+ latency) but not prompt or response content by default. The external gateway
+ is the place to enforce content-level audit logging if needed.
+- If the external gateway is outside the OHE cluster, use HTTPS and ensure the
+ LiteLLM pod can resolve and reach the gateway's DNS name.
+
+## Troubleshooting
+
+
+
+ - Verify the model appears in `GET /v1/models` on the built-in LiteLLM.
+ - If added via admin API, check the response from `/model/new` for errors.
+ - If added via Helm values, verify the pod restarted after the values
+ change.
+
+
+
+ - Verify the `api_key` in `litellm_params` is a valid key on the external
+ gateway.
+ - For Bifrost, check that `enforceAuthOnInference` is either `false` (for
+ testing) or that a valid virtual key is configured.
+
+
+
+ The `model` field in `litellm_params` must match what the external gateway
+ expects:
+ - For LiteLLM gateways: use the `model_name` from the gateway's config,
+ for example `litellm_proxy/claude-sonnet-4-5-20250929`.
+ - For Bifrost: use `provider/model`, for example
+ `openai/anthropic/claude-sonnet-4-5-20250929`.
+
+
+
+ - Verify the model supports tool/function calling (some smaller models do
+ not).
+ - Test directly against the external gateway (bypass the built-in LiteLLM)
+ to isolate whether the issue is in the gateway or the chaining.
+
+
+
+ This means a wildcard (`model_name: "*"`) entry is in the `model_list`.
+ The `openai/*` prefix causes LiteLLM to auto-populate its internal OpenAI
+ model registry into `/v1/models`. Remove the wildcard entry and use
+ explicit per-model entries (Pattern A) instead.
+
+
+
+## Reference
+
+- OpenHands LLM configuration overview: [LLM Configuration](/openhands/usage/llms/llms)
+- LiteLLM proxy (OSS/Cloud path, no built-in LiteLLM): [LiteLLM Proxy](/openhands/usage/llms/litellm-proxy)
+- LiteLLM model config reference: [LiteLLM docs](https://docs.litellm.ai/docs/proxy/configs)
+- Bifrost configuration reference: [Bifrost docs](https://docs.bifrost.maxim.ai)
+
+### GitHub
+Source: https://docs.openhands.dev/enterprise/integrations/github.md
+
+This guide explains how to connect GitHub to a self-hosted OpenHands Enterprise
+installation. The integration lets users sign in with GitHub, open repositories,
+and invoke OpenHands from issue and pull request comments.
+
+
+ For OpenHands Cloud, see [GitHub Integration](/openhands/usage/cloud/github-installation).
+ This page covers the GitHub App that you create and operate for OpenHands Enterprise.
+
+
+## Overview
+
+A self-hosted installation needs its own GitHub App so GitHub can send events to
+your domain. Setup has four parts:
+
+1. Create a GitHub App for the installation.
+2. Install the app on the organizations and repositories where OpenHands should run.
+3. Add the app credentials to the OpenHands Enterprise Admin Console and deploy the configuration.
+4. Have each user sign in to OpenHands with GitHub before they invoke `@openhands`.
+
+The integration uses two GitHub identities:
+
+- The GitHub App posts acknowledgements and completion messages as the OpenHands bot.
+- The agent uses the triggering user's GitHub authorization for repository operations,
+ including formal pull request reviews.
+
+This is why an `I'm on it!` comment can appear as the bot while the resulting pull
+request review appears as the user who requested it.
+
+## Prerequisites
+
+Before you start, confirm:
+
+- OpenHands Enterprise is reachable at `https://app.`.
+- The authentication service is reachable at `https://auth.`
+ when using the default **Simple** hostname mode.
+- Both hostnames use publicly trusted TLS certificates.
+- You can create a GitHub App for your user or organization.
+- You can install the app on the organizations and repositories that should use OpenHands.
+- Your workstation has [uv](https://docs.astral.sh/uv/) and can open a browser to GitHub.
+
+## Step 1: Create the GitHub App
+
+Use the helper script in the
+[`OpenHands-Cloud`](https://github.com/OpenHands/OpenHands-Cloud/tree/main/scripts/create_github_app)
+repository. It creates a private GitHub App with the callback URL, webhook URL,
+permissions, and events expected by OpenHands Enterprise.
+
+```bash
+git clone https://github.com/OpenHands/OpenHands-Cloud.git
+cd OpenHands-Cloud
+./scripts/create_github_app/create_github_app.py \
+ --base-domain
+```
+
+Use the base domain without the `app.` or `auth.` prefix. For example:
+
+```bash
+./scripts/create_github_app/create_github_app.py \
+ --base-domain openhands.example.com
+```
+
+Pass `--org ` to create the app under a GitHub organization instead
+of your personal account. If the installation uses the **Legacy** hostname mode,
+also pass `--dns-layout nested` so the OAuth callback uses
+`auth.app.` instead of `auth.`.
+
+The script starts a temporary callback server on port `9876`, opens GitHub's App
+creation page, and asks you to create the app. After creation, it opens the app's
+installation page.
+
+Save these values from the script output:
+
+- GitHub App Client ID
+- GitHub App Client Secret
+- GitHub App ID
+- GitHub App Slug
+- GitHub App Webhook Secret
+- GitHub App Private Key, saved under `scripts/create_github_app/keys/`
+
+
+ Store the client secret, webhook secret, and private key securely. Do not commit
+ them to a repository.
+
+
+### App Configuration
+
+The helper configures these URLs:
+
+| GitHub App setting | URL |
+|---|---|
+| Homepage URL | `https://app.` |
+| OAuth callback URL | `https://auth./realms/allhands/broker/github/endpoint` |
+| Webhook URL | `https://app./integration/github/events` |
+
+The OAuth callback URL above is for the default **Simple** hostname mode. The
+helper uses `auth.app.` when run with `--dns-layout nested` for
+the **Legacy** mode. The OAuth callback handles user sign-in, while the webhook
+URL receives issue and pull request events; these URLs are not interchangeable.
+
+The app subscribes to these events:
+
+- Issue comments
+- Pull requests
+- Pull request review comments
+
+The app requests write access to repository contents, issues, pull requests,
+repository webhooks, commit statuses, Actions, and workflows. It also requests
+read access to metadata, user email addresses, and organization events.
+
+## Step 2: Install the GitHub App
+
+On the installation page opened by the helper script:
+
+1. Select the GitHub user or organization that owns the repositories.
+2. Choose **All repositories** or select the repositories that should use OpenHands.
+3. Review the requested permissions.
+4. Select **Install**.
+
+You can change repository access later from the GitHub App's installation settings.
+OpenHands receives events only for repositories included in the installation.
+
+
+ Installing multiple OpenHands GitHub Apps on the same repository causes each app
+ to receive the same `@openhands` mention. This can start duplicate conversations
+ and produce duplicate acknowledgements, reviews, and completion comments.
+
+
+## Step 3: Configure OpenHands Enterprise
+
+Open the Replicated Admin Console and find **GitHub Authentication** in the
+application configuration.
+
+1. Enable **GitHub Authentication**.
+2. Enter the **GitHub App Client ID**.
+3. Enter the **GitHub App Client Secret**.
+4. Enter the numeric **GitHub App ID**.
+5. Enter the **GitHub App Slug**.
+6. Enter the **GitHub App Webhook Secret**.
+7. Upload the **GitHub App Private Key** (`.pem`).
+8. Save the configuration and deploy the new version.
+9. Wait for the deployment to reach **Ready**.
+
+The [Enterprise Quick Start](/enterprise/quick-start) covers the surrounding
+installation and deployment steps.
+
+## Step 4: Sign In with GitHub
+
+Each user must sign in to OpenHands with GitHub before invoking the resolver.
+The first sign-in links the GitHub identity to the user's OpenHands account and
+stores the authorization needed to perform repository operations as that user.
+
+If a GitHub user who has not linked an OpenHands account mentions `@openhands`,
+the bot responds with instructions to sign in before starting a job.
+
+## Use the Built-In Resolver
+
+Mention `@openhands` in an issue, pull request comment, or inline pull request
+review comment. You can also add the `openhands` label to an issue. Include the
+task after the mention, for example:
+
+```text
+@openhands explain why this test is failing
+```
+
+```text
+@openhands /codereview
+```
+
+The resolver starts a job only when:
+
+- The GitHub App is installed for the repository.
+- GitHub can deliver a valid webhook to the OpenHands webhook URL.
+- The triggering user has signed in to OpenHands with GitHub.
+- The triggering user has write access to the repository.
+
+When a job starts, OpenHands:
+
+1. Adds an eyes reaction to the triggering issue or comment.
+2. Creates an OpenHands conversation with the issue or pull request context.
+3. Posts an `I'm on it!` acknowledgement as the GitHub App and links to the conversation.
+4. Runs the task using the triggering user's GitHub authorization.
+5. Posts the conversation's final response as a completion comment from the GitHub App.
+
+The acknowledgement and completion comment are part of the built-in resolver.
+They are not custom event automations.
+
+## Customize Resolver Conversations
+
+The resolver creates a standard OpenHands conversation. The triggering comment
+or labeled issue defines the task, and the issue or pull request provides
+additional context. Once the conversation starts, normal skill discovery and
+triggering apply.
+
+Available skills can come from OpenHands, the repository, or the organization.
+OpenHands exposes their names and descriptions to the agent. A matching trigger
+injects a skill automatically, and the agent can invoke other skills that appear
+relevant to the task.
+
+By default, GitHub resolver conversations automatically receive the built-in
+GitHub skill. The resolver's initial message refers to GitHub APIs, which matches
+the skill's `github` trigger. This gives the agent the baseline instructions for
+using GitHub, but it does not limit the conversation to that skill. Repository,
+organization, and other task-specific skills can apply alongside it. For example,
+`@openhands /codereview` also activates the matching code review skill.
+
+Choose the customization scope that matches the behavior you want to change:
+
+| Goal | Use |
+|---|---|
+| Apply instructions to every OpenHands task in one repository | Repository `AGENTS.md` |
+| Add guidance for a specific workflow, such as issue triage, test diagnosis, or pull request review | Repository skill |
+| Apply the same workflow across repositories | Organization skill |
+| Change acknowledgements, GitHub identity, trigger eligibility, or completion callbacks | Product or integration change; skills do not control these behaviors |
+
+For example, repository instructions can tell the agent not to push directly, an
+issue-triage skill can define labels and escalation rules, and a review skill can
+specify the expected format and event for a formal pull request review.
+
+### Pull Request Review Example
+
+Use `@openhands /codereview` to activate the built-in code review skill instead
+of relying on the agent to interpret a general `@openhands review` request. Add
+repository or organization guidance when your team needs a consistent review
+policy.
+
+For example, create `.agents/skills/custom-codereview-guide.md` to tell the agent
+to submit informational reviews instead of approvals:
+
+```markdown
+---
+name: custom-codereview-guide
+description: Apply this repository's GitHub pull request review policy.
+triggers:
+- /codereview
+---
+
+# GitHub Review Policy
+
+When submitting a GitHub pull request review:
+
+- Always use `event: COMMENT`.
+- Never use `event: APPROVE` or `event: REQUEST_CHANGES`.
+- Put all findings in the formal review body or inline review comments.
+- Keep the final response brief and point readers to the formal review instead of repeating it.
+```
+
+Do not name this skill `code-review`; that name conflicts with the built-in review
+skill. Keep the `/codereview` trigger so both skills activate for the same request.
+Start a new resolver conversation after committing the skill because skills do
+not retroactively change a conversation that is already running.
+
+See [Code Review](/openhands/usage/use-cases/code-review#customization) for more
+review examples and [Skills and Plugins](/enterprise/skills-and-plugins) for all
+repository and organization distribution options.
+
+## Integration-Owned Behavior
+
+Skills guide the agent after the conversation starts. They do not change how the
+GitHub integration authenticates users, accepts events, or posts status messages.
+
+### Review and Comment Identity
+
+The built-in resolver intentionally uses different credentials for different actions:
+
+| Action | GitHub identity |
+|---|---|
+| Eyes reaction | GitHub App bot |
+| `I'm on it!` acknowledgement | GitHub App bot |
+| Repository changes and formal pull request reviews | Triggering user |
+| Completion comment | GitHub App bot |
+
+There is currently no supported setting that makes formal reviews run as the
+GitHub App bot. If your organization requires reviews to have a machine identity,
+use an [OpenHands code review automation](/openhands/usage/use-cases/code-review#option-b-openhands-automation-org-wide)
+with a dedicated bot credential.
+
+### Completion Comments
+
+The built-in resolver posts the agent's final response as a completion comment.
+There is currently no Admin Console setting to disable this comment while keeping
+the built-in resolver enabled.
+
+A repository or organization skill can reduce duplication by telling the agent
+to keep its final response brief and refer readers to the formal review. A skill
+cannot disable the resolver's completion callback itself.
+
+## Troubleshooting
+
+| Symptom | Check |
+|---|---|
+| **Login with GitHub** is not visible | Confirm **GitHub Authentication** is enabled and the updated configuration has been deployed. |
+| GitHub OAuth redirects fail | Confirm the callback URL uses `https://auth./realms/allhands/broker/github/endpoint` for **Simple** mode or `https://auth.app./realms/allhands/broker/github/endpoint` for **Legacy** mode. Recreate the app or update its callback URL if the helper was run with the wrong DNS layout. |
+| GitHub reports failed webhook deliveries | Confirm GitHub can reach `https://app./integration/github/events`, the TLS certificate is trusted, and the webhook secret matches the Admin Console value. |
+| `@openhands` is ignored | Confirm the app is installed for the repository, the sender has write access, and the sender has signed in to OpenHands with GitHub. |
+| OpenHands posts duplicate acknowledgements or reviews | Check whether more than one OpenHands GitHub App is installed for the repository. |
+| The acknowledgement is from the bot but the review is from a user | This is expected. The app posts resolver status messages, while repository operations use the triggering user's GitHub authorization. |
+| A review is submitted as **Approve** instead of **Comment** | Add repository or organization guidance that tells the agent to use `event: COMMENT`, then start a new resolver conversation. |
+| The review and completion comment repeat the same content | Add a skill that keeps the final response brief. The completion comment cannot currently be disabled through the Admin Console. |
+| OpenHands can read the repository but cannot post a review | Confirm the app and user authorization include write access to pull requests, and confirm the user can review the pull request in GitHub. |
+
+## Related Documentation
+
+- [Enterprise Quick Start](/enterprise/quick-start)
+- [Skills and Plugins](/enterprise/skills-and-plugins)
+- [Code Review](/openhands/usage/use-cases/code-review)
+
+### Jira Cloud
+Source: https://docs.openhands.dev/enterprise/integrations/jira-cloud.md
+
+This guide explains how to connect Jira Cloud to an OpenHands Enterprise
+Replicated installation. The integration lets users start OpenHands from Jira
+issues by commenting with `@openhands` or by adding the `openhands` label.
+OpenHands replies on the issue with a link to the conversation and posts the
+result back when it finishes.
+
+Jira Cloud users are linked to OpenHands accounts by **email match**: no
+Atlassian OAuth app is required, and users need no per-user setup beyond
+making their email visible (see [User requirements](#user-requirements)).
+Users are enrolled automatically the first time they trigger OpenHands.
+
+## Prerequisites
+
+- Jira Cloud **site administrator** access, to invite the service account and
+ register a webhook.
+- An OpenHands Enterprise **organization admin or owner** account, to
+ configure the integration inside OpenHands.
+- Network access from Jira Cloud to the OpenHands app URL over HTTPS with a
+ publicly trusted certificate (for webhook delivery), and from OpenHands to
+ `api.atlassian.com` (for Jira API calls).
+
+## Create a service account
+
+Create a dedicated Atlassian account for OpenHands, for example
+`openhands-bot@company.com`. OpenHands uses this account to read issues and
+post comments, and its replies appear under this account's name.
+
+1. Invite the account to your Jira site and grant it access to every project
+ where OpenHands should read and comment.
+2. Log in as the service account and create an API token at
+ **id.atlassian.com → Security → API tokens**. Save the token somewhere
+ safe. You will need it for the next configuration step below.
+
+
+ Mentions and labels made by the service account itself are ignored to
+ prevent the agent from triggering itself. Always test from a regular user
+ account, not the service account.
+
+
+## Enable the integration in the Admin Console
+
+1. In the OpenHands Enterprise Admin Console, open **Config** and check
+ **Enable Jira Cloud Integration** under **Jira Cloud Integration**.
+2. Save and deploy the new version, and wait for the rollout to finish.
+
+After the deploy, a **Jira** card appears under **Settings → Integrations**
+in the OpenHands app.
+
+## Configure the workspace in OpenHands
+
+As an organization admin or owner, open **Settings → Integrations → Jira**
+in OpenHands and select **Configure**:
+
+- **Workspace**: the full site hostname, for example
+ `yourcompany.atlassian.net`. Webhook events are matched against this
+ hostname, so the bare site name is not sufficient.
+- **Service account email**: the service account's email address.
+- **Service account API token**: the token created above. The credentials are
+ validated against Jira when you save, so a typo fails immediately.
+- **Webhook secret**: choose a strong secret. You will paste the same secret
+ into Jira in the next step.
+
+Save, then copy the **events URL** shown below the webhook secret field. It
+has the form:
+
+```
+https://app./integration/jira/events
+```
+
+## Register the webhook in Jira
+
+In Jira, open **Settings (gear icon) → System → WebHooks** and create a
+webhook:
+
+- **URL**: the events URL copied above.
+- **Secret**: the same webhook secret entered in OpenHands. Jira uses it to
+ sign deliveries, and OpenHands rejects unsigned or mis-signed events.
+- **Events**: check **Issue → updated** and **Comment → created**. These are
+ the only two events OpenHands processes.
+- Optionally scope the webhook with a JQL filter (for example
+ `project = ENG`).
+- Leave the request body included (do not check "Exclude body").
+
+## User requirements
+
+Each user who wants to trigger OpenHands from Jira must satisfy two
+conditions:
+
+1. **Matching email**: the user's Atlassian account email must exactly match
+ their OpenHands login email.
+2. **Visible email**: in the user's Atlassian account settings
+ (**id.atlassian.com → Profile and visibility → Contact → Email address**),
+ visibility must be set to **Anyone**. Jira omits the email from webhook
+ payloads otherwise, and OpenHands cannot match the user without it.
+
+
+ Atlassian can take 15 minutes or more to propagate an email-visibility
+ change into webhook payloads. If OpenHands replies that it could not
+ determine your email address right after you changed the setting, wait and
+ try again before assuming the setting is wrong.
+
+
+No further setup is needed: the first successful mention enrolls the user
+automatically.
+
+## Start OpenHands from an issue
+
+- Comment `@openhands` followed by instructions on any issue in a project the
+ webhook covers, or add the `openhands` label to the issue. Both the typed
+ literal text and the mention selected from Jira's autocomplete picker work.
+- To have OpenHands work in a repository, include the repository URL (for
+ example `https://gitlab.com/group/project` or
+ `https://github.com/org/repo`) in the issue description or the comment. The
+ triggering user must have that Git provider connected in OpenHands, and
+ exactly one repository should be mentioned. Without a repository, OpenHands
+ still answers on the issue but works without a workspace.
+
+OpenHands reacts with a comment linking to the conversation, and the service
+account posts the result back to the issue when the run completes.
+
+## Troubleshooting
+
+- **OpenHands replies "Could not determine your Jira email address"**: the
+ email-visibility requirement above is not met, or the change has not
+ propagated yet. Verify the exact setting and retry after 15 minutes.
+- **A mention does nothing, with no reply at all**: check that the comment
+ was not made by the service account (those are ignored), that the user's
+ Atlassian email matches their OpenHands email, and that the webhook covers
+ the issue's project. Jira Cloud does not show a delivery log for system
+ webhooks, so check the OpenHands logs (the `openhands-integrations`
+ workload) or collect a support bundle.
+- **Logs show `403 Unidentified workspace`**: the Workspace field in the
+ OpenHands configuration does not equal the site hostname in the webhook
+ payload. Re-open the configuration and set it to
+ `yourcompany.atlassian.net`.
+- **OpenHands replies that multiple repositories were found**: mention
+ exactly one repository in the issue and comment text.
+
### Jira Data Center
Source: https://docs.openhands.dev/enterprise/integrations/jira-data-center.md
@@ -47297,6 +50819,493 @@ access.
| Jira webhook deliveries do not reach OpenHands | Confirm the Jira Data Center network can reach the OpenHands app URL. |
| Jira API calls fail with TLS errors | Upload the Jira Data Center CA certificate in **Additional Trusted CA Certificates** and redeploy. |
+### External Observability Platforms
+Source: https://docs.openhands.dev/enterprise/integrations/observability-platforms.md
+
+OpenHands Enterprise (OHE) ships with [Laminar](/enterprise/analytics) as its
+built-in tracing backend. Every conversation emits OpenTelemetry traces that
+flow to the in-cluster Laminar service. If your organization already operates a
+different OpenTelemetry-compatible observability platform — Langfuse, Honeycomb,
+Tempo, Datadog, or any backend that speaks OTLP — you can redirect all OHE
+conversation traces to it without modifying OHE source or patching the Helm
+chart. The change is a set of environment variables on the runtime pod.
+
+This guide walks an operator through pointing OHE at an external observability
+platform and confirms what you get versus the built-in Laminar experience.
+
+
+ This guide is for **OpenHands Enterprise** operators who want to use an
+ external OTLP backend instead of, or in addition to, the bundled Laminar. If
+ you want to enable the bundled Laminar, see
+ [Analytics](/enterprise/analytics) instead. To route LLM traffic through an
+ external gateway (a separate concern from trace export), see
+ [External LLM Gateways](/enterprise/integrations/external-llm-gateways). For
+ SDK-level tracing concepts and the full list of OTLP backends the OpenHands
+ SDK supports, see [Observability & Tracing](/sdk/guides/observability).
+
+
+## Overview
+
+OHE's tracing layer is the Laminar Python SDK (`lmnr`), which is a thin wrapper
+over the OpenTelemetry SDK. The `lmnr` SDK respects standard
+`OTEL_EXPORTER_OTLP_TRACES_*` environment variables whenever its own
+Laminar-specific `LMNR_BASE_URL` is not set. That gives you a clean switch with
+no code changes:
+
+```text
+OpenHands Runtime (lmnr SDK + OpenTelemetry SDK)
+ │
+ ├── LMNR_BASE_URL set? ──► routes to in-cluster Laminar (default)
+ │
+ └── LMNR_BASE_URL unset? ──► reads OTEL_EXPORTER_OTLP_TRACES_* ──► your backend
+ (Langfuse, Honeycomb, …)
+```
+
+There are two integration paths:
+
+- **Direct (recommended).** Point the runtime straight at your OTLP/HTTP
+ backend. No extra infrastructure. Use this when your backend speaks OTLP/HTTP,
+ which Langfuse, Honeycomb, Tempo, and Datadog all do.
+- **Collector tap (optional).** Put an OpenTelemetry Collector between the
+ runtime and your backend. Use this when you need batching, retry, fan-out to
+ multiple backends, or a non-OTLP destination.
+
+Both paths leave OHE stock. The only change is pod environment variables.
+
+## Prerequisites
+
+Before you start, confirm:
+
+- **OHE is installed and reachable.** You can sign in at
+ `https://app.`.
+- **Your observability backend is reachable from the OHE cluster.** The runtime
+ pod makes outbound HTTP/S calls to the backend, so DNS and network paths must
+ resolve from inside the `openhands` namespace.
+- **You have an ingest endpoint and credentials on your backend.** You need the
+ OTLP traces URL and whatever auth the backend expects (an API key, Basic auth,
+ or a bearer token).
+- **You have cluster access** to edit Helm values or the Replicated Admin
+ Console, and can restart the runtime pod.
+
+## Choose your backend
+
+The configuration is the same for every OTLP/HTTP backend. Only the endpoint
+URL, auth header, and protocol differ.
+
+
+
+ Self-hosted or Cloud. OTLP/HTTP with Basic auth. Maps OHE LLM spans to
+ Langfuse generations with model, tokens, and cost.
+
+
+ OTLP/HTTP with a header API key. High-cardinality distributed tracing.
+
+
+ OTLP/gRPC or HTTP. Open-source trace storage, queried from Grafana.
+
+
+ Any backend that accepts OTLP. Jaeger, Datadog, New Relic, Splunk, and more.
+
+
+
+## How tracing works in OHE
+
+The runtime pod sets these environment variables by default when Laminar is
+enabled (see [Analytics](/enterprise/analytics)):
+
+```yaml
+LMNR_BASE_URL: "http://laminar-app-server-service"
+LMNR_FORCE_HTTP: "true"
+LMNR_HTTP_PORT: "8000"
+LMNR_PROJECT_API_KEY: ""
+```
+
+The `lmnr` SDK resolves its trace exporter like this:
+
+1. If `LMNR_BASE_URL` is set, the SDK routes to Laminar and **ignores** any
+ `OTEL_EXPORTER_OTLP_TRACES_*` variables. This is the default state.
+2. If `LMNR_BASE_URL` is **not** set, the SDK falls back to the standard
+ OpenTelemetry environment variables and emits OTLP directly to whatever
+ endpoint you configure.
+
+
+ The switch is `LMNR_BASE_URL`. As long as it is set, the runtime keeps
+ sending traces to Laminar and ignores your `OTEL_*` variables. To redirect
+ traces to your own backend, you must unset `LMNR_BASE_URL` (and the other
+ `LMNR_*` connection variables) **and** set the `OTEL_EXPORTER_OTLP_TRACES_*`
+ variables. Setting only the `OTEL_*` variables while Laminar is still
+ enabled has no effect.
+
+
+The SDK reads these variables in standard OpenTelemetry precedence (highest
+first): `OTEL_EXPORTER_OTLP_TRACES_*`, then `OTEL_EXPORTER_OTLP_*`, then
+`OTEL_*`. Setting the `_TRACES_` variants is the most explicit and recommended
+form.
+
+## Configure OHE
+
+Pick the path that matches how OHE is deployed.
+
+
+
+ Disable the bundled Laminar and set the OpenTelemetry exporter variables
+ under the top-level `env` block in your `values.yaml`:
+
+ ```yaml
+ laminar:
+ enabled: false
+
+ env:
+ # Unset the Laminar connection variables explicitly so no chart
+ # default re-injects them:
+ LMNR_BASE_URL: ""
+ LMNR_PROJECT_API_KEY: ""
+ LMNR_FORCE_HTTP: ""
+ LMNR_HTTP_PORT: ""
+
+ # Point the OpenTelemetry SDK at your backend:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http:///api/public/otel/v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+ OTEL_EXPORTER_OTLP_TRACES_HEADERS: "Authorization=Basic "
+ ```
+
+ Supply any secret values (API keys, Basic auth strings) as a Kubernetes
+ secret rather than committing them in `values.yaml`:
+
+ ```bash
+ kubectl -n openhands create secret generic observability-auth \
+ --from-literal=OTLP_AUTH_HEADER='Authorization=Basic '
+ ```
+
+ Then reference the secret in `values.yaml` and redeploy:
+
+ ```yaml
+ env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http:///api/public/otel/v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+ OTEL_EXPORTER_OTLP_TRACES_HEADERS:
+ valueFrom:
+ secretKeyRef:
+ name: observability-auth
+ key: OTLP_AUTH_HEADER
+ ```
+
+ ```bash
+ helm upgrade openhands oci://registry.replicated.com/openhands/openhands \
+ --namespace openhands \
+ --values values.yaml
+ ```
+
+ Restart the runtime pod after the upgrade so the new environment is picked
+ up:
+
+ ```bash
+ kubectl -n openhands rollout restart deploy/openhands
+ ```
+
+
+
+ The Replicated Admin Console exposes the Laminar configuration fields (see
+ [Analytics](/enterprise/analytics)) but does not currently expose
+ `OTEL_EXPORTER_OTLP_TRACES_*` fields directly. To redirect traces to your
+ own backend on a VM install:
+
+ 1. In the **Analytics Configuration** section, **uncheck Enable Analytics**
+ so the installer stops setting the `LMNR_*` variables.
+ 2. Use the Replicated **Custom Environment Variables** feature (Advanced
+ Options) to add the three `OTEL_EXPORTER_OTLP_TRACES_*` variables above.
+ 3. Save and deploy. The runtime pod restarts with the new environment.
+
+
+ If your OHE version's Admin Console does not expose a custom environment
+ variable section, this path is not available on VM installs without a
+ support escalation. The Helm (Kubernetes) path is fully supported. Check
+ your release notes or contact OpenHands support for the custom-env
+ availability on your version.
+
+
+
+
+## Backend-specific configuration
+
+The three values you need differ per backend: the endpoint URL, the auth
+header, and the protocol.
+
+### Langfuse {#langfuse}
+
+Langfuse v3 and v4 expose an OTLP/HTTP ingestion endpoint. Authentication is
+HTTP Basic, with the Langfuse **public key** as the username and the **secret
+key** as the password.
+
+```yaml
+env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "https:///api/public/otel/v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+ OTEL_EXPORTER_OTLP_TRACES_HEADERS: "Authorization=Basic "
+```
+
+Compute the Basic auth value with:
+
+```bash
+echo -n "pk-lf-xxxxxxxx:sk-lf-yyyyyyyy" | base64
+```
+
+
+ Langfuse v4 self-hosted installs default to **events-only mode**, which
+ accepts traces on `/api/public/otel/v1/traces` but does not expose the
+ legacy `GET /api/public/traces` endpoint. Read trace data with
+ `GET /api/public/v2/observations` instead. The Langfuse UI reads from the
+ same store, so traces appear in the UI regardless of mode.
+
+
+Langfuse maps the OpenTelemetry `gen_ai.*` semantic conventions that the `lmnr`
+SDK emits onto its own observation model, so LLM calls render as **GENERATION**
+observations with model, token usage, and input/output content. See
+[What you get](#what-you-get) below.
+
+### Honeycomb {#honeycomb}
+
+Honeycomb accepts OTLP/HTTP with the API key in the `x-honeycomb-team` header.
+
+```yaml
+env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "https://api.honeycomb.io/v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+ OTEL_EXPORTER_OTLP_TRACES_HEADERS: "x-honeycomb-team="
+```
+
+Set the Honeycomb dataset by adding `x-honeycomb-dataset=` to the
+headers value, comma-separated.
+
+### Grafana Tempo {#tempo}
+
+Tempo accepts OTLP over gRPC or HTTP. For gRPC:
+
+```yaml
+env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://:4317"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "grpc/protobuf"
+```
+
+For HTTP:
+
+```yaml
+env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://:4318/v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+```
+
+Tempo does not require auth on the OTLP receiver by default. If you put Tempo
+behind a gateway that requires auth, add the header to
+`OTEL_EXPORTER_OTLP_TRACES_HEADERS`.
+
+### Generic OTLP {#generic-otlp}
+
+For any backend that accepts OTLP (Jaeger, Datadog, New Relic, Splunk
+Observability, and others), set the endpoint and protocol your backend
+documents, plus any auth header it requires:
+
+```yaml
+env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "https:///v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+ OTEL_EXPORTER_OTLP_TRACES_HEADERS: "=,="
+```
+
+Headers are comma-separated `key=value` pairs, URL-encoded. Most backends
+accept a single `Authorization` or `X-API-Key` header.
+
+## What you get
+
+A single OHE conversation produces one trace with a nested span tree. The
+shape is the same whether the traces land in Laminar or in your external
+backend:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Each conversation is grouped under a single trace ID (the OpenHands
+conversation UUID), so all spans from one conversation — across every agent
+step, LLM call, and tool execution — appear together.
+
+For LLM spans, the `lmnr` SDK emits standard OpenTelemetry `gen_ai.*` semantic
+conventions:
+
+| Attribute | Meaning |
+|-----------|---------|
+| `gen_ai.request.model` | Model name (for example, `claude-sonnet-4-5-20250929`) |
+| `gen_ai.usage.input_tokens` | Prompt tokens |
+| `gen_ai.usage.output_tokens` | Completion tokens |
+| `gen_ai.input.messages` | The request messages (JSON) |
+| `gen_ai.output` / `gen_ai.completion` | The response content |
+| `openinference.span.kind` | Span classification: `LLM`, `TOOL`, `AGENT`, `CHAIN` |
+
+Backends that understand these conventions render LLM calls as first-class
+generation spans with model, token usage, and prompt content. In Langfuse,
+LLM spans become **GENERATION** observations; tool spans become **TOOL**
+observations; the conversation root becomes an **AGENT** observation. The
+nesting, trace ID, session ID, and user ID are all preserved.
+
+### Cost calculation
+
+Laminar computes cost from the token usage on each LLM span. External backends
+do the same, but only when the model is registered in the backend's model
+catalog with pricing. If a model is missing from the catalog, the span still
+appears with token counts, but cost is blank.
+
+
+ After pointing OHE at Langfuse, add each model your runtime uses (for example,
+ `claude-sonnet-4-5-20250929`, `gpt-4o`) to Langfuse's **Settings → Models**
+ table with input and output token prices. Until you do, cost columns are
+ empty even though token usage is captured.
+
+
+## Optional: OTel Collector tap
+
+If you want batching, retry, fan-out to multiple backends, or a non-OTLP
+destination, deploy an OpenTelemetry Collector in the `openhands` namespace and
+point the runtime at it instead of directly at your backend.
+
+```text
+OpenHands Runtime ──► OTel Collector ──► your backend(s)
+ (batch, retry, (Langfuse, Tempo, …)
+ fan-out, filter)
+```
+
+Point the runtime at the collector's OTLP receiver:
+
+```yaml
+env:
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://otel-collector.openhands.svc:4318/v1/traces"
+ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: "http/protobuf"
+```
+
+Collector config (`otel-collector-config.yaml`):
+
+```yaml
+receivers:
+ otlp:
+ protocols:
+ http:
+ endpoint: 0.0.0.0:4318
+ grpc:
+ endpoint: 0.0.0.0:4317
+
+processors:
+ batch:
+ timeout: 5s
+ send_batch_size: 512
+
+exporters:
+ otlphttp/langfuse:
+ endpoint: http:///api/public/otel
+ headers:
+ Authorization: "Basic "
+ # Add a second exporter to dual-sink into Laminar or another backend.
+
+service:
+ pipelines:
+ traces:
+ receivers: [otlp]
+ processors: [batch]
+ exporters: [otlphttp/langfuse]
+```
+
+This is also how you keep Laminar running as a secondary sink while sending
+traces to your own platform: add a second exporter pointing at the in-cluster
+Laminar service.
+
+## Keep Laminar and add a second backend
+
+If you want traces in **both** Laminar and your own backend, do not unset
+`LMNR_BASE_URL`. Instead, deploy an OTel Collector as above and configure the
+runtime to send to the collector, with the collector exporting to both
+Laminar and your backend. This preserves the built-in Laminar experience
+(including the Admin Console Traces tab and Laminar signals) while mirroring
+the same traces to your platform.
+
+## Troubleshooting
+
+
+
+ `LMNR_BASE_URL` is still set. As long as it is present, the `lmnr` SDK
+ routes to Laminar and ignores `OTEL_*` variables. Confirm the runtime pod
+ does not have `LMNR_BASE_URL` set:
+
+ ```bash
+ kubectl -n openhands exec deploy/openhands -- printenv | grep -E 'LMNR_|OTEL_'
+ ```
+
+ You should see the `OTEL_*` variables and **no** `LMNR_BASE_URL`. If
+ `LMNR_BASE_URL` is still present, the Laminar block in your `values.yaml`
+ or Admin Console is still enabled. Disable it and restart the pod.
+
+
+
+ - Confirm the endpoint URL is reachable from inside the cluster:
+
+ ```bash
+ kubectl -n openhands exec deploy/openhands -- \
+ curl -sS -o /dev/null -w "%{http_code}" \
+ http:///api/public/otel/v1/traces
+ ```
+
+ A `405` (Method Not Allowed) on `GET` is fine — it means the endpoint
+ exists. A timeout or connection refused means DNS or network policy is
+ blocking the path.
+
+ - Confirm the auth header is correct. Most OTLP backends return `401` for
+ a bad key. Langfuse requires HTTP Basic with `publicKey:secretKey`;
+ a bearer token returns `401 Invalid public key`.
+ - Confirm the protocol matches your endpoint. Most backends require
+ `http/protobuf`. Use `grpc/protobuf` only if your backend exposes a
+ gRPC OTLP receiver.
+
+
+
+ The token usage is captured, but the model is not in your backend's model
+ catalog. Add the model with pricing in your backend's settings (in
+ Langfuse, **Settings → Models**). See [Cost calculation](#cost-calculation).
+
+
+
+ The `lmnr` SDK emits input content under `gen_ai.input.messages` and output
+ under `gen_ai.completion` (or `gen_ai.output` depending on the provider
+ instrumentation). If your backend maps a different attribute name, the
+ content field is blank while token counts still populate. This is a
+ backend-side mapping difference, not an OHE issue. Real OHE conversations
+ use the `lmnr` Anthropic and OpenAI auto-instrumentation, which emits the
+ standard attribute names.
+
+
+
+ The Replicated Admin Console does not currently expose
+ `OTEL_EXPORTER_OTLP_TRACES_*` fields directly. Uncheck **Enable Analytics**
+ to clear the `LMNR_*` variables, then use the Replicated custom environment
+ variable feature to add the `OTEL_*` variables. If your version does not
+ expose custom environment variables, contact OpenHands support.
+
+
+
+## Reference
+
+- Built-in Laminar setup: [Analytics](/enterprise/analytics)
+- SDK tracing concepts and OTLP backends: [Observability & Tracing](/sdk/guides/observability)
+- OpenTelemetry OTLP exporter environment variables: [OTEL spec](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exporter-configuration)
+- Langfuse OTLP ingestion: [Langfuse docs](https://langfuse.com/docs/tracing-data/otel/overview)
+- OpenTelemetry Collector configuration: [OTel Collector docs](https://opentelemetry.io/docs/collector/configuration/)
+
### Slack
Source: https://docs.openhands.dev/enterprise/integrations/slack.md
@@ -47779,6 +51788,10 @@ OpenHands Enterprise consists of several components deployed as Kubernetes workl
## Guides
+
+ Size your node pools, volume storage, and database from peak concurrent sandboxes.
+
+
End-to-end installation instructions using your OpenHands Enterprise license.
@@ -47803,6 +51816,10 @@ OpenHands Enterprise consists of several components deployed as Kubernetes workl
Configure memory, CPU, and storage for optimal performance.
+
+ Generic advice for upgrading the Kubernetes cluster underneath OpenHands.
+
+
## Request Access
Kubernetes-based installation is currently available to select customers on request.
@@ -48365,6 +52382,9 @@ overrides on the same release — edit your `values.yaml` and apply with
## Troubleshooting
+For a guided diagnostic workflow and a map of OHE components, see
+[Troubleshooting](/enterprise/troubleshooting).
+
### Generate a support bundle
If something isn't working, generate a support bundle with the
@@ -48373,7 +52393,7 @@ It discovers the diagnostic specs that ship with the chart and collects logs,
resource states, and health checks from the installation:
```bash
-support-bundle --load-cluster-specs --namespace openhands
+kubectl support-bundle --load-cluster-specs --namespace openhands
```
### Send it to us
@@ -48382,7 +52402,7 @@ Upload the resulting archive directly to our support team — the upload
authenticates with the license embedded in the bundle:
```bash
-support-bundle upload support-bundle-.tar.gz
+kubectl support-bundle upload support-bundle-.tar.gz
```
### Common issues
@@ -48660,6 +52680,9 @@ For production deployments, we recommend integrating with a monitoring solution
## Next Steps
+
+ Translate peak concurrent sandboxes into node pools, storage, and database size.
+
Return to the Kubernetes installation overview.
@@ -48756,6 +52779,103 @@ The output should be `sysbox-runc`.
+### Upgrade Guidance
+Source: https://docs.openhands.dev/enterprise/k8s-install/upgrade-guidance.md
+
+A few OpenHands-specific properties may make a cluster upgrade more high-touch than usual. Sandboxes run on a [Sysbox](/enterprise/k8s-install/sysbox) node pool. The pods in this node pool carry a zero-tolerance [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) which means that typical upgrade operations will hang indefinitely while those pods refuse eviction.
+
+This page collects general guidance that applies on any managed Kubernetes offering (GKE, EKS, AKS) or on self-managed clusters. See the information below in an advisory capacity, rather than a runbook.
+
+Upgrade in this order: control plane first, then your ordinary node pools, then the Sysbox pool. Never let nodes run ahead of the control plane. Only the sysbox node pool may need special handling
+
+## Control Plane
+
+A plain upgrade is fine. Follow the usual pre-upgrade best practices for your platform, such as:
+
+- **Review removed and deprecated APIs** for the target version and confirm nothing you deploy still uses them. Most managed platforms surface this for you — GKE deprecation insights, `kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis`, or a tool like [Pluto](https://github.com/FairwindsOps/pluto) against your manifests.
+- **Move one minor version at a time** and check the version skew policy of your provider before you start.
+- **Expect the upgrade to be one-way.** No managed platform lets you roll a control plane back, so verify on a non-production cluster first if you have one.
+
+OpenHands itself is unaffected by a control-plane upgrade. Sandboxes keep running throughout.
+
+## Non-Sandbox Node Pools
+
+Also a plain upgrade. A standard surge upgrade is appropriate here — the platform brings up new nodes, drains the old ones, and your workloads reschedule.
+
+Expect roughly the same behavior you would see when upgrading OpenHands itself: server and supporting pods restart, in-flight requests may blip, and the UI briefly reconnects. If your OpenHands deployment runs a single replica, that blip is a short outage. Scale up beforehand if you need to avoid it — see [Resource Limits](/enterprise/k8s-install/resource-limits) for replica and autoscaling settings.
+
+Running sandboxes are not affected, since they live on the Sysbox pool.
+
+## Sysbox Node Pool
+
+This is the pool that needs a decision. Sandbox pods refuse eviction while they are alive, so a plain drain will not complete — the upgrade hangs rather than fails, often with no obvious signal beyond a node stuck in `SchedulingDisabled`.
+
+Pick a branch based on whether you can tolerate interrupting active conversations.
+
+
+
+ Simpler and needs no extra capacity, but it ends active conversations.
+
+ 1. **Cordon the Sysbox nodes** so no new sandboxes land on them, and lower the pool's autoscaler ceiling if it has one.
+ 2. **Drain the remaining sandboxes.** Either wait for active conversations to finish, or end them. The upgrade will not proceed while sandbox pods are still alive, so getting to zero is the gating step — not an optimization.
+ 3. **Confirm the pool is empty** before starting:
+
+ ```bash
+ kubectl get pods -n openhands -o wide --field-selector spec.nodeName=
+ ```
+
+ 4. **Run a plain upgrade** on the pool once no sandbox pods remain.
+
+ Communicate the window to your users. From their side, an ended sandbox looks like a conversation that stopped working.
+
+
+ Stand up a second Sysbox pool at the target version and let the old one drain by attrition. No running sandbox is ever evicted, so the disruption budget never comes into play.
+
+ 1. **Create a new Sysbox pool** at the target version, alongside the existing one. Install Sysbox on it as usual — see [Installing Sysbox](/enterprise/k8s-install/sysbox).
+ 2. **Verify the new pool functionally, not just that nodes report `Ready`.** A node can be `Ready` with Sysbox not installed correctly. Confirm the RuntimeClass is registered and land one real sandbox on the new pool before steering anything to it:
+
+ ```bash
+ kubectl get runtimeclass sysbox-runc
+ kubectl get pods -n openhands -o wide | grep
+ ```
+
+ 3. **Cordon the old pool and lower its autoscaler ceiling.** New sandboxes then schedule onto the new pool while existing ones keep running where they are.
+ 4. **Wait for the old pool to empty** as conversations finish and their sandboxes terminate. How long that takes is a function of your conversation lifetimes, not the upgrade.
+ 5. **Delete the old pool** once no sandbox pods remain on it.
+
+
+ This approach needs enough capacity for both pools at once, at least briefly. On a large pool that can mean a meaningful number of extra instances — reserve the capacity ahead of the window if your cloud supports reservations, since instance stockouts are a more common cause of a stalled cutover than anything Kubernetes does.
+
+
+
+
+### Pod Disruption Budgets
+
+The sandbox disruption budget only interferes when active sandboxes are in play. Once no sandbox pods are running, it is inert and the pool upgrades like any other. That is why both branches above converge on the same thing: get the pool to zero sandboxes, by attrition or by ending them, and the rest is ordinary.
+
+If an upgrade appears to hang, check what is still holding the budget:
+
+```bash
+kubectl get pdb -A
+kubectl get pods -n openhands -o wide
+```
+
+## Upgrading OpenHands Itself
+
+Cluster upgrades are independent of OpenHands releases. To upgrade the OpenHands Enterprise chart, see [Install with Helm](/enterprise/k8s-install/installation) and the [Release Notes](/enterprise/release-notes).
+
+Avoid changing both at once: upgrade the cluster, verify sandboxes still launch, and only then move the application version.
+
+## Additional Info
+
+
+ Requirements and installation for the sandbox node pool runtime.
+
+
+
+ Size the application and sandbox workloads before planning capacity.
+
+
### Plugin Marketplace
Source: https://docs.openhands.dev/enterprise/plugin-marketplace.md
@@ -48998,6 +53118,10 @@ Before you begin, make sure you have the following ready:
You will need a VM to host OpenHands Enterprise. Choose one of the options below to provision your infrastructure.
+
+ The requirements below are the trial baseline, which comfortably supports about 15 concurrent sandboxes. For a larger rollout, pick your VM from the [Sizing Guide](/enterprise/sizing-guide) before provisioning.
+
+
We provide a [Terraform module](https://github.com/All-Hands-AI/OpenHands-Cloud/tree/main/terraform/aws) that provisions a properly configured environment
@@ -49029,6 +53153,17 @@ You will need a VM to host OpenHands Enterprise. Choose one of the options below
| **OS** | Linux (x86-64 architecture) |
| **Init system** | systemd |
| **Access** | Root access (sudo) required |
+
+
+ We recommend **Ubuntu 24.04 LTS**. The default **Sandbox Isolation** runtime
+ (Sysbox) is best supported on Ubuntu and requires **Linux kernel 6.3 or newer**,
+ which Ubuntu 24.04 provides. Very new, non-LTS releases (for example, Ubuntu 25.10
+ or later) may ship kernels that are not yet supported by Sysbox and can cause
+ sandbox containers to fail during startup. If you do not need Docker inside the
+ sandbox, you can instead select the standard runtime under **Sandbox Isolation** in
+ the installer, which does not require a Sysbox-compatible kernel. See
+ [Docker in Sandbox](/enterprise/docker-in-sandbox) for details.
+
@@ -49234,7 +53369,9 @@ The install guide provides commands to run on your VM. SSH into your VM and exec
3. **Extract the installation assets** -- run the `tar` command shown (this includes your license file)
4. **Install** -- run the install command shown
-If the install command fails after preflight checks pass, run `sudo ./openhands support-bundle` and share the resulting bundle with support.
+If the install command fails after preflight checks pass, see
+[Troubleshooting](/enterprise/troubleshooting) to generate a support
+bundle and open a support ticket.
**We recommend providing your TLS certificates during installation.** If you used the
@@ -49339,6 +53476,10 @@ Run our [script](https://github.com/All-Hands-AI/OpenHands-Cloud/tree/main/scrip
Go back to the Installer Admin Console in your browser and enter the values from the Create GitHub App script output. For the private key, upload the file from the `keys` directory of the script location.
+See [GitHub](/enterprise/integrations/github) for GitHub App installation,
+`@openhands` resolver behavior, pull request review identity, and repository-level
+review controls.
+
### Additional Integrations
If your team uses Jira Data Center or Bitbucket Data Center, follow these guides
@@ -49391,8 +53532,8 @@ OpenHands Enterprise is now running. You can open a repository or start a new co
Get the most out of your AI coding agents with effective prompting techniques.
-
- Reach out to the OpenHands team for deployment assistance or questions.
+
+ Collect diagnostics, inspect workloads, and contact OpenHands Support.
Explore the full OpenHands documentation for usage guides and features.
@@ -49402,6 +53543,532 @@ OpenHands Enterprise is now running. You can open a repository or start a new co
### Release Notes
Source: https://docs.openhands.dev/enterprise/release-notes.md
+## 0.64.0
+
+This release brings **shared LLM provider connections at the org level**, letting one connection back many members' managed profiles, and adds **configurable GPG commit signing** at the user level with a Set GPG Key button in app settings. Administrators gain new tools for organization lifecycle: a superadmin can seed a new org via a normal invitation, and Git providers can now be connected and disconnected post-auth from Settings → Integrations. Enterprise also splits automation permissions into separate view and manage roles.
+
+### Enterprise Server
+
+#### Features
+* feat: add ENABLE_BYOR_EXPORT env var and frontend feature flag by @tofarr in https://github.com/OpenHands/enterprise/pull/232
+* feat: configurable GPG commit signing at user level (OHE-3115) by @tofarr in https://github.com/OpenHands/enterprise/pull/264
+* feat: add Set GPG Key button to app settings by @tofarr in https://github.com/OpenHands/enterprise/pull/274
+* feat: add database-driven feature flag library (OHE-3101) by @tofarr in https://github.com/OpenHands/enterprise/pull/217
+* feat(org): shared LLM provider connections (cloud) by @juanmichelini in https://github.com/OpenHands/enterprise/pull/219
+* feat: link daily quota increase requests by @neubig in https://github.com/OpenHands/enterprise/pull/283
+* feat: add cron script to clean stale app_conversation_start_task rows by @tofarr in https://github.com/OpenHands/enterprise/pull/290
+* feat: OHE-3197 : Unify ENABLE_BILLING resolution through the feature flag env fallback by @tofarr in https://github.com/OpenHands/enterprise/pull/301
+* feat: split automations permission into view and manage by @tofarr in https://github.com/OpenHands/enterprise/pull/304
+* feat: add GET /organizations/{org_id}/members/{user_id} by @hieptl in https://github.com/OpenHands/enterprise/pull/313
+* feat: connect and disconnect Git providers post-auth from Settings > Integrations by @hieptl in https://github.com/OpenHands/enterprise/pull/309
+* feat(enterprise): allow superadmin to seed a new org via a normal invitation by @lilagrc in https://github.com/OpenHands/enterprise/pull/292
+* feat(enterprise): instance-level admin user lifecycle API (disable/enable/delete) by @neubig in https://github.com/OpenHands/enterprise/pull/181
+* feat: OHE-3178 : add per-conversation event index for efficient search by @tofarr in https://github.com/OpenHands/enterprise/pull/327
+
+#### Bug Fixes
+* fix: delete MCP servers from a null mcp_config entry by @hieptl in https://github.com/OpenHands/enterprise/pull/270
+* fix: remove --forked from test commands to fix coverage measurement by @tofarr in https://github.com/OpenHands/enterprise/pull/277
+* fix: include registered marketplaces in the conversation skills listing by @hieptl in https://github.com/OpenHands/enterprise/pull/286
+* fix: stop polling behind the re-auth modal once the session expires by @hieptl in https://github.com/OpenHands/enterprise/pull/298
+* fix: stop title updates clobbering conversation metadata by @hieptl in https://github.com/OpenHands/enterprise/pull/299
+* fix(budgets): make LiteLLM spend reporting resilient by @ak684 in https://github.com/OpenHands/enterprise/pull/242
+* fix: prevent invalid proxy tokens after managed profile changes by @saurya in https://github.com/OpenHands/enterprise/pull/209
+* fix(analytics): use detected automation trigger by @neubig in https://github.com/OpenHands/enterprise/pull/147
+* fix: Updated release please config to include uv.lock by @tofarr in https://github.com/OpenHands/enterprise/pull/330
+* fix: prevent cross-user managed LLM key attribution by @ak684 in https://github.com/OpenHands/enterprise/pull/317
+* fix(ui): disable telemetry UI in self-hosted enterprise by @ak684 in https://github.com/OpenHands/enterprise/pull/326
+
+#### Maintenance
+* refactor(frontend): remove legacy max-budget settings control by @saurya in https://github.com/OpenHands/enterprise/pull/213
+* chore: remove dead code by @tofarr in https://github.com/OpenHands/enterprise/pull/271
+* chore: remove redundant comments across enterprise codebase by @tofarr in https://github.com/OpenHands/enterprise/pull/272
+* chore: remove comments referencing previous functionality by @tofarr in https://github.com/OpenHands/enterprise/pull/273
+* test: replace mocked sessions with SQLite fixtures in org invitation store by @tofarr in https://github.com/OpenHands/enterprise/pull/276
+* docs: fix stale, wrong, and inapplicable documentation references by @tofarr in https://github.com/OpenHands/enterprise/pull/275
+* chore: remove Reo tracking integration by @neubig in https://github.com/OpenHands/enterprise/pull/227
+* refactor: PLTF-3545 PLTF-3546 flatten enterprise/ into the repo root and move to uv by @jlav in https://github.com/OpenHands/enterprise/pull/312
+
+---
+
+### Software Agent SDK
+
+#### Features
+* feat: add manifest to installed canvas extension responses by @hieptl in https://github.com/OpenHands/software-agent-sdk/pull/4611
+* feat(sdk): add ask_oracle tool by @enyst in https://github.com/OpenHands/software-agent-sdk/pull/3673
+* feat(agent-server): add INSTALL_ACP_PROVIDERS build arg by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4687
+* feat: move TypeScript client into monorepo by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4702
+* feat(agent-server): add INSTALL_CAPABILITIES build arg by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4698
+* feat: add ACP-less agent-server image fallback by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4805
+* feat(observability): allow selecting Laminar instruments by @Shimada666 in https://github.com/OpenHands/software-agent-sdk/pull/4434
+* feat(acp): centralize ACP npm installation metadata by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4832
+* feat(agent-server): add /sockets/session/{id} with a non-Event envelope by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4807
+* feat(acp): add Kimi Code, plus the hardening the other provider PRs share by @ysntony in https://github.com/OpenHands/software-agent-sdk/pull/4714
+* feat(sdk): register Pi as a built-in ACP provider by @Deep070203 in https://github.com/OpenHands/software-agent-sdk/pull/4419
+* feat(acp): add OpenCode as a built-in ACP provider by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4827
+* feat: add GPT-6 Astra model support by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4861
+* Add claude-sonnet-5 to PROMPT_CACHE_MODELS by @swabeinvader in https://github.com/OpenHands/software-agent-sdk/pull/4043
+* feat(plugin): map client extensions under the dev.openhands namespace by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4496
+
+#### Bug Fixes
+* fix(agent-server): keep crash recovery result on interrupted action branch by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4488
+* fix(workspace): honor explicit provider host when injecting git clone tokens by @rsd-darshan in https://github.com/OpenHands/software-agent-sdk/pull/4571
+* fix(agent-server): replace global _lifecycle_lock with per-conversation locks by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4570
+* fix(tools): unique user_data_dir per conversation to prevent SingletonLock collisions by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4602
+* fix(sdk): bound AsyncExecutor.close() so it cannot hang forever by @AaronAbuUsama in https://github.com/OpenHands/software-agent-sdk/pull/4548
+* fix(agent-server): detect all secret-bearing fields for the plaintext-save warning, not just llm.api_key by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4618
+* fix: enable condenser for subscription LLMs via existing completion dispatch by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4517
+* fix(sdk): resolve structured builtin tool specs remotely by @malhotra5 in https://github.com/OpenHands/software-agent-sdk/pull/4691
+* fix(agent-server): stop fanning streaming deltas out to every subscriber by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4689
+* fix(acp): never inject workspace project skills into an ACP agent (#4019) by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4699
+* fix(sdk): mask model output in the durable MessageEvent by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4783
+* fix(sdk): match nested repo paths by ancestry, not string prefix by @alanhuangyoo in https://github.com/OpenHands/software-agent-sdk/pull/4767
+* fix(tools): mask secrets in every tool's observation at the shared chokepoint by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4788
+* fix(agent-server): keep the idle timer alive during streamed completions by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4790
+* fix(sdk): remove secrets from subprocess env by @smolpaws in https://github.com/OpenHands/software-agent-sdk/pull/4801
+* fix(sdk): persist events before publishing them, return the assigned seq by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4806
+* fix(llm): allow security_risk param on read-only tools like finish by @sideeffffect in https://github.com/OpenHands/software-agent-sdk/pull/4153
+* fix(sdk): require fastmcp>=3.2.0 so expired MCP OAuth tokens refresh by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4857
+* fix(sdk): pick up a user message that arrives during an async step by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4194
+* fix(agent-server): propagate load_memory preference to all launch paths by @vnktadithya in https://github.com/OpenHands/software-agent-sdk/pull/4566
+* fix: respect OH_PERSISTENCE_DIR for all ~/.openhands paths by @jpshackelford in https://github.com/OpenHands/software-agent-sdk/pull/4476
+* fix(ci): align ready-for-dev gates with OpenHands pipefail-safe approach by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4607
+* fix(tests): stop pinning LLM capability tests to upstream metadata by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4879
+* fix(ci): centralize release publication dispatches by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4886
+* fix(agent-server): restore subscription credentials in pre-flight validation by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4898
+* fix(llm): register litellm_proxy alias pricing so spans aren't silently $0 by @juanmichelini in https://github.com/OpenHands/software-agent-sdk/pull/4836
+* fix(extensions): compose local source with repo_path by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4839
+
+#### Maintenance
+* docs: document SDK repository boundaries by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4587
+* chore(ci): clarify issue readiness bot comment and reference templates by @jpshackelford in https://github.com/OpenHands/software-agent-sdk/pull/4625
+* Relax ready-for-dev heading check to accept h2 headings by @all-hands-bot in https://github.com/OpenHands/software-agent-sdk/pull/4632
+* docs(examples): align Ask Oracle conventions by @enyst in https://github.com/OpenHands/software-agent-sdk/pull/4655
+* refactor(agent-server): share ACP provider payload as a parent-independent Docker layer by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4651
+* test(agent-server): cover conversation reads not serializing behind an unrelated start by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4685
+* ci: enforce SDK and TypeScript client version parity by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4779
+* refactor(agent-server): remove the VNC/desktop stack entirely by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4792
+* refactor(agent-server,ci): remove overdue org_config field and catch this class of gap in check_deprecations.py by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4795
+* ci: remove the endpoint-audit PR comment, report via the job summary by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4825
+* test(acp): live conformance + model-acceptance probes for built-in providers (#4830 P0) by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4834
+* ci(typescript-client): run integration tests against the branch's agent-server by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4844
+* perf(sdk): make EventLog.append cost flat against conversation length by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4697
+
+---
+
+### Runtime API
+
+#### Features
+* feat: OHE-3139 : Split cleanup CronJob into per-phase jobs by @tofarr in https://github.com/OpenHands/runtime-api/pull/729
+* feat: overlay database warm-runtime configs onto ConfigMap entries by name by @ak684 in https://github.com/OpenHands/runtime-api/pull/731
+* feat: Add coverage gate to unit test workflow by @tofarr in https://github.com/OpenHands/runtime-api/pull/737
+
+#### Bug Fixes
+* fix: redact sensitive URL query parameters in pod crash logs by @all-hands-bot in https://github.com/OpenHands/runtime-api/pull/706
+* fix: treat empty ADMIN_PASSWORD as unset so admin routes stay disabled by @ak684 in https://github.com/OpenHands/runtime-api/pull/730
+* fix: OHE-3187 : clean up warm runtimes orphaned by split-brain claim by @tofarr in https://github.com/OpenHands/runtime-api/pull/735
+
+---
+
+### Automation
+
+#### Features
+* feat: add structured task outcomes to preset finish tool by @malhotra5 in https://github.com/OpenHands/automation/pull/334
+* feat: replace the parse-only source registry with a provider descriptor and verifier registry by @VascoSch92 in https://github.com/OpenHands/automation/pull/378
+* feat: persist accepted events to deduplicate redeliveries and expose events that matched nothing by @VascoSch92 in https://github.com/OpenHands/automation/pull/381
+* feat: report lifetime per-status run counts on the runs list by @hieptl in https://github.com/OpenHands/automation/pull/383
+* feat: report live run phases for dashboard visibility by @hieptl in https://github.com/OpenHands/automation/pull/388
+* feat: add in-service Slack Socket Mode via a supervised stream transport by @VascoSch92 in https://github.com/OpenHands/automation/pull/384
+* feat: split automation permissions into view and manage by @tofarr in https://github.com/OpenHands/automation/pull/415
+* feat: auto-disable for consecutively failing automations [PLTF-3374] by @dylan-openhands in https://github.com/OpenHands/automation/pull/397
+* feat: route events to an existing conversation via a derived conversation id by @VascoSch92 in https://github.com/OpenHands/automation/pull/385
+* feat: add ready-for-dev issue and PR readiness gates by @neubig in https://github.com/OpenHands/automation/pull/380
+* feat: restrict automation edits to the creator by @hieptl in https://github.com/OpenHands/automation/pull/427
+
+#### Bug Fixes
+* fix: capture automation failure modes as status states by @malhotra5 in https://github.com/OpenHands/automation/pull/345
+* fix: treat missing tarball objects as permanent and defer superseded deletes until commit by @hieptl in https://github.com/OpenHands/automation/pull/356
+* fix: auto-disable unhealthy automations by @malhotra5 in https://github.com/OpenHands/automation/pull/352
+* fix: scope automation management to the org instead of the owner by @VascoSch92 in https://github.com/OpenHands/automation/pull/399
+* fix: require preset automations to use finish tool by @malhotra5 in https://github.com/OpenHands/automation/pull/405
+* fix: Forward X-Org-Id during automation auth by @malhotra5 in https://github.com/OpenHands/automation/pull/403
+* fix(automation): purge expired local-mode run workspaces by @trungminhdo4-glitch in https://github.com/OpenHands/automation/pull/277
+
+#### Maintenance
+* perf: remove redundant readiness query by @Linxiushen in https://github.com/OpenHands/automation/pull/303
+* refactor: extract a transport-neutral accept_event() from the webhook handler by @VascoSch92 in https://github.com/OpenHands/automation/pull/367
+* chore: add Dependabot configuration by @neubig in https://github.com/OpenHands/automation/pull/372
+* docs: document automation repository boundaries by @neubig in https://github.com/OpenHands/automation/pull/369
+* ci: enforce minimum 76% coverage on unit tests by @tofarr in https://github.com/OpenHands/automation/pull/419
+
+---
+
+### OpenHands Cloud (Helm Chart)
+
+#### Features
+* feat(local-kind): PLTF-3527 enable Agent Canvas at /canvas by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1168
+* feat(replicated): PLTF-3456 enable automations by default for new installs by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1158
+* feat(runtime-api): sync split cleanup CronJob from runtime-api#729 by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1178
+* feat(e2e): PLTF-3514 dispatch e2e test revision bumps to saas-deploy by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1148
+* feat: enable warm-runtime config overlay mode for Replicated by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1183
+* feat: configure Enterprise SSO for Replicated VM deployments by @jpelletier1 in https://github.com/OpenHands/OpenHands-Cloud/pull/1116
+* feat: add CronJob to clean stale app_conversation_start_task rows by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1196
+* feat: enable appConversationStartTaskClean CronJob by default by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1197
+* feat(skills): PLTF-3531 add upgrade-rollback-runbook skill by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1204
+* feat(skills): PLTF-3531 add gke-install cluster-install skill by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1205
+* feat(skills): PLTF-3531 add eks-install cluster-install skill by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1203
+* feat: diagnose runtime ingress failures in support bundles by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1208
+
+#### Bug Fixes
+* fix(local-kind): PLTF-3527 use bundled MinIO for conversation/event storage by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1163
+* fix(replicated): drop the KOTS update check that ruins the target cursor by @dylan-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1175
+* fix: Disable agent-canvas telemetry by default for self-hosted by @lilagrc in https://github.com/OpenHands/OpenHands-Cloud/pull/1156
+* fix(e2e): PLTF-3515 give the Tavily test its own conversation by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1146
+* fix: rename warm-runtime default config to v1_current to match the app default spec lookup by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1181
+* fix: give the Runtime API admin password a real KOTS field with a generated default by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1182
+* fix: advertise the runtime API ingress to fuse mounts by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1184
+* fix(chart): render reaper archive volume under a volumes: key (staging reaper outage) by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1185
+* fix(ci): bypass broken deploy-gate check temporarily by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1186
+* fix: make E2E repo-test prompt explicitly instruct file edit by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1189
+
+#### Maintenance
+* ci: check the agent-server tag against the enterprise SDK pin by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1167
+* ci: make the Replicated deploy check blocking, with a break-glass label [PLTF-3535] by @dylan-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1187
+* test: harden 003 legacy conversations spec (from #1176, without 005 canvas spec) by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1200
+* docs(skills): PLTF-3531 use --context=0 for helm diff in upgrade-rollback runbook by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1206
+* test(e2e): verify managed LLM key ownership by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1207
+
+## 0.55.0
+
+This release centers on **daily conversation quotas** for Enterprise Server, which add a read-only usage page with a reset countdown, org-level exemptions, and self-service quota increase requests verified by work email. Enterprise installs also gain **dedicated sandbox node scheduling**, with declared app and sandbox node roles, affinity plumbing across all pod specs, a config option to turn it on, and a preflight check that warns when it is enabled without a matching node. Issue tracker coverage expanded through an org-scoped Jira Cloud resolver with an email-match mode and through Azure DevOps resolver webhook configuration. The Agent SDK added an Agent Plugins manifest loader, structured output, a pre-flight LLM validation endpoint, and read-at-use LLM provider connections, while the Runtime API now anchors runtime reaping, database pruning, and the idle-grace period on last activity rather than creation time. The remainder of the release covers extensive billing and credit-handling fixes and hardened Keycloak identity matching that keys on the Keycloak subject rather than email.
+
+### Enterprise Server
+
+#### Features
+* feat(settings): increase LLM profile limit to 50 and make it configurable by @jpelletier1 in https://github.com/OpenHands/enterprise/pull/114
+* feat: add cloud workspace file-listing endpoint (OHE-3053) by @lilagrc in https://github.com/OpenHands/enterprise/pull/135
+* feat: Expose organization creation teaser UX by @malhotra5 in https://github.com/OpenHands/enterprise/pull/151
+* feat: set SaaS default model to Kimi K3 and migrate GLM 5.2 settings by @juanmichelini in https://github.com/OpenHands/enterprise/pull/190
+* feat: org-scope the Jira Cloud resolver and add email-match mode for OHE by @hieptl in https://github.com/OpenHands/enterprise/pull/192
+* feat(frontend): add data-testid to changes refresh button by @tofarr in https://github.com/OpenHands/enterprise/pull/203
+* feat: add daily conversation quota schema foundation by @neubig in https://github.com/OpenHands/enterprise/pull/180
+* feat: add read-only quota usage page with reset countdown by @neubig in https://github.com/OpenHands/enterprise/pull/199
+* feat: add work-email quota increase requests with self-service verification by @neubig in https://github.com/OpenHands/enterprise/pull/200
+* feat: add org-level daily conversation quota exemptions by @neubig in https://github.com/OpenHands/enterprise/pull/212
+* feat: accept Jira Cloud picker mentions of the service account by @ak684 in https://github.com/OpenHands/enterprise/pull/223
+* feat(settings): auto-rotate invalid managed LLM keys on settings writes by @tofarr in https://github.com/OpenHands/enterprise/pull/231
+* feat: migrate Kimi K3 settings to DeepSeek V4 Flash by @neubig in https://github.com/OpenHands/enterprise/pull/253
+
+#### Bug Fixes
+* fix: resolve LLM profile keys in /users/me expose-secrets response by @hieptl in https://github.com/OpenHands/enterprise/pull/168
+* fix: handle null identity_provider for direct Keycloak logins by @tofarr in https://github.com/OpenHands/enterprise/pull/169
+* fix: URL-encode Redis password in authed URL for coredis/limits by @tofarr in https://github.com/OpenHands/enterprise/pull/177
+* fix: close dropdown menu after selection when wrapped in a label by @hieptl in https://github.com/OpenHands/enterprise/pull/176
+* fix: stop redacting the Jira DC base URL in agent output by @hieptl in https://github.com/OpenHands/enterprise/pull/182
+* fix: inject Bitbucket DC server URL, repo URL, and token context into agent prompt by @hieptl in https://github.com/OpenHands/enterprise/pull/183
+* fix(auth): make Keycloak HTTP retries configurable by @neubig in https://github.com/OpenHands/enterprise/pull/186
+* fix: OHE-3100 : use sandbox_spec.working_dir instead of hardcoded /workspace by @tofarr in https://github.com/OpenHands/enterprise/pull/188
+* fix(auth): make LiteLLM management timeout configurable by @neubig in https://github.com/OpenHands/enterprise/pull/189
+* fix: handle null runtime context values by @ak684 in https://github.com/OpenHands/enterprise/pull/112
+* fix: use agent server as conversation creation source by @malhotra5 in https://github.com/OpenHands/enterprise/pull/156
+* fix: let managed LLM profiles take the org's current key on rotation by @dylan-openhands in https://github.com/OpenHands/enterprise/pull/178
+* fix(budgets): persist maintenance updates by @saurya in https://github.com/OpenHands/enterprise/pull/204
+* fix: let free-tier (no-credit) teams run $0-cost models by @juanmichelini in https://github.com/OpenHands/enterprise/pull/143
+* fix: protect personal organization billing credits by @saurya in https://github.com/OpenHands/enterprise/pull/167
+* fix(budgets): prevent per-user allowance renewal on sync by @saurya in https://github.com/OpenHands/enterprise/pull/205
+* fix: display usage monitoring timestamps in local time by @saurya in https://github.com/OpenHands/enterprise/pull/208
+* fix: use verified repo provider in Jira Cloud conversation start request by @ak684 in https://github.com/OpenHands/enterprise/pull/216
+* fix(billing): show personal-workspace credits without a member budget row by @aivong-openhands in https://github.com/OpenHands/enterprise/pull/218
+* fix: clarify Jira email-visibility guidance with exact setting and delay by @ak684 in https://github.com/OpenHands/enterprise/pull/222
+* fix(enterprise): match provisioned user on Keycloak sub, not email by @tofarr in https://github.com/OpenHands/enterprise/pull/224
+* fix(enterprise): match on Keycloak sub in TOCTOU idempotent recovery too by @tofarr in https://github.com/OpenHands/enterprise/pull/225
+* fix(enterprise): await session.merge in billing success callback by @tofarr in https://github.com/OpenHands/enterprise/pull/226
+* fix: OHE-3127 : return null credits instead of 503 when budget is None by @tofarr in https://github.com/OpenHands/enterprise/pull/228
+* fix: return 0 credits instead of None for users without a budget by @tofarr in https://github.com/OpenHands/enterprise/pull/238
+* fix(settings): stop a member's settings save writing to the whole org by @jlav in https://github.com/OpenHands/enterprise/pull/254
+
+#### Maintenance
+* chore: remove dead localStorage feature-flag mechanism by @tofarr in https://github.com/OpenHands/enterprise/pull/230
+* docs: Replace with Polyform License by @jpelletier1 in https://github.com/OpenHands/enterprise/pull/240
+
+---
+
+### Software Agent SDK
+
+#### Features
+* Feat: structured output by @luciobaiocchi in https://github.com/OpenHands/software-agent-sdk/pull/4207
+* agent-server: make conversation worktree root configurable by @xmrflipflop in https://github.com/OpenHands/software-agent-sdk/pull/4362
+* feat(observability): emit LLM and TOOL spans for ACP turns by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4376
+* feat: derive automation conversation tags in base RemoteWorkspace by @hieptl in https://github.com/OpenHands/software-agent-sdk/pull/4414
+* feat: emit canonical conversation telemetry from agent server by @malhotra5 in https://github.com/OpenHands/software-agent-sdk/pull/4459
+* feat(hooks): implement prompt-based evaluation by @onatozmenn in https://github.com/OpenHands/software-agent-sdk/pull/4160
+* feat(security): AST-backed shell command-name resolution (#2721 Phase 2b) by @eeee2345 in https://github.com/OpenHands/software-agent-sdk/pull/3944
+* feat: add public from_persisted() entry point to AgentSettingsBase by @mvanhorn in https://github.com/OpenHands/software-agent-sdk/pull/3503
+* feat(sdk): add cleanup LLM profile for outward agent text by @smolpaws in https://github.com/OpenHands/software-agent-sdk/pull/4344
+* feat(llm): resolve provider-specific runtime metadata for routed models by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4423
+* feat: add pre-flight LLM validation endpoint (POST /api/profiles/{name}/validate) by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4422
+* feat: carry ConversationErrorEvent on ConversationRunError for automation callbacks by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4458
+* feat(plugin): add Agent Plugins manifest loader (root plugin.json, closed schema) by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4474
+* feat(file-router): add POST /file/create_directory by @georgeglarson in https://github.com/OpenHands/software-agent-sdk/pull/4482
+* Add read-at-use LLM provider connections by @juanmichelini in https://github.com/OpenHands/software-agent-sdk/pull/4492
+* feat: Add deployment kind to agent-server telemetry by @malhotra5 in https://github.com/OpenHands/software-agent-sdk/pull/4522
+* feat(telemetry): identify automation conversations by @malhotra5 in https://github.com/OpenHands/software-agent-sdk/pull/4529
+* feat(tools): add structured task outcome preset by @malhotra5 in https://github.com/OpenHands/software-agent-sdk/pull/4479
+* feat(prompt): mention local conversation history by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4527
+
+#### Bug Fixes
+* fix(mcp): close reconciliation gaps left by #4367 by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4369
+* fix(acp): recover credential monitor after transient errors by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4403
+* fix(sdk): make ACP auth failures self-diagnosing by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4404
+* fix(observability): record non-executed tool results by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4415
+* fix(agent-server): compose ConversationInfo off the event loop to avoid GC wedge by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4417
+* fix(agent-server): initialize observability after deferred env by @Shimada666 in https://github.com/OpenHands/software-agent-sdk/pull/4426
+* fix(settings): inherit condenser max_tokens from LLM effective_max_input_tokens by @vnktadithya in https://github.com/OpenHands/software-agent-sdk/pull/4435
+* fix(goal): don't halt the goal loop on a STUCK run by @all-hands-bot in https://github.com/OpenHands/software-agent-sdk/pull/4381
+* fix(llm): stop serializing calls through global config by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4473
+* fix(security-scan): improve release security scan comment by @all-hands-bot in https://github.com/OpenHands/software-agent-sdk/pull/4397
+* fix(profiles): repair v1 skills migration by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4320
+* fix(agent-server): base_state.json as single source of truth for the agent (end meta.json duplication) by @enyst in https://github.com/OpenHands/software-agent-sdk/pull/4440
+* fix(sdk): cap condenser token limit by agent context by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4461
+* fix(agent-server): move bash event search off event loop and replace glob with scandir by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4481
+* fix: redact API key from validate_profile error responses and logs by @all-hands-bot in https://github.com/OpenHands/software-agent-sdk/pull/4506
+* fix: make dict-entry secret redaction case-insensitive by @chintan-diwakar in https://github.com/OpenHands/software-agent-sdk/pull/4508
+* fix(agent-server): propagate out-of-band run failures as ConversationErrorEvent (#16686) by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4535
+* fix(sdk): normalize Kimi K3 vision metadata by @malhotra5 in https://github.com/OpenHands/software-agent-sdk/pull/4567
+* fix(agent): keep terminal prefix aliases from doubling an existing executable by @onatozmenn in https://github.com/OpenHands/software-agent-sdk/pull/4471
+* fix(sdk): resolve workspace default from active LLM profile by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4497
+
+#### Maintenance
+* chore: drop the OpenHands/OpenHands bump-PR target from version-bump-prs.yml by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4400
+* refactor(plugin): extract PluginFormat strategy (prep for Agent Plugins support) by @jpshackelford in https://github.com/OpenHands/software-agent-sdk/pull/4420
+* chore(ci): collapse the auto-posted Agent Server images PR section by @smolpaws in https://github.com/OpenHands/software-agent-sdk/pull/4442
+* Add ready-for-dev issue and PR gates by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4464
+* test(terminal): stabilize Windows Ctrl-C cleanup assertion by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4290
+* perf(agent-server): cache unchanged conversation summaries by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4483
+* ci: re-run PR description check when new commits are pushed by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4486
+* Weekly test sweep: remove low-value tests + simplify by @enyst in https://github.com/OpenHands/software-agent-sdk/pull/4484
+* test(sdk): pin events_to_messages boundaries + fix responses_reasoning_item batch drop by @georgeglarson in https://github.com/OpenHands/software-agent-sdk/pull/4526
+* test(sdk): pin send_message skill-activation wiring by @georgeglarson in https://github.com/OpenHands/software-agent-sdk/pull/4536
+
+---
+
+### Runtime API
+
+#### Bug Fixes
+* fix: anchor runtime reaping and DB pruning on last activity, not creation time by @hieptl in https://github.com/OpenHands/runtime-api/pull/707
+* fix: anchor the idle-grace period on last_state_change, not created_at by @hieptl in https://github.com/OpenHands/runtime-api/pull/713
+* fix: OHE-3100 : root-owned working_dir subdirs on PVC via init container by @tofarr in https://github.com/OpenHands/runtime-api/pull/714
+* fix: reorder cleanup phases and resume expired deployment list tokens by @dylan-openhands in https://github.com/OpenHands/runtime-api/pull/712
+
+---
+
+### Automation
+
+#### Features
+* feat(automation): tag local automation conversations by @neubig in https://github.com/OpenHands/automation/pull/319
+* feat: sync automations to a git repository by @VascoSch92 in https://github.com/OpenHands/automation/pull/327
+* feat: accept catalog bundle automations on the raw create path by @VascoSch92 in https://github.com/OpenHands/automation/pull/346
+
+#### Bug Fixes
+* fix: stop marking successful automation runs as FAILED by @hieptl in https://github.com/OpenHands/automation/pull/331
+
+#### Maintenance
+* chore: add success logging for tarball storage writes and deletes by @jpshackelford in https://github.com/OpenHands/automation/pull/335
+* chore: remove QA changes workflow by @neubig in https://github.com/OpenHands/automation/pull/340
+
+---
+
+### OpenHands Cloud (Helm Chart)
+
+#### Features
+* feat: e2e: restructure for Keycloak admin + dual GitHub user flows by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1089
+* feat: add configurable daily conversation limit to chart by @neubig in https://github.com/OpenHands/OpenHands-Cloud/pull/1100
+* feat: wire Jira Cloud email-match integration for Replicated installs by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1113
+* feat: add org-management e2e suite with super-admin REST provisioning by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1122
+* feat(replicated): declare app and sandbox node roles by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1133
+* feat(chart): add affinity plumbing to all pod specs by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1134
+* feat(replicated): gate dedicated sandbox nodes behind a config option by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1135
+* feat(preflight): warn when dedicated sandbox nodes are enabled with no sandbox node by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1136
+* feat(replicated): PLTF-3461 configure duplicate email checks by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1139
+* feat(azure-devops): wire the resolver webhook secret into the chart and KOTS config by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1160
+
+#### Bug Fixes
+* fix: Bound Laminar ClickHouse diagnostic log retention by @juanmichelini in https://github.com/OpenHands/OpenHands-Cloud/pull/1031
+* fix: wire installer SMTP config into Keycloak realm email by @hieptl in https://github.com/OpenHands/OpenHands-Cloud/pull/1090
+* fix(e2e): handle onboarding-form and 2FA auto-navigate race conditions by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1091
+* fix(e2e): enable role during static discovery by @saurya in https://github.com/OpenHands/OpenHands-Cloud/pull/1099
+* fix(e2e): replace networkidle waits and fix Promise.race short-circuit by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1108
+* fix(automation): keep events service available during node drains by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1112
+* fix: refresh changes panel when empty in VSCode integration test by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1114
+* fix(e2e): order API keys spec after billing so new-user has credits by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1118
+* fix(e2e): PLTF-3461 honor AUTH_BASE_URL for Keycloak admin URL by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1126
+* fix(chart): set the warm pool working dir to /workspace/project by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1140
+* fix(deploy): tolerate a restarting kotsadm in replicated_deploy.sh by @dylan-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1141
+* fix(e2e): PLTF-3461 move the credit-gated API key check into the billing suite by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1143
+* fix(ci): PLTF-3461 call the E2E trigger from each release workflow by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1144
+
+#### Maintenance
+* test(e2e): add Playwright release harness by @saurya in https://github.com/OpenHands/OpenHands-Cloud/pull/1048
+* test(e2e): cover organization-scoped member API keys by @saurya in https://github.com/OpenHands/OpenHands-Cloud/pull/1049
+* test(e2e): add optional ReportPortal reporting by @saurya in https://github.com/OpenHands/OpenHands-Cloud/pull/1088
+* test(e2e): make returning/new-user roles opt-in via *_GITHUB_USERNAME by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1092
+* test(e2e): migrate Stripe credit purchase into billing suite by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1094
+* test(e2e): migrate home avatar and user-menu tests by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1095
+* test(e2e): remove example.spec.ts by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1096
+* test(e2e): migrate API key creation and API access test by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1097
+* test(e2e): migrate legacy conversation control tests by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1101
+* ci: auto-deploy Replicated releases to internal instances by @dylan-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1123
+* ci: PLTF-3461 run E2E after Replicated deploys by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1129
+* ci: name the Replicated release workflows consistently for README badges by @dylan-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1131
+* ci: fix unparseable expression in deploy-replicated, lint workflows in CI by @dylan-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1132
+
+---
+
+## 0.45.0
+
+This release introduces **Canvas Extensions**, a major new capability that enables installing, managing, and refreshing extensions with manifest support and persistent storage. The Agent SDK saw significant improvements with conversation error classification, accumulated LLM cost tracking, and observability enhancements including detached traces for delegate conversations. The Automation component was modernized with the retirement of the standalone frontend, enhanced preset metadata, and LLM cost tracking. Critical stability fixes addressed S3/MinIO silent truncation issues, improved CSP compatibility for the Monaco diff viewer, and enhanced secrets handling across the platform.
+
+### Enterprise Server
+
+#### Features
+* feat: migrate existing managed MiniMax M2.7 settings to the GLM 5.2 default by @juanmichelini in https://github.com/OpenHands/enterprise/pull/140
+
+#### Bug Fixes
+* fix(sandbox): OHE-3021 : honor OH_SANDBOX_MAX_NUM_SANDBOXES in RemoteSandboxServiceInjector fallback by @tofarr in https://github.com/OpenHands/enterprise/pull/153
+* fix: self-host Monaco so the diff viewer works under CSP by @hieptl in https://github.com/OpenHands/enterprise/pull/155
+* fix: stop silent truncation of archived and shared conversations on S3/MinIO by @hieptl in https://github.com/OpenHands/enterprise/pull/158
+* fix: stop surfacing Git provider token required errors for SSO-only users by @hieptl in https://github.com/OpenHands/enterprise/pull/159
+* fix(s3 file store): OHE-3079 : paginate list_objects_v2 to avoid silent truncation at 1000 keys by @tofarr in https://github.com/OpenHands/enterprise/pull/157
+* fix: redirect Automations sidebar icon to /canvas/automations by @hieptl in https://github.com/OpenHands/enterprise/pull/162
+
+---
+
+### Software Agent SDK
+
+#### Features
+* feat(llm): verify kimi-for-coding (Kimi Code membership) by @georgeglarson in https://github.com/OpenHands/software-agent-sdk/pull/4150
+* feat(sdk): classify conversation errors by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4316
+* feat: report accumulated LLM cost in the automation completion callback by @hieptl in https://github.com/OpenHands/software-agent-sdk/pull/4311
+* feat(agent-server): Canvas Extensions manifest and containment [1/4] by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4361
+* feat(sdk): track requested_ref alongside resolved_ref in InstallationInfo [2/4] by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4375
+* feat(agent-server): Canvas Extensions installation persistence [3/4] by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4364
+* feat(agent-server): Canvas Extensions staged refresh (check/apply) [4/4] by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4374
+
+#### Bug Fixes
+* fix(sdk): respect subscription validator composition by @Sehlani042 in https://github.com/OpenHands/software-agent-sdk/pull/3953
+* fix(agent-server): keep secrets out of workspace persistence by @enyst in https://github.com/OpenHands/software-agent-sdk/pull/3990
+* fix(acp): surface Claude Opus 5 in Claude Code model picker by @nicolasdmolina in https://github.com/OpenHands/software-agent-sdk/pull/4326
+* fix: PATCH /api/settings loads the profile's LLM when setting active_profile by @emmanuel-adu in https://github.com/OpenHands/software-agent-sdk/pull/4319
+* fix(git): demote expected command failures to debug by @neubig in https://github.com/OpenHands/software-agent-sdk/pull/4341
+* fix(sdk): nudge before hard-terminating on a repeating action-error pattern by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4332
+* fix(mcp): reconcile live agent tool snapshots by @Shimada666 in https://github.com/OpenHands/software-agent-sdk/pull/4367
+* fix(observability): mark utility LLM spans (title generation, ask_agent) by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4359
+* fix(observability): give delegate conversations their own detached Laminar trace by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4378
+* fix(browser): a browser tool that cannot start should not fail the conversation by @onatozmenn in https://github.com/OpenHands/software-agent-sdk/pull/4342
+* fix(observability): keep the conversation object out of TOOL span input by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4379
+
+#### Maintenance
+* chore(ci): remove QA Changes workflows by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4299
+* refactor(llm): add LiteLLM-backed provider abstraction by @enyst in https://github.com/OpenHands/software-agent-sdk/pull/2363
+* chore(sdk): deprecate AgentBase.model_dump_succint by @AzeelSajjad in https://github.com/OpenHands/software-agent-sdk/pull/4328
+* refactor(observability): stop depending on lmnr to propagate trace context into tool workers by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4360
+* test: stop ambient LMNR env vars deciding what the tracing tests measure by @simonrosenberg in https://github.com/OpenHands/software-agent-sdk/pull/4390
+* chore: remove deprecated features past their 1.41.0 removal deadline by @VascoSch92 in https://github.com/OpenHands/software-agent-sdk/pull/4394
+
+---
+
+### Automation
+
+#### Features
+* feat: retire the standalone automation frontend by @hieptl in https://github.com/OpenHands/automation/pull/284
+* feat: report the configured automation timeout cap by @neubig in https://github.com/OpenHands/automation/pull/296
+* feat: record accumulated LLM cost per automation run by @hieptl in https://github.com/OpenHands/automation/pull/280
+* feat: set descriptive titles on automation-born conversations by @hieptl in https://github.com/OpenHands/automation/pull/312
+* feat: add generic preset metadata field to Automation model by @hieptl in https://github.com/OpenHands/automation/pull/313
+* feat: add template provenance, idempotent enablement, and first-run outcome to presets by @hieptl in https://github.com/OpenHands/automation/pull/322
+
+#### Bug Fixes
+* fix: normalize SQLite telemetry timestamps by @Linxiushen in https://github.com/OpenHands/automation/pull/301
+* fix: default FILE_STORE to local instead of gcs by @neubig in https://github.com/OpenHands/automation/pull/314
+
+---
+
+### OpenHands Cloud (Helm Chart)
+
+#### Features
+* feat(chart): OHE-3021 : expose OH_SANDBOX_MAX_NUM_SANDBOXES as a ConfigOption by @tofarr in https://github.com/OpenHands/OpenHands-Cloud/pull/1035
+
+---
+
+## 0.41.0
+
+This release advances the **Agent Canvas** rollout with a new homepage banner and an updated Canvas build, and sets GLM 5.2 as the default model for SaaS deployments. The remainder of the release focuses on Codex authentication handling, secrets and settings reliability, and a range of stability fixes across the Enterprise Server and Helm charts.
+
+### Enterprise Server
+
+#### Features
+* feat: set SaaS default model to GLM 5.2 by @juanmichelini in https://github.com/OpenHands/enterprise/pull/89
+* feat: Add Agent Canvas homepage banner by @malhotra5 in https://github.com/OpenHands/enterprise/pull/124
+* feat: expose observability fields on app conversations by @juanmichelini in https://github.com/OpenHands/enterprise/pull/130
+
+#### Bug Fixes
+* fix(frontend): wire Export CSV buttons on Usage & Monitoring Overview and Models tabs by @saurya in https://github.com/OpenHands/enterprise/pull/78
+* fix: Pass pod security context from runtime-api warm configs to sandbox start by @tofarr in https://github.com/OpenHands/enterprise/pull/108
+* fix: skip default CSP on FastAPI docs paths (OHE-2815) by @tofarr in https://github.com/OpenHands/enterprise/pull/118
+* fix(settings): keep active LLM profile selected during updates by @saurya in https://github.com/OpenHands/enterprise/pull/107
+* fix(enterprise): Fix 405 error when uploading files before conversation is ready by @jpelletier1 in https://github.com/OpenHands/enterprise/pull/134
+* fix: propagate registered marketplaces to conversations by @tofarr in https://github.com/OpenHands/enterprise/pull/126
+* fix(app-server): serialize secrets writes to fix lost-write race (OHE-3052) by @tofarr in https://github.com/OpenHands/enterprise/pull/133
+* fix: load_settings should show meta for secrets by @tofarr in https://github.com/OpenHands/enterprise/pull/138
+* fix(enterprise): make POST /api/organizations/provision-user idempotent (OHE-2980) by @tofarr in https://github.com/OpenHands/enterprise/pull/117
+* fix: validate Codex auth secrets on save by @simonrosenberg in https://github.com/OpenHands/enterprise/pull/141
+* fix(app-server): pre-flight Codex credentials by @simonrosenberg in https://github.com/OpenHands/enterprise/pull/139
+
+#### Maintenance
+* chore(enterprise): enforce PostgreSQL-only migrations by @simonrosenberg in https://github.com/OpenHands/enterprise/pull/95
+
+---
+
+### Runtime API
+
+#### Features
+* feat(helm): add generic-device-plugin DaemonSet for FUSE support by @tofarr in https://github.com/OpenHands/runtime-api/pull/685
+
+#### Bug Fixes
+* fix: resolve real service-account email for GCS URL signing by @jlav in https://github.com/OpenHands/runtime-api/pull/686
+
+#### Maintenance
+* chore: PLTF-3242 Emit cleanup backlog/throughput counts as a structured log summary by @aivong-openhands in https://github.com/OpenHands/runtime-api/pull/665
+* build(deps): bump aiohttp from 3.13.4 to 3.14.1 by @dependabot[bot] in https://github.com/OpenHands/runtime-api/pull/680
+* build(deps): bump ddtrace from 3.5.1 to 4.8.2 by @dependabot[bot] in https://github.com/OpenHands/runtime-api/pull/687
+* build(deps): bump awscli from 1.44.38 to 1.44.78 by @dependabot[bot] in https://github.com/OpenHands/runtime-api/pull/689
+* build(deps): bump pyasn1 from 0.6.3 to 0.6.4 by @dependabot[bot] in https://github.com/OpenHands/runtime-api/pull/688
+
+---
+
+### OpenHands Cloud (Helm Chart)
+
+#### Features
+* feat(charts): device-plugin subchart for kvm/fuse passthrough by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1006
+* feat(openhands): PLTF-1247 offer Valkey as an opt-in cache backend by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1007
+* feat(agent-canvas): bump chart image tag to 1.10.0 by @hieptl in https://github.com/OpenHands/OpenHands-Cloud/pull/1024
+
+#### Bug Fixes
+* fix(budget-maintenance): disable cronjob until fixed image ships by @saurya in https://github.com/OpenHands/OpenHands-Cloud/pull/999
+* fix(replicated): preserve Keycloak identity provider timeout by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1001
+* fix: disable email changes for Replicated installs by @ak684 in https://github.com/OpenHands/OpenHands-Cloud/pull/1002
+* fix(rustfs): PLTF-1250 make the bundled store deployable when enabled by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1010
+* fix(charts): pass fuse_s3_mount through warm-runtimes configmap by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1011
+* fix(build): PLTF-1250 stop shipping Chart.yaml.bak in released charts by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1013
+* fix(build): PLTF-1250 restore Chart.lock after packaging by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1014
+* fix(charts)!: OHE-3033 durable automation package storage by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1015
+* fix(charts): restore the nested sandbox hostname default by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1021
+* fix(litellm-helm): bump default image tag to 1.94.1 for memory fix by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/1023
+* fix(budget-maintenance): re-enable cronjob with 1.49.1 by @saurya in https://github.com/OpenHands/OpenHands-Cloud/pull/1018
+
+#### Maintenance
+* chore: bump Agent Canvas chart image to 1.9.0 by @malhotra5 in https://github.com/OpenHands/OpenHands-Cloud/pull/1009
+* chore: add storage-lifetime and naming checks to the code-review skill by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/1016
+
## 0.36.1
This patch release was focused on stability fixes for the Enterprise Server, including preserving user sessions during transient network failures and giving deployments the ability to disable email changes.
@@ -49779,6 +54446,107 @@ Several additional Jira Cloud and Data CEnter enhancements have been made to imp
* test: PLTF-1257 helm-unittest setup by @aivong-openhands in https://github.com/OpenHands/OpenHands-Cloud/pull/894
* chore: add CODEOWNERS by @jlav in https://github.com/OpenHands/OpenHands-Cloud/pull/878
+### Sizing Guide
+Source: https://docs.openhands.dev/enterprise/sizing-guide.md
+
+OpenHands Enterprise deployments are sized primarily based on expected **peak concurrent sandboxes** — the largest number of sandboxes you expect to be running at the same time. Keep in mind that one user can have multiple sandboxes running at one time.
+
+
+ The **Users** column in the tables below is a rough translation of peak sandboxes into headcount, not an input. Size on peak sandboxes; the user estimate is a very rough guide
+
+
+## Planning Unit
+
+Both tables below are built from the same per-sandbox allocation:
+
+| Resource | Per sandbox |
+|----------|-------------|
+| CPU | 0.5 vCPU |
+| Memory | 4 GiB |
+| Node disk | 10 GiB |
+| Volume storage | 10 GiB |
+
+If you raise the sandbox defaults (for large monorepos or memory-hungry builds), scale the totals in the tables by the same factor. See [Resource Limits](/enterprise/k8s-install/resource-limits) for how to change these values.
+
+## Installation Modes
+
+This guide covers the two supported installation modes:
+
+
+
+ The installer builds a single-node k0s cluster on a VM you provide. Fixed capacity, configured through the Admin Console, everything bundled on one machine.
+
+
+ Install into a cluster you already run, with standard Kubernetes elasticity and autoscaling.
+
+
+
+## Replicated Embedded Cluster — Single VM
+
+Machine sizes below are based on the peak sandboxes, so feel free to size up or down based on expected usage.
+
+| Peak sandboxes | Users (estimate) | VM | Example machine types | Data disk (starting recommendation) |
+|----------------|------------------|----|-----------------------|-------------------------------------|
+| **5** | ~25 | 8 vCPU / 32 GiB | `e2-standard-8`, `m6i.2xlarge`, `D8s_v5` | 500 GiB SSD |
+| **15** | ~60 | 16 vCPU / 64 GiB | `n2-standard-16`, `m6i.4xlarge`, `D16s_v5` | 1 TiB SSD |
+| **30** | ~125 | 32 vCPU / 128 GiB | `n2-standard-32`, `m6i.8xlarge`, `D32s_v5` | 1.5 TiB SSD |
+| **50** | ~250 | 64 vCPU / 256 GiB | `n2-standard-64`, `m6i.16xlarge`, `D64s_v5` | 3 TiB SSD |
+| **100** | ~400 | 96 vCPU / 384 GiB | `n2-standard-96`, `m6i.24xlarge`, `D96s_v5` | 4 TiB SSD |
+| **Above 100** | — | Use a Kubernetes install, or contact us for a sizing consultation | — | — |
+
+The 16 vCPU / 64 GiB row matches the minimum VM in the [Quick Start](/enterprise/quick-start) system requirements. Trials that stay below roughly 15 concurrent sandboxes are well served by that baseline.
+
+
+ **Put the data disk on a separate expandable volume, not the boot disk.** Sandbox volumes on a single VM are host directories that consume actual bytes rather than preallocating, so the disk grows with real usage and is meant to be resized in place as demand increases.
+
+
+## Replicated Helm Installation
+
+Use two node pools: a tainted pool that runs **only** sandboxes, and an untainted pool that runs everything else. This keeps a burst of sandboxes from evicting platform components.
+
+Recommended node pools:
+
+- **Sandbox pool**: 16 vCPU / 64 GiB / 400 GiB SSD
+- **Platform pool**: 8 vCPU / 32 GiB / 100 GiB
+
+| Peak sandboxes | Users (estimate) | Sandbox nodes (min–max) | Platform nodes | Volume storage (start) | PostgreSQL (in-cluster by default) |
+|----------------|------------------|-------------------------|----------------|------------------------|------------------------------------|
+| **10** | ~50 | 1–1 | 2 | 1 TiB | 2 vCPU / 8 GiB — fits the platform pool |
+| **25** | ~125 | 1–3 | 2 | 2.5 TiB | 2 vCPU / 8 GiB — fits the platform pool |
+| **50** | ~250 | 1–5 | 2 | 5 TiB | 2 vCPU / 8 GiB — fits the platform pool |
+| **100** | ~500 | 1–10 | 3 | 10 TiB | 4 vCPU / 16 GiB — fits the platform pool |
+| **200** | ~1,000 | 2–20 | 3 | 20 TiB | 4 vCPU / 16 GiB — fits the platform pool |
+| **500** | ~2,500 | 3–48 | 4 | 50 TiB | 8 vCPU / 32 GiB — **needs a dedicated node** |
+| **1,000** | ~5,000 | 5–96 | 5 | 100 TiB | 16 vCPU / 64 GiB — **needs a dedicated node** |
+
+Notes on the table:
+
+- **Minimum node counts assume autoscaling.** If your cluster cannot scale up quickly, raise the minimum toward your typical daily peak so users don't wait on node provisioning.
+- **PostgreSQL** is deployed in-cluster by default. At 500 peak sandboxes and above, give it a dedicated node — or use [External PostgreSQL](/enterprise/external-postgres) and size it with your database team.
+
+## Adjusting After Rollout
+
+- Track sandbox pod count over time and size to the observed peak, plus headroom.
+- Watch memory usage against limits to catch OOMKills, and usage against requests to catch evictions. See [Resource Limits](/enterprise/k8s-install/resource-limits) for the metrics and the settings to change.
+- Grow volume storage before it fills. Sandbox workspaces are deleted with their sandbox, but their usage and retention may outstrip initial storage numbers
+
+## Next Steps
+
+
+
+ Provision a VM and install OpenHands Enterprise.
+
+
+ Deploy into an existing cluster with Helm.
+
+
+ Tune CPU, memory, and storage for the application server and sandboxes.
+
+
+ Understand how conversations map onto sandboxes and how placement affects capacity.
+
+
+
### Skills and Plugins
Source: https://docs.openhands.dev/enterprise/skills-and-plugins.md
@@ -50009,6 +54777,12 @@ a conversation created before the setting changed with a new conversation create
is `.agents/skills//SKILL.md` and that the source control integration can clone the
repository.
+
+ Skill enablement is based on the skill name, not its source. Disabling a built-in skill also
+ disables a custom skill with the same `name` in its `SKILL.md` frontmatter. A custom skill name
+ should not conflict with a built-in skill name. Rename the custom skill and its parent directory
+ to a unique name, such as `acme-github`.
+
Confirm that its trigger matches the user message or explicitly ask the agent to invoke the
skill. Test with a unique trigger and exact expected behavior.
@@ -50032,6 +54806,218 @@ a conversation created before the setting changed with a new conversation create
+### Troubleshooting
+Source: https://docs.openhands.dev/enterprise/troubleshooting.md
+
+OpenHands Enterprise Replicated VM installations run in a Replicated Embedded
+Cluster which is a Kubernetes cluster based on k0s. Once you have access to the
+VM, you can use standard Kubernetes commands to inspect OHE. For Helm
+deployments, use your existing Kubernetes access to run the same commands.
+
+Most OHE workloads run in the `openhands` namespace. The Replicated Admin
+Console runs in `kotsadm`, and ingress runs in `traefik`.
+
+## Start With a Support Bundle
+
+A support bundle is the fastest way to give OpenHands Support a snapshot of the
+installation. You do not need to investigate the problem yourself before opening
+a support ticket.
+
+### Use the Admin Console
+
+For a Replicated VM installation:
+
+1. Open `https://admin.:30000`.
+2. Select `Troubleshoot`.
+3. Select `Analyze` and wait for it to finish.
+4. Select `Download bundle`.
+
+If `Send bundle to vendor` is available, you can upload the bundle for us to
+inspect directly. Sending a support bundle does not automatically create a
+support ticket, so be sure to still open a support ticket and mention the
+support bundle upload.
+
+### Use the Command Line
+
+On a Replicated VM, use the command line when the Admin Console is unavailable.
+For a Helm installation, run the Kubernetes command from a workstation with
+`kubectl` access.
+
+
+
+ Connect to the VM and run:
+
+ ```bash
+ sudo /var/lib/embedded-cluster/bin/openhands support-bundle
+ ```
+
+ If the installation did not complete, run the original installer from the
+ directory where you extracted it:
+
+ ```bash
+ sudo ./openhands support-bundle
+ ```
+
+
+ For OHE installed with Helm in an existing Kubernetes cluster, run this
+ command from a workstation with `kubectl` access:
+
+ ```bash
+ kubectl support-bundle --load-cluster-specs --namespace openhands
+ ```
+
+ See the [Kubernetes installation guide](/enterprise/k8s-install/installation#step-5-validate-the-installation)
+ if the `support-bundle` CLI is not installed.
+
+
+
+The bundle includes cluster health, Kubernetes resource state, application logs,
+and OHE service checks.
+
+### Open a Support Ticket
+
+Open the OpenHands Support Portal provided during Enterprise onboarding. Please
+attach the generated archive. If you used `Send bundle to vendor`, mention the
+upload in the ticket. Include:
+
+- When the problem occurred, including the time zone.
+- The affected user or conversation ID, when applicable.
+- The expected and actual behavior.
+- Any recent upgrade or configuration change.
+- Steps that reproduce the problem.
+
+If you cannot access the Support Portal, please contact your OpenHands
+representative for more assistance.
+
+## Inspect the Deployment
+
+This workflow is for practitioners who are already familiar with `kubectl`.
+
+
+ Keep your investigation read-only. Do not change Kubernetes resources unless
+ directed by OpenHands Support. Ad hoc `kubectl` changes can be overwritten
+ during a deployment or upgrade and may leave the installation in an
+ inconsistent state.
+
+
+### Get a Kubernetes Session
+
+
+
+ Connect to a controller VM. On a single-node installation, this is the OHE
+ VM. Then run:
+
+ ```bash
+ sudo /var/lib/embedded-cluster/bin/openhands shell
+ ```
+
+ This opens a shell with `kubectl` configured for the embedded cluster. Run
+ `exit` when finished.
+
+
+ Use your existing Kubernetes access and confirm the current context:
+
+ ```bash
+ kubectl config current-context
+ kubectl get pods -n openhands
+ ```
+
+
+
+### Check Overall Status
+
+Record the time, then inspect the cluster and recent events:
+
+```bash
+date -u
+kubectl get nodes -o wide
+kubectl get pods -n openhands -o wide
+kubectl get deployments,statefulsets -n openhands
+kubectl get events -n openhands --sort-by=.metadata.creationTimestamp
+```
+
+Start with the `STATUS`, `READY`, and `RESTARTS` columns:
+
+- `Pending` usually points to scheduling, storage, or capacity problems.
+- `Init:` means an init container has not completed. Check that container's logs.
+- `CrashLoopBackOff` means a container repeatedly exits. Check previous logs.
+- A pod that is not ready or keeps restarting usually has a failed dependency,
+ health check, or resource limit.
+
+If the Kubernetes Metrics API is available, check current resource usage:
+
+```bash
+kubectl top pods -n openhands
+```
+
+### Inspect a Pod and Its Logs
+
+```bash
+kubectl describe pod -n openhands
+
+kubectl logs -n openhands \
+ --all-containers=true --since=30m --timestamps
+
+kubectl logs -n openhands \
+ --all-containers=true --previous --timestamps
+
+kubectl logs -n openhands -c \
+ --since=10m --timestamps --follow
+```
+
+Use `--previous` after a container restarts. Use `-c` to select a specific
+container, including an init container such as `migrate-db`.
+
+On a Replicated VM, these logs are also written to files on the VM. See
+[Log Collection](/enterprise/vm-install/log-collection) to send them to your own
+observability platform.
+
+### Choose the Right Component
+
+Pod names may include a release prefix and generated suffix. Match the
+recognizable component name to the table below.
+
+| Component | Investigate when |
+|---|---|
+| `openhands` | Web application, API, conversations, and general application errors. |
+| `openhands-integrations` | Integration events and background integration work. |
+| `runtime-api` | Sandbox creation, startup, pause, and cleanup. |
+| `runtime-...` | A particular conversation's sandbox. |
+| `litellm` | Model-provider requests and authentication. |
+| `keycloak` | Login, SSO, and authentication. |
+| `kotsadm` namespace | Replicated Admin Console problems. |
+
+### Temporarily Enable Debug Logging
+
+On a Replicated VM, `Log Level` defaults to `INFO`. Use `DEBUG` only during a
+short investigation:
+
+1. In the Admin Console, select `Config`.
+2. Under `Troubleshooting`, set `Log Level` to `DEBUG`.
+3. Save and deploy, then reproduce the problem.
+4. Collect the logs or a support bundle.
+5. Return `Log Level` to `INFO`, then save and deploy again.
+
+## Related Guides
+
+
+
+ Install an OpenHands Enterprise VM deployment.
+
+
+ Configure a Replicated VM installation.
+
+
+ Install OHE into an existing Kubernetes cluster.
+
+
+ Diagnose and tune CPU, memory, replicas, and storage.
+
+
+ Send VM installation logs to your own observability platform.
+
+
+
### Admin Console Configuration
Source: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration.md
@@ -50251,6 +55237,15 @@ See [External PostgreSQL](/enterprise/external-postgres) for version, encoding,
| `Warm Runtime Count` | Number of ready sandboxes kept for faster conversation startup. Set to `0` for cold starts only. |
| `Additional Host Path Mounts` | Host paths mounted into every sandbox, one per line as `host_path:container_path[:ro\|rw]`. |
| `Enable /dev/kvm passthrough (QEMU/KVM)` | Makes host KVM acceleration available inside sandboxes. The node must expose `/dev/kvm`. |
+| `Run sandboxes on dedicated nodes` | Confines sandboxes to machines added with the `sandbox` role, and keeps the application off those machines. Requires at least one `sandbox` machine already joined. See [Scaling the Cluster](/enterprise/vm-install/scaling). |
+
+
+ `Idle Time` and `Deletion Time` control when idle and paused conversations are
+ reclaimed. A single running session is additionally capped at 12 hours
+ regardless of these values; this maximum is not currently configurable. See
+ [Conversations and Sandboxes](/enterprise/conversations-and-sandboxes) for the
+ full conversation lifecycle.
+
Resource requests are scheduling reservations. Multiply per-sandbox requests by the expected concurrent sandbox count and leave capacity for the platform services.
@@ -50275,6 +55270,9 @@ Prefer adding the proxy CA under `Additional Trusted CA Certificates` instead of
`Log Level` defaults to `INFO`. Use `DEBUG` only while investigating a problem because it produces significantly more log output. Return to `INFO` after collecting the necessary diagnostics.
+See [Troubleshooting](/enterprise/troubleshooting) to generate a
+support bundle, inspect component logs, and open a support ticket.
+
## Experimental
`Enable Plugin Directory` deploys the experimental plugin marketplace at `/plugins`. When enabled, configure a marketplace source beginning with `github://`, `https://`, or `http://`.
@@ -50330,4 +55328,201 @@ Replicated generates internal PostgreSQL, Redis, JWT, Keycloak, LiteLLM, sandbox
Configure Laminar observability.
+
+ Collect diagnostics and inspect the deployment.
+
+
+
+### Log Collection
+Source: https://docs.openhands.dev/enterprise/vm-install/log-collection.md
+
+An OpenHands Enterprise VM installation writes the output of every service to log files on the VM. To
+bring those logs into your observability platform, install your platform's log agent on the VM and
+point it at those files.
+
+For one-off diagnostics, collect a support bundle instead. See
+[Troubleshooting](/enterprise/troubleshooting).
+
+## Where the Logs Are
+
+Application logs live under `/var/log/pods`. Each path is built from the namespace, the pod, and the
+container:
+
+```
+/var/log/pods/__//.log
+```
+
+For example:
+
+```
+/var/log/pods/openhands_openhands-cbdbd996b-r54j8_30f64156-29b8-4b64-b663-cf5b4c697b64/openhands/17.log
+```
+
+The VM installation writes to files ending in `.log`. It rotates a file once it grows large,
+appending a timestamp to the name and compressing it, for example `16.log.20260824-235907.gz`. A
+pattern ending in `*.log` therefore collects current output and skips the rotated copies.
+
+`/var/log/containers` holds a symlink to every one of those files, carrying the same details in the
+file name rather than in the directories:
+
+```
+/var/log/containers/__-.log
+```
+
+Log agents with built-in Kubernetes support read that directory, because they can take the pod and
+container names straight from the file name.
+
+| Location | Contains |
+|---|---|
+| `/var/log/pods/` | Output from OpenHands, its supporting services, and sandboxes. |
+| The systemd journal | Cluster and operating system logs. |
+| `/var/log/embedded-cluster/` | Installer output, written during installation and upgrades. |
+
+The application log files are readable only by `root`.
+
+
+ The VM keeps only recent output, roughly 50 MB per service, and the log files for a sandbox are
+ deleted when its conversation is cleaned up. Run your log agent continuously and set your
+ retention period in your observability platform.
+
+
+## Collect the Logs
+
+
+
+ Install the Linux log agent for your observability platform on the VM, following your vendor's
+ instructions. Run it as `root` so that it can read the log files.
+
+
+ Configure a file input for `/var/log/pods/*/*/*.log`, or `/var/log/containers/*.log` if your
+ log agent reads the symlinks.
+
+ Every line begins with a timestamp and the output stream:
+
+ ```
+ 2026-08-25T13:12:11.300228843Z stdout F {"message": "GET /health 200", "severity": "INFO"}
+ ```
+
+ Enable your log agent's parser for this format, called `cri` in Fluent Bit, so that the
+ timestamp and the message arrive as separate fields. The message itself is JSON.
+
+
+ Enable your log agent's journald input to pick up cluster and operating system logs.
+
+
+ Print a recent line on the VM, then search for it in your observability platform:
+
+ ```bash
+ sudo sh -c 'tail -n 1 /var/log/pods/openhands_openhands-*/openhands/*.log'
+ ```
+
+
+ A VM only holds the logs for the services that run on it. Repeat these steps on each VM in the
+ installation, including any VM that runs sandboxes.
+
+
+
+## Related Guides
+
+
+
+ Collect a support bundle and inspect workloads.
+
+
+ Configure a Replicated VM installation.
+
+
+### Scaling the Cluster
+Source: https://docs.openhands.dev/enterprise/vm-install/scaling.md
+
+An OpenHands Enterprise VM deployment starts as a single machine that runs everything: the OpenHands application, its supporting services, and the sandboxes where conversations execute. Add machines when you need more capacity.
+
+## Machine Roles
+
+When you add a machine, you choose the role it takes. The role determines what runs on it and cannot be changed afterward.
+
+| Role | Runs |
+|---|---|
+| `app` | The OpenHands application and its supporting services. |
+| `sandbox` | Sandboxes only. |
+
+## Recommended: Dedicated Sandbox Machines
+
+For production, run sandboxes on dedicated `sandbox` machines.
+
+Sandboxes are the most variable workload in a deployment. When sandboxes share a machine with the OpenHands application, a burst of conversations competes for the same CPU and memory the application needs to serve requests. Separating them means sandbox demand cannot degrade or take down the application.
+
+Dedicated sandbox machines also give you a dial for conversation capacity.
+
+## Before You Begin
+
+
+ New machines must be able to reach the existing machines over your private network. If your environment restricts traffic between machines, open these ports first. A machine that cannot reach the others will appear to join successfully and then fail to run workloads.
+
+ Open in both directions between all machines:
+
+ - `2380/TCP`
+ - `4789/UDP`
+ - `6443/TCP`
+ - `9091/TCP`
+ - `9443/TCP`
+ - `10249/TCP`
+ - `10250/TCP`
+ - `10256/TCP`
+
+ A joining machine also needs to reach `30000/TCP` and `50000/TCP` on the existing machines.
+
+ Note that `4789` is UDP.
+
+
+## Add a Machine
+
+
+
+ In the Admin Console, select `Cluster Management`, then `Add node`.
+
+
+ Select `app` or `sandbox`. The role cannot be changed after the machine is added.
+
+
+ The Admin Console displays download, extraction, and join commands for the role you selected. Connect to the new machine and run them in order.
+
+
+ Return to `Cluster Management` and wait for the new machine's status to become `Ready`.
+
+
+
+
+ You can select both `app` and `sandbox`, but this is not recommended. A machine with both roles runs the application and sandboxes together, which gives up the separation you are adding the machine for. When adding a sandbox machine, make sure `app` is unchecked.
+
+
+## Add Sandbox Capacity
+
+Add one or more machines with the `sandbox` role, then confine sandboxes to them.
+
+
+
+ Follow [Add a Machine](#add-a-machine) and select the `sandbox` role. Wait for its status to become `Ready`.
+
+
+ Open `Config`, find `Sandbox Configuration`, and enable `Run sandboxes on dedicated nodes`. Save and deploy the change.
+
+
+
+
+ You can enable `Run sandboxes on dedicated nodes` before adding a `sandbox` machine, but new conversations cannot start until one is `Ready`. A configuration check warns you if the setting is enabled while no sandbox machine exists.
+
+
+Conversations that were already running stay on their original machine and are cleaned up normally as they go idle. Only new conversations move to the sandbox machines, so the transition needs no downtime.
+
+To add more conversation capacity later, add another `sandbox` machine.
+
+## Add Application Capacity
+
+Add machines with the `app` role to increase capacity for the OpenHands application itself.
+
+## Related Guides
+
+- [Admin Console Configuration](/enterprise/vm-install/admin-console-configuration)
+- [Conversations and Sandboxes](/enterprise/conversations-and-sandboxes)
diff --git a/llms.txt b/llms.txt
index 1372fd8c..13728c7b 100644
--- a/llms.txt
+++ b/llms.txt
@@ -15,6 +15,7 @@ from the OpenHands Software Agent SDK.
- [API-based Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/api-sandbox.md): Connect to hosted API-based agent server for fully managed infrastructure.
- [Apptainer Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/apptainer-sandbox.md): Run agent server in rootless Apptainer containers for HPC and shared computing environments.
- [Ask Agent Questions](https://docs.openhands.dev/sdk/guides/convo-ask-agent.md): Get sidebar replies from the agent during conversation execution without interrupting the main flow.
+- [Ask Oracle](https://docs.openhands.dev/sdk/guides/agent-ask-oracle.md): Let an agent consult a saved Oracle LLM profile for stateless second-opinion advice.
- [Assign Reviews](https://docs.openhands.dev/sdk/guides/github-workflows/assign-reviews.md): Automate PR management with intelligent reviewer assignment and workflow notifications using OpenHands Agent
- [Browser Session Recording](https://docs.openhands.dev/sdk/guides/browser-session-recording.md): Record and replay your agent's browser sessions using rrweb.
- [Browser Use](https://docs.openhands.dev/sdk/guides/agent-browser-use.md): Enable web browsing and interaction capabilities for your agent.
@@ -56,7 +57,7 @@ from the OpenHands Software Agent SDK.
- [Model Context Protocol](https://docs.openhands.dev/sdk/guides/mcp.md): Model Context Protocol (MCP) enables dynamic tool integration from external servers. Agents can discover and use MCP-provided tools automatically.
- [Model Routing](https://docs.openhands.dev/sdk/guides/llm-routing.md): Route agent's LLM requests to different models.
- [Observability & Tracing](https://docs.openhands.dev/sdk/guides/observability.md): Enable OpenTelemetry tracing to monitor and debug your agent's execution with tools like Laminar, MLflow, Honeycomb, or any OTLP-compatible backend.
-- [OpenAI-Compatible Endpoint](https://docs.openhands.dev/sdk/guides/agent-server/openai-gateway.md): Call an OpenHands agent-server through the OpenAI Chat Completions protocol.
+- [OpenAI-Compatible Endpoint](https://docs.openhands.dev/sdk/guides/agent-server/openai-gateway.md): Call an OpenHands agent-server through the OpenAI Chat Completions or Responses protocol.
- [OpenHands Cloud Workspace](https://docs.openhands.dev/sdk/guides/agent-server/cloud-workspace.md): Connect to OpenHands Cloud for fully managed sandbox environments with optional SaaS credential inheritance.
- [openhands.sdk.agent](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.agent.md): API reference for openhands.sdk.agent module
- [openhands.sdk.conversation](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.conversation.md): API reference for openhands.sdk.conversation module
@@ -82,6 +83,7 @@ from the OpenHands Software Agent SDK.
- [Send Message While Running](https://docs.openhands.dev/sdk/guides/convo-send-message-while-running.md): Interrupt running agents to provide additional context or corrections.
- [Skill](https://docs.openhands.dev/sdk/arch/skill.md): High-level architecture of the reusable prompt system
- [Software Agent SDK](https://docs.openhands.dev/sdk.md): Build AI agents that write software. A clean, modular SDK with production-ready tools.
+- [Structured Output](https://docs.openhands.dev/sdk/guides/structured-output.md): Attach a schema to any tool so the LLM returns typed, validated fields alongside the tool's own arguments.
- [Stuck Detector](https://docs.openhands.dev/sdk/guides/agent-stuck-detector.md): Detect and handle stuck agents automatically with timeout mechanisms.
- [Task Tool Set](https://docs.openhands.dev/sdk/guides/task-tool-set.md): Delegate complex work to specialized sub-agents that run synchronously and return results to the parent agent.
- [Theory of Mind (TOM) Agent](https://docs.openhands.dev/sdk/guides/agent-tom-agent.md): Enable your agent to understand user intent and preferences through Theory of Mind capabilities, providing personalized guidance based on user modeling.
@@ -112,11 +114,21 @@ from the OpenHands Software Agent SDK.
- [About OpenHands](https://docs.openhands.dev/openhands/usage/about.md)
- [ACP Agents](https://docs.openhands.dev/openhands/usage/agent-canvas/acp-agents.md): Run Claude Code, Codex, or Gemini CLI in Agent Canvas through the Agent Client Protocol.
+- [Agent Canvas 1.10.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.10.0.md): Release notes for Agent Canvas version 1.10.0
+- [Agent Canvas 1.11.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.11.0.md): Release notes for Agent Canvas version 1.11.0
+- [Agent Canvas 1.12.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.12.0.md): Release notes for Agent Canvas version 1.12.0
+- [Agent Canvas 1.13.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.13.0.md): Release notes for Agent Canvas version 1.13.0
+- [Agent Canvas 1.14.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.14.0.md): Release notes for Agent Canvas version 1.14.0
+- [Agent Canvas 1.15.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.15.0.md): Release notes for Agent Canvas version 1.15.0
+- [Agent Canvas 1.16.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.16.0.md): Release notes for Agent Canvas version 1.16.0
+- [Agent Canvas 1.17.0](https://docs.openhands.dev/openhands/usage/agent-canvas/release-notes/v1.17.0.md): Release notes for Agent Canvas version 1.17.0
- [Agent Canvas Architecture](https://docs.openhands.dev/openhands/usage/agent-canvas/architecture.md): Understand how Agent Canvas connects to execution, automation, and sandbox services.
- [Agent Canvas Overview](https://docs.openhands.dev/openhands/usage/agent-canvas/overview.md): Understand Agent Canvas, how it runs agents, and which setup path to choose.
- [Agent Profiles](https://docs.openhands.dev/openhands/usage/agent-canvas/agent-profiles.md): Manage reusable agent configurations for Agent Canvas conversations.
+- [Agent-Driven Daily Workflow](https://docs.openhands.dev/openhands/usage/use-cases/daily-workflow.md): Use the OpenHands Agent Canvas to gather, prioritize, and work through your daily development tasks
- [API Keys Settings](https://docs.openhands.dev/openhands/usage/settings/api-keys-settings.md): View your OpenHands LLM key and create API keys to work with OpenHands programmatically.
- [Application Settings](https://docs.openhands.dev/openhands/usage/settings/application-settings.md): Configure application-level settings for OpenHands.
+- [Apps (Beta)](https://docs.openhands.dev/openhands/usage/agent-canvas/canvas-extensions.md): Add trusted custom pages and integrated tools to Agent Canvas without forking the application.
- [Automated Code Review](https://docs.openhands.dev/openhands/usage/use-cases/code-review.md): Set up automated PR reviews using OpenHands and the Software Agent SDK
- [Automated QA Testing](https://docs.openhands.dev/openhands/usage/use-cases/qa-changes.md): Validate pull request changes by actually running the software — not just reading code or running tests
- [Automations Overview](https://docs.openhands.dev/openhands/usage/automations/overview.md): Create scheduled tasks that run automatically in OpenHands.
@@ -127,6 +139,7 @@ from the OpenHands Software Agent SDK.
- [COBOL Modernization](https://docs.openhands.dev/openhands/usage/use-cases/cobol-modernization.md): Modernizing legacy COBOL systems with OpenHands
- [Configuration Options](https://docs.openhands.dev/openhands/usage/advanced/configuration-options.md): How to configure OpenHands V1 (Web UI, env vars, and sandbox settings).
- [Configure](https://docs.openhands.dev/openhands/usage/run-openhands/gui-mode.md): High level overview of configuring the OpenHands Web interface.
+- [Configure a Model](https://docs.openhands.dev/openhands/usage/agent-canvas/model-configuration.md): Choose and verify an LLM configuration path in Agent Canvas.
- [Contributing](https://docs.openhands.dev/openhands/usage/agent-canvas/development.md): Contribute to Agent Canvas development.
- [Conversations](https://docs.openhands.dev/openhands/usage/agent-canvas/conversations.md): Work with Agent Canvas conversations, including branching from previous messages.
- [Creating Automations](https://docs.openhands.dev/openhands/usage/automations/creating-automations.md): Learn how to create scheduled automations using the Automation Skill.
@@ -151,6 +164,7 @@ from the OpenHands Software Agent SDK.
- [Incident Triage](https://docs.openhands.dev/openhands/usage/use-cases/incident-triage.md): Using OpenHands to investigate and resolve production incidents
- [Install Agent Canvas](https://docs.openhands.dev/openhands/usage/agent-canvas/setup.md): Install, run, update, or uninstall Agent Canvas.
- [Integrations Settings](https://docs.openhands.dev/openhands/usage/settings/integrations-settings.md): How to setup and modify the various integrations in OpenHands.
+- [Isolate Tool Execution with Docker](https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/docker-execution.md): Keep Agent Canvas orchestration on the host while running filesystem and process tools in an ephemeral Docker container per conversation.
- [Key Features](https://docs.openhands.dev/openhands/usage/key-features.md)
- [Kubernetes (Helm)](https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/kubernetes.md): Install Agent Canvas into a Kubernetes cluster with the official Helm chart.
- [Language Model (LLM) Settings](https://docs.openhands.dev/openhands/usage/settings/llm-settings.md): This page goes over how to set the LLM to use in OpenHands, including LLM profiles for switching models during conversations.
@@ -166,7 +180,6 @@ from the OpenHands Software Agent SDK.
- [OpenAI](https://docs.openhands.dev/openhands/usage/llms/openai-llms.md): OpenHands uses LiteLLM to make calls to OpenAI's chat models. You can find their documentation on using OpenAI as a provider [here](https://docs.litellm.ai/docs/providers/openai).
- [OpenHands](https://docs.openhands.dev/openhands/usage/llms/openhands-llms.md): OpenHands LLM provider with access to state-of-the-art (SOTA) agentic coding models.
- [OpenHands in Your SDLC](https://docs.openhands.dev/openhands/usage/essential-guidelines/sdlc-integration.md): How OpenHands fits into your software development lifecycle
-- [OpenRouter](https://docs.openhands.dev/openhands/usage/llms/openrouter.md): OpenHands uses LiteLLM to make calls to chat models on OpenRouter. You can find their documentation on using OpenRouter as a provider [here](https://docs.litellm.ai/docs/providers/openrouter).
- [Overview](https://docs.openhands.dev/openhands/usage/llms/llms.md): OpenHands can connect to any LLM supported by LiteLLM. However, it requires a powerful model to work.
- [Overview](https://docs.openhands.dev/openhands/usage/sandboxes/overview.md): Where OpenHands runs code in V1: Docker sandbox, Process, or Remote.
- [Phone & Tablet Access](https://docs.openhands.dev/openhands/usage/agent-canvas/mobile-access.md): Access Agent Canvas from a phone or tablet using Tailscale or ngrok.
@@ -176,19 +189,21 @@ from the OpenHands Software Agent SDK.
- [Remote Backend](https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/remote.md): Connect Agent Canvas to an Agent Server backend running on another machine or container.
- [Remote Sandbox](https://docs.openhands.dev/openhands/usage/sandboxes/remote.md): Run conversations in a remote sandbox environment.
- [Repository Customization](https://docs.openhands.dev/openhands/usage/customization/repository.md): You can customize how OpenHands interacts with your repository by creating a `.openhands` directory at the root level.
+- [REST API (V1)](https://docs.openhands.dev/openhands/usage/api/v1.md): Overview of the Sandbox Server V1 REST endpoints for conversations and sandboxes.
- [Run Local LLMs with OpenHands](https://docs.openhands.dev/openhands/usage/llms/local-llms.md): Connect OpenHands to local LLM servers such as LM Studio, Ollama, vLLM, and SGLang.
-- [Sandbox Server REST API (V1)](https://docs.openhands.dev/openhands/usage/api/v1.md): Overview of the Sandbox Server V1 REST endpoints for conversations and sandboxes.
- [Search Engine Setup](https://docs.openhands.dev/openhands/usage/advanced/search-engine-setup.md): Configure OpenHands to use Tavily as a search engine.
- [Secrets Management](https://docs.openhands.dev/openhands/usage/settings/secrets-settings.md): How to manage secrets in OpenHands.
- [Setup](https://docs.openhands.dev/openhands/usage/run-openhands/local-setup.md): Getting started with running OpenHands on your own.
- [Setup a Pre-built Automation](https://docs.openhands.dev/openhands/usage/agent-canvas/prebuilt-automations.md): Get started quickly with a pre-built automation for common workflows.
- [Slack Channel Monitor](https://docs.openhands.dev/openhands/usage/agent-canvas/prebuilt/slack-channel-monitor.md): Watch a Slack channel and trigger agent actions on messages.
- [Spark Migrations](https://docs.openhands.dev/openhands/usage/use-cases/spark-migrations.md): Migrating Apache Spark applications with OpenHands
+- [Sync Automations with Git](https://docs.openhands.dev/openhands/usage/agent-canvas/git-sync.md): Back up, share, and edit Agent Canvas automations through a Git repository.
- [Troubleshooting](https://docs.openhands.dev/openhands/usage/agent-canvas/troubleshooting.md): Fix common Agent Canvas install, startup, backend, model, workspace, and uninstall issues.
- [Troubleshooting](https://docs.openhands.dev/openhands/usage/troubleshooting/troubleshooting.md)
- [Tutorial Library](https://docs.openhands.dev/openhands/usage/get-started/tutorials.md): Centralized hub for OpenHands tutorials and examples
- [Use Cases Overview](https://docs.openhands.dev/openhands/usage/use-cases/overview.md): Explore how OpenHands can help with common software development challenges
- [Use Docker with Agent Canvas](https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/docker.md): Run Agent Canvas with Docker for a sandboxed backend and mounted project workspace.
+- [Use OpenRouter with OpenHands](https://docs.openhands.dev/openhands/usage/llms/openrouter.md): Configure an OpenRouter model and API key in Agent Canvas or OpenHands.
- [VM / Self-Hosted Installation](https://docs.openhands.dev/openhands/usage/agent-canvas/backend-setup/vm.md): Install Agent Canvas on a VM as a backend-only service or full self-hosted Canvas.
- [Vulnerability Remediation](https://docs.openhands.dev/openhands/usage/use-cases/vulnerability-remediation.md): Using OpenHands to identify and fix security vulnerabilities in your codebase
- [WebSocket Connection](https://docs.openhands.dev/openhands/usage/developers/websocket-connection.md)
@@ -198,7 +213,7 @@ from the OpenHands Software Agent SDK.
- [Bitbucket Integration](https://docs.openhands.dev/openhands/usage/cloud/bitbucket-installation.md): This guide walks you through the process of installing OpenHands Cloud for your Bitbucket repositories. Once
- [Budgets](https://docs.openhands.dev/openhands/usage/cloud/organizations/budgets.md): Set spending limits for your organization and its members to keep AI spend under control.
-- [Cloud API](https://docs.openhands.dev/openhands/usage/cloud/cloud-api.md): OpenHands Cloud provides a REST API that allows you to programmatically interact with OpenHands.
+- [Cloud API Overview](https://docs.openhands.dev/openhands/usage/cloud/cloud-api.md): OpenHands Cloud provides a REST API that allows you to programmatically interact with OpenHands.
- [Cloud UI](https://docs.openhands.dev/openhands/usage/cloud/cloud-ui.md): The Cloud UI provides a web interface for interacting with OpenHands. This page provides references on
- [Getting Started](https://docs.openhands.dev/openhands/usage/cloud/openhands-cloud.md): Getting started with OpenHands Cloud.
- [GitHub Integration](https://docs.openhands.dev/openhands/usage/cloud/github-installation.md): This guide walks you through the process of installing OpenHands Cloud for your GitHub repositories. Once
@@ -218,13 +233,14 @@ from the OpenHands Software Agent SDK.
- [Adding New Skills](https://docs.openhands.dev/overview/skills/adding.md): Learn how to add existing skills to your OpenHands workspace from the official registry or custom repositories.
- [Community](https://docs.openhands.dev/overview/community.md): Learn about the OpenHands community, mission, and values
-- [Contributing](https://docs.openhands.dev/overview/contributing.md): Find the right OpenHands repository and contribution guide for your change.
+- [Contributing](https://docs.openhands.dev/overview/contributing.md): Join us in building OpenHands and the future of AI. Learn how to contribute to make a meaningful impact.
- [Creating New Skills](https://docs.openhands.dev/overview/skills/creating.md): Learn how to create reusable skills instead of repeating prompts, with best practices for structure, triggers, and content organization.
- [FAQs](https://docs.openhands.dev/overview/faqs.md): Frequently asked questions about OpenHands.
- [First Projects](https://docs.openhands.dev/overview/first-projects.md): So you've [run OpenHands](/overview/quickstart). Now what?
- [General Skills](https://docs.openhands.dev/overview/skills/repo.md): General guidelines for OpenHands to work more effectively with the repository.
- [Global Skills](https://docs.openhands.dev/overview/skills/public.md): Global skills are [keyword-triggered skills](/overview/skills/keyword) that apply to all OpenHands users. The official global skill registry is maintained at [github.com/OpenHands/extensions](https://github.com/OpenHands/extensions).
- [Introduction](https://docs.openhands.dev/overview/introduction.md): Welcome to OpenHands, a community focused on AI-driven development
+- [Issue Triage and the ready-for-dev Gate](https://docs.openhands.dev/overview/issue-lifecycle.md): How issues are labeled and marked ready-for-dev, and what the pull request description check enforces.
- [Keyword-Triggered Skills](https://docs.openhands.dev/overview/skills/keyword.md): Keyword-triggered skills provide OpenHands with specific instructions that are activated when certain keywords appear in the prompt. This is useful for tailoring behavior based on particular tools, languages, or frameworks.
- [Model Context Protocol (MCP)](https://docs.openhands.dev/overview/model-context-protocol.md): Model Context Protocol support across OpenHands platforms
- [Monitoring and Improving Skills](https://docs.openhands.dev/overview/skills/monitoring.md): Monitor skill performance in production using logging, evaluation metrics, dashboarding, and automated feedback aggregation.
@@ -242,19 +258,28 @@ from the OpenHands Software Agent SDK.
- [Azure DevOps](https://docs.openhands.dev/enterprise/integrations/azure-devops.md): Configure Azure DevOps authentication and automation triggers for OpenHands Enterprise.
- [Bitbucket Data Center](https://docs.openhands.dev/enterprise/integrations/bitbucket-data-center.md): Configure Bitbucket Data Center authentication and repository webhooks for OpenHands Enterprise.
- [Conversations And Sandboxes](https://docs.openhands.dev/enterprise/conversations-and-sandboxes.md): Understand and manage conversation execution, sandbox placement, sharing, and lifecycle in OpenHands Enterprise.
-- [Custom Sandbox Images](https://docs.openhands.dev/enterprise/custom-sandbox-image.md): Preload repos, dependencies, and tooling into a custom sandbox image to make your agents faster and more reliable.
+- [Custom Sandbox Images](https://docs.openhands.dev/enterprise/custom-sandbox-image.md): Preload repos, dependencies, and tooling into custom sandbox images, and run multiple images side by side with warm runtime pools.
- [DNS and TLS](https://docs.openhands.dev/enterprise/k8s-install/dns-and-tls.md): Automate DNS records and TLS certificates with external-dns and cert-manager
- [Enterprise vs. Open Source](https://docs.openhands.dev/enterprise/enterprise-vs-oss.md): Compare OpenHands Enterprise and Open Source offerings to choose the right option for your team
+- [External LLM Gateways](https://docs.openhands.dev/enterprise/integrations/external-llm-gateways.md): Chain OpenHands Enterprise to an existing LiteLLM or Bifrost gateway so LLM traffic flows through your existing routing, cost tracking, and audit layer.
+- [External Observability Platforms](https://docs.openhands.dev/enterprise/integrations/observability-platforms.md): Send OpenHands Enterprise conversation traces to your own OTLP-compatible observability platform such as Langfuse, Honeycomb, or Tempo.
- [External PostgreSQL](https://docs.openhands.dev/enterprise/external-postgres.md): Configure OpenHands Enterprise to use your own PostgreSQL database
+- [GitHub](https://docs.openhands.dev/enterprise/integrations/github.md): Configure the GitHub App and control the built-in GitHub resolver in OpenHands Enterprise.
- [Install with Helm](https://docs.openhands.dev/enterprise/k8s-install/installation.md): End-to-end installation of OpenHands Enterprise on Kubernetes using Helm
- [Installing Sysbox](https://docs.openhands.dev/enterprise/k8s-install/sysbox.md): Install the Sysbox runtime so agent sandboxes can run securely
+- [Jira Cloud](https://docs.openhands.dev/enterprise/integrations/jira-cloud.md): Configure Jira Cloud for OpenHands Enterprise.
- [Jira Data Center](https://docs.openhands.dev/enterprise/integrations/jira-data-center.md): Configure Jira Data Center for OpenHands Enterprise.
- [Kubernetes Installation](https://docs.openhands.dev/enterprise/k8s-install.md): Deploy OpenHands Enterprise into your own Kubernetes cluster using Helm
+- [Log Collection](https://docs.openhands.dev/enterprise/vm-install/log-collection.md): Send logs from an OpenHands Enterprise VM installation to your own observability platform.
- [OpenHands Enterprise](https://docs.openhands.dev/enterprise.md): Run AI coding agents on your own infrastructure with complete control
- [Plugin Marketplace](https://docs.openhands.dev/enterprise/plugin-marketplace.md): Enable and configure the Plugin Marketplace to browse and install community-built OpenHands plugins.
- [Quick Start](https://docs.openhands.dev/enterprise/quick-start.md): Get started with a 30-day trial of OpenHands Enterprise.
- [Release Notes](https://docs.openhands.dev/enterprise/release-notes.md): Release notes for OpenHands Enterprise
- [Resource Limits](https://docs.openhands.dev/enterprise/k8s-install/resource-limits.md): Configure memory, CPU, and storage for OpenHands Enterprise components
- [Running Docker in the Agent Sandbox](https://docs.openhands.dev/enterprise/docker-in-sandbox.md): Let agents run containers, Docker Compose, and image builds inside their isolated sandbox—safely, without privileged access to your cluster.
+- [Scaling the Cluster](https://docs.openhands.dev/enterprise/vm-install/scaling.md): Add machines to an OpenHands Enterprise VM deployment to increase capacity, and run sandboxes on dedicated machines.
+- [Sizing Guide](https://docs.openhands.dev/enterprise/sizing-guide.md): Recommended VM or Cluster sizing for an OpenHands Enterprise deployment
- [Skills and Plugins](https://docs.openhands.dev/enterprise/skills-and-plugins.md): Manage repository, organization, and user skills and control how plugins are discovered and loaded in OpenHands Enterprise.
- [Slack](https://docs.openhands.dev/enterprise/integrations/slack.md): Configure the Slack integration for a self-hosted OpenHands Enterprise install.
+- [Troubleshooting](https://docs.openhands.dev/enterprise/troubleshooting.md): Collect diagnostics and inspect OpenHands Enterprise (OHE) workloads.
+- [Upgrade Guidance](https://docs.openhands.dev/enterprise/k8s-install/upgrade-guidance.md): Generic advice for upgrading a Kubernetes cluster running OpenHands Enterprise