From 4c4b8aecd6a929d5d6aec94bb67417f81f64cf75 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 17 Dec 2025 13:21:24 +0000 Subject: [PATCH 01/11] docs: Add guide for running V1 app-server with local agent-server and integrating custom agents Co-authored-by: openhands --- .../developers/v1-local-agent-server.mdx | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 openhands/usage/developers/v1-local-agent-server.mdx diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx new file mode 100644 index 00000000..0d4309b7 --- /dev/null +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -0,0 +1,124 @@ +--- +title: Run OpenHands V1 app-server with a local SDK agent-server (no Docker) and integrate a custom agent +description: Step-by-step guide to run the OpenHands V1 app-server backed by a purely local agent-server from software-agent-sdk, plus multiple ways to integrate a custom SDK agent +--- + +This guide shows how to: +- Run the OpenHands V1 app-server while spawning a fully local agent-server process (no Docker, no remote runtime) +- Build a custom agent with software-agent-sdk and integrate it into the locally running app-server + +The instructions below are grounded in code from OpenHands V1 app-server and software-agent-sdk. Direct source links to the relevant files are included. + +Prerequisites +- Python 3.12, Node 22.x, Poetry 1.8+ +- OpenHands repo checked out +- software-agent-sdk is an install-time dependency of OpenHands (see pyproject), and the agent-server binary entrypoint is provided by that package + +Where V1 lives (execution path overview) +OpenHands V1 exposes its API under /api/v1 and keeps the V1 server logic in app_server/: +- The FastAPI app includes V1 only when ENABLE_V1 != '0'. See [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98). +- The V1 router aggregates app_server endpoints. See [v1_router.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/v1_router.py). +- For a “local” runtime, the app-server launches a separate agent-server process (from software-agent-sdk) on a free localhost port. This is done by the process sandbox service: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L113-L154) which executes python -m openhands.agent_server and then probes /alive. +- That default choice comes from env → config wiring. When RUNTIME is local or process, the injectors select the process-based sandbox and spec: see [app_server/config.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) and [process_sandbox_spec_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_spec_service.py#L17-L34). +- On the SDK side, the agent-server exposes /alive and /health (and /api/*). See [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41) and the FastAPI app bootstrap in [agent_server/__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40). +- The app-server talks to the agent-server using AsyncRemoteWorkspace and the agent-server REST/WebSocket API. See [AsyncRemoteWorkspace](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/remote/async_remote_workspace.py) and where the app-server builds conversation requests in [live_status_app_conversation_service._build_start_conversation_request_for_user](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L929-L1014). + +Part 1 — Run OpenHands app-server with a purely local agent-server +1) Build OpenHands and enable V1 +- By default V1 is enabled (unless ENABLE_V1=0). Ensure you’re on Python 3.12 and have Poetry and Node installed, then: + +```bash +export INSTALL_DOCKER=0 # we won’t use Docker +export RUNTIME=local # force process-based sandbox (spawns local agent-server) +# optional: export ENABLE_V1=1 # V1 is enabled by default; set explicitly if you disabled it elsewhere + +make build +``` + +2) Run backend + frontend +- For local dev, either: + +```bash +# Full app (backend + frontend). Adjust ports/hosts if you’re on a remote machine. +make run FRONTEND_PORT=12000 FRONTEND_HOST=0.0.0.0 BACKEND_HOST=0.0.0.0 +``` + +or start servers individually: + +```bash +make start-backend +make start-frontend +``` + +3) Start a V1 conversation to spawn the local agent-server +- From the UI (Chat → Start), or via the V1 endpoints under /api/v1, create a new conversation. The app-server will: + - Start a “sandbox” using the process sandbox service, which launches a local agent-server process via python -m openhands.agent_server + - Poll the agent-server /alive endpoint until it reports status ok + - Store the agent-server URL and a per-sandbox session API key, then use it for subsequent operations + +4) Verify the local agent-server +- You can list sandboxes via V1 API and find the exposed agent-server URL; the name in the response is "agent-server". The health checks are: + - GET {agent_server_url}/alive → {"status":"ok"} (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) + - GET {agent_server_url}/server_info for uptime/idle info + +5) How the app-server talks to the agent-server +- When reading/writing files or executing commands in the conversation’s workspace, the app-server uses AsyncRemoteWorkspace that targets the agent-server. Example usage in the app-server: [app_conversation_router.read_conversation_file](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_router.py#L335-L409) and throughout [live_status_app_conversation_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py). + +Part 2 — Build a custom agent with the SDK and integrate it locally +There are two practical paths, depending on how much you want to change. + +A) Zero-code integration via Skills and MCP servers (recommended) +- V1 lets you customize the agent that runs inside the agent-server by layering skills and MCP servers. The app-server automatically loads: + - User skills from ~/.openhands/skills and ~/.openhands/microagents/ via the SDK’s loader (see [load_user_skills](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills.py)) which the app-server calls in [skill loading](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L56-L104). + - Org/repo skills from your target repository via [skill_loader.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/skill_loader.py). + - MCP servers: the app-server assembles an SDK-compatible mcpServers config (default OpenHands server + Tavily if available, and any custom MCP servers you set in user settings). See [_configure_llm_and_mcp](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L804-L865). + +Example: add a user skill +1. Create a file ~/.openhands/skills/security_expert.md + +```markdown +--- +triggers: +- security +--- +# Security Expert +You are a cybersecurity expert. Always consider security implications. +``` + +2. Start a V1 conversation and include the word “security” in your ask. The skill is merged into the agent’s context by the app-server (see [merge path](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L84-L115)). + +B) Build a custom SDK Agent and run it through the app-server +- The agent-server API accepts a full Agent specification (LLM, tools, context, etc.) as part of StartConversationRequest (see [agent-server conversation_router](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/conversation_router.py#L67-L105)). +- In OpenHands V1, the app-server constructs this Agent for you based on AgentType (DEFAULT or PLAN), LLM settings, MCP config, and merged skills. See [LiveStatusAppConversationService._create_agent_with_context](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923) and how it finishes the request in [_finalize_conversation_request](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L1016-L1082). + +You can customize behavior without forking by: +- Switching AgentType between DEFAULT and PLAN via the Start request (UI or API) to change tool presets (see [tool presets](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-tools/openhands/tools/preset)). +- Supplying skills and MCP servers as described above. + +Advanced: add a new "agent type" to OpenHands +If you want the UI and app-server to create your own agent layout (custom tools/system prompt/etc.), extend OpenHands: +1) Add a new enum to [AgentType](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_models.py#L18-L26). +2) Update [LiveStatusAppConversationService._create_agent_with_context](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923) to construct your Agent when your new type is selected. +3) Optionally expose the type in the frontend to make it selectable. + +C) Test your custom agent directly with the SDK (optional but useful) +- The SDK ships standalone examples you can run locally to validate your Agent design before wiring through OpenHands. See the “Local Agent Server” guide: [/sdk/guides/agent-server/local-server](/sdk/guides/agent-server/local-server) and examples under software-agent-sdk/examples. + +Troubleshooting tips +- If no agent-server starts when you create a V1 conversation, ensure: + - ENABLE_V1 is not '0' (V1 router included): [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98) + - RUNTIME=local or process so process sandbox is selected: [config_from_env](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) + - The spawned server is probing /alive: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L155-L200) +- To inspect the agent-server API, open its Swagger at {agent_server_url}/docs (the server is started via uvicorn in [__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40)). + +References (source of truth) +- OpenHands V1 app-server boot and routing: [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98), [v1_router.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/v1_router.py) +- Sandbox process service (spawns local agent-server): [process_sandbox_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L113-L200) +- Env→injector selection for local runtime: [config.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) +- Default command and env to start agent-server: [process_sandbox_spec_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_spec_service.py#L17-L34) +- Agent-server app and health endpoints: [__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40), [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41) +- Agent-server conversation API: [conversation_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/conversation_router.py) +- AsyncRemoteWorkspace client: [async_remote_workspace.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/remote/async_remote_workspace.py) +- V1 agent composition in app-server: [live_status_app_conversation_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py) +- Skills loading and merge points: [app_conversation_service_base.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L56-L115), [skill_loader.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/skill_loader.py) +- SDK documentation on agent-server modes: [/sdk/guides/agent-server/overview](/sdk/guides/agent-server/overview), [/sdk/guides/agent-server/local-server](/sdk/guides/agent-server/local-server) From b3df7b833cb5f892077054b6e293dea7a5d51fc8 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 17 Dec 2025 13:34:01 +0000 Subject: [PATCH 02/11] docs: fix MDX code span for alive/server_info to satisfy link checker Co-authored-by: openhands --- openhands/usage/developers/v1-local-agent-server.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index 0d4309b7..891571e2 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -58,8 +58,8 @@ make start-frontend 4) Verify the local agent-server - You can list sandboxes via V1 API and find the exposed agent-server URL; the name in the response is "agent-server". The health checks are: - - GET {agent_server_url}/alive → {"status":"ok"} (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) - - GET {agent_server_url}/server_info for uptime/idle info + - GET `{agent_server_url}/alive` → `{"status":"ok"}` (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) + - GET `{agent_server_url}/server_info` for uptime/idle info 5) How the app-server talks to the agent-server - When reading/writing files or executing commands in the conversation’s workspace, the app-server uses AsyncRemoteWorkspace that targets the agent-server. Example usage in the app-server: [app_conversation_router.read_conversation_file](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_router.py#L335-L409) and throughout [live_status_app_conversation_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py). From d3cf9a927368297364196566ccf233898adceee4 Mon Sep 17 00:00:00 2001 From: enyst Date: Wed, 17 Dec 2025 15:13:14 +0000 Subject: [PATCH 03/11] docs: add developers guide to docs.json nav and polish formatting for readability\n\n- Add openhands/usage/developers/v1-local-agent-server to Web tab under Developers\n- Improve headings, styled notes, and code block labels in the guide\n\nCo-authored-by: openhands --- docs.json | 6 + .../developers/v1-local-agent-server.mdx | 135 +++++++++--------- 2 files changed, 76 insertions(+), 65 deletions(-) diff --git a/docs.json b/docs.json index ddeff833..753c7944 100644 --- a/docs.json +++ b/docs.json @@ -103,6 +103,12 @@ "openhands/usage/run-openhands/gui-mode" ] }, + { + "group": "Developers", + "pages": [ + "openhands/usage/developers/v1-local-agent-server" + ] + }, { "group": "REST API", "openapi": "openapi/openapi.json" diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index 891571e2..e756ec5c 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -1,82 +1,85 @@ --- -title: Run OpenHands V1 app-server with a local SDK agent-server (no Docker) and integrate a custom agent -description: Step-by-step guide to run the OpenHands V1 app-server backed by a purely local agent-server from software-agent-sdk, plus multiple ways to integrate a custom SDK agent +title: Run OpenHands V1 App-Server with Local SDK Agent-Server (No Docker) and Integrate a Custom Agent +description: Run the OpenHands V1 app-server backed by a purely local agent-server from software-agent-sdk, and learn multiple ways to integrate a custom SDK agent. --- This guide shows how to: - Run the OpenHands V1 app-server while spawning a fully local agent-server process (no Docker, no remote runtime) - Build a custom agent with software-agent-sdk and integrate it into the locally running app-server -The instructions below are grounded in code from OpenHands V1 app-server and software-agent-sdk. Direct source links to the relevant files are included. + +Applies to the V1 app-server path enabled under /api/v1. + -Prerequisites +## Prerequisites - Python 3.12, Node 22.x, Poetry 1.8+ -- OpenHands repo checked out -- software-agent-sdk is an install-time dependency of OpenHands (see pyproject), and the agent-server binary entrypoint is provided by that package - -Where V1 lives (execution path overview) -OpenHands V1 exposes its API under /api/v1 and keeps the V1 server logic in app_server/: -- The FastAPI app includes V1 only when ENABLE_V1 != '0'. See [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98). -- The V1 router aggregates app_server endpoints. See [v1_router.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/v1_router.py). -- For a “local” runtime, the app-server launches a separate agent-server process (from software-agent-sdk) on a free localhost port. This is done by the process sandbox service: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L113-L154) which executes python -m openhands.agent_server and then probes /alive. -- That default choice comes from env → config wiring. When RUNTIME is local or process, the injectors select the process-based sandbox and spec: see [app_server/config.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) and [process_sandbox_spec_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_spec_service.py#L17-L34). -- On the SDK side, the agent-server exposes /alive and /health (and /api/*). See [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41) and the FastAPI app bootstrap in [agent_server/__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40). -- The app-server talks to the agent-server using AsyncRemoteWorkspace and the agent-server REST/WebSocket API. See [AsyncRemoteWorkspace](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/remote/async_remote_workspace.py) and where the app-server builds conversation requests in [live_status_app_conversation_service._build_start_conversation_request_for_user](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L929-L1014). - -Part 1 — Run OpenHands app-server with a purely local agent-server -1) Build OpenHands and enable V1 -- By default V1 is enabled (unless ENABLE_V1=0). Ensure you’re on Python 3.12 and have Poetry and Node installed, then: - -```bash -export INSTALL_DOCKER=0 # we won’t use Docker -export RUNTIME=local # force process-based sandbox (spawns local agent-server) -# optional: export ENABLE_V1=1 # V1 is enabled by default; set explicitly if you disabled it elsewhere +- OpenHands repository checked out +- software-agent-sdk is an install-time dependency of OpenHands (see pyproject.toml), and provides the openhands.agent_server entrypoint + +## Where V1 Lives (Execution Path Overview) +OpenHands V1 exposes its API under /api/v1 and keeps the V1 server logic in app_server/: +- The FastAPI app includes V1 only when ENABLE_V1 != "0". See [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98). +- The V1 router aggregates app_server endpoints. See [v1_router.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/v1_router.py). +- For a local runtime, the app-server launches a separate agent-server process (from software-agent-sdk) on a free localhost port via the process sandbox: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L113-L154). It executes python -m openhands.agent_server and probes /alive. +- This selection comes from env→config wiring. When RUNTIME is local or process, injectors select the process-based sandbox/spec: see [app_server/config.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) and [process_sandbox_spec_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_spec_service.py#L17-L34). +- On the SDK side, the agent-server exposes /alive and /health (and /api/*). See [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41) and bootstrap in [agent_server/__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40). +- The app-server talks to the agent-server using AsyncRemoteWorkspace and the agent-server REST/WebSocket API. See [AsyncRemoteWorkspace](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/remote/async_remote_workspace.py) and where the app-server builds conversation requests in _build_start_conversation_request_for_user ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L929-L1014)). + +## Part 1 — Run App-Server with a Purely Local Agent-Server + +### 1) Build OpenHands and Enable V1 +By default V1 is enabled (unless ENABLE_V1=0). Ensure you’re on Python 3.12 and have Poetry and Node installed, then: + +```bash Build +export INSTALL_DOCKER=0 # No Docker for this guide +export RUNTIME=local # Force process-based sandbox (spawns local agent-server) +# optional: export ENABLE_V1=1 # V1 is enabled by default; set explicitly if you disabled it elsewhere make build ``` -2) Run backend + frontend -- For local dev, either: +### 2) Run Backend and Frontend +For local development, either run everything together or separately. -```bash -# Full app (backend + frontend). Adjust ports/hosts if you’re on a remote machine. +```bash Full App (Backend + Frontend) +# Adjust ports/hosts if you’re on a remote machine. make run FRONTEND_PORT=12000 FRONTEND_HOST=0.0.0.0 BACKEND_HOST=0.0.0.0 ``` or start servers individually: -```bash +```bash Separate Servers make start-backend make start-frontend ``` -3) Start a V1 conversation to spawn the local agent-server -- From the UI (Chat → Start), or via the V1 endpoints under /api/v1, create a new conversation. The app-server will: - - Start a “sandbox” using the process sandbox service, which launches a local agent-server process via python -m openhands.agent_server - - Poll the agent-server /alive endpoint until it reports status ok - - Store the agent-server URL and a per-sandbox session API key, then use it for subsequent operations +### 3) Start a V1 Conversation (Spawns Local Agent-Server) +From the UI (Chat → Start) or via the V1 endpoints under /api/v1, create a new conversation. The app-server will: +- Start a sandbox using the process sandbox service, which launches a local agent-server process via python -m openhands.agent_server +- Poll the agent-server /alive endpoint until it reports status ok +- Store the agent-server URL and a per-sandbox session API key, then reuse it for subsequent operations -4) Verify the local agent-server -- You can list sandboxes via V1 API and find the exposed agent-server URL; the name in the response is "agent-server". The health checks are: - - GET `{agent_server_url}/alive` → `{"status":"ok"}` (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) - - GET `{agent_server_url}/server_info` for uptime/idle info +### 4) Verify the Local Agent-Server +You can list sandboxes via V1 API and find the exposed agent-server URL; the name in the response is "agent-server". The health checks are: +- GET {agent_server_url}/alive{"status":"ok"} (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) +- GET {agent_server_url}/server_info for uptime/idle info -5) How the app-server talks to the agent-server -- When reading/writing files or executing commands in the conversation’s workspace, the app-server uses AsyncRemoteWorkspace that targets the agent-server. Example usage in the app-server: [app_conversation_router.read_conversation_file](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_router.py#L335-L409) and throughout [live_status_app_conversation_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py). +### 5) How the App-Server Talks to the Agent-Server +When reading/writing files or executing commands in the conversation’s workspace, the app-server uses AsyncRemoteWorkspace that targets the agent-server. Example usage: [app_conversation_router.read_conversation_file](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_router.py#L335-L409) and throughout [live_status_app_conversation_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py). -Part 2 — Build a custom agent with the SDK and integrate it locally +## Part 2 — Build a Custom Agent with the SDK and Integrate Locally There are two practical paths, depending on how much you want to change. -A) Zero-code integration via Skills and MCP servers (recommended) -- V1 lets you customize the agent that runs inside the agent-server by layering skills and MCP servers. The app-server automatically loads: - - User skills from ~/.openhands/skills and ~/.openhands/microagents/ via the SDK’s loader (see [load_user_skills](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills.py)) which the app-server calls in [skill loading](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L56-L104). - - Org/repo skills from your target repository via [skill_loader.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/skill_loader.py). - - MCP servers: the app-server assembles an SDK-compatible mcpServers config (default OpenHands server + Tavily if available, and any custom MCP servers you set in user settings). See [_configure_llm_and_mcp](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L804-L865). +### Path A — Skills and MCP Servers (No-Code) +V1 lets you customize the agent that runs inside the agent-server by layering skills and MCP servers. The app-server automatically loads: +- User skills from ~/.openhands/skills and ~/.openhands/microagents/ via the SDK’s loader (see [load_user_skills](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills.py)), which the app-server calls in [skill loading](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L56-L104). +- Org/repo skills from your target repository via [skill_loader.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/skill_loader.py). +- MCP servers: the app-server assembles an SDK-compatible mcpServers config (default OpenHands server + Tavily if available, and any custom MCP servers you set in user settings). See _configure_llm_and_mcp ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L804-L865)). -Example: add a user skill -1. Create a file ~/.openhands/skills/security_expert.md +Example: Add a User Skill +1. Create a file ~/.openhands/skills/security_expert.md -```markdown +```markdown Skill: security_expert.md --- triggers: - security @@ -87,31 +90,33 @@ You are a cybersecurity expert. Always consider security implications. 2. Start a V1 conversation and include the word “security” in your ask. The skill is merged into the agent’s context by the app-server (see [merge path](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L84-L115)). -B) Build a custom SDK Agent and run it through the app-server -- The agent-server API accepts a full Agent specification (LLM, tools, context, etc.) as part of StartConversationRequest (see [agent-server conversation_router](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/conversation_router.py#L67-L105)). -- In OpenHands V1, the app-server constructs this Agent for you based on AgentType (DEFAULT or PLAN), LLM settings, MCP config, and merged skills. See [LiveStatusAppConversationService._create_agent_with_context](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923) and how it finishes the request in [_finalize_conversation_request](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L1016-L1082). +### Path B — Custom SDK Agent via App-Server +- The agent-server API accepts a full Agent specification (LLM, tools, context, etc.) as part of StartConversationRequest (see [conversation_router](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/conversation_router.py#L67-L105)). +- In OpenHands V1, the app-server constructs this Agent for you based on AgentType (DEFAULT or PLAN), LLM settings, MCP config, and merged skills. See _create_agent_with_context ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923)) and how it finishes the request in _finalize_conversation_request ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L1016-L1082)). You can customize behavior without forking by: -- Switching AgentType between DEFAULT and PLAN via the Start request (UI or API) to change tool presets (see [tool presets](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-tools/openhands/tools/preset)). +- Switching AgentType between DEFAULT and PLAN via the Start request (UI or API) to change tool presets (see [tool presets](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-tools/openhands/tools/preset)). - Supplying skills and MCP servers as described above. -Advanced: add a new "agent type" to OpenHands +Advanced: Add a New Agent Type to OpenHands If you want the UI and app-server to create your own agent layout (custom tools/system prompt/etc.), extend OpenHands: -1) Add a new enum to [AgentType](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_models.py#L18-L26). -2) Update [LiveStatusAppConversationService._create_agent_with_context](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923) to construct your Agent when your new type is selected. -3) Optionally expose the type in the frontend to make it selectable. +1. Add a new enum to [AgentType](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_models.py#L18-L26). +2. Update _create_agent_with_context ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923)) to construct your Agent when your new type is selected. +3. Optionally expose the type in the frontend to make it selectable. -C) Test your custom agent directly with the SDK (optional but useful) -- The SDK ships standalone examples you can run locally to validate your Agent design before wiring through OpenHands. See the “Local Agent Server” guide: [/sdk/guides/agent-server/local-server](/sdk/guides/agent-server/local-server) and examples under software-agent-sdk/examples. +### Path C — Test with the SDK Directly (Optional but Useful) +The SDK ships standalone examples you can run locally to validate your Agent design before wiring through OpenHands. See: +- **[Local Agent Server](/sdk/guides/agent-server/local-server)** +- **[Agent Server Overview](/sdk/guides/agent-server/overview)** -Troubleshooting tips +## Troubleshooting - If no agent-server starts when you create a V1 conversation, ensure: - - ENABLE_V1 is not '0' (V1 router included): [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98) - - RUNTIME=local or process so process sandbox is selected: [config_from_env](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) - - The spawned server is probing /alive: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L155-L200) -- To inspect the agent-server API, open its Swagger at {agent_server_url}/docs (the server is started via uvicorn in [__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40)). + - ENABLE_V1 is not "0" (V1 router included): [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98) + - RUNTIME = local or process so the process sandbox is selected: [config_from_env](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) + - The spawned server is probed via /alive: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L155-L200) +- To inspect the agent-server API, open its Swagger at {agent_server_url}/docs (the server is started via uvicorn in [__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40)). -References (source of truth) +## References - OpenHands V1 app-server boot and routing: [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98), [v1_router.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/v1_router.py) - Sandbox process service (spawns local agent-server): [process_sandbox_service.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L113-L200) - Env→injector selection for local runtime: [config.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) From 67a7969819ae496f16f8e31239088e9c0eb09196 Mon Sep 17 00:00:00 2001 From: enyst Date: Wed, 17 Dec 2025 15:16:30 +0000 Subject: [PATCH 04/11] fix(docs): resolve Mint acorn parse error by removing {...} expressions in inline literals\n\n- Switch to backticked inline code for {agent_server_url} examples\n\nCo-authored-by: openhands --- openhands/usage/developers/v1-local-agent-server.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index e756ec5c..17faffe9 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -61,8 +61,8 @@ From the UI (Chat → Start) or via the V1 endpoints under /api/v1, ### 4) Verify the Local Agent-Server You can list sandboxes via V1 API and find the exposed agent-server URL; the name in the response is "agent-server". The health checks are: -- GET {agent_server_url}/alive{"status":"ok"} (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) -- GET {agent_server_url}/server_info for uptime/idle info +- GET `{agent_server_url}/alive` → `{"status":"ok"}` (see [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41)) +- GET `{agent_server_url}/server_info` for uptime/idle info ### 5) How the App-Server Talks to the Agent-Server When reading/writing files or executing commands in the conversation’s workspace, the app-server uses AsyncRemoteWorkspace that targets the agent-server. Example usage: [app_conversation_router.read_conversation_file](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_router.py#L335-L409) and throughout [live_status_app_conversation_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py). @@ -114,7 +114,7 @@ The SDK ships standalone examples you can run locally to validate your Agent des - ENABLE_V1 is not "0" (V1 router included): [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98) - RUNTIME = local or process so the process sandbox is selected: [config_from_env](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/config.py#L102-L160) - The spawned server is probed via /alive: [process_sandbox_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/sandbox/process_sandbox_service.py#L155-L200) -- To inspect the agent-server API, open its Swagger at {agent_server_url}/docs (the server is started via uvicorn in [__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40)). +- To inspect the agent-server API, open its Swagger at `{agent_server_url}/docs` (the server is started via uvicorn in [__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40)). ## References - OpenHands V1 app-server boot and routing: [server/app.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/server/app.py#L90-L98), [v1_router.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/v1_router.py) From cb9d2cd32157cd60c630f0177fbc424280f94cdc Mon Sep 17 00:00:00 2001 From: enyst Date: Wed, 17 Dec 2025 15:18:42 +0000 Subject: [PATCH 05/11] =?UTF-8?q?docs(nav):=20move=20local=20agent-server?= =?UTF-8?q?=20guide=20under=20Web=20=E2=86=92=20Advanced=20Configuration?= =?UTF-8?q?=20and=20remove=20new=20Developers=20group\n\n-=20Place=20openh?= =?UTF-8?q?ands/usage/developers/v1-local-agent-server=20at=20end=20of=20A?= =?UTF-8?q?dvanced=20Configuration=20pages\n\nCo-authored-by:=20openhands?= =?UTF-8?q?=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/docs.json b/docs.json index 753c7944..227b1493 100644 --- a/docs.json +++ b/docs.json @@ -103,12 +103,6 @@ "openhands/usage/run-openhands/gui-mode" ] }, - { - "group": "Developers", - "pages": [ - "openhands/usage/developers/v1-local-agent-server" - ] - }, { "group": "REST API", "openapi": "openapi/openapi.json" @@ -178,7 +172,8 @@ }, "openhands/usage/advanced/configuration-options", "openhands/usage/advanced/custom-sandbox-guide", - "openhands/usage/advanced/search-engine-setup" + "openhands/usage/advanced/search-engine-setup", + "openhands/usage/developers/v1-local-agent-server" ] } ] From d38492f288797dd294bc4f777d47dbe2ae11cbfb Mon Sep 17 00:00:00 2001 From: Engel Nyst Date: Wed, 17 Dec 2025 19:08:06 +0100 Subject: [PATCH 06/11] Update openhands/usage/developers/v1-local-agent-server.mdx --- openhands/usage/developers/v1-local-agent-server.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index 17faffe9..28d731d6 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -1,5 +1,5 @@ --- -title: Run OpenHands V1 App-Server with Local SDK Agent-Server (No Docker) and Integrate a Custom Agent +title: Run OpenHands App-Server with Local SDK Agent-Server and Custom Agent description: Run the OpenHands V1 app-server backed by a purely local agent-server from software-agent-sdk, and learn multiple ways to integrate a custom SDK agent. --- From 7d5058c406e4081a2b6b3b05e6e22ffa04caa69b Mon Sep 17 00:00:00 2001 From: Engel Nyst Date: Wed, 17 Dec 2025 19:08:39 +0100 Subject: [PATCH 07/11] Update openhands/usage/developers/v1-local-agent-server.mdx --- openhands/usage/developers/v1-local-agent-server.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index 28d731d6..c1ae9b93 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -25,7 +25,7 @@ OpenHands V1 exposes its API under /api/v1 and keeps the V1 server - On the SDK side, the agent-server exposes /alive and /health (and /api/*). See [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41) and bootstrap in [agent_server/__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40). - The app-server talks to the agent-server using AsyncRemoteWorkspace and the agent-server REST/WebSocket API. See [AsyncRemoteWorkspace](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/remote/async_remote_workspace.py) and where the app-server builds conversation requests in _build_start_conversation_request_for_user ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L929-L1014)). -## Part 1 — Run App-Server with a Purely Local Agent-Server +## Part 1 — Run App-Server with a Local Agent-Server ### 1) Build OpenHands and Enable V1 By default V1 is enabled (unless ENABLE_V1=0). Ensure you’re on Python 3.12 and have Poetry and Node installed, then: From 156e8fd4839d3b29d9909df63f5c7e7fe6d088e4 Mon Sep 17 00:00:00 2001 From: enyst Date: Wed, 17 Dec 2025 18:22:08 +0000 Subject: [PATCH 08/11] docs: split local GUI runtime vs SDK agent customization\n\n- Scope v1-local-agent-server.mdx to fully local app-server + local SDK agent-server flow\n- Add new SDK guide: sdk/guides/agent-server/app-integration (how GUI composes/loads SDK Agents)\n- Wire new page into Mintlify nav (docs.json)\n\nCo-authored-by: openhands --- docs.json | 1 + .../developers/v1-local-agent-server.mdx | 55 +++------------- sdk/guides/agent-server/app-integration.mdx | 64 +++++++++++++++++++ 3 files changed, 74 insertions(+), 46 deletions(-) create mode 100644 sdk/guides/agent-server/app-integration.mdx diff --git a/docs.json b/docs.json index 227b1493..b73d6f0a 100644 --- a/docs.json +++ b/docs.json @@ -244,6 +244,7 @@ "pages": [ "sdk/guides/agent-server/overview", "sdk/guides/agent-server/local-server", + "sdk/guides/agent-server/app-integration", "sdk/guides/agent-server/docker-sandbox", "sdk/guides/agent-server/api-sandbox", { diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index c1ae9b93..0c1e4110 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -1,11 +1,9 @@ --- -title: Run OpenHands App-Server with Local SDK Agent-Server and Custom Agent -description: Run the OpenHands V1 app-server backed by a purely local agent-server from software-agent-sdk, and learn multiple ways to integrate a custom SDK agent. +title: Run OpenHands App-Server with Local SDK Agent-Server +description: Run the OpenHands V1 app-server backed by a purely local SDK agent-server, no Docker or remote runtime required. --- -This guide shows how to: -- Run the OpenHands V1 app-server while spawning a fully local agent-server process (no Docker, no remote runtime) -- Build a custom agent with software-agent-sdk and integrate it into the locally running app-server +This guide shows how to run the OpenHands V1 app-server while spawning a fully local agent-server process (no Docker, no remote runtime). Applies to the V1 app-server path enabled under /api/v1. @@ -25,7 +23,7 @@ OpenHands V1 exposes its API under /api/v1 and keeps the V1 server - On the SDK side, the agent-server exposes /alive and /health (and /api/*). See [server_details_router.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/server_details_router.py#L27-L41) and bootstrap in [agent_server/__main__.py](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/__main__.py#L1-L40). - The app-server talks to the agent-server using AsyncRemoteWorkspace and the agent-server REST/WebSocket API. See [AsyncRemoteWorkspace](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/workspace/remote/async_remote_workspace.py) and where the app-server builds conversation requests in _build_start_conversation_request_for_user ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L929-L1014)). -## Part 1 — Run App-Server with a Local Agent-Server +## Run App-Server with a Local Agent-Server ### 1) Build OpenHands and Enable V1 By default V1 is enabled (unless ENABLE_V1=0). Ensure you’re on Python 3.12 and have Poetry and Node installed, then: @@ -67,47 +65,12 @@ You can list sandboxes via V1 API and find the exposed agent-server URL; the nam ### 5) How the App-Server Talks to the Agent-Server When reading/writing files or executing commands in the conversation’s workspace, the app-server uses AsyncRemoteWorkspace that targets the agent-server. Example usage: [app_conversation_router.read_conversation_file](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_router.py#L335-L409) and throughout [live_status_app_conversation_service](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py). -## Part 2 — Build a Custom Agent with the SDK and Integrate Locally -There are two practical paths, depending on how much you want to change. +## Customize the Agent Loaded by the GUI -### Path A — Skills and MCP Servers (No-Code) -V1 lets you customize the agent that runs inside the agent-server by layering skills and MCP servers. The app-server automatically loads: -- User skills from ~/.openhands/skills and ~/.openhands/microagents/ via the SDK’s loader (see [load_user_skills](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-sdk/openhands/sdk/context/skills.py)), which the app-server calls in [skill loading](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L56-L104). -- Org/repo skills from your target repository via [skill_loader.py](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/skill_loader.py). -- MCP servers: the app-server assembles an SDK-compatible mcpServers config (default OpenHands server + Tavily if available, and any custom MCP servers you set in user settings). See _configure_llm_and_mcp ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L804-L865)). - -Example: Add a User Skill -1. Create a file ~/.openhands/skills/security_expert.md - -```markdown Skill: security_expert.md ---- -triggers: -- security ---- -# Security Expert -You are a cybersecurity expert. Always consider security implications. -``` - -2. Start a V1 conversation and include the word “security” in your ask. The skill is merged into the agent’s context by the app-server (see [merge path](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_service_base.py#L84-L115)). - -### Path B — Custom SDK Agent via App-Server -- The agent-server API accepts a full Agent specification (LLM, tools, context, etc.) as part of StartConversationRequest (see [conversation_router](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-agent-server/openhands/agent_server/conversation_router.py#L67-L105)). -- In OpenHands V1, the app-server constructs this Agent for you based on AgentType (DEFAULT or PLAN), LLM settings, MCP config, and merged skills. See _create_agent_with_context ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923)) and how it finishes the request in _finalize_conversation_request ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L1016-L1082)). - -You can customize behavior without forking by: -- Switching AgentType between DEFAULT and PLAN via the Start request (UI or API) to change tool presets (see [tool presets](https://github.com/OpenHands/software-agent-sdk/blob/main/openhands-tools/openhands/tools/preset)). -- Supplying skills and MCP servers as described above. - -Advanced: Add a New Agent Type to OpenHands -If you want the UI and app-server to create your own agent layout (custom tools/system prompt/etc.), extend OpenHands: -1. Add a new enum to [AgentType](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/app_conversation_models.py#L18-L26). -2. Update _create_agent_with_context ([source](https://github.com/OpenHands/OpenHands/blob/main/openhands/app_server/app_conversation/live_status_app_conversation_service.py#L866-L923)) to construct your Agent when your new type is selected. -3. Optionally expose the type in the frontend to make it selectable. - -### Path C — Test with the SDK Directly (Optional but Useful) -The SDK ships standalone examples you can run locally to validate your Agent design before wiring through OpenHands. See: -- **[Local Agent Server](/sdk/guides/agent-server/local-server)** -- **[Agent Server Overview](/sdk/guides/agent-server/overview)** +For customization paths (skills/MCP, agent presets, or defining a new Agent type the app can instantiate), see: +- /sdk/guides/agent-server/app-integration +- /sdk/guides/agent-custom +- /sdk/guides/custom-tools ## Troubleshooting - If no agent-server starts when you create a V1 conversation, ensure: diff --git a/sdk/guides/agent-server/app-integration.mdx b/sdk/guides/agent-server/app-integration.mdx new file mode 100644 index 00000000..bc423c10 --- /dev/null +++ b/sdk/guides/agent-server/app-integration.mdx @@ -0,0 +1,64 @@ +--- +title: Integrate SDK Agents with the OpenHands App +description: How the OpenHands app uses the SDK Agent Server and where to customize the agent that the GUI loads +--- + +This guide explains how the OpenHands app (V1) composes an SDK Agent when you start a conversation in the GUI, and where you can customize behavior using the SDK. + + +Best read alongside:
+- Agent Server Overview
+- Run a Local Agent Server
+- Creating Custom Agent +
+ +## How the App Loads an SDK Agent + +When you start a V1 conversation from the GUI, the app-server: +- Launches an SDK Agent Server (locally or via the configured runtime) +- Builds a StartConversationRequest that includes an Agent specification +- Sends that request to the Agent Server's conversation API + +Key references: +- App builds the V1 router only if V1 is enabled: server/app.py +- Conversation request assembly: live_status_app_conversation_service.py +- Agent Server endpoints: conversation_router.py, server_details_router.py + +## Customization Paths + +### 1) Skills and MCP (No-Code) +The app merges skills and MCP server config into the agent context: +- User skills from ~/.openhands/skills and ~/.openhands/microagents/ +- Repo/org skills resolved from your working repository +- MCP servers from settings and defaults (OpenHands + Tavily) + +This path lets you steer agent behavior without changing code. + +### 2) Agent Type Selection (Low-Code) +The app selects an Agent preset based on AgentType (DEFAULT or PLAN). You can: +- Toggle the AgentType in the Start request (UI or API) +- Adjust LLM and MCP settings in the UI + +See also SDK presets for default and planning agents. + +### 3) Define a New Agent Type in the App (Advanced) +If you need the GUI to instantiate a different agent layout (custom tools, system prompt, etc.): +1. Add a new enum value to AgentType in the app +2. Extend the builder to construct your custom Agent for that type +3. Optionally expose it in the frontend for selection + +This keeps the App as the source of truth for Agent construction while leveraging SDK components. + +## Validate with the SDK First + +Before wiring into the App, validate your design directly with the SDK: +- Run the Local Agent Server guide to test endpoints +- Use the Creating Custom Agent guide to build presets and behaviors + +## See Also + +- /sdk/guides/agent-custom +- /sdk/guides/custom-tools +- /sdk/guides/mcp +- /sdk/guides/agent-server/overview +- /sdk/guides/agent-server/local-server From d34fa623eba5fbaa86fdae95926883b1e76cb469 Mon Sep 17 00:00:00 2001 From: Engel Nyst Date: Mon, 22 Dec 2025 10:39:28 +0100 Subject: [PATCH 09/11] Update openhands/usage/developers/v1-local-agent-server.mdx --- openhands/usage/developers/v1-local-agent-server.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands/usage/developers/v1-local-agent-server.mdx b/openhands/usage/developers/v1-local-agent-server.mdx index 0c1e4110..8477e659 100644 --- a/openhands/usage/developers/v1-local-agent-server.mdx +++ b/openhands/usage/developers/v1-local-agent-server.mdx @@ -30,7 +30,7 @@ By default V1 is enabled (unless ENABLE_V1=0). Ensure you’re on P ```bash Build export INSTALL_DOCKER=0 # No Docker for this guide -export RUNTIME=local # Force process-based sandbox (spawns local agent-server) +export RUNTIME=process # Force process-based sandbox (spawns sub-process agent-server) # optional: export ENABLE_V1=1 # V1 is enabled by default; set explicitly if you disabled it elsewhere make build From a85c2d9ed00978ec5f0dc1038143c4f337fa9a41 Mon Sep 17 00:00:00 2001 From: Engel Nyst Date: Mon, 22 Dec 2025 10:40:30 +0100 Subject: [PATCH 10/11] Update sdk/guides/agent-server/app-integration.mdx --- sdk/guides/agent-server/app-integration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/guides/agent-server/app-integration.mdx b/sdk/guides/agent-server/app-integration.mdx index bc423c10..14cb6a60 100644 --- a/sdk/guides/agent-server/app-integration.mdx +++ b/sdk/guides/agent-server/app-integration.mdx @@ -15,7 +15,7 @@ Best read alongside:
## How the App Loads an SDK Agent When you start a V1 conversation from the GUI, the app-server: -- Launches an SDK Agent Server (locally or via the configured runtime) +- Launches an SDK Agent Server (locally or via the configured host) - Builds a StartConversationRequest that includes an Agent specification - Sends that request to the Agent Server's conversation API From d148877a7a8ec88791660faee4f611d6a05f9137 Mon Sep 17 00:00:00 2001 From: Engel Nyst Date: Mon, 22 Dec 2025 10:41:38 +0100 Subject: [PATCH 11/11] Update sdk/guides/agent-server/app-integration.mdx --- sdk/guides/agent-server/app-integration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/guides/agent-server/app-integration.mdx b/sdk/guides/agent-server/app-integration.mdx index 14cb6a60..b0d3d1eb 100644 --- a/sdk/guides/agent-server/app-integration.mdx +++ b/sdk/guides/agent-server/app-integration.mdx @@ -28,7 +28,7 @@ Key references: ### 1) Skills and MCP (No-Code) The app merges skills and MCP server config into the agent context: -- User skills from ~/.openhands/skills and ~/.openhands/microagents/ +- User skills from `~/.openhands/skills` and `~/.openhands/microagents/` - Repo/org skills resolved from your working repository - MCP servers from settings and defaults (OpenHands + Tavily)