From 068ff5a95ef25d82e80ea08398e2ff7ad08b09dc Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Wed, 5 Aug 2026 12:45:09 -0500 Subject: [PATCH 1/6] feat: add Replicated OHE install skill Co-authored-by: openhands --- README.md | 5 +- marketplaces/openhands-extensions.json | 13 ++ skills/index.js | 7 + .../.claude-plugin | 1 + .../.codex-plugin | 1 + .../.plugin/plugin.json | 19 ++ skills/install-openhands-replicated/README.md | 40 ++++ skills/install-openhands-replicated/SKILL.md | 145 ++++++++++++ .../agents/openai.yaml | 4 + .../assets/install-plan.yaml | 60 +++++ .../references/admin-config.md | 118 ++++++++++ .../references/backup-and-durability.md | 66 ++++++ .../references/blue-green-reinstall.md | 126 +++++++++++ .../references/git-provider-auth.md | 69 ++++++ .../references/install-flow.md | 184 +++++++++++++++ .../references/integrations.md | 67 ++++++ .../references/operator-requests.md | 95 ++++++++ .../scripts/apply_kots_config.sh | 187 ++++++++++++++++ .../scripts/check_dns.sh | 64 ++++++ .../scripts/check_host_preflight.sh | 134 +++++++++++ .../scripts/check_outbound.sh | 44 ++++ .../scripts/check_tls_files.sh | 174 +++++++++++++++ .../scripts/preflight_storage_guard.sh | 209 ++++++++++++++++++ .../scripts/summarize_terraform_outputs.sh | 48 ++++ .../scripts/verify_github_setup.sh | 18 ++ .../scripts/verify_jira_setup.sh | 22 ++ .../scripts/verify_laminar_setup.sh | 21 ++ .../scripts/verify_slack_setup.sh | 19 ++ tests/test_skills_catalog.py | 2 +- 29 files changed, 1959 insertions(+), 3 deletions(-) create mode 120000 skills/install-openhands-replicated/.claude-plugin create mode 120000 skills/install-openhands-replicated/.codex-plugin create mode 100644 skills/install-openhands-replicated/.plugin/plugin.json create mode 100644 skills/install-openhands-replicated/README.md create mode 100644 skills/install-openhands-replicated/SKILL.md create mode 100644 skills/install-openhands-replicated/agents/openai.yaml create mode 100644 skills/install-openhands-replicated/assets/install-plan.yaml create mode 100644 skills/install-openhands-replicated/references/admin-config.md create mode 100644 skills/install-openhands-replicated/references/backup-and-durability.md create mode 100644 skills/install-openhands-replicated/references/blue-green-reinstall.md create mode 100644 skills/install-openhands-replicated/references/git-provider-auth.md create mode 100644 skills/install-openhands-replicated/references/install-flow.md create mode 100644 skills/install-openhands-replicated/references/integrations.md create mode 100644 skills/install-openhands-replicated/references/operator-requests.md create mode 100755 skills/install-openhands-replicated/scripts/apply_kots_config.sh create mode 100755 skills/install-openhands-replicated/scripts/check_dns.sh create mode 100755 skills/install-openhands-replicated/scripts/check_host_preflight.sh create mode 100755 skills/install-openhands-replicated/scripts/check_outbound.sh create mode 100755 skills/install-openhands-replicated/scripts/check_tls_files.sh create mode 100755 skills/install-openhands-replicated/scripts/preflight_storage_guard.sh create mode 100755 skills/install-openhands-replicated/scripts/summarize_terraform_outputs.sh create mode 100755 skills/install-openhands-replicated/scripts/verify_github_setup.sh create mode 100755 skills/install-openhands-replicated/scripts/verify_jira_setup.sh create mode 100755 skills/install-openhands-replicated/scripts/verify_laminar_setup.sh create mode 100755 skills/install-openhands-replicated/scripts/verify_slack_setup.sh diff --git a/README.md b/README.md index 424440b1..ee2de0d0 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ The JS and Python versions are kept in lock-step by `release-please` and guarded ## Extensions Catalog -This repository contains **2 marketplace(s)** with **64 extensions** (54 skills, 10 plugins). +This repository contains **2 marketplace(s)** with **65 extensions** (55 skills, 10 plugins). ### large-codebase @@ -108,7 +108,7 @@ OpenHands skills for interacting, improving, and refactoring large codebases Official skills and plugins for OpenHands — the open-source AI software engineer. -**60 extensions** (52 skills, 8 plugins) +**61 extensions** (53 skills, 8 plugins) | Name | Type | Description | Commands | |------|------|-------------|----------| @@ -138,6 +138,7 @@ Official skills and plugins for OpenHands — the open-source AI software engine | github-repo-monitor | skill | Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger p... | `/github-monitor:poll` | | gitlab | skill | Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when wor... | — | | incident-retrospective | skill | Create an automation that drafts incident retrospectives by gathering incident-channel messages from Slack, collectin... | `/incident-retro:setup` | +| install-openhands-replicated | skill | Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with read-only preflights, ... | — | | iterate | skill | Iterate on a GitHub pull request — drive it through CI, code review, and QA until merge-ready. Monitors state, fixes ... | `/iterate`, `/verify`, `/babysit` | | jira-issue-to-pr | skill | Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable lab... | — | | jupyter | skill | Read, modify, execute, and convert Jupyter notebooks programmatically. Use when working with .ipynb files for data sc... | — | diff --git a/marketplaces/openhands-extensions.json b/marketplaces/openhands-extensions.json index dfed7887..9ef76e6c 100644 --- a/marketplaces/openhands-extensions.json +++ b/marketplaces/openhands-extensions.json @@ -770,6 +770,19 @@ "jira", "atlassian" ] + }, + { + "name": "install-openhands-replicated", + "source": "./skills/install-openhands-replicated", + "description": "Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with read-only preflights, explicit approval gates, provider setup, and end-to-end validation.", + "category": "environment", + "keywords": [ + "openhands-enterprise", + "replicated", + "embedded-cluster", + "vm-install", + "preflight" + ] } ] } diff --git a/skills/index.js b/skills/index.js index 5fe5d59c..70fba5d7 100644 --- a/skills/index.js +++ b/skills/index.js @@ -262,6 +262,13 @@ export const SKILLS_CATALOG = [ "content": "# Incident Retrospective Drafter Automation\n\nSet up an automation that drafts incident retrospectives by pulling data from\nSlack, Linear, and Notion.\n\n---\n\n## Prerequisites\n\n### Required integrations\n\nAll three MCP integrations must be installed in Settings → MCP:\n\n- **Slack MCP** — to gather incident-channel messages\n- **Linear MCP** — to collect linked tickets and follow-ups\n- **Notion MCP** — to publish the retrospective draft\n\n### Information to collect\n\nAsk the user for:\n\n1. **Incident identification** — how are incidents identified? (e.g. Slack channel naming convention like `#inc-*`, a Linear label, or manual trigger)\n2. **Slack channels** — which channels contain incident chatter (e.g. `#incidents`, `#inc-*` pattern)\n3. **Linear teams** — which Linear teams/projects to inspect for follow-up tickets\n4. **Retrospective template** — what sections should the retro include? Default: Timeline, Impact, Root Cause, Action Items, Lessons Learned\n5. **Notion destination** — which Notion database or page should receive the draft\n6. **Trigger type** — manual dispatch, cron schedule, or triggered by an incident label being added\n\n---\n\n## Setup Workflow\n\n### Step 1 — Verify MCP access\n\nTest each integration:\n```\nUse the Slack MCP to list recent messages in an incident channel.\nUse the Linear MCP to list recent issues for the target team.\nUse the Notion MCP to search for the destination database.\n```\n\nIf any fail, tell the user which integration needs to be installed first.\n\n### Step 2 — Determine trigger type\n\nAsk the user how retros should be triggered:\n- **Manual** — dispatch from the automations page when an incident wraps up\n- **Cron** — run daily/weekly to check for recent incidents\n- **Event** — triggered by a Linear label change or Slack message\n\n### Step 3 — Build the retro prompt\n\nConstruct a prompt that includes:\n- How to identify the incident (channel pattern, label, etc.)\n- Which Slack channels and Linear teams to query\n- The retrospective template/sections\n- Where to publish in Notion\n\n### Step 4 — Create the automation\n\nRead the Automation backend URL and auth from ``:\n- Use the **Automation backend** `url_from_agent` as `OPENHANDS_HOST`\n- Auth: `X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY`\n\nUse the **prompt preset** endpoint:\n```bash\ncurl -s -X POST \"${OPENHANDS_HOST}/api/automation/v1/preset/prompt\" \\\n -H \"X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"name\": \"Incident Retrospective Drafter\",\n \"prompt\": \"\",\n \"trigger\": \n }'\n```\n\nPowerShell note: use `curl.exe` for this exact flag syntax, and replace `${OPENHANDS_HOST}` / `$OPENHANDS_AUTOMATION_API_KEY` with `$env:OPENHANDS_HOST` / `$env:OPENHANDS_AUTOMATION_API_KEY` if running it natively.\n\n### Step 5 — Confirm\n\nTell the user:\n> ✅ **Incident Retrospective Drafter** is running!\n>\n> - Automation ID: `{id}`\n> - Incident source: `{identification method}`\n> - Slack channels: `{channels}`\n> - Linear teams: `{teams}`\n> - Notion destination: `{destination}`\n> - Trigger: `{trigger description}`", "category": "automations" }, + { + "name": "install-openhands-replicated", + "description": "This skill should be used when the user asks to \"install OpenHands Enterprise\", \"set up OHE on a VM\", \"run an OHE install preflight\", \"configure the Replicated Admin Console\", \"prepare DNS and TLS for OpenHands Enterprise\", or \"validate a Replicated Embedded Cluster installation\". It guides supported AWS Terraform or manual VM installations from scoping through end-to-end validation.", + "triggers": [], + "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Prefer supported Replicated and KOTS surfaces. Do not use direct Kubernetes patches as installation steps. Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nUse the current OpenHands AWS Terraform module when AWS Terraform is selected. For a manual VM, require the documented CPU, memory, disk, latency, OS, systemd, root access, inbound ports, local ports, and outbound destinations.\n\nRun read-only preflights on the target VM:\n\n```bash\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, and outbound preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nUse the current `Simple` hostname mode unless the customer requires manual hostnames. Configure and validate one layer at a time:\n\n1. domain and publicly trusted TLS;\n2. one LLM provider;\n3. database choice and storage durability;\n4. core application deployment;\n5. first login and organization;\n6. Git provider authentication using `references/git-provider-auth.md`;\n7. optional integrations, analytics, automations, and advanced settings.\n\nRead `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution.\n\n### 5. Prove the Core Product\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Mutating Helper Gate\n\nUse `scripts/apply_kots_config.sh` in preview mode first:\n\n```bash\nscripts/apply_kots_config.sh \\\n --appslug openhands \\\n --config-file ./config-values.patch.yaml \\\n --current\n```\n\nAfter reviewing impact and obtaining explicit approval, add `--execute`; add `--deploy` only when an immediate deployment is approved. Re-run workload, readiness, storage, and user-path verification after deployment.\n\n## Resources\n\n- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria.\n- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and guarded ConfigValues guidance.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux host and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: preview-first KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", + "category": "environment" + }, { "name": "iterate", "description": "Iterate on a GitHub pull request — drive it through CI, code review, and QA until it is merge-ready. Poll verification layers with `gh` CLI, diagnose and fix CI failures, address review feedback, retry flaky checks, push fixes, and repeat. The agent is the orchestration loop.", diff --git a/skills/install-openhands-replicated/.claude-plugin b/skills/install-openhands-replicated/.claude-plugin new file mode 120000 index 00000000..665797f0 --- /dev/null +++ b/skills/install-openhands-replicated/.claude-plugin @@ -0,0 +1 @@ +.plugin \ No newline at end of file diff --git a/skills/install-openhands-replicated/.codex-plugin b/skills/install-openhands-replicated/.codex-plugin new file mode 120000 index 00000000..665797f0 --- /dev/null +++ b/skills/install-openhands-replicated/.codex-plugin @@ -0,0 +1 @@ +.plugin \ No newline at end of file diff --git a/skills/install-openhands-replicated/.plugin/plugin.json b/skills/install-openhands-replicated/.plugin/plugin.json new file mode 100644 index 00000000..f9dc7e45 --- /dev/null +++ b/skills/install-openhands-replicated/.plugin/plugin.json @@ -0,0 +1,19 @@ +{ + "name": "install-openhands-replicated", + "version": "1.0.0", + "description": "Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with read-only preflights, explicit approval gates, provider setup, and end-to-end validation.", + "author": { + "name": "OpenHands", + "email": "contact@all-hands.dev" + }, + "homepage": "https://github.com/OpenHands/extensions", + "repository": "https://github.com/OpenHands/extensions", + "license": "MIT", + "keywords": [ + "openhands-enterprise", + "replicated", + "embedded-cluster", + "vm-install", + "preflight" + ] +} diff --git a/skills/install-openhands-replicated/README.md b/skills/install-openhands-replicated/README.md new file mode 100644 index 00000000..f735131f --- /dev/null +++ b/skills/install-openhands-replicated/README.md @@ -0,0 +1,40 @@ +# Install OpenHands Enterprise on Replicated + +Guide a customer or field engineer through a supported OpenHands Enterprise VM installation delivered with Replicated Embedded Cluster. + +## Use this skill for + +- scoping AWS Terraform or manual VM installations; +- checking host resources, ports, DNS, TLS, outbound access, and LLM endpoints; +- preparing GitHub, GitLab, Bitbucket Data Center, or Azure DevOps authentication; +- guiding version-specific installer and Admin Console steps; +- validating login, LLM routing, conversations, repository access, integrations, and storage; +- drafting DNS, firewall, certificate, infrastructure, and access requests for IT teams. + +## Safety model + +The skill starts read-only. Infrastructure changes, installer execution, ConfigValues merges, deployments, provider application creation, DNS changes, restores, and cutovers require explicit approval for the exact operation. + +Installer download URLs, license files, private keys, provider credentials, ConfigValues, and support bundles are treated as sensitive. The bundled YAML asset records only non-secret scope and validation status; it is not a headless deployment configuration. + +## Current scope + +This draft implements the PRD-137 first milestone: comprehensive preflight, provider setup guidance, guided ClickOps, post-install verification, and customer-ready IT requests. + +A fully headless install remains conditional on a documented, release-specific installer schema and supported secret-input mechanism. The skill does not infer or invent those interfaces. + +## Primary triggers + +- `install OpenHands Enterprise` +- `set up OHE on a VM` +- `run an OHE install preflight` +- `configure the Replicated Admin Console` +- `prepare DNS and TLS for OpenHands Enterprise` +- `validate a Replicated Embedded Cluster installation` + +## Official references + +- [OpenHands Enterprise quick start](https://docs.openhands.dev/enterprise/quick-start) +- [Admin Console configuration](https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration) +- [Replicated Embedded Cluster installation](https://docs.replicated.com/enterprise/installing-embedded) +- [Replicated Embedded Cluster requirements](https://docs.replicated.com/enterprise/installing-embedded-requirements) diff --git a/skills/install-openhands-replicated/SKILL.md b/skills/install-openhands-replicated/SKILL.md new file mode 100644 index 00000000..8c43bc29 --- /dev/null +++ b/skills/install-openhands-replicated/SKILL.md @@ -0,0 +1,145 @@ +--- +name: install-openhands-replicated +description: This skill should be used when the user asks to "install OpenHands Enterprise", "set up OHE on a VM", "run an OHE install preflight", "configure the Replicated Admin Console", "prepare DNS and TLS for OpenHands Enterprise", or "validate a Replicated Embedded Cluster installation". It guides supported AWS Terraform or manual VM installations from scoping through end-to-end validation. +--- + +# Install OpenHands Enterprise on Replicated + +Guide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope. + +## Safety Contract + +- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation. +- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values. +- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase. +- Prefer supported Replicated and KOTS surfaces. Do not use direct Kubernetes patches as installation steps. Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support. +- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them. +- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements. +- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state. + +## Installation Workflow + +### 1. Establish the Contract + +Record: + +- OHE target release and installer/Embedded Cluster version shown by the dashboard; +- AWS Terraform or manual VM path; +- base domain, DNS owner, TLS owner, and hostname mode; +- LLM provider and authentication owner; +- Git provider and optional integrations; +- embedded or external PostgreSQL and backup expectations; +- change approver, maintenance window, and support contact. + +Copy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure. + +### 2. Provision or Inspect Infrastructure + +Use the current OpenHands AWS Terraform module when AWS Terraform is selected. For a manual VM, require the documented CPU, memory, disk, latency, OS, systemd, root access, inbound ports, local ports, and outbound destinations. + +Run read-only preflights on the target VM: + +```bash +scripts/check_host_preflight.sh +scripts/check_dns.sh simple +scripts/check_tls_files.sh wildcard +scripts/check_outbound.sh +``` + +Resolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist. + +### 3. Review the Installer Operation + +Use only commands copied from the customer's installer dashboard for the chosen release. Before execution: + +1. Confirm the VM and base domain. +2. Confirm the installer-side instance name is not being confused with the cloud resource name. +3. Confirm the license and TLS file paths exist without printing their contents. +4. Confirm host, DNS, port, and outbound preflights passed. +5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console. +6. Obtain explicit approval to run the exact dashboard-provided install command. + +Run the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps. + +### 4. Configure the Admin Console in Layers + +Use the current `Simple` hostname mode unless the customer requires manual hostnames. Configure and validate one layer at a time: + +1. domain and publicly trusted TLS; +2. one LLM provider; +3. database choice and storage durability; +4. core application deployment; +5. first login and organization; +6. Git provider authentication using `references/git-provider-auth.md`; +7. optional integrations, analytics, automations, and advanced settings. + +Read `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution. + +### 5. Prove the Core Product + +Do not declare completion from pod readiness alone. Verify: + +- Admin Console and application TLS validate for the configured hostnames; +- deployment status is Ready and workloads have no new warning events; +- login works in a clean browser session; +- the first organization and bounded API key work; +- the configured model completes one tiny request; +- one no-repository conversation finishes with an expected marker; +- repository search and one repository-backed conversation work when a Git provider is in scope. + +Run `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover. + +### 6. Add Optional Integrations + +Validate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient. + +### 7. Produce the Handoff + +Record: + +```text +OHE release: +Embedded Cluster/installer version: +Infrastructure path and region/site: +Hostname mode and base domain: +Database and storage class: +Enabled integrations: +Preflight evidence: +Core smoke-test evidence: +Backup and restore boundary: +Known limitations: +Support-bundle command and approved support channel: +``` + +Exclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps. + +## Mutating Helper Gate + +Use `scripts/apply_kots_config.sh` in preview mode first: + +```bash +scripts/apply_kots_config.sh \ + --appslug openhands \ + --config-file ./config-values.patch.yaml \ + --current +``` + +After reviewing impact and obtaining explicit approval, add `--execute`; add `--deploy` only when an immediate deployment is approved. Re-run workload, readiness, storage, and user-path verification after deployment. + +## Resources + +- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria. +- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and guarded ConfigValues guidance. +- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation. +- `references/backup-and-durability.md`: persistence checks and recovery boundaries. +- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow. +- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates. +- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing. +- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues. +- `scripts/check_host_preflight.sh`: read-only Linux host and port checks. +- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks. +- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks. +- `scripts/check_outbound.sh`: required outbound reachability checks. +- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary. +- `scripts/apply_kots_config.sh`: preview-first KOTS ConfigValues helper. +- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks. diff --git a/skills/install-openhands-replicated/agents/openai.yaml b/skills/install-openhands-replicated/agents/openai.yaml new file mode 100644 index 00000000..1b23433c --- /dev/null +++ b/skills/install-openhands-replicated/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Install OpenHands Replicated" + short_description: "Install OpenHands Enterprise on Replicated" + default_prompt: "Use $install-openhands-replicated to plan, execute, and validate a generic OpenHands Enterprise Replicated install." diff --git a/skills/install-openhands-replicated/assets/install-plan.yaml b/skills/install-openhands-replicated/assets/install-plan.yaml new file mode 100644 index 00000000..df4949c1 --- /dev/null +++ b/skills/install-openhands-replicated/assets/install-plan.yaml @@ -0,0 +1,60 @@ +# Non-secret planning record only. Do not place credentials, license contents, +# private keys, download URLs, tokens, or decrypted ConfigValues in this file. +installation: + target_ohe_release: "" + installer_version: "" + infrastructure_path: "aws-terraform-or-manual-vm" + environment_name: "" + change_approver: "" + maintenance_window: "" + +infrastructure: + cloud_or_datacenter: "" + region_or_site: "" + vm_identifier: "" + cpu_count: 0 + memory_gib: 0 + disk_gib: 0 + storage_type: "" + disk_p99_write_latency_ms: null + +network: + base_domain: "" + hostname_mode: "simple" + dns_owner: "" + firewall_owner: "" + proxy_required: false + public_tls: true + certificate_owner: "" + +application: + llm_provider: "" + git_provider: "" + database_mode: "embedded-or-external" + optional_integrations: [] + analytics_enabled: false + automations_enabled: false + +recovery: + backup_owner: "" + rpo: "" + rto: "" + restore_procedure: "" + +validation: + host_preflight: "pending" + dns_preflight: "pending" + tls_preflight: "pending" + outbound_preflight: "pending" + installer_approved: false + deployment_ready: false + login: "pending" + llm_smoke_test: "pending" + conversation_smoke_test: "pending" + repository_smoke_test: "not-in-scope" + storage_guard: "pending" + +handoff: + known_limitations: [] + support_channel: "" + cleanup_owner: "" diff --git a/skills/install-openhands-replicated/references/admin-config.md b/skills/install-openhands-replicated/references/admin-config.md new file mode 100644 index 00000000..c87ac1e4 --- /dev/null +++ b/skills/install-openhands-replicated/references/admin-config.md @@ -0,0 +1,118 @@ +# Admin Console Configuration + +Use the Admin Console for supported settings. Treat a saved configuration as a mutating operation that can restart components. Review the intended values, impact, and verification plan before selecting Deploy. + +## Domain and TLS + +Use `Simple` hostname mode for new installations unless DNS policy requires manual hostnames. In Simple mode, all service names sit directly under the base domain: + +```text +admin. +app. +auth. +analytics. +llm-proxy. +runtime-api. +-runtime. +``` + +Keep existing Legacy installations on their current layout unless hostname migration is the approved change. Legacy layouts can include `auth.app.` and `.runtime.`. + +Use a publicly trusted wildcard certificate for customer-facing installations whenever possible. Include intermediate certificates and verify that the private key matches the server certificate without printing either value. + +Self-signed certificates are not supported for the OpenHands application. A private CA requires every browser, OAuth provider, and webhook sender to trust the CA; otherwise callbacks can fail TLS validation. + +If certificates are not passed during installation, use the Admin Console certificate upload flow. Store local certificate and key files outside repositories with restrictive permissions and remove temporary copies after use. + +## Runtime Routing + +Subdomain routing in Simple mode requires wildcard coverage for `*.`. If wildcard certificates are unavailable, use the target release's supported path-based routing mode and provision the complete SAN set from its documentation. + +## LLM Provider + +Configure one working provider first. For Bedrock, verify: + +- AWS auth mode is correct: access key/secret or EC2 instance profile. +- Region has access to the chosen model. +- Model ID is the exact Bedrock or inference-profile ID exposed by AWS. +- LiteLLM model alias is visible through `/v1/models`. + +For current Bedrock model IDs, query AWS rather than relying on stale notes: + +```bash +aws bedrock list-foundation-models --region +``` + +If OpenHands profiles use the internal proxy, model names should normally look like: + +```text +litellm_proxy/ +``` + +and the base URL should be: + +```text +http://openhands-litellm:4000 +``` + +## Sandbox Settings + +Common settings: + +- idle time: how long before idle conversations pause; +- deletion time: how long paused runtimes/PVCs are retained before deletion; +- storage size: PVC size per sandbox; +- memory request/limit and CPU request/limit; +- warm runtime count. + +Interpretation: + +- A longer deletion time helps users resume old conversations, but it keeps runtime PVCs around longer. +- A warm runtime can improve start latency, but it must match the environment needed by the conversation. If a warm runtime lacks required secrets/env vars, the request may cold-start anyway. +- More running sandboxes consume memory and CPU. On small single-node installs, too many active runtimes can indirectly make login and API paths feel unstable. + +## Declarative KOTS Config + +Prefer the Admin Console for interactive customer configuration. Use a small KOTS `ConfigValues` merge patch only when the operator requires repeatable declarative configuration and the target release supports the referenced keys: + +```yaml +apiVersion: kots.io/v1beta1 +kind: ConfigValues +spec: + values: + config_key: + value: "new-value" +``` + +Treat ConfigValues files as potentially secret-bearing. Keep them outside repositories, restrict permissions, avoid shell tracing, and do not paste their contents into chat or tickets. + +Preview the command first: + +```bash +scripts/apply_kots_config.sh \ + --appslug openhands \ + --config-file ./config-values.patch.yaml \ + --current +``` + +After reviewing the preview and obtaining approval, execute without deployment: + +```bash +scripts/apply_kots_config.sh \ + --appslug openhands \ + --config-file ./config-values.patch.yaml \ + --current \ + --execute +``` + +Add `--deploy` only when an immediate rollout is approved. Verify the new sequence, rollout status, application readiness, storage guard, and affected user path. + +## Secret Field Shape + +Avoid exporting decrypted configuration unless a support or migration procedure requires it. When a version-matched procedure requires a decrypted export, preserve the original field shape for secret/file items and do not encode an already encoded KOTS value again. + +A double-encoded GitHub App private key can cause key parsing failures in components that consume it. Correct the value through the supported configuration surface; do not extract or patch Kubernetes Secret values as an installation shortcut. + +## Installer-Managed Secrets + +Do not rotate installer-managed PostgreSQL, Redis, JWT, Keycloak, LiteLLM, sandbox, plugin-directory, or Automations secrets manually. Use a component-specific procedure from OpenHands Support. Changing encryption or salt keys can make previously stored provider credentials unreadable. diff --git a/skills/install-openhands-replicated/references/backup-and-durability.md b/skills/install-openhands-replicated/references/backup-and-durability.md new file mode 100644 index 00000000..a998ed15 --- /dev/null +++ b/skills/install-openhands-replicated/references/backup-and-durability.md @@ -0,0 +1,66 @@ +# Backup And Durability + +At minimum, confirm the main OpenHands Postgres data directory is PVC-backed before production/demo use or any redeploy. + +Run on the target VM or from an operator environment with cluster access: + +```bash +scripts/preflight_storage_guard.sh openhands +``` + +The script automatically uses the Embedded Cluster kubectl path when present on the target VM. Otherwise, set `KUBECTL` to one executable kubectl path; do not include shell words such as `sudo` in the variable. + +The guard checks: + +- main Postgres data path is backed by a Bound PVC; +- node is not under `DiskPressure`; +- host disk has enough free space when checkable; +- ClickHouse diagnostic system logs are not consuming dangerous space. + +## What Postgres Backup Covers + +A daily Postgres dump is cheap and useful for fast recovery of: + +- users/org metadata; +- API keys and app DB records; +- LLM profile metadata; +- LiteLLM DB state when stored in the shared Postgres cluster; +- automation definitions and runs; +- integration state stored in app DBs. + +It does not cover: + +- runtime sandbox PVC contents; +- full VM root disk; +- MinIO/blob storage; +- external provider state; +- Laminar state unless Laminar is also backed up separately. + +## Example Daily Backup Pattern + +Treat this as an architecture pattern, not a ready-to-run customer procedure. A PostgreSQL dump contains credentials, tokens, user data, and other sensitive application state. + +A lightweight design can use: + +- a scheduled job running a version-compatible PostgreSQL dump; +- compression and checksum generation; +- encryption in transit and at rest; +- object storage with tightly scoped write/read permissions and retention controls; +- monitoring for missed or failed jobs; +- a documented, tested restore procedure. + +Define RPO and RTO with the customer rather than assuming a universal value. Confirm whether the design also covers MinIO/blob data, runtime PVCs, analytics, external databases, and infrastructure state. + +## Restore Gate + +Do not execute a restore from this skill alone. A restore can overwrite application state and invalidate newer credentials or integration records. Require: + +1. a version-matched backup and restore procedure; +2. explicit approval and a maintenance window; +3. a verified backup and checksum; +4. source and destination version compatibility; +5. a rollback or snapshot boundary; +6. a plan to quiesce application writers; +7. post-restore login, API, LLM, integration, and conversation tests. + +Escalate to OpenHands Support when database layout, encryption keys, external PostgreSQL, or partial-component recovery is involved. diff --git a/skills/install-openhands-replicated/references/blue-green-reinstall.md b/skills/install-openhands-replicated/references/blue-green-reinstall.md new file mode 100644 index 00000000..1467d68f --- /dev/null +++ b/skills/install-openhands-replicated/references/blue-green-reinstall.md @@ -0,0 +1,126 @@ +# Blue/Green Reinstall + +Use this reference only after the operator explicitly approves a rebuild and cutover. Rebuilding, restoring, switching DNS, or changing provider callbacks can cause downtime, duplicate events, or data loss. + +Prefer a version-matched OpenHands Support procedure when preserving application state across OHE versions. Use this reference when rebuilding an OpenHands Enterprise Replicated instance with minimal downtime or when stale state makes an in-place reinstall risky. + +## Default Recommendation + +Prefer blue/green over in-place wipe: + +1. Keep the current instance running. +2. Provision a new VM or cluster with temporary hostnames. +3. Recreate configuration and app state intentionally. +4. Validate the new instance. +5. Cut DNS and provider webhooks over during a quiet window. +6. Keep the old instance as rollback until the new instance survives real use. + +Use in-place reinstall only when downtime and rollback loss are acceptable. + +## What To Preserve + +Preserve as source material: + +- redacted KOTS `ConfigValues`; +- Terraform inputs and outputs; +- DNS record inventory; +- TLS certificate coverage; +- org secret names, not values; +- LLM profile definitions; +- automation definitions; +- GitHub/Jira/Slack/Laminar integration settings; +- current backup status and restore expectations. + +Preserve backups and snapshots, but do not restore old Postgres by default when +the goal is to remove stale state. + +## Temporary Hostnames + +Temporary hostnames let the new instance be validated without disrupting the old one. For a Simple-mode base domain like `openhands-next.example.com`, expect: + +```text +admin.openhands-next.example.com +app.openhands-next.example.com +auth.openhands-next.example.com +analytics.openhands-next.example.com +llm-proxy.openhands-next.example.com +runtime-api.openhands-next.example.com +-runtime.openhands-next.example.com +``` + +Keep a Legacy-mode source installation on its existing hostname layout unless hostname migration is part of the approved change. + +Before final cutover, update the new instance's Replicated/KOTS hostname config +to the original domains, upload/provision certs for those domains, redeploy, and +then switch DNS. + +## External Provider Constraints + +Do not assume GitHub, Jira, or Slack can point to both old and new instances at +the same time. + +Recommended approach: + +- Use temporary provider apps/webhooks for pre-cutover testing when available. +- Otherwise keep production provider URLs on the old instance until cutover. +- Validate production provider routing immediately after DNS/webhook cutover. + +GitHub has separate concerns: + +- sign-in/OAuth callback; +- user provider token for repo search and repo-backed conversations; +- GitHub App webhook delivery into automations. + +Jira and Slack also have separate delivery and user/workspace-linking states. + +## Clean-State Rehydrate Order + +1. Configure domain, TLS, LLM, sandbox lifecycle, and required app features. +2. Validate `/ready`, pods, statefulsets, and storage guard. +3. Sign in and create/claim the org. +4. Create a fresh org API key. +5. Import canonical org secrets. +6. Recreate LLM profiles with fresh LiteLLM proxy tokens. +7. Recreate automations. +8. Validate one manual conversation. +9. Validate integrations one at a time. +10. Configure and test backups. + +## Cutover Checklist + +Before cutover: + +- final old-instance backup exists; +- old instance remains untouched for rollback; +- new instance passes core smoke tests; +- provider URL changes are known; +- DNS TTL is understood; +- original-domain TLS certs are ready. + +During cutover: + +1. Disable old automations if duplicate events are risky. +2. Set original hostnames in the new Replicated/KOTS config. +3. Deploy and verify new app readiness. +4. Switch DNS records. +5. Update GitHub/Jira/Slack callbacks/webhooks if needed. +6. Re-enable automations on the new instance. +7. Run login, API key, LLM, conversation, and integration smoke tests. + +Rollback: + +1. Switch DNS/webhooks back to the old instance. +2. Re-enable old automations. +3. Keep the failed new instance for analysis. + +## Completion Criteria + +A blue/green reinstall is complete only when: + +- original app URL works on the new instance; +- protected API endpoint works with a new org key; +- at least one LLM-backed conversation completes; +- GitHub/Jira/Slack paths needed for demos are validated; +- Laminar traces are visible if analytics is enabled; +- backups are scheduled and at least one backup job succeeds; +- old instance rollback is no longer needed. diff --git a/skills/install-openhands-replicated/references/git-provider-auth.md b/skills/install-openhands-replicated/references/git-provider-auth.md new file mode 100644 index 00000000..4fe25b4d --- /dev/null +++ b/skills/install-openhands-replicated/references/git-provider-auth.md @@ -0,0 +1,69 @@ +# Git Provider Authentication + +Select one provider for the first installation pass. Configure additional providers only after core login, LLM, and conversation checks pass. + +## Approval and Secret Handling + +Treat provider application creation and callback changes as external mutations. Before running a helper or creating an application: + +1. identify the provider organization and approved test repository; +2. review requested scopes, callback URLs, webhook URLs, and events; +3. identify the provider administrator who approves the change; +4. explain created resources and cleanup steps; +5. obtain explicit approval; +6. transfer generated secrets through an approved secret channel. + +Do not print client secrets, webhook secrets, user tokens, or private keys. Use least privilege and a disposable test repository where possible. + +## GitHub + +The current OpenHands Enterprise quick start links to the official `scripts/create_github_app` helper in the OpenHands Cloud repository. + +Review the current helper before execution. Confirm the base URL and requested permissions match the target release, then obtain approval to run it. Configure the Admin Console with the generated: + +- Client ID +- Client Secret +- App ID +- App Slug +- Webhook Secret +- Private Key + +Use a GitHub App, not a GitHub OAuth App. Install the app only on approved repositories for the initial test. + +Validate sign-in, repository discovery, one bounded repository-backed conversation, and one webhook event when Automations is in scope. + +Official quick start: https://docs.openhands.dev/enterprise/quick-start + +## GitLab + +Configure the GitLab host and OAuth client values supported by the target OHE release. Keep `gitlab.com` for GitLab SaaS or use the customer-managed hostname. + +Follow the current Admin Console and provider documentation rather than adapting the GitHub helper. Validate callback TLS, sign-in, repository discovery, and one bounded repository-backed conversation. + +## Bitbucket Data Center + +Use the current OpenHands Enterprise Bitbucket Data Center guide for application, bot identity, callback, and webhook requirements. Do not assume Bitbucket Cloud instructions apply. + +Official guide: https://docs.openhands.dev/enterprise/integrations/bitbucket-data-center + +## Azure DevOps + +Use the current OpenHands Enterprise Azure DevOps guide for Microsoft Entra tenant, organization, client application, permissions, and callbacks. Validate the exact organization and a disposable repository before broadening access. + +Official guide: https://docs.openhands.dev/enterprise/integrations/azure-devops + +## Completion Record + +Record only non-secret evidence: + +```text +Provider: +Provider organization/host: +Application name and non-secret ID: +Approved repository scope: +Callback/webhook validation: +Sign-in result: +Repository discovery result: +Repository-backed conversation result: +Cleanup owner: +``` diff --git a/skills/install-openhands-replicated/references/install-flow.md b/skills/install-openhands-replicated/references/install-flow.md new file mode 100644 index 00000000..8fe2bfe4 --- /dev/null +++ b/skills/install-openhands-replicated/references/install-flow.md @@ -0,0 +1,184 @@ +# Install Flow + +Use this checklist for a new OpenHands Enterprise VM installation delivered through Replicated Embedded Cluster. Confirm current values against the target OHE release and the customer's installer dashboard. + +## Phase 1: Scope and Approval + +Capture before changing infrastructure: + +- target OHE release and installer/Embedded Cluster version; +- AWS Terraform or manual VM path; +- base domain, DNS owner, hostname mode, and TLS owner; +- LLM provider and authentication owner; +- Git provider and optional integrations; +- embedded or external PostgreSQL; +- backup, recovery, and maintenance-window expectations; +- named approver for infrastructure, installer, DNS, and application changes. + +Keep installer URLs, license files, private keys, and credentials out of tickets, chat, shell history, and repositories. + +## Phase 2: Infrastructure Requirements + +The current OpenHands Enterprise quick start requires the following for a manual VM: + +| Resource | Requirement | +| --- | --- | +| CPU | 16 vCPUs | +| Memory | 64 GB | +| Disk | 200 GB | +| Disk P99 write latency | 10 ms maximum | +| Architecture | Linux x86-64 | +| Init system | systemd | +| Access | root or sudo | + +Inbound TCP ports: + +```text +80 443 30000 +``` + +Local ports that must be available before installation: + +```text +2379 7443 9099 10248 10257 10259 +``` + +Run on the target VM: + +```bash +scripts/check_host_preflight.sh +scripts/check_outbound.sh +``` + +Pass each customer-approved LLM, cloud-model, or corporate gateway HTTPS endpoint required by the selected authentication mode. + +The host script cannot prove P99 storage latency without a write benchmark. Rely on the installer host preflight for the final latency check. Do not bypass a failed latency preflight; increase disk IOPS/throughput or use faster storage. + +For AWS Terraform, use the current module linked by the OpenHands Enterprise quick start. Review `terraform plan` before requesting approval for `apply`. Use the allowlisted output helper after apply: + +```bash +scripts/summarize_terraform_outputs.sh +``` + +Do not print the full Terraform output set because it can include sensitive values or local key paths. + +## Phase 3: DNS and TLS + +The current default is `Simple` hostname mode. A wildcard DNS record and certificate for `*.` cover: + +```text +admin. +app. +auth. +analytics. +llm-proxy. +runtime-api. +-runtime. +``` + +Validate the wildcard route with a synthetic runtime name: + +```bash +scripts/check_dns.sh simple +``` + +Older installations can use `Legacy` hostnames such as `auth.app.` and `.runtime.`. Do not migrate an existing installation's hostname mode during unrelated work. For a confirmed Legacy installation, run: + +```bash +scripts/check_dns.sh legacy +``` + +Use a publicly trusted wildcard certificate whenever possible. Self-signed certificates are not supported for the OpenHands application. A private CA requires every browser, OAuth provider, and webhook sender to trust the chain. + +If wildcard certificates are unavailable, select path-based sandbox routing and obtain the complete SAN set documented for the target release. + +## Phase 4: Outbound Preflight + +Run outbound checks from the target VM. Required destinations currently include Replicated control-plane endpoints, OpenHands image/chart/update endpoints, GitHub, Traefik charts, Docker Hub, GHCR, and each endpoint required by the selected LLM provider or corporate gateway. + +Treat HTTP responses such as 301, 401, 403, or 405 as reachable. Treat HTTP `000` as a DNS, timeout, proxy, or firewall failure. + +Resolve all preflight failures before running the installer. + +## Phase 5: Installer + +Obtain the version-specific commands from the customer's installer dashboard. The normal sequence is: + +1. select the OHE version; +2. download the installation assets with the dashboard-provided command; +3. extract the assets, including the license file; +4. review the exact install command and TLS paths; +5. obtain explicit approval; +6. run the install command in a real interactive PTY. + +A representative command shape is: + +```bash +sudo ./openhands install --license \ + --tls-cert \ + --tls-key +``` + +Do not substitute a representative command for the dashboard-provided command. Do not expose the dashboard download URL or license contents. + +If installation fails after preflights pass, collect a support bundle with the installed application binary: + +```bash +sudo ./openhands support-bundle +``` + +Treat the bundle as sensitive and share it only through the approved support channel. + +## Headless and Declarative Boundary + +Do not claim a fully headless installation unless the target OHE release exposes a documented installer flag, configuration schema, and supported secret-input mechanism. The current customer-safe default is: + +- use the installer dashboard for version-specific download and license commands; +- run the interactive installer in a real PTY; +- complete required Admin Console steps with guided ClickOps; +- use KOTS ConfigValues only for documented keys and preview each merge; +- keep `assets/install-plan.yaml` as a non-secret planning record, not deployment input. + +When headless installation is required, collect the target binary's `install --help`, the release-specific schema, secret-injection method, and rollback procedure from official documentation or OpenHands Support before implementation. + +## Phase 6: Admin Console Configuration + +For a single-node deployment, continue past the add-node screen. Configure in layers: + +1. Simple hostname mode and base domain; +2. certificate and private key; +3. one LLM provider; +4. database choice; +5. core application deployment; +6. first login and organization; +7. Git provider authentication; +8. optional integrations, analytics, and automations. + +Wait for deployment status to reach Ready and inspect resource details before moving to user-path validation. + +## Phase 7: Core Validation + +Minimum done state: + +- `https://admin.:30000` and `https://app.` present valid TLS; +- app readiness succeeds; +- login works in a clean browser session; +- first organization and bounded API key work; +- one tiny model request succeeds; +- one no-repository conversation completes with an expected marker; +- repository search and a repository-backed conversation work when a Git provider is in scope; +- storage guard passes; +- no new warning events appear during the smoke tests. + +Add optional integrations only after these checks pass. + +## Phase 8: Handoff + +Provide versions, topology, hostnames, enabled features, smoke-test evidence, backup boundaries, known limitations, and the approved support path. Exclude secrets and customer data. Use `operator-requests.md` for unresolved DNS, firewall, TLS, and access requests. + +## Official References + +- OpenHands Enterprise quick start: https://docs.openhands.dev/enterprise/quick-start +- Admin Console configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration +- Replicated Embedded Cluster installation: https://docs.replicated.com/enterprise/installing-embedded +- Replicated requirements: https://docs.replicated.com/enterprise/installing-embedded-requirements diff --git a/skills/install-openhands-replicated/references/integrations.md b/skills/install-openhands-replicated/references/integrations.md new file mode 100644 index 00000000..8fc354ac --- /dev/null +++ b/skills/install-openhands-replicated/references/integrations.md @@ -0,0 +1,67 @@ +# Integration Validation + +Add integrations only after core login, LLM, and conversation checks pass. Validate each integration independently. A working callback URL does not prove account linking, repository access, event routing, or provider-side permissions. + +Never print provider tokens, app secrets, signing secrets, private keys, or complete webhook bodies containing customer data. + +## GitHub + +Use a GitHub App rather than a GitHub OAuth App. Validate separate paths: + +1. user sign-in; +2. GitHub App installation on an approved test repository; +3. repository search for the signed-in user; +4. one bounded repository-backed conversation; +5. webhook or automation delivery when it is in scope. + +Useful bounded checks: + +```bash +curl -sS -H "Authorization: Bearer $OPENHANDS_API_KEY" \ + "$APP_URL/api/v1/users/me" + +curl -sS -H "Authorization: Bearer $OPENHANDS_API_KEY" \ + "$APP_URL/api/v1/git/repositories/search?provider=github&query=/&limit=5" +``` + +Do not enable shell tracing while using API keys. If repository search reports an invalid GitHub token, refresh the user's GitHub authorization rather than extracting credentials from the cluster. + +## GitLab, Bitbucket, and Azure DevOps + +Follow the version-matched OpenHands Enterprise guide for the chosen provider. Validate login or account linking, repository discovery, one bounded repository operation, and any required callback or webhook. Use a disposable test repository when possible. + +## Jira + +The current VM documentation provides a supported Jira Data Center integration. Validate: + +- Admin Console configuration exists for the supported Jira deployment type; +- account linking or service-account access works as configured; +- the Jira webhook reaches the documented OpenHands endpoint; +- one disposable test issue event produces the expected bounded result. + +Treat custom Jira-to-Automations webhooks as a separate automation design, not a generic installation requirement. Do not copy customer-specific shim URLs, project keys, cloud IDs, tokens, or one-off routing patches into this skill. + +## Slack + +Validate both setup layers: + +1. Admin Console credentials and Slack request URL verification; +2. OpenHands-side `Install Slack` workspace and user linking. + +Then invite the bot to a test channel and send one bounded mention. If Slack delivers the event but no conversation starts, verify workspace/user linking before changing webhook configuration. + +## Analytics (Laminar) + +For the bundled analytics option, validate: + +- `https://analytics.` loads; +- Keycloak login works; +- a project exists; +- an ingest-only project API key is configured through the Admin Console; +- a fresh conversation creates a trace. + +Use Laminar for trace-level observability. Use OpenHands application storage for durable conversation metadata and product state. + +## Automations + +When Automations is enabled, create or dispatch one bounded test using the supported UI or API. Verify the event, run, and conversation identifiers without logging secrets or full customer payloads. Delete disposable triggers and credentials after testing when required by policy. diff --git a/skills/install-openhands-replicated/references/operator-requests.md b/skills/install-openhands-replicated/references/operator-requests.md new file mode 100644 index 00000000..00e72798 --- /dev/null +++ b/skills/install-openhands-replicated/references/operator-requests.md @@ -0,0 +1,95 @@ +# Operator Request Templates + +Use these templates to request prerequisites without asking recipients to send credentials in email or chat. Replace placeholders and remove sections that do not apply. + +## DNS and TLS Request + +```text +Subject: DNS and TLS prerequisites for OpenHands Enterprise + +Please create a wildcard DNS record for *. that resolves to . + +The default Simple hostname layout uses: +- admin. +- app. +- auth. +- analytics. +- llm-proxy. +- runtime-api. +- -runtime. + +Please provide a publicly trusted wildcard certificate for *., including the complete intermediate chain. Store the certificate and matching private key in the approved secret-transfer system; do not send the private key by email or chat. + +Owner for DNS validation: +Owner for certificate transfer: +Required by: +``` + +## Firewall and Proxy Request + +```text +Subject: Network prerequisites for OpenHands Enterprise VM + +Target VM or security group: + +Allow inbound TCP: +- 80 +- 443 +- 30000, restricted to approved administrator CIDRs where possible + +Keep these local TCP ports available on the VM before installation: +- 2379 +- 7443 +- 9099 +- 10248 +- 10257 +- 10259 + +Allow outbound HTTPS to the destinations listed in the current OpenHands Enterprise quick start, including Replicated control-plane endpoints, OpenHands image/chart/update endpoints, GitHub, Traefik charts, Docker Hub, and GHCR. + +If TLS inspection or an HTTP proxy is required, provide the proxy URL and CA certificate through the approved configuration channel. Do not disable TLS verification. + +Owner for validation: +Required by: +``` + +## Infrastructure Request + +```text +Subject: VM prerequisites for OpenHands Enterprise + +Please provide a dedicated Linux x86-64 VM with: +- 16 vCPUs +- 64 GB memory +- 200 GB disk +- disk P99 write latency no greater than 10 ms +- systemd +- root or sudo access for the installation operator + +Please identify: +- VM hostname and environment +- cloud region or datacenter +- storage class/type and provisioned IOPS/throughput +- administrator access method +- backup/snapshot owner + +Do not include passwords, SSH private keys, or cloud credentials in the response. +``` + +## Access and Ownership Request + +```text +Subject: Administrative access needed for OpenHands Enterprise setup + +Please identify an authorized owner for each required surface: +- OpenHands installer dashboard and license +- VM sudo access +- DNS +- TLS certificate transfer +- LLM provider +- Git provider application +- optional Slack/Jira/Bitbucket/Azure DevOps administration +- database and backup operations + +Use approved secret-management and transfer systems for all credentials. The installation record will contain only owner names, resource identifiers, and validation results. +``` diff --git a/skills/install-openhands-replicated/scripts/apply_kots_config.sh b/skills/install-openhands-replicated/scripts/apply_kots_config.sh new file mode 100755 index 00000000..f7aed8a4 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/apply_kots_config.sh @@ -0,0 +1,187 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +usage: apply_kots_config.sh --appslug --config-file (--current | --sequence ) [options] + +Previews a KOTS ConfigValues merge by default. Add --execute only after the +specific operation has been reviewed and approved. Add --deploy only when an +immediate rollout is also approved. + +Options: + --namespace KOTS Admin Console namespace. Default: kotsadm + --app-namespace OpenHands app namespace for guard checks. Default: openhands + --current Use the currently deployed version as the base + --sequence Use a specific app sequence as the base + --execute Execute the config merge; otherwise print a preview + --deploy Deploy the resulting sequence after setting config + --skip-guard Skip storage guard before/after an approved deployment + -h, --help Show this help + +Environment: + KUBECTL Path to a kubectl binary that supports `kubectl kots` +EOF +} + +KOTS_NAMESPACE="kotsadm" +APP_NAMESPACE="openhands" +APPSLUG="" +CONFIG_FILE="" +EXECUTE=0 +DEPLOY=0 +RUN_GUARD=1 +CURRENT=0 +SEQUENCE="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --appslug) + APPSLUG="${2:-}" + shift 2 + ;; + --config-file) + CONFIG_FILE="${2:-}" + shift 2 + ;; + --namespace) + KOTS_NAMESPACE="${2:-}" + shift 2 + ;; + --app-namespace) + APP_NAMESPACE="${2:-}" + shift 2 + ;; + --current) + CURRENT=1 + shift + ;; + --sequence) + SEQUENCE="${2:-}" + shift 2 + ;; + --execute) + EXECUTE=1 + shift + ;; + --deploy) + DEPLOY=1 + shift + ;; + --skip-guard) + RUN_GUARD=0 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "unknown argument: $1" >&2 + usage + exit 1 + ;; + esac +done + +if [[ -z "${APPSLUG}" || -z "${CONFIG_FILE}" ]]; then + usage + exit 1 +fi + +if [[ "${CURRENT}" == "1" && -n "${SEQUENCE}" ]]; then + echo "choose either --current or --sequence, not both" >&2 + exit 1 +fi + +if [[ "${CURRENT}" != "1" && -z "${SEQUENCE}" ]]; then + echo "choose --current or --sequence" >&2 + exit 1 +fi + +if [[ ! -f "${CONFIG_FILE}" ]]; then + echo "config file not found: ${CONFIG_FILE}" >&2 + exit 1 +fi + +if ! grep -Eq '^apiVersion:[[:space:]]*kots.io/v1beta1[[:space:]]*$' "${CONFIG_FILE}"; then + echo "config file must include apiVersion: kots.io/v1beta1" >&2 + exit 1 +fi + +if ! grep -Eq '^kind:[[:space:]]*ConfigValues[[:space:]]*$' "${CONFIG_FILE}"; then + echo "config file must include kind: ConfigValues" >&2 + exit 1 +fi + +KUBECTL_CMD=() +if [[ -n "${KUBECTL:-}" ]]; then + if [[ ! -x "${KUBECTL}" ]]; then + echo "KUBECTL must be an executable path: ${KUBECTL}" >&2 + exit 1 + fi + KUBECTL_CMD=("${KUBECTL}") +elif command -v kubectl >/dev/null 2>&1; then + KUBECTL_CMD=(kubectl) +elif [[ -x /var/lib/embedded-cluster/bin/kubectl ]]; then + KUBECTL_CMD=(/var/lib/embedded-cluster/bin/kubectl) +else + echo "kubectl not found. Install kubectl and the KOTS CLI plugin, or set KUBECTL=/path/to/kubectl." >&2 + exit 1 +fi + +k() { + "${KUBECTL_CMD[@]}" "$@" +} + +if ! k kots version >/dev/null 2>&1; then + cat >&2 < [simple|legacy]" >&2 + exit 1 +fi + +BASE_DOMAIN="${1%.}" +MODE="${2:-simple}" + +if [[ ! "${BASE_DOMAIN}" =~ ^[A-Za-z0-9.-]+$ || "${BASE_DOMAIN}" != *.* ]]; then + echo "invalid base domain: ${BASE_DOMAIN}" >&2 + exit 1 +fi + +case "${MODE}" in + simple) + hosts=( + "admin.${BASE_DOMAIN}" + "app.${BASE_DOMAIN}" + "auth.${BASE_DOMAIN}" + "analytics.${BASE_DOMAIN}" + "llm-proxy.${BASE_DOMAIN}" + "runtime-api.${BASE_DOMAIN}" + "test-runtime.${BASE_DOMAIN}" + ) + ;; + legacy) + hosts=( + "${BASE_DOMAIN}" + "app.${BASE_DOMAIN}" + "auth.app.${BASE_DOMAIN}" + "analytics.app.${BASE_DOMAIN}" + "llm-proxy.${BASE_DOMAIN}" + "runtime-api.${BASE_DOMAIN}" + "test.runtime.${BASE_DOMAIN}" + ) + ;; + *) + echo "mode must be simple or legacy" >&2 + exit 1 + ;; +esac + +failed=0 +printf 'Checking %s-mode DNS for base domain: %s\n\n' "${MODE}" "${BASE_DOMAIN}" + +for host in "${hosts[@]}"; do + echo "[DNS] ${host}" + if command -v getent >/dev/null 2>&1 && output="$(getent hosts "${host}" 2>/dev/null)" && [[ -n "${output}" ]]; then + printf '%s\n' "${output}" + elif command -v dig >/dev/null 2>&1 && output="$(dig +short "${host}" 2>/dev/null)" && [[ -n "${output}" ]]; then + printf '%s\n' "${output}" + elif command -v nslookup >/dev/null 2>&1 && nslookup "${host}"; then + : + else + echo "FAIL ${host} did not resolve" >&2 + failed=1 + fi + echo +done + +exit "${failed}" diff --git a/skills/install-openhands-replicated/scripts/check_host_preflight.sh b/skills/install-openhands-replicated/scripts/check_host_preflight.sh new file mode 100755 index 00000000..dfca7dae --- /dev/null +++ b/skills/install-openhands-replicated/scripts/check_host_preflight.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +set -u + +MIN_CPUS="${MIN_CPUS:-16}" +MIN_MEMORY_GIB="${MIN_MEMORY_GIB:-64}" +MIN_DISK_GIB="${MIN_DISK_GIB:-200}" +MAX_DISK_USE_PERCENT="${MAX_DISK_USE_PERCENT:-80}" +INSTALL_PATH="${INSTALL_PATH:-/}" + +local_ports=(2379 7443 9099 10248 10257 10259) +edge_ports=(80 443 30000) +installer_paths=( + /etc/k0s + /opt/containerd + /run/k0s + /usr/local/bin/k0s + /var/lib/embedded-cluster + /var/lib/kubelet +) +failed=0 + +ok() { printf 'OK %s\n' "$*"; } +warn() { printf 'WARN %s\n' "$*" >&2; } +fail() { printf 'FAIL %s\n' "$*" >&2; failed=1; } + +if [[ "$(uname -s)" == "Linux" ]]; then + ok "operating system is Linux" +else + fail "target must run Linux; found $(uname -s)" +fi + +arch="$(uname -m)" +if [[ "${arch}" == "x86_64" || "${arch}" == "amd64" ]]; then + ok "architecture is ${arch}" +else + fail "target must use x86-64; found ${arch}" +fi + +cpu_count="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 0)" +if [[ "${cpu_count}" =~ ^[0-9]+$ ]] && (( cpu_count >= MIN_CPUS )); then + ok "${cpu_count} logical CPUs available" +else + fail "${cpu_count:-unknown} logical CPUs available; minimum is ${MIN_CPUS}" +fi + +if [[ -r /proc/meminfo ]]; then + memory_kib="$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)" + memory_gib=$((memory_kib / 1024 / 1024)) + if (( memory_gib >= MIN_MEMORY_GIB )); then + ok "${memory_gib} GiB memory available" + else + fail "${memory_gib} GiB memory available; minimum is ${MIN_MEMORY_GIB} GiB" + fi +else + fail "cannot read /proc/meminfo on the target" +fi + +if [[ -e "${INSTALL_PATH}" ]]; then + read -r disk_kib disk_used_percent < <(df -Pk "${INSTALL_PATH}" | awk 'NR == 2 {gsub(/%/, "", $5); print $2, $5}') + disk_gib=$((disk_kib / 1024 / 1024)) + if (( disk_gib >= MIN_DISK_GIB )); then + ok "filesystem containing ${INSTALL_PATH} has ${disk_gib} GiB total" + else + fail "filesystem containing ${INSTALL_PATH} has ${disk_gib} GiB total; minimum is ${MIN_DISK_GIB} GiB" + fi + if (( disk_used_percent < MAX_DISK_USE_PERCENT )); then + ok "filesystem containing ${INSTALL_PATH} is ${disk_used_percent}% full" + else + fail "filesystem containing ${INSTALL_PATH} is ${disk_used_percent}% full; required maximum is below ${MAX_DISK_USE_PERCENT}%" + fi +else + fail "INSTALL_PATH does not exist: ${INSTALL_PATH}" +fi + +if command -v systemctl >/dev/null 2>&1 && [[ -d /run/systemd/system ]]; then + ok "systemd is available" + for service in k0scontroller kubelet containerd docker; do + if systemctl is-active --quiet "${service}" 2>/dev/null; then + warn "${service} is already active; confirm this is an approved reinstall or resolve the runtime conflict" + fi + done +else + fail "systemd is not active" +fi + +existing_paths=() +for path in "${installer_paths[@]}"; do + [[ -e "${path}" ]] && existing_paths+=("${path}") +done +if (( ${#existing_paths[@]} > 0 )); then + warn "existing Embedded Cluster or Kubernetes paths found: ${existing_paths[*]}" + warn "do not delete them automatically; determine whether this is an approved reinstall and follow a version-matched procedure" +else + ok "no common Embedded Cluster or Kubernetes installation paths found" +fi + +if [[ -d /sys/fs/cgroup ]]; then + cgroup_type="$(stat -fc '%T' /sys/fs/cgroup 2>/dev/null || true)" + if [[ "${cgroup_type}" == "cgroup2fs" ]]; then + ok "cgroups v2 is active" + else + warn "cgroups v2 is not detected; confirm compatibility with the Kubernetes version in the target OHE release" + fi +fi + +if [[ "${EUID}" -eq 0 ]]; then + ok "running with root privileges" +elif command -v sudo >/dev/null 2>&1; then + ok "sudo is installed; validate operator authorization before installation" +else + fail "root or sudo access is required" +fi + +if command -v ss >/dev/null 2>&1; then + listeners="$(ss -ltnH 2>/dev/null || true)" + for port in "${local_ports[@]}" "${edge_ports[@]}"; do + if awk -v port="${port}" '$4 ~ (":" port "$|\\]" port "$") {found=1} END {exit !found}' <<<"${listeners}"; then + fail "TCP port ${port} is already listening; identify the process before installation" + else + ok "TCP port ${port} is available locally" + fi + done +else + warn "ss is unavailable; local port availability was not verified" +fi + +warn "disk P99 write latency is not measured by this script; require the installer host preflight to report 10 ms or less" +warn "firewall policy is not verified locally; confirm inbound TCP 80, 443, and 30000 with the network owner" + +if (( failed != 0 )); then + exit 1 +fi + +printf '\nHost preflight passed. Continue with DNS and outbound checks before requesting installer approval.\n' diff --git a/skills/install-openhands-replicated/scripts/check_outbound.sh b/skills/install-openhands-replicated/scripts/check_outbound.sh new file mode 100755 index 00000000..ff75f171 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/check_outbound.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + echo "usage: $0 [additional-https-url ...]" + exit 0 +fi + +urls=( + "https://replicated.app" + "https://proxy.replicated.com/v2/" + "https://images.r9.all-hands.dev/v2/" + "https://install.r9.all-hands.dev" + "https://charts.r9.all-hands.dev" + "https://updates.r9.all-hands.dev" + "https://github.com" + "https://traefik.github.io/charts/index.yaml" + "https://registry-1.docker.io/v2/" + "https://ghcr.io/v2/" +) + +for url in "$@"; do + if [[ ! "${url}" =~ ^https://[^[:space:]]+$ ]]; then + echo "additional endpoint must be an https URL: ${url}" >&2 + exit 1 + fi + urls+=("${url}") +done + +echo "Checking outbound reachability" +echo + +failed=0 +for url in "${urls[@]}"; do + code="$(curl -sSIL --max-time 15 -o /dev/null -w "%{http_code}" "${url}" || true)" + if [[ "${code}" == "000" ]]; then + echo "FAIL ${url}" >&2 + failed=1 + else + echo "OK ${url} (HTTP ${code})" + fi +done + +exit "${failed}" diff --git a/skills/install-openhands-replicated/scripts/check_tls_files.sh b/skills/install-openhands-replicated/scripts/check_tls_files.sh new file mode 100755 index 00000000..7117f679 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/check_tls_files.sh @@ -0,0 +1,174 @@ +#!/usr/bin/env bash +set -u + +usage() { + cat >&2 <<'EOF' +usage: check_tls_files.sh [wildcard|path] + +Validates certificate dates, key matching, hostname coverage, self-signing, and +the certificate chain against the operating system CA bundle. It never prints +the private key or derived key hashes. + +Environment: + CA_BUNDLE Optional trusted CA bundle for enterprise/private CA validation +EOF +} + +if [[ $# -lt 3 || $# -gt 4 ]]; then + usage + exit 1 +fi + +BASE_DOMAIN="${1%.}" +CERT_FILE="$2" +KEY_FILE="$3" +ROUTING_MODE="${4:-wildcard}" +failed=0 + +ok() { printf 'OK %s\n' "$*"; } +warn() { printf 'WARN %s\n' "$*" >&2; } +fail() { printf 'FAIL %s\n' "$*" >&2; failed=1; } + +if [[ ! "${BASE_DOMAIN}" =~ ^[A-Za-z0-9.-]+$ || "${BASE_DOMAIN}" != *.* ]]; then + echo "invalid base domain: ${BASE_DOMAIN}" >&2 + exit 1 +fi + +if [[ "${ROUTING_MODE}" != "wildcard" && "${ROUTING_MODE}" != "path" ]]; then + echo "routing mode must be wildcard or path" >&2 + exit 1 +fi + +if ! command -v openssl >/dev/null 2>&1; then + echo "openssl is required" >&2 + exit 1 +fi + +for file in "${CERT_FILE}" "${KEY_FILE}"; do + if [[ ! -r "${file}" ]]; then + echo "file is not readable: ${file}" >&2 + exit 1 + fi +done + +if openssl x509 -in "${CERT_FILE}" -noout >/dev/null 2>&1; then + ok "certificate bundle is parseable" +else + echo "certificate bundle is not parseable" >&2 + exit 1 +fi + +if openssl x509 -in "${CERT_FILE}" -checkend 604800 -noout >/dev/null 2>&1; then + ok "certificate remains valid for at least seven days" +else + fail "certificate is expired or expires within seven days" +fi + +subject="$(openssl x509 -in "${CERT_FILE}" -noout -subject -nameopt RFC2253 2>/dev/null | sed 's/^subject=//')" +issuer="$(openssl x509 -in "${CERT_FILE}" -noout -issuer -nameopt RFC2253 2>/dev/null | sed 's/^issuer=//')" +if [[ -n "${subject}" && "${subject}" == "${issuer}" ]]; then + fail "leaf certificate is self-signed; OpenHands application certificates must be trusted" +else + ok "leaf certificate is not self-signed" +fi + +cert_key_hash="$(openssl x509 -in "${CERT_FILE}" -pubkey -noout 2>/dev/null | openssl pkey -pubin -outform DER 2>/dev/null | openssl dgst -sha256 2>/dev/null || true)" +key_hash="$(openssl pkey -in "${KEY_FILE}" -pubout -outform DER 2>/dev/null | openssl dgst -sha256 2>/dev/null || true)" +if [[ -z "${key_hash}" ]]; then + fail "private key could not be parsed non-interactively; validate encrypted keys in an approved interactive session" +elif [[ -n "${cert_key_hash}" && "${cert_key_hash}" == "${key_hash}" ]]; then + ok "private key matches the leaf certificate" +else + fail "private key does not match the leaf certificate" +fi +unset cert_key_hash key_hash + +sans="$(openssl x509 -in "${CERT_FILE}" -noout -ext subjectAltName 2>/dev/null | tr -d '[:space:]' || true)" +if [[ "${ROUTING_MODE}" == "wildcard" ]]; then + if grep -Fq "DNS:*.${BASE_DOMAIN}" <<<"${sans}"; then + ok "certificate covers wildcard *.${BASE_DOMAIN}" + else + fail "certificate does not contain DNS:*.${BASE_DOMAIN}" + fi +else + required_hosts=( + "admin.${BASE_DOMAIN}" + "app.${BASE_DOMAIN}" + "auth.${BASE_DOMAIN}" + "analytics.${BASE_DOMAIN}" + "llm-proxy.${BASE_DOMAIN}" + "runtime-api.${BASE_DOMAIN}" + "runtime.${BASE_DOMAIN}" + ) + for host in "${required_hosts[@]}"; do + if grep -Fq "DNS:${host}" <<<"${sans}"; then + ok "certificate covers ${host}" + else + fail "certificate does not contain DNS:${host} for path-based routing" + fi + done +fi + +ca_bundle="${CA_BUNDLE:-}" +if [[ -n "${ca_bundle}" && ! -r "${ca_bundle}" ]]; then + echo "CA_BUNDLE is not readable: ${ca_bundle}" >&2 + exit 1 +fi + +if [[ -z "${ca_bundle}" ]]; then + for candidate in /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/cert.pem; do + if [[ -r "${candidate}" ]]; then + ca_bundle="${candidate}" + break + fi + done +fi + +if [[ -n "${ca_bundle}" ]]; then + temp_dir="$(mktemp -d)" + cleanup() { + rm -f "${temp_dir}"/cert-*.pem "${temp_dir}/chain.pem" + rmdir "${temp_dir}" 2>/dev/null || true + } + trap cleanup EXIT + awk -v dir="${temp_dir}" ' + /-----BEGIN CERTIFICATE-----/ { n++; file=sprintf("%s/cert-%03d.pem", dir, n) } + n > 0 { print > file } + /-----END CERTIFICATE-----/ { close(file) } + ' "${CERT_FILE}" + + leaf="${temp_dir}/cert-001.pem" + chain="${temp_dir}/chain.pem" + : >"${chain}" + for cert in "${temp_dir}"/cert-*.pem; do + [[ "${cert}" == "${leaf}" ]] && continue + cat "${cert}" >>"${chain}" + done + + if [[ -s "${chain}" ]]; then + if openssl verify -purpose sslserver -CAfile "${ca_bundle}" -untrusted "${chain}" "${leaf}" >/dev/null 2>&1; then + ok "certificate chain validates against ${ca_bundle}" + else + fail "certificate chain does not validate against ${ca_bundle}" + fi + elif openssl verify -purpose sslserver -CAfile "${ca_bundle}" "${leaf}" >/dev/null 2>&1; then + ok "certificate validates directly against ${ca_bundle}" + else + fail "certificate does not validate against ${ca_bundle}; include required intermediates" + fi +else + warn "system CA bundle not found; certificate chain was not verified" +fi + +if command -v stat >/dev/null 2>&1; then + mode="$(stat -c '%a' "${KEY_FILE}" 2>/dev/null || true)" + if [[ -n "${mode}" && $((8#${mode} & 8#077)) -ne 0 ]]; then + warn "private key permissions are ${mode}; remove group and other access" + fi +fi + +if (( failed != 0 )); then + exit 1 +fi + +printf '\nTLS file preflight passed. Keep the private key outside repositories and approved logs.\n' diff --git a/skills/install-openhands-replicated/scripts/preflight_storage_guard.sh b/skills/install-openhands-replicated/scripts/preflight_storage_guard.sh new file mode 100755 index 00000000..275e8ca5 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/preflight_storage_guard.sh @@ -0,0 +1,209 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +usage: preflight_storage_guard.sh [namespace] + +Fails the install/configure flow if the main OpenHands Postgres data path is +not backed by a PVC, if any node has DiskPressure=True, or if optional disk +growth checks exceed thresholds. + +Environment: + KUBECTL one executable kubectl path; defaults to kubectl, + then /var/lib/embedded-cluster/bin/kubectl + POSTGRES_POD_NAME default: openhands-postgresql-0 + POSTGRES_SELECTOR default: app.kubernetes.io/name=postgresql,app.kubernetes.io/instance=openhands + DATA_MOUNT_PATH default: /bitnami/postgresql + MIN_ROOT_FREE_GIB default: 20 + CHECK_HOST_DISK 1, 0, or auto; default: auto + CHECK_CLICKHOUSE 1 or 0; default: 1 + CLICKHOUSE_SYSTEM_LOG_MAX_GIB default: 10 +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +NAMESPACE="${1:-${NAMESPACE:-openhands}}" +POSTGRES_POD_NAME="${POSTGRES_POD_NAME:-openhands-postgresql-0}" +POSTGRES_SELECTOR="${POSTGRES_SELECTOR:-app.kubernetes.io/name=postgresql,app.kubernetes.io/instance=openhands}" +DATA_MOUNT_PATH="${DATA_MOUNT_PATH:-/bitnami/postgresql}" +MIN_ROOT_FREE_GIB="${MIN_ROOT_FREE_GIB:-20}" +CHECK_HOST_DISK="${CHECK_HOST_DISK:-auto}" +CHECK_CLICKHOUSE="${CHECK_CLICKHOUSE:-1}" +CLICKHOUSE_SYSTEM_LOG_MAX_GIB="${CLICKHOUSE_SYSTEM_LOG_MAX_GIB:-10}" + +failed=0 + +info() { + echo "INFO $*" +} + +ok() { + echo "OK $*" +} + +warn() { + echo "WARN $*" >&2 +} + +record_fail() { + echo "FAIL $*" >&2 + failed=1 +} + +KUBECTL_CMD=() +if [[ -n "${KUBECTL:-}" ]]; then + KUBECTL_CMD=("${KUBECTL}") +elif command -v kubectl >/dev/null 2>&1; then + KUBECTL_CMD=(kubectl) +elif [[ -x /var/lib/embedded-cluster/bin/kubectl ]]; then + if [[ "${EUID}" -eq 0 ]]; then + KUBECTL_CMD=(/var/lib/embedded-cluster/bin/kubectl) + else + KUBECTL_CMD=(sudo /var/lib/embedded-cluster/bin/kubectl) + fi +else + echo "FAIL kubectl not found. Set KUBECTL=/path/to/kubectl." >&2 + exit 1 +fi + +k() { + "${KUBECTL_CMD[@]}" "$@" +} + +if ! k get namespace "${NAMESPACE}" >/dev/null 2>&1; then + echo "FAIL namespace ${NAMESPACE} is not reachable with ${KUBECTL_CMD[*]}" >&2 + exit 1 +fi + +info "checking OpenHands storage in namespace ${NAMESPACE}" + +postgres_pod="" +if k get pod -n "${NAMESPACE}" "${POSTGRES_POD_NAME}" >/dev/null 2>&1; then + postgres_pod="${POSTGRES_POD_NAME}" +else + pod_list="$(k get pods -n "${NAMESPACE}" -l "${POSTGRES_SELECTOR}" -o "jsonpath={range .items[*]}{.metadata.name}{'\n'}{end}" || true)" + pod_count="$(printf '%s\n' "${pod_list}" | sed '/^$/d' | wc -l | tr -d ' ')" + if [[ "${pod_count}" == "1" ]]; then + postgres_pod="$(printf '%s\n' "${pod_list}" | sed '/^$/d' | sed -n '1p')" + elif [[ "${pod_count}" == "0" ]]; then + echo "FAIL no Postgres pod found by name ${POSTGRES_POD_NAME} or selector ${POSTGRES_SELECTOR}" >&2 + exit 1 + else + echo "FAIL multiple Postgres pods matched selector ${POSTGRES_SELECTOR}; set POSTGRES_POD_NAME" >&2 + printf '%s\n' "${pod_list}" >&2 + exit 1 + fi +fi + +ok "found Postgres pod ${postgres_pod}" + +data_volume="$(k get pod -n "${NAMESPACE}" "${postgres_pod}" -o "jsonpath={range .spec.containers[*].volumeMounts[?(@.mountPath=='${DATA_MOUNT_PATH}')]}{.name}{'\n'}{end}" | sed '/^$/d' | sed -n '1p')" + +if [[ -z "${data_volume}" ]]; then + record_fail "no container volumeMount found for ${DATA_MOUNT_PATH} on ${postgres_pod}" +else + ok "${DATA_MOUNT_PATH} is mounted from volume ${data_volume}" +fi + +if [[ -n "${data_volume}" ]]; then + volume_result="$(k get pod -n "${NAMESPACE}" "${postgres_pod}" -o "go-template={{range .spec.volumes}}{{if eq .name \"${data_volume}\"}}{{if .persistentVolumeClaim}}pvc:{{.persistentVolumeClaim.claimName}}{{else if .emptyDir}}emptyDir{{else if .hostPath}}hostPath:{{.hostPath.path}}{{else}}other{{end}}{{end}}{{end}}")" + + case "${volume_result}" in + pvc:*) + claim="${volume_result#pvc:}" + phase="$(k get pvc -n "${NAMESPACE}" "${claim}" -o "jsonpath={.status.phase}" 2>/dev/null || true)" + storage_class="$(k get pvc -n "${NAMESPACE}" "${claim}" -o "jsonpath={.spec.storageClassName}" 2>/dev/null || true)" + if [[ "${phase}" == "Bound" ]]; then + ok "Postgres data volume uses Bound PVC ${claim} (storageClass=${storage_class:-unset})" + else + record_fail "Postgres data volume uses PVC ${claim}, but PVC phase is ${phase:-unknown}" + fi + ;; + emptyDir) + record_fail "Postgres data volume ${data_volume} is emptyDir. This can reset OpenHands, Keycloak, LiteLLM, automation, plugin-directory, and runtime API data when the pod is recreated." + ;; + hostPath:*) + record_fail "Postgres data volume ${data_volume} is hostPath (${volume_result#hostPath:}), not PVC-backed storage" + ;; + "") + record_fail "volume ${data_volume} was not found in pod spec" + ;; + *) + record_fail "Postgres data volume ${data_volume} is ${volume_result}, not PVC-backed storage" + ;; + esac +fi + +info "checking node DiskPressure" +node_pressure_lines="$(k get nodes -o 'go-template={{range .items}}{{.metadata.name}} {{range .status.conditions}}{{if eq .type "DiskPressure"}}{{.status}}{{end}}{{end}}{{"\n"}}{{end}}')" +while read -r node_name pressure_status; do + [[ -z "${node_name:-}" ]] && continue + if [[ "${pressure_status}" == "True" ]]; then + record_fail "node ${node_name} reports DiskPressure=True" + else + ok "node ${node_name} DiskPressure=${pressure_status:-unknown}" + fi +done <<< "${node_pressure_lines}" + +check_host_disk=false +if [[ "${CHECK_HOST_DISK}" == "1" ]]; then + check_host_disk=true +elif [[ "${CHECK_HOST_DISK}" == "auto" && -x /var/lib/embedded-cluster/bin/kubectl ]]; then + check_host_disk=true +fi + +if [[ "${check_host_disk}" == "true" ]]; then + info "checking root filesystem free space on this host" + avail_kb="$(df -Pk / | awk 'NR == 2 {print $4}')" + avail_gib=$((avail_kb / 1024 / 1024)) + if (( avail_gib < MIN_ROOT_FREE_GIB )); then + record_fail "root filesystem has ${avail_gib} GiB free; minimum is ${MIN_ROOT_FREE_GIB} GiB" + else + ok "root filesystem has ${avail_gib} GiB free" + fi +else + warn "skipping host disk free-space check; set CHECK_HOST_DISK=1 when running on the target VM" +fi + +if [[ "${CHECK_CLICKHOUSE}" == "1" ]]; then + info "checking ClickHouse diagnostic system log table size if ClickHouse is present" + clickhouse_pod="$(k get pods -n "${NAMESPACE}" -o name | sed 's#^pod/##' | grep -E 'clickhouse' | sed -n '1p' || true)" + if [[ -z "${clickhouse_pod}" ]]; then + warn "no ClickHouse pod found in namespace ${NAMESPACE}; skipping ClickHouse system log check" + else + max_bytes=$((CLICKHOUSE_SYSTEM_LOG_MAX_GIB * 1024 * 1024 * 1024)) + query="SELECT table, sum(bytes_on_disk) FROM system.parts WHERE active AND database = 'system' AND table IN ('trace_log', 'text_log', 'metric_log', 'asynchronous_metric_log') GROUP BY table FORMAT TabSeparated" + raw_sizes="$(k exec -n "${NAMESPACE}" "${clickhouse_pod}" -- clickhouse-client --query "${query}" 2>/dev/null || true)" + if [[ -z "${raw_sizes}" ]]; then + warn "could not read ClickHouse system.parts from ${clickhouse_pod}; skipping size threshold" + else + while IFS=$'\t' read -r table_name bytes_on_disk; do + [[ -z "${table_name:-}" ]] && continue + if [[ "${bytes_on_disk}" =~ ^[0-9]+$ ]]; then + gib=$((bytes_on_disk / 1024 / 1024 / 1024)) + if (( bytes_on_disk > max_bytes )); then + record_fail "ClickHouse system.${table_name} is ${gib} GiB, above ${CLICKHOUSE_SYSTEM_LOG_MAX_GIB} GiB" + else + ok "ClickHouse system.${table_name} is ${gib} GiB" + fi + else + warn "unexpected ClickHouse size output for ${table_name}: ${bytes_on_disk}" + fi + done <<< "${raw_sizes}" + fi + fi +fi + +if (( failed != 0 )); then + echo + echo "Storage guard failed. Do not proceed with production/demo use until the failed checks are fixed." >&2 + exit 1 +fi + +echo +ok "storage guard passed" diff --git a/skills/install-openhands-replicated/scripts/summarize_terraform_outputs.sh b/skills/install-openhands-replicated/scripts/summarize_terraform_outputs.sh new file mode 100755 index 00000000..dc6e1e59 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/summarize_terraform_outputs.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 1 ]]; then + echo "usage: $0 " >&2 + exit 1 +fi + +TF_DIR="$1" + +if [[ ! -d "${TF_DIR}" ]]; then + echo "terraform directory not found: ${TF_DIR}" >&2 + exit 1 +fi + +if ! command -v terraform >/dev/null 2>&1; then + echo "terraform is required" >&2 + exit 1 +fi + +cd "${TF_DIR}" + +keys=( + instance_public_ip + instance_id + admin_console_url + app_url + base_url + base_domain +) + +found=0 +for key in "${keys[@]}"; do + if value="$(terraform output -raw "${key}" 2>/dev/null)" && [[ -n "${value}" ]]; then + printf '%s=%s\n' "${key}" "${value}" + found=1 + fi +done + +if (( found == 0 )); then + echo "no allowlisted non-sensitive outputs were found" >&2 + exit 1 +fi + +cat <<'EOF' + +Sensitive outputs and local certificate, private-key, and SSH-key paths are intentionally omitted. +EOF diff --git a/skills/install-openhands-replicated/scripts/verify_github_setup.sh b/skills/install-openhands-replicated/scripts/verify_github_setup.sh new file mode 100755 index 00000000..ae407e7f --- /dev/null +++ b/skills/install-openhands-replicated/scripts/verify_github_setup.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat <<'EOF' +GitHub validation checklist + +1. Create a GitHub App with the current OpenHands Enterprise helper; do not use a GitHub OAuth App. +2. Transfer the App ID, slug, client ID, client secret, webhook secret, and private key through approved secret channels. +3. Deploy the Replicated sequence with GitHub authentication enabled. +4. Install the GitHub App on an approved disposable test repository with least privilege. +5. Sign in at https://app. in a clean browser session. +6. Verify the signed-in user can discover the approved test repository. +7. Run one bounded repository-backed conversation. +8. If webhook or Automations routing is in scope, trigger one disposable issue or pull-request event and verify the expected result. +9. Remove disposable credentials or test artifacts when required by policy. + +Do not print the private key, client secret, webhook secret, user token, or complete webhook payload. +EOF diff --git a/skills/install-openhands-replicated/scripts/verify_jira_setup.sh b/skills/install-openhands-replicated/scripts/verify_jira_setup.sh new file mode 100755 index 00000000..3bd1c867 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/verify_jira_setup.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat <<'EOF' +Jira Data Center validation checklist + +1. Confirm the target OHE release supports the required Jira deployment type. +2. Configure Jira through the Replicated Admin Console using the version-matched OpenHands Enterprise guide. +3. Store OAuth, service-account, and webhook credentials only in approved secret surfaces. +4. Confirm the Jira base URL presents a trusted certificate to OpenHands. +5. Complete user account linking when the configured flow requires user context. +6. Create a disposable Jira project or issue for validation. +7. Configure the documented OpenHands webhook endpoint and required Jira events. +8. Trigger one bounded test issue or comment event. +9. Confirm OpenHands receives the event and creates the expected bounded result. +10. Record issue, run, and conversation identifiers without recording credentials or full customer payloads. +11. Remove disposable webhooks, test issues, or credentials when required by policy. + +Custom Jira-to-Automations webhooks are a separate automation design. Do not copy +customer-specific cloud IDs, project keys, shim URLs, tokens, or routing patches +into a generic installation. +EOF diff --git a/skills/install-openhands-replicated/scripts/verify_laminar_setup.sh b/skills/install-openhands-replicated/scripts/verify_laminar_setup.sh new file mode 100755 index 00000000..3681683d --- /dev/null +++ b/skills/install-openhands-replicated/scripts/verify_laminar_setup.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat <<'EOF' +Analytics validation checklist + +1. Enable Analytics in the Replicated Admin Console only when it is in scope. +2. Review resource impact and deploy the approved Replicated sequence. +3. Confirm https://analytics. presents valid TLS and reaches the sign-in flow. +4. Log in through the supported OpenHands/Keycloak identity path. +5. Create or select the approved Laminar project. +6. Create an ingest-only project API key and enter it through the Admin Console without printing it. +7. Deploy the approved sequence after changing the project key. +8. Start one fresh bounded OpenHands conversation. +9. Confirm the conversation creates a trace in the expected project. +10. Record trace identifiers and timestamps, not prompt contents or credentials. + +A reachable analytics UI does not prove trace ingestion. Treat missing or malformed +traces as a troubleshooting or version-compatibility issue rather than applying +unverified database or Kubernetes patches. +EOF diff --git a/skills/install-openhands-replicated/scripts/verify_slack_setup.sh b/skills/install-openhands-replicated/scripts/verify_slack_setup.sh new file mode 100755 index 00000000..dc26b728 --- /dev/null +++ b/skills/install-openhands-replicated/scripts/verify_slack_setup.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat <<'EOF' +Slack validation checklist + +1. Slack app created and credentials entered in Replicated +2. Replicated sequence deployed with Slack enabled +3. Event Subscriptions request URL is verified +4. Bot event includes app_mention +5. Slack app is installed or reinstalled to the workspace +6. User completed OpenHands UI -> Integrations -> Install Slack +7. User completed the Keycloak login flow using the same OpenHands identity +8. Bot is invited to the test channel +9. A fresh @OpenHands mention creates a conversation in the self-hosted instance + +If steps 1-5 are true but mentions still fail, inspect logs for: +- Did not find slack team +EOF diff --git a/tests/test_skills_catalog.py b/tests/test_skills_catalog.py index ea4666b6..d90d2380 100644 --- a/tests/test_skills_catalog.py +++ b/tests/test_skills_catalog.py @@ -374,7 +374,7 @@ def test_index_is_up_to_date(self): SKILLS_WITHOUT_MARKETPLACE_ENTRY = {"qa-changes", "release-notes"} EXPECTED_CATEGORY_COUNTS = { - "environment": 10, + "environment": 11, "automations": 9, "code-hosting": 8, "agent-authoring": 8, From d0aa0b1e7994893840b9ee702f2f7d8b59764f9e Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Tue, 11 Aug 2026 06:59:48 -0500 Subject: [PATCH 2/6] fix: refresh generated skills catalog Co-authored-by: openhands --- skills/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/index.js b/skills/index.js index a6bc32d1..08a12f3d 100644 --- a/skills/index.js +++ b/skills/index.js @@ -401,7 +401,7 @@ export const SKILLS_CATALOG = [ "agent-sdk", "/sdk" ], - "content": "# OpenHands Software Agent SDK\n\nAll SDK documentation lives at .\n\nFor the full topic index, fetch and read\nthe \"OpenHands Software Agent SDK\" section.\n\n## Quick reference\n\nInstall: `pip install openhands-sdk openhands-tools`\n\n```python\nimport os\n\nfrom openhands.sdk import LLM, Agent, Conversation, Tool\nfrom openhands.tools.file_editor import FileEditorTool\nfrom openhands.tools.task_tracker import TaskTrackerTool\nfrom openhands.tools.terminal import TerminalTool\n\n\nllm = LLM(\n model=os.getenv(\"LLM_MODEL\", \"gpt-5.5\"),\n api_key=os.getenv(\"LLM_API_KEY\"),\n base_url=os.getenv(\"LLM_BASE_URL\", None),\n)\n\nagent = Agent(\n llm=llm,\n tools=[\n Tool(name=TerminalTool.name),\n Tool(name=FileEditorTool.name),\n Tool(name=TaskTrackerTool.name),\n ],\n)\n\ncwd = os.getcwd()\nconversation = Conversation(agent=agent, workspace=cwd)\n\nconversation.send_message(\"Write 3 facts about the current project into FACTS.txt.\")\nconversation.run()\nprint(\"All done!\")\n```\n\n## Core classes (`openhands.sdk`)\n\n| Class | Purpose |\n|---|---|\n| [`Agent`](https://docs.openhands.dev/sdk/arch/agent.md) | Reasoning-action loop |\n| [`Condenser`](https://docs.openhands.dev/sdk/arch/condenser.md) | Conversation history compression system |\n| [`Conversation`](https://docs.openhands.dev/sdk/arch/conversation.md) | Conversation orchestration system |\n| [`Event`](https://docs.openhands.dev/sdk/arch/events.md) | Typed event framework |\n| [`LLM`](https://docs.openhands.dev/sdk/arch/llm.md) | Provider-agnostic language model interface |\n| [`SecurityAnalyzer`](https://docs.openhands.dev/sdk/arch/security.md) | Action security analysis and validation |\n| [`Skill`](https://docs.openhands.dev/sdk/arch/skill.md) | Reusable prompt system |\n| [`Tool / ToolDefinition`](https://docs.openhands.dev/sdk/arch/tool-system.md) | Action-observation tool framework |\n| [`Workspace`](https://docs.openhands.dev/sdk/arch/workspace.md) | Execution environment abstraction |\n\n## API reference\n\n[`openhands.sdk.agent`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.agent.md), [`openhands.sdk.conversation`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.conversation.md), [`openhands.sdk.event`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.event.md), [`openhands.sdk.llm`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.llm.md), [`openhands.sdk.security`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.security.md), [`openhands.sdk.tool`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.tool.md), [`openhands.sdk.utils`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.utils.md), [`openhands.sdk.workspace`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.workspace.md)\n\n## Guides\n\n- [ACP Agent](https://docs.openhands.dev/sdk/guides/agent-acp.md): Delegate to an ACP-compatible server (Claude Code, Gemini CLI, etc.) instead of calling an LLM directly.\n- [Agent Settings](https://docs.openhands.dev/sdk/guides/agent-settings.md): Configure, serialize, and recreate agents from structured settings.\n- [Agent Skills & Context](https://docs.openhands.dev/sdk/guides/skill.md): Skills add specialized behaviors, domain knowledge, and context-aware triggers to your agent through structured prompts.\n- [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.\n- [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.\n- [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.\n- [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\n- [Browser Session Recording](https://docs.openhands.dev/sdk/guides/browser-session-recording.md): Record and replay your agent's browser sessions using rrweb.\n- [Browser Use](https://docs.openhands.dev/sdk/guides/agent-browser-use.md): Enable web browsing and interaction capabilities for your agent.\n- [Context Condenser](https://docs.openhands.dev/sdk/guides/context-condenser.md): Manage agent memory by condensing conversation history to save tokens.\n- [Conversation Goals](https://docs.openhands.dev/sdk/guides/agent-server/conversation-goals.md): Add a resumable goal strategy to a normal agent-server conversation.\n- [Conversation with Async](https://docs.openhands.dev/sdk/guides/convo-async.md): Use async/await for concurrent agent operations and non-blocking execution.\n- [Creating Custom Agent](https://docs.openhands.dev/sdk/guides/agent-custom.md): Learn how to design specialized agents with custom tool sets\n- [Critic (Experimental)](https://docs.openhands.dev/sdk/guides/critic.md): Real-time evaluation of agent actions using an LLM-based critic model, with built-in iterative refinement.\n- [Custom Tools](https://docs.openhands.dev/sdk/guides/custom-tools.md): Tools define what agents can do. The SDK includes built-in tools for common operations and supports creating custom tools for specialized needs.\n- [Custom Tools with Remote Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/custom-tools.md): Learn how to use custom tools with a remote agent server by building a custom base image that includes your tool implementations.\n- [Custom Visualizer](https://docs.openhands.dev/sdk/guides/convo-custom-visualizer.md): Customize conversation visualization by creating custom visualizers or configuring the default visualizer.\n- [Deferred Init (Warm-Pool)](https://docs.openhands.dev/sdk/guides/agent-server/deferred-init.md): Pre-warm agent-server pods before a user is matched, then activate them at runtime with POST /api/init.\n- [Docker Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/docker-sandbox.md): Run agent server in isolated Docker containers for security and reproducibility.\n- [Exception Handling](https://docs.openhands.dev/sdk/guides/llm-error-handling.md): Provider‑agnostic exceptions raised by the SDK and recommended patterns for handling them.\n- [FAQ](https://docs.openhands.dev/sdk/faq.md): Frequently asked questions about the OpenHands SDK\n- [File-Based Agents](https://docs.openhands.dev/sdk/guides/agent-file-based.md): Define specialized sub-agents as simple Markdown files with YAML frontmatter — no Python code required.\n- [Fork a Conversation](https://docs.openhands.dev/sdk/guides/convo-fork.md): Branch off an existing conversation for follow-up exploration without contaminating the original.\n- [Getting Started](https://docs.openhands.dev/sdk/getting-started.md): Install the OpenHands SDK and build AI agents that write software.\n- [Goal Completion Loop](https://docs.openhands.dev/sdk/guides/convo-goal.md): Drive a conversation toward a verifiable objective with a judge-driven, self-continuing completion loop.\n- [GPT-5 Preset (ApplyPatchTool)](https://docs.openhands.dev/sdk/guides/llm-gpt5-preset.md): Use the GPT-5 preset to build an agent that swaps the standard FileEditorTool for ApplyPatchTool.\n- [Hello World](https://docs.openhands.dev/sdk/guides/hello-world.md): The simplest possible OpenHands agent - configure an LLM, create an agent, and complete a task.\n- [Hooks](https://docs.openhands.dev/sdk/guides/hooks.md): Use lifecycle hooks to observe, log, and customize agent execution.\n- [Image Input](https://docs.openhands.dev/sdk/guides/llm-image-input.md): Send images to multimodal agents for vision-based tasks and analysis.\n- [Interactive Terminal](https://docs.openhands.dev/sdk/guides/agent-interactive-terminal.md): Enable agents to interact with terminal applications like ipython, python REPL, and other interactive CLI tools.\n- [Iterative Refinement](https://docs.openhands.dev/sdk/guides/iterative-refinement.md): Implement iterative refinement workflows where agents refine their work based on critique feedback until quality thresholds are met.\n- [LLM Fallback Strategy](https://docs.openhands.dev/sdk/guides/llm-fallback.md): Automatically try alternate LLMs when the primary model fails with a transient error.\n- [LLM Profile Store](https://docs.openhands.dev/sdk/guides/llm-profile-store.md): Save, load, and manage reusable LLM configurations so you never repeat setup code again.\n- [LLM Registry](https://docs.openhands.dev/sdk/guides/llm-registry.md): Dynamically select and configure language models using the LLM registry.\n- [LLM Streaming](https://docs.openhands.dev/sdk/guides/llm-streaming.md): Stream LLM responses token-by-token for real-time display and interactive user experiences.\n- [LLM Subscriptions](https://docs.openhands.dev/sdk/guides/llm-subscriptions.md): Use your ChatGPT Plus/Pro subscription to access Codex models without consuming API credits.\n- [Local Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/local-server.md): Install and run an OpenHands Agent Server on your machine, then connect to it from the SDK.\n- [Metrics Tracking](https://docs.openhands.dev/sdk/guides/metrics.md): Track token usage, costs, and latency metrics for your agents.\n- [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.\n- [Model Routing](https://docs.openhands.dev/sdk/guides/llm-routing.md): Route agent's LLM requests to different models.\n- [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.\n- [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.\n- [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.\n- [Overview](https://docs.openhands.dev/sdk/guides/agent-server/overview.md): Run agents on remote servers with isolated workspaces for production deployments.\n- [Parallel Tool Execution](https://docs.openhands.dev/sdk/guides/parallel-tool-execution.md): Execute multiple tools concurrently within a single LLM response to improve throughput for independent operations.\n- [Pause and Resume](https://docs.openhands.dev/sdk/guides/convo-pause-and-resume.md): Pause agent execution, perform operations, and resume without losing state.\n- [Persistence](https://docs.openhands.dev/sdk/guides/convo-persistence.md): Save and restore conversation state for multi-session workflows.\n- [Persistent Memory](https://docs.openhands.dev/sdk/guides/persistent-memory.md): Give agents opt-in, two-tier memory that survives across conversations.\n- [Plugins](https://docs.openhands.dev/sdk/guides/plugins.md): Plugins bundle skills, hooks, MCP servers, agents, and commands into reusable packages that extend agent capabilities.\n- [PR Review](https://docs.openhands.dev/sdk/guides/github-workflows/pr-review.md): Use OpenHands Agent to generate meaningful pull request review\n- [Reasoning](https://docs.openhands.dev/sdk/guides/llm-reasoning.md): Access model reasoning traces from Anthropic extended thinking and OpenAI responses API.\n- [Secret Registry](https://docs.openhands.dev/sdk/guides/secrets.md): Provide environment variables and secrets to agent workspace securely.\n- [Security & Action Confirmation](https://docs.openhands.dev/sdk/guides/security.md): Control agent action execution through confirmation policy and security analyzer.\n- [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.\n- [Software Agent SDK](https://docs.openhands.dev/sdk.md): Build AI agents that write software. A clean, modular SDK with production-ready tools.\n- [Stuck Detector](https://docs.openhands.dev/sdk/guides/agent-stuck-detector.md): Detect and handle stuck agents automatically with timeout mechanisms.\n- [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.\n- [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.\n- [TODO Management](https://docs.openhands.dev/sdk/guides/github-workflows/todo-management.md): Implement TODOs using OpenHands Agent\n\n## Examples\n\nSource: [`examples/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples)\n\n### [`01_standalone_sdk/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk)\n\n- [`01_hello_world.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/01_hello_world.py)\n- [`02_custom_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/02_custom_tools.py)\n- [`03_activate_skill.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/03_activate_skill.py)\n- [`04_confirmation_mode_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/04_confirmation_mode_example.py)\n- [`05_use_llm_registry.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/05_use_llm_registry.py)\n- [`06_interactive_terminal_w_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/06_interactive_terminal_w_reasoning.py)\n- [`07_mcp_integration.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/07_mcp_integration.py)\n- [`08_mcp_with_oauth.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/08_mcp_with_oauth.py)\n- [`09_pause_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/09_pause_example.py)\n- [`10_persistence.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/10_persistence.py)\n- [`11_async.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/11_async.py)\n- [`12_custom_secrets.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/12_custom_secrets.py)\n- [`13_get_llm_metrics.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/13_get_llm_metrics.py)\n- [`14_context_condenser.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/14_context_condenser.py)\n- [`15_browser_use.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/15_browser_use.py)\n- [`16_llm_security_analyzer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/16_llm_security_analyzer.py)\n- [`17_image_input.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/17_image_input.py)\n- [`18_send_message_while_processing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/18_send_message_while_processing.py)\n- [`19_llm_routing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/19_llm_routing.py)\n- [`20_stuck_detector.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/20_stuck_detector.py)\n- [`21_generate_extraneous_conversation_costs.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/21_generate_extraneous_conversation_costs.py)\n- [`22_anthropic_thinking.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/22_anthropic_thinking.py)\n- [`23_responses_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/23_responses_reasoning.py)\n- [`24_planning_agent_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/24_planning_agent_workflow.py)\n- [`25_agent_delegation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/25_agent_delegation.py)\n- [`26_custom_visualizer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/26_custom_visualizer.py)\n- [`27_observability_laminar.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/27_observability_laminar.py)\n- [`28_ask_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/28_ask_agent_example.py)\n- [`29_llm_streaming.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/29_llm_streaming.py)\n- [`30_tom_agent.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/30_tom_agent.py)\n- [`31_iterative_refinement.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/31_iterative_refinement.py)\n- [`32_configurable_security_policy.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/32_configurable_security_policy.py)\n- [`33_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/33_hooks)\n- [`34_critic_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/34_critic_example.py)\n- [`35_subscription_login.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/35_subscription_login.py)\n- [`36_event_json_to_openai_messages.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/36_event_json_to_openai_messages.py)\n- [`37_llm_profile_store`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/37_llm_profile_store)\n- [`38_browser_session_recording.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/38_browser_session_recording.py)\n- [`39_llm_fallback.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/39_llm_fallback.py)\n- [`40_acp_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/40_acp_agent_example.py)\n- [`41_task_tool_set.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/41_task_tool_set.py)\n- [`42_file_based_subagents.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/42_file_based_subagents.py)\n- [`44_model_switching_in_convo.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/44_model_switching_in_convo.py)\n- [`45_parallel_tool_execution.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/45_parallel_tool_execution.py)\n- [`46_agent_settings.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/46_agent_settings.py)\n- [`47_defense_in_depth_security.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/47_defense_in_depth_security.py)\n- [`48_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/48_conversation_fork.py)\n- [`49_switch_llm_tool.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/49_switch_llm_tool.py)\n- [`50_async_cancellation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/50_async_cancellation.py)\n- [`51_agent_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/51_agent_hooks)\n- [`52_dynamic_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/52_dynamic_workflow.py)\n- [`53_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/53_client_defined_tools.py)\n- [`54_goal_completion_loop.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/54_goal_completion_loop.py)\n- [`55_persistent_memory.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/55_persistent_memory.py)\n\n### [`02_remote_agent_server/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server)\n\n- [`01_convo_with_local_agent_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/01_convo_with_local_agent_server.py)\n- [`02_convo_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/02_convo_with_docker_sandboxed_server.py)\n- [`03_browser_use_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/03_browser_use_with_docker_sandboxed_server.py)\n- [`04_convo_with_api_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/04_convo_with_api_sandboxed_server.py)\n- [`05_vscode_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/05_vscode_with_docker_sandboxed_server.py)\n- [`06_custom_tool`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/06_custom_tool)\n- [`07_convo_with_cloud_workspace.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/07_convo_with_cloud_workspace.py)\n- [`08_convo_with_apptainer_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/08_convo_with_apptainer_sandboxed_server.py)\n- [`09_acp_agent_with_remote_runtime.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/09_acp_agent_with_remote_runtime.py)\n- [`10_cloud_workspace_share_credentials.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/10_cloud_workspace_share_credentials.py)\n- [`11_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/11_conversation_fork.py)\n- [`12_settings_and_secrets_api.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/12_settings_and_secrets_api.py)\n- [`13_workspace_get_llm.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/13_workspace_get_llm.py)\n- [`14_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/14_client_defined_tools.py)\n- [`15_openai_compatible_gateway.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/15_openai_compatible_gateway.py)\n- [`16_deferred_init.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/16_deferred_init.py)\n- [`hook_scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/hook_scripts)\n- [`scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/scripts)\n\n### [`03_github_workflows/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows)\n\n- [`01_basic_action`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/01_basic_action)\n- [`02_pr_review`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/02_pr_review)\n- [`03_todo_management`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/03_todo_management)\n- [`04_datadog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/04_datadog_debugging)\n- [`05_posthog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/05_posthog_debugging)\n\n### [`04_llm_specific_tools/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/04_llm_specific_tools)\n\n- [`01_gpt5_apply_patch_preset.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/01_gpt5_apply_patch_preset.py)\n- [`02_gemini_file_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/02_gemini_file_tools.py)\n\n### [`05_skills_and_plugins/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins)\n\n- [`01_loading_agentskills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/01_loading_agentskills)\n- [`02_loading_plugins`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/02_loading_plugins)\n- [`03_managing_installed_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/03_managing_installed_skills)\n- [`04_mixed_marketplace_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/04_mixed_marketplace_skills)", + "content": "# OpenHands Software Agent SDK\n\nAll SDK documentation lives at .\n\nFor the full topic index, fetch and read\nthe \"OpenHands Software Agent SDK\" section.\n\n## Quick reference\n\nInstall: `pip install openhands-sdk openhands-tools`\n\n```python\nimport os\n\nfrom openhands.sdk import LLM, Agent, Conversation, Tool\nfrom openhands.tools.file_editor import FileEditorTool\nfrom openhands.tools.task_tracker import TaskTrackerTool\nfrom openhands.tools.terminal import TerminalTool\n\n\nllm = LLM(\n model=os.getenv(\"LLM_MODEL\", \"gpt-5.5\"),\n api_key=os.getenv(\"LLM_API_KEY\"),\n base_url=os.getenv(\"LLM_BASE_URL\", None),\n)\n\nagent = Agent(\n llm=llm,\n tools=[\n Tool(name=TerminalTool.name),\n Tool(name=FileEditorTool.name),\n Tool(name=TaskTrackerTool.name),\n ],\n)\n\ncwd = os.getcwd()\nconversation = Conversation(agent=agent, workspace=cwd)\n\nconversation.send_message(\"Write 3 facts about the current project into FACTS.txt.\")\nconversation.run()\nprint(\"All done!\")\n```\n\n## Core classes (`openhands.sdk`)\n\n| Class | Purpose |\n|---|---|\n| [`Agent`](https://docs.openhands.dev/sdk/arch/agent.md) | Reasoning-action loop |\n| [`Condenser`](https://docs.openhands.dev/sdk/arch/condenser.md) | Conversation history compression system |\n| [`Conversation`](https://docs.openhands.dev/sdk/arch/conversation.md) | Conversation orchestration system |\n| [`Event`](https://docs.openhands.dev/sdk/arch/events.md) | Typed event framework |\n| [`LLM`](https://docs.openhands.dev/sdk/arch/llm.md) | Provider-agnostic language model interface |\n| [`SecurityAnalyzer`](https://docs.openhands.dev/sdk/arch/security.md) | Action security analysis and validation |\n| [`Skill`](https://docs.openhands.dev/sdk/arch/skill.md) | Reusable prompt system |\n| [`Tool / ToolDefinition`](https://docs.openhands.dev/sdk/arch/tool-system.md) | Action-observation tool framework |\n| [`Workspace`](https://docs.openhands.dev/sdk/arch/workspace.md) | Execution environment abstraction |\n\n## API reference\n\n[`openhands.sdk.agent`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.agent.md), [`openhands.sdk.conversation`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.conversation.md), [`openhands.sdk.event`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.event.md), [`openhands.sdk.llm`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.llm.md), [`openhands.sdk.security`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.security.md), [`openhands.sdk.tool`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.tool.md), [`openhands.sdk.utils`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.utils.md), [`openhands.sdk.workspace`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.workspace.md)\n\n## Guides\n\n- [ACP Agent](https://docs.openhands.dev/sdk/guides/agent-acp.md): Delegate to an ACP-compatible server (Claude Code, Gemini CLI, etc.) instead of calling an LLM directly.\n- [Agent Settings](https://docs.openhands.dev/sdk/guides/agent-settings.md): Configure, serialize, and recreate agents from structured settings.\n- [Agent Skills & Context](https://docs.openhands.dev/sdk/guides/skill.md): Skills add specialized behaviors, domain knowledge, and context-aware triggers to your agent through structured prompts.\n- [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.\n- [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.\n- [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.\n- [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\n- [Browser Session Recording](https://docs.openhands.dev/sdk/guides/browser-session-recording.md): Record and replay your agent's browser sessions using rrweb.\n- [Browser Use](https://docs.openhands.dev/sdk/guides/agent-browser-use.md): Enable web browsing and interaction capabilities for your agent.\n- [Context Condenser](https://docs.openhands.dev/sdk/guides/context-condenser.md): Manage agent memory by condensing conversation history to save tokens.\n- [Conversation Goals](https://docs.openhands.dev/sdk/guides/agent-server/conversation-goals.md): Add a resumable goal strategy to a normal agent-server conversation.\n- [Conversation with Async](https://docs.openhands.dev/sdk/guides/convo-async.md): Use async/await for concurrent agent operations and non-blocking execution.\n- [Creating Custom Agent](https://docs.openhands.dev/sdk/guides/agent-custom.md): Learn how to design specialized agents with custom tool sets\n- [Critic (Experimental)](https://docs.openhands.dev/sdk/guides/critic.md): Real-time evaluation of agent actions using an LLM-based critic model, with built-in iterative refinement.\n- [Custom Tools](https://docs.openhands.dev/sdk/guides/custom-tools.md): Tools define what agents can do. The SDK includes built-in tools for common operations and supports creating custom tools for specialized needs.\n- [Custom Tools with Remote Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/custom-tools.md): Learn how to use custom tools with a remote agent server by building a custom base image that includes your tool implementations.\n- [Custom Visualizer](https://docs.openhands.dev/sdk/guides/convo-custom-visualizer.md): Customize conversation visualization by creating custom visualizers or configuring the default visualizer.\n- [Deferred Init (Warm-Pool)](https://docs.openhands.dev/sdk/guides/agent-server/deferred-init.md): Pre-warm agent-server pods before a user is matched, then activate them at runtime with POST /api/init.\n- [Docker Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/docker-sandbox.md): Run agent server in isolated Docker containers for security and reproducibility.\n- [Exception Handling](https://docs.openhands.dev/sdk/guides/llm-error-handling.md): Provider‑agnostic exceptions raised by the SDK and recommended patterns for handling them.\n- [FAQ](https://docs.openhands.dev/sdk/faq.md): Frequently asked questions about the OpenHands SDK\n- [File-Based Agents](https://docs.openhands.dev/sdk/guides/agent-file-based.md): Define specialized sub-agents as simple Markdown files with YAML frontmatter — no Python code required.\n- [Fork a Conversation](https://docs.openhands.dev/sdk/guides/convo-fork.md): Branch off an existing conversation for follow-up exploration without contaminating the original.\n- [Getting Started](https://docs.openhands.dev/sdk/getting-started.md): Install the OpenHands SDK and build AI agents that write software.\n- [Goal Completion Loop](https://docs.openhands.dev/sdk/guides/convo-goal.md): Drive a conversation toward a verifiable objective with a judge-driven, self-continuing completion loop.\n- [GPT-5 Preset (ApplyPatchTool)](https://docs.openhands.dev/sdk/guides/llm-gpt5-preset.md): Use the GPT-5 preset to build an agent that swaps the standard FileEditorTool for ApplyPatchTool.\n- [Hello World](https://docs.openhands.dev/sdk/guides/hello-world.md): The simplest possible OpenHands agent - configure an LLM, create an agent, and complete a task.\n- [Hooks](https://docs.openhands.dev/sdk/guides/hooks.md): Use lifecycle hooks to observe, log, and customize agent execution.\n- [Image Input](https://docs.openhands.dev/sdk/guides/llm-image-input.md): Send images to multimodal agents for vision-based tasks and analysis.\n- [Interactive Terminal](https://docs.openhands.dev/sdk/guides/agent-interactive-terminal.md): Enable agents to interact with terminal applications like ipython, python REPL, and other interactive CLI tools.\n- [Iterative Refinement](https://docs.openhands.dev/sdk/guides/iterative-refinement.md): Implement iterative refinement workflows where agents refine their work based on critique feedback until quality thresholds are met.\n- [LLM Fallback Strategy](https://docs.openhands.dev/sdk/guides/llm-fallback.md): Automatically try alternate LLMs when the primary model fails with a transient error.\n- [LLM Profile Store](https://docs.openhands.dev/sdk/guides/llm-profile-store.md): Save, load, and manage reusable LLM configurations so you never repeat setup code again.\n- [LLM Registry](https://docs.openhands.dev/sdk/guides/llm-registry.md): Dynamically select and configure language models using the LLM registry.\n- [LLM Streaming](https://docs.openhands.dev/sdk/guides/llm-streaming.md): Stream LLM responses token-by-token for real-time display and interactive user experiences.\n- [LLM Subscriptions](https://docs.openhands.dev/sdk/guides/llm-subscriptions.md): Use your ChatGPT Plus/Pro subscription to access Codex models without consuming API credits.\n- [Local Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/local-server.md): Install and run an OpenHands Agent Server on your machine, then connect to it from the SDK.\n- [Metrics Tracking](https://docs.openhands.dev/sdk/guides/metrics.md): Track token usage, costs, and latency metrics for your agents.\n- [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.\n- [Model Routing](https://docs.openhands.dev/sdk/guides/llm-routing.md): Route agent's LLM requests to different models.\n- [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.\n- [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.\n- [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.\n- [Overview](https://docs.openhands.dev/sdk/guides/agent-server/overview.md): Run agents on remote servers with isolated workspaces for production deployments.\n- [Parallel Tool Execution](https://docs.openhands.dev/sdk/guides/parallel-tool-execution.md): Execute multiple tools concurrently within a single LLM response to improve throughput for independent operations.\n- [Pause and Resume](https://docs.openhands.dev/sdk/guides/convo-pause-and-resume.md): Pause agent execution, perform operations, and resume without losing state.\n- [Persistence](https://docs.openhands.dev/sdk/guides/convo-persistence.md): Save and restore conversation state for multi-session workflows.\n- [Persistent Memory](https://docs.openhands.dev/sdk/guides/persistent-memory.md): Give agents opt-in, two-tier memory that survives across conversations.\n- [Plugins](https://docs.openhands.dev/sdk/guides/plugins.md): Plugins bundle skills, hooks, MCP servers, agents, and commands into reusable packages that extend agent capabilities.\n- [PR Review](https://docs.openhands.dev/sdk/guides/github-workflows/pr-review.md): Use OpenHands Agent to generate meaningful pull request review\n- [Reasoning](https://docs.openhands.dev/sdk/guides/llm-reasoning.md): Access model reasoning traces from Anthropic extended thinking and OpenAI responses API.\n- [Secret Registry](https://docs.openhands.dev/sdk/guides/secrets.md): Provide environment variables and secrets to agent workspace securely.\n- [Security & Action Confirmation](https://docs.openhands.dev/sdk/guides/security.md): Control agent action execution through confirmation policy and security analyzer.\n- [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.\n- [Software Agent SDK](https://docs.openhands.dev/sdk.md): Build AI agents that write software. A clean, modular SDK with production-ready tools.\n- [Stuck Detector](https://docs.openhands.dev/sdk/guides/agent-stuck-detector.md): Detect and handle stuck agents automatically with timeout mechanisms.\n- [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.\n- [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.\n- [TODO Management](https://docs.openhands.dev/sdk/guides/github-workflows/todo-management.md): Implement TODOs using OpenHands Agent\n\n## Examples\n\nSource: [`examples/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples)\n\n### [`01_standalone_sdk/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk)\n\n- [`01_hello_world.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/01_hello_world.py)\n- [`02_custom_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/02_custom_tools.py)\n- [`03_activate_skill.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/03_activate_skill.py)\n- [`04_confirmation_mode_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/04_confirmation_mode_example.py)\n- [`05_use_llm_registry.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/05_use_llm_registry.py)\n- [`06_interactive_terminal_w_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/06_interactive_terminal_w_reasoning.py)\n- [`07_mcp_integration.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/07_mcp_integration.py)\n- [`08_mcp_with_oauth.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/08_mcp_with_oauth.py)\n- [`09_pause_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/09_pause_example.py)\n- [`10_persistence.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/10_persistence.py)\n- [`11_async.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/11_async.py)\n- [`12_custom_secrets.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/12_custom_secrets.py)\n- [`13_get_llm_metrics.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/13_get_llm_metrics.py)\n- [`14_context_condenser.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/14_context_condenser.py)\n- [`15_browser_use.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/15_browser_use.py)\n- [`16_llm_security_analyzer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/16_llm_security_analyzer.py)\n- [`17_image_input.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/17_image_input.py)\n- [`18_send_message_while_processing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/18_send_message_while_processing.py)\n- [`19_llm_routing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/19_llm_routing.py)\n- [`20_stuck_detector.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/20_stuck_detector.py)\n- [`21_generate_extraneous_conversation_costs.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/21_generate_extraneous_conversation_costs.py)\n- [`22_anthropic_thinking.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/22_anthropic_thinking.py)\n- [`23_responses_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/23_responses_reasoning.py)\n- [`24_planning_agent_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/24_planning_agent_workflow.py)\n- [`25_agent_delegation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/25_agent_delegation.py)\n- [`26_custom_visualizer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/26_custom_visualizer.py)\n- [`27_observability_laminar.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/27_observability_laminar.py)\n- [`28_ask_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/28_ask_agent_example.py)\n- [`29_llm_streaming.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/29_llm_streaming.py)\n- [`30_tom_agent.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/30_tom_agent.py)\n- [`31_iterative_refinement.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/31_iterative_refinement.py)\n- [`32_configurable_security_policy.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/32_configurable_security_policy.py)\n- [`33_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/33_hooks)\n- [`34_critic_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/34_critic_example.py)\n- [`35_subscription_login.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/35_subscription_login.py)\n- [`36_event_json_to_openai_messages.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/36_event_json_to_openai_messages.py)\n- [`37_llm_profile_store`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/37_llm_profile_store)\n- [`38_browser_session_recording.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/38_browser_session_recording.py)\n- [`39_llm_fallback.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/39_llm_fallback.py)\n- [`40_acp_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/40_acp_agent_example.py)\n- [`41_task_tool_set.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/41_task_tool_set.py)\n- [`42_file_based_subagents.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/42_file_based_subagents.py)\n- [`44_model_switching_in_convo.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/44_model_switching_in_convo.py)\n- [`45_parallel_tool_execution.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/45_parallel_tool_execution.py)\n- [`46_agent_settings.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/46_agent_settings.py)\n- [`47_defense_in_depth_security.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/47_defense_in_depth_security.py)\n- [`48_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/48_conversation_fork.py)\n- [`49_switch_llm_tool.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/49_switch_llm_tool.py)\n- [`50_async_cancellation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/50_async_cancellation.py)\n- [`51_agent_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/51_agent_hooks)\n- [`52_dynamic_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/52_dynamic_workflow.py)\n- [`53_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/53_client_defined_tools.py)\n- [`54_goal_completion_loop.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/54_goal_completion_loop.py)\n- [`55_persistent_memory.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/55_persistent_memory.py)\n- [`56_structured_output.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/56_structured_output.py)\n\n### [`02_remote_agent_server/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server)\n\n- [`01_convo_with_local_agent_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/01_convo_with_local_agent_server.py)\n- [`02_convo_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/02_convo_with_docker_sandboxed_server.py)\n- [`03_browser_use_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/03_browser_use_with_docker_sandboxed_server.py)\n- [`04_convo_with_api_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/04_convo_with_api_sandboxed_server.py)\n- [`05_vscode_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/05_vscode_with_docker_sandboxed_server.py)\n- [`06_custom_tool`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/06_custom_tool)\n- [`07_convo_with_cloud_workspace.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/07_convo_with_cloud_workspace.py)\n- [`08_convo_with_apptainer_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/08_convo_with_apptainer_sandboxed_server.py)\n- [`09_acp_agent_with_remote_runtime.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/09_acp_agent_with_remote_runtime.py)\n- [`10_cloud_workspace_share_credentials.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/10_cloud_workspace_share_credentials.py)\n- [`11_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/11_conversation_fork.py)\n- [`12_settings_and_secrets_api.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/12_settings_and_secrets_api.py)\n- [`13_workspace_get_llm.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/13_workspace_get_llm.py)\n- [`14_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/14_client_defined_tools.py)\n- [`15_openai_compatible_gateway.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/15_openai_compatible_gateway.py)\n- [`16_deferred_init.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/16_deferred_init.py)\n- [`hook_scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/hook_scripts)\n- [`scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/scripts)\n\n### [`03_github_workflows/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows)\n\n- [`01_basic_action`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/01_basic_action)\n- [`02_pr_review`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/02_pr_review)\n- [`03_todo_management`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/03_todo_management)\n- [`04_datadog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/04_datadog_debugging)\n- [`05_posthog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/05_posthog_debugging)\n\n### [`04_llm_specific_tools/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/04_llm_specific_tools)\n\n- [`01_gpt5_apply_patch_preset.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/01_gpt5_apply_patch_preset.py)\n- [`02_gemini_file_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/02_gemini_file_tools.py)\n\n### [`05_skills_and_plugins/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins)\n\n- [`01_loading_agentskills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/01_loading_agentskills)\n- [`02_loading_plugins`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/02_loading_plugins)\n- [`03_managing_installed_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/03_managing_installed_skills)\n- [`04_mixed_marketplace_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/04_mixed_marketplace_skills)", "category": "agent-authoring" }, { From a06523559260b5c4fbf3af16b3c9648f625f42e9 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Fri, 14 Aug 2026 09:04:22 -0500 Subject: [PATCH 3/6] docs: strengthen replicated install safety gates Co-authored-by: openhands --- skills/index.js | 2 +- skills/install-openhands-replicated/SKILL.md | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/skills/index.js b/skills/index.js index 08a12f3d..4e5f59c8 100644 --- a/skills/index.js +++ b/skills/index.js @@ -266,7 +266,7 @@ export const SKILLS_CATALOG = [ "name": "install-openhands-replicated", "description": "This skill should be used when the user asks to \"install OpenHands Enterprise\", \"set up OHE on a VM\", \"run an OHE install preflight\", \"configure the Replicated Admin Console\", \"prepare DNS and TLS for OpenHands Enterprise\", or \"validate a Replicated Embedded Cluster installation\". It guides supported AWS Terraform or manual VM installations from scoping through end-to-end validation.", "triggers": [], - "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Prefer supported Replicated and KOTS surfaces. Do not use direct Kubernetes patches as installation steps. Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nUse the current OpenHands AWS Terraform module when AWS Terraform is selected. For a manual VM, require the documented CPU, memory, disk, latency, OS, systemd, root access, inbound ports, local ports, and outbound destinations.\n\nRun read-only preflights on the target VM:\n\n```bash\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, and outbound preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nUse the current `Simple` hostname mode unless the customer requires manual hostnames. Configure and validate one layer at a time:\n\n1. domain and publicly trusted TLS;\n2. one LLM provider;\n3. database choice and storage durability;\n4. core application deployment;\n5. first login and organization;\n6. Git provider authentication using `references/git-provider-auth.md`;\n7. optional integrations, analytics, automations, and advanced settings.\n\nRead `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution.\n\n### 5. Prove the Core Product\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Mutating Helper Gate\n\nUse `scripts/apply_kots_config.sh` in preview mode first:\n\n```bash\nscripts/apply_kots_config.sh \\\n --appslug openhands \\\n --config-file ./config-values.patch.yaml \\\n --current\n```\n\nAfter reviewing impact and obtaining explicit approval, add `--execute`; add `--deploy` only when an immediate deployment is approved. Re-run workload, readiness, storage, and user-path verification after deployment.\n\n## Resources\n\n- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria.\n- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and guarded ConfigValues guidance.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux host and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: preview-first KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", + "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Prefer supported configuration surfaces. Use the V1 API (`POST /api/v1/settings` with `*_diff` payloads) for supported user and organization settings. Use the Replicated/KOTS Admin Console or documented Helm values for deployment settings such as environment variables and image overrides.\n- Never use raw `kubectl patch`, `kubectl set env`, `kubectl edit`, or direct database queries as the first resort. Treat them as escape hatches. Use one only when the documented configuration path is broken, the user explicitly approves the operation, and the change and rationale are recorded for rollback or migration into supported configuration during the next deployment.\n- Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nUse the current OpenHands AWS Terraform module when AWS Terraform is selected. For a manual VM, require the documented CPU, memory, disk, latency, OS, systemd, root access, inbound ports, local ports, and outbound destinations.\n\nRun read-only preflights on the target VM:\n\n```bash\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, and outbound preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nUse the current `Simple` hostname mode unless the customer requires manual hostnames. Configure and validate only the minimum required layers before the baseline test:\n\n1. domain and publicly trusted TLS;\n2. one LLM provider;\n3. database choice and storage durability;\n4. core application deployment;\n5. first login and organization.\n\nRead `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution. Defer Git provider authentication, integrations, analytics, automations, and advanced settings until the baseline passes.\n\n### 5. Prove the Core Product\n\nOn a fresh install, validate the baseline before adding optional configuration. Create one simple conversation through the UI or V1 API and confirm that its sandbox reaches `READY`. If the baseline is broken, report it as a platform or product issue rather than patching around it with infrastructure changes. Treat a fresh install that cannot start a sandbox as a bug, not a configuration task.\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation reaches `READY` and finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Mutating Helper Gate\n\nUse `scripts/apply_kots_config.sh` in preview mode first:\n\n```bash\nscripts/apply_kots_config.sh \\\n --appslug openhands \\\n --config-file ./config-values.patch.yaml \\\n --current\n```\n\nAfter reviewing impact and obtaining explicit approval, add `--execute`; add `--deploy` only when an immediate deployment is approved. Re-run workload, readiness, storage, and user-path verification after deployment.\n\n## Resources\n\n- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria.\n- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and guarded ConfigValues guidance.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux host and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: preview-first KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", "category": "environment" }, { diff --git a/skills/install-openhands-replicated/SKILL.md b/skills/install-openhands-replicated/SKILL.md index 8c43bc29..7342da50 100644 --- a/skills/install-openhands-replicated/SKILL.md +++ b/skills/install-openhands-replicated/SKILL.md @@ -12,7 +12,9 @@ Guide a customer or field engineer from installation scoping to a usable OpenHan - Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation. - Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values. - State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase. -- Prefer supported Replicated and KOTS surfaces. Do not use direct Kubernetes patches as installation steps. Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support. +- Prefer supported configuration surfaces. Use the V1 API (`POST /api/v1/settings` with `*_diff` payloads) for supported user and organization settings. Use the Replicated/KOTS Admin Console or documented Helm values for deployment settings such as environment variables and image overrides. +- Never use raw `kubectl patch`, `kubectl set env`, `kubectl edit`, or direct database queries as the first resort. Treat them as escape hatches. Use one only when the documented configuration path is broken, the user explicitly approves the operation, and the change and rationale are recorded for rollback or migration into supported configuration during the next deployment. +- Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support. - Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them. - Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements. - Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state. @@ -63,20 +65,20 @@ Run the interactive installer in a real PTY. Stop rather than scripting around a ### 4. Configure the Admin Console in Layers -Use the current `Simple` hostname mode unless the customer requires manual hostnames. Configure and validate one layer at a time: +Use the current `Simple` hostname mode unless the customer requires manual hostnames. Configure and validate only the minimum required layers before the baseline test: 1. domain and publicly trusted TLS; 2. one LLM provider; 3. database choice and storage durability; 4. core application deployment; -5. first login and organization; -6. Git provider authentication using `references/git-provider-auth.md`; -7. optional integrations, analytics, automations, and advanced settings. +5. first login and organization. -Read `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution. +Read `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution. Defer Git provider authentication, integrations, analytics, automations, and advanced settings until the baseline passes. ### 5. Prove the Core Product +On a fresh install, validate the baseline before adding optional configuration. Create one simple conversation through the UI or V1 API and confirm that its sandbox reaches `READY`. If the baseline is broken, report it as a platform or product issue rather than patching around it with infrastructure changes. Treat a fresh install that cannot start a sandbox as a bug, not a configuration task. + Do not declare completion from pod readiness alone. Verify: - Admin Console and application TLS validate for the configured hostnames; @@ -84,7 +86,7 @@ Do not declare completion from pod readiness alone. Verify: - login works in a clean browser session; - the first organization and bounded API key work; - the configured model completes one tiny request; -- one no-repository conversation finishes with an expected marker; +- one no-repository conversation reaches `READY` and finishes with an expected marker; - repository search and one repository-backed conversation work when a Git provider is in scope. Run `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover. From a4ffdad0da58a2a9a0c28d248a5f6eed46e723c7 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Fri, 14 Aug 2026 10:20:43 -0500 Subject: [PATCH 4/6] chore: retrigger review after validation update Co-authored-by: openhands From a33c4d16916e5d2a408d3fa398bcadaaaf3bbdc1 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Wed, 26 Aug 2026 13:01:57 -0500 Subject: [PATCH 5/6] docs: align Replicated install skill with current guidance Co-authored-by: openhands --- README.md | 2 +- marketplaces/openhands-extensions.json | 2 +- skills/index.js | 2 +- .../.plugin/plugin.json | 2 +- skills/install-openhands-replicated/README.md | 17 ++-- skills/install-openhands-replicated/SKILL.md | 71 ++++++++------- .../assets/install-plan.yaml | 20 ++++- .../references/admin-config.md | 53 +++++++---- .../references/backup-and-durability.md | 4 +- .../references/install-flow.md | 69 ++++++++++----- .../references/operator-requests.md | 16 +++- .../scripts/apply_kots_config.sh | 16 +++- .../scripts/check_host_preflight.sh | 87 +++++++++++++++++++ 13 files changed, 280 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 58b175b9..86efc613 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ Official skills and plugins for OpenHands — the open-source AI software engine | github-repo-monitor | skill | Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger p... | `/github-monitor:poll` | | gitlab | skill | Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when wor... | — | | incident-retrospective | skill | Create an automation that drafts incident retrospectives by gathering incident-channel messages from Slack, collectin... | `/incident-retro:setup` | -| install-openhands-replicated | skill | Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with read-only preflights, ... | — | +| install-openhands-replicated | skill | Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with capacity planning, rea... | — | | iterate | skill | Iterate on a GitHub pull request — drive it through CI, code review, and QA until merge-ready. Monitors state, fixes ... | `/iterate`, `/verify`, `/babysit` | | jira-issue-to-pr | skill | Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable lab... | — | | jupyter | skill | Read, modify, execute, and convert Jupyter notebooks programmatically. Use when working with .ipynb files for data sc... | — | diff --git a/marketplaces/openhands-extensions.json b/marketplaces/openhands-extensions.json index 6844efc4..686e25c8 100644 --- a/marketplaces/openhands-extensions.json +++ b/marketplaces/openhands-extensions.json @@ -838,7 +838,7 @@ { "name": "install-openhands-replicated", "source": "./skills/install-openhands-replicated", - "description": "Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with read-only preflights, explicit approval gates, provider setup, and end-to-end validation.", + "description": "Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with capacity planning, read-only preflights, explicit approval gates, and end-to-end validation.", "category": "environment", "keywords": [ "openhands-enterprise", diff --git a/skills/index.js b/skills/index.js index dadc7238..2d5cad6d 100644 --- a/skills/index.js +++ b/skills/index.js @@ -291,7 +291,7 @@ export const SKILLS_CATALOG = [ "name": "install-openhands-replicated", "description": "This skill should be used when the user asks to \"install OpenHands Enterprise\", \"set up OHE on a VM\", \"run an OHE install preflight\", \"configure the Replicated Admin Console\", \"prepare DNS and TLS for OpenHands Enterprise\", or \"validate a Replicated Embedded Cluster installation\". It guides supported AWS Terraform or manual VM installations from scoping through end-to-end validation.", "triggers": [], - "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Prefer supported configuration surfaces. Use the V1 API (`POST /api/v1/settings` with `*_diff` payloads) for supported user and organization settings. Use the Replicated/KOTS Admin Console or documented Helm values for deployment settings such as environment variables and image overrides.\n- Never use raw `kubectl patch`, `kubectl set env`, `kubectl edit`, or direct database queries as the first resort. Treat them as escape hatches. Use one only when the documented configuration path is broken, the user explicitly approves the operation, and the change and rationale are recorded for rollback or migration into supported configuration during the next deployment.\n- Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nUse the current OpenHands AWS Terraform module when AWS Terraform is selected. For every fresh installation, explicitly set Terraform `hostname_mode = \"wildcard\"`; this maps to `Simple` in the Admin Console. Do not select Terraform `legacy` or Admin Console `Legacy` unless the task is to reproduce an existing Legacy installation. Before applying, confirm the plan creates `*.` rather than `auth.app.` or `*.runtime.`.\n\nFor a manual VM, require the documented CPU, memory, disk, latency, OS, systemd, root access, inbound ports, local ports, and outbound destinations.\n\nRun read-only preflights on the target VM:\n\n```bash\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, and outbound preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nExplicitly select `Simple` hostname mode for a fresh installation unless the customer requires manual hostnames. Confirm it matches Terraform `hostname_mode = \"wildcard\"`; never select `Legacy` merely because an older runbook or Terraform copy uses nested hostnames. Configure and validate only the minimum required layers before the baseline test:\n\n1. domain and publicly trusted TLS;\n2. one LLM provider;\n3. database choice and storage durability;\n4. core application deployment;\n5. first login and organization.\n\nRead `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution. Defer Git provider authentication, integrations, analytics, automations, and advanced settings until the baseline passes.\n\n### 5. Prove the Core Product\n\nOn a fresh install, validate the baseline before adding optional configuration. Create one simple conversation through the UI or V1 API and confirm that its sandbox reaches `READY`. If the baseline is broken, report it as a platform or product issue rather than patching around it with infrastructure changes. Treat a fresh install that cannot start a sandbox as a bug, not a configuration task.\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation reaches `READY` and finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Mutating Helper Gate\n\nUse `scripts/apply_kots_config.sh` in preview mode first:\n\n```bash\nscripts/apply_kots_config.sh \\\n --appslug openhands \\\n --config-file ./config-values.patch.yaml \\\n --current\n```\n\nAfter reviewing impact and obtaining explicit approval, add `--execute`; add `--deploy` only when an immediate deployment is approved. Re-run workload, readiness, storage, and user-path verification after deployment.\n\n## Resources\n\n- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria.\n- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and guarded ConfigValues guidance.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux host and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: preview-first KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", + "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n> **Failed-install troubleshooting must remain read-only**\n>\n> 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.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, save Admin Console configuration, or deploy a new sequence without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Use the Admin Console for documented deployment settings and the V1 API for documented application settings. Use KOTS ConfigValues only under a version-matched OpenHands Support procedure.\n- Do not patch or edit Kubernetes resources, restart workloads, query databases directly, or rotate installer-managed secrets unless OpenHands Support directs the specific operation and the administrator approves it.\n- Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- trial or rollout intent and expected peak concurrent sandboxes;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- sandbox isolation mode and whether Docker-in-sandbox is required;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nSize the VM from expected **peak concurrent sandboxes**, not user count. The Quick Start baseline is a trial starting point; use the current Sizing Guide for larger rollouts and place application data on a separate expandable volume rather than the boot disk.\n\nUse the current OpenHands AWS Terraform module when AWS Terraform is selected. Its default `hostname_mode = \"wildcard\"` maps to `Simple` in the Admin Console. Use `legacy` only to reproduce an existing Legacy installation; use manual infrastructure when every hostname must be customized. Review the complete Terraform plan before applying.\n\nFor a manual VM, require the documented CPU, memory, disk, latency, Linux x86-64, systemd, root access, inbound ports, local ports, and outbound destinations. Ubuntu 24.04 LTS is recommended. If the default stronger sandbox isolation or Docker-in-sandbox is required, the host kernel must be 6.3 or newer; the standard isolation mode does not support Docker-in-sandbox.\n\nRun read-only preflights on the target VM, setting the planned data path and isolation mode:\n\n```bash\nDATA_PATH=/path/to/data-volume \\\nMIN_DATA_DISK_GIB=\"${PLANNED_DATA_DISK_GIB:?set from approved sizing plan}\" \\\nSANDBOX_ISOLATION=sysbox \\\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. In the dashboard, name the instance and select **Outbound requests allowed** for Network Availability. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, outbound, sizing, disk, and isolation preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nAccess the Admin Console at `https://admin.:30000` when TLS was supplied during installation, or `http://:30000` when it was not. For a single-node deployment, continue past the add-node screen.\n\nKeep `Simple (default)` hostname mode for a fresh installation unless the customer requires Manual hostnames. Confirm it matches Terraform `hostname_mode = \"wildcard\"`; keep existing Legacy installations on Legacy. Configure and validate only the minimum required layers before the baseline test:\n\n1. domain, publicly trusted TLS, and any required additional trusted CA;\n2. one administrator-managed LLM provider and its exact model identifiers;\n3. bundled or prepared external PostgreSQL;\n4. sandbox isolation, routing, resources, and lifecycle values sized for the planned peak;\n5. GitHub App authentication when GitHub is the selected provider;\n6. core application deployment;\n7. first login and default organization behavior.\n\nRead `references/admin-config.md` before saving settings. Treat every populated configuration screen and ConfigValues file as potentially secret-bearing. Defer additional providers, SMTP, proxy overrides, integrations, analytics, automations, plugins, and advanced settings until the baseline passes.\n\n### 5. Prove the Core Product\n\nOn a fresh install, validate the baseline before adding optional configuration. Create one simple conversation through the UI or V1 API and confirm that its sandbox reaches `READY`. If the baseline is broken, report it as a platform or product issue rather than patching around it with infrastructure changes. Treat a fresh install that cannot start a sandbox as a bug, not a configuration task.\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation reaches `READY` and finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Support-Directed ConfigValues Gate\n\nThe current OpenHands installation workflow uses the Admin Console. Do not use `scripts/apply_kots_config.sh` unless a version-matched OpenHands Support procedure directs a KOTS ConfigValues change. The helper prints its command by default and requires both `--support-directed` and `--execute` before it can mutate configuration. Re-run workload, readiness, storage, and user-path verification after any approved deployment.\n\n## Resources\n\n- OpenHands Enterprise Quick Start: https://docs.openhands.dev/enterprise/quick-start\n- OpenHands Enterprise Sizing Guide: https://docs.openhands.dev/enterprise/sizing-guide\n- Admin Console Configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration\n- Conversations and Sandboxes: https://docs.openhands.dev/enterprise/conversations-and-sandboxes\n- Docker in the Agent Sandbox: https://docs.openhands.dev/enterprise/docker-in-sandbox\n- Troubleshooting: https://docs.openhands.dev/enterprise/troubleshooting\n- VM Log Collection: https://docs.openhands.dev/enterprise/vm-install/log-collection\n- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria.\n- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and Support-directed ConfigValues guidance.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux, sizing, data-disk, isolation, and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: OpenHands Support-directed KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", "category": "environment" }, { diff --git a/skills/install-openhands-replicated/.plugin/plugin.json b/skills/install-openhands-replicated/.plugin/plugin.json index f9dc7e45..b92fa41c 100644 --- a/skills/install-openhands-replicated/.plugin/plugin.json +++ b/skills/install-openhands-replicated/.plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "install-openhands-replicated", "version": "1.0.0", - "description": "Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with read-only preflights, explicit approval gates, provider setup, and end-to-end validation.", + "description": "Guide supported OpenHands Enterprise VM installations through Replicated Embedded Cluster with capacity planning, read-only preflights, explicit approval gates, and end-to-end validation.", "author": { "name": "OpenHands", "email": "contact@all-hands.dev" diff --git a/skills/install-openhands-replicated/README.md b/skills/install-openhands-replicated/README.md index 25e8a5d9..db54e701 100644 --- a/skills/install-openhands-replicated/README.md +++ b/skills/install-openhands-replicated/README.md @@ -13,15 +13,17 @@ Guide a customer or field engineer through a supported OpenHands Enterprise VM i ## Safety model -The skill starts read-only. Infrastructure changes, installer execution, ConfigValues merges, deployments, provider application creation, DNS changes, restores, and cutovers require explicit approval for the exact operation. +> **Keep failed-install investigations 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. + +The skill starts with read-only planning and preflights. Infrastructure changes, installer execution, Admin Console saves, deployments, provider application creation, DNS changes, restores, and cutovers require explicit approval for the exact operation. KOTS ConfigValues changes require a version-matched OpenHands Support procedure in addition to administrator approval. Installer download URLs, license files, private keys, provider credentials, ConfigValues, and support bundles are treated as sensitive. The bundled YAML asset records only non-secret scope and validation status; it is not a headless deployment configuration. ## Current scope -This draft implements the PRD-137 first milestone: comprehensive preflight, provider setup guidance, guided ClickOps, post-install verification, and customer-ready IT requests. +The skill covers sizing by peak concurrent sandboxes, host and network preflight, provider setup guidance, guided Admin Console configuration, post-install verification, and customer-ready IT requests. -Fresh installations use `Simple` hostname mode. In the AWS Terraform module, the matching value is `hostname_mode = "wildcard"`; Legacy is reserved for reproducing an existing Legacy installation. +Fresh installations use `Simple` hostname mode. In the AWS Terraform module, the matching default is `hostname_mode = "wildcard"`; Legacy is reserved for reproducing an existing Legacy installation. Ubuntu 24.04 LTS is recommended, and the default stronger sandbox isolation requires Linux kernel 6.3 or newer. A fully headless install remains conditional on a documented, release-specific installer schema and supported secret-input mechanism. The skill does not infer or invent those interfaces. @@ -36,7 +38,12 @@ A fully headless install remains conditional on a documented, release-specific i ## Official references -- [OpenHands Enterprise quick start](https://docs.openhands.dev/enterprise/quick-start) -- [Admin Console configuration](https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration) +- [OpenHands Enterprise Quick Start](https://docs.openhands.dev/enterprise/quick-start) +- [OpenHands Enterprise Sizing Guide](https://docs.openhands.dev/enterprise/sizing-guide) +- [Admin Console Configuration](https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration) +- [Conversations and Sandboxes](https://docs.openhands.dev/enterprise/conversations-and-sandboxes) +- [Docker in the Agent Sandbox](https://docs.openhands.dev/enterprise/docker-in-sandbox) +- [Troubleshooting](https://docs.openhands.dev/enterprise/troubleshooting) +- [VM Log Collection](https://docs.openhands.dev/enterprise/vm-install/log-collection) - [Replicated Embedded Cluster installation](https://docs.replicated.com/enterprise/installing-embedded) - [Replicated Embedded Cluster requirements](https://docs.replicated.com/enterprise/installing-embedded-requirements) diff --git a/skills/install-openhands-replicated/SKILL.md b/skills/install-openhands-replicated/SKILL.md index efd4dcfb..df64b552 100644 --- a/skills/install-openhands-replicated/SKILL.md +++ b/skills/install-openhands-replicated/SKILL.md @@ -7,13 +7,17 @@ description: This skill should be used when the user asks to "install OpenHands Guide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope. +> **Failed-install troubleshooting must remain read-only** +> +> 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. + ## Safety Contract -- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, deploy ConfigValues, restart workloads, or rotate credentials without explicit approval for that exact operation. +- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, save Admin Console configuration, or deploy a new sequence without explicit approval for that exact operation. - Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values. - State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase. -- Prefer supported configuration surfaces. Use the V1 API (`POST /api/v1/settings` with `*_diff` payloads) for supported user and organization settings. Use the Replicated/KOTS Admin Console or documented Helm values for deployment settings such as environment variables and image overrides. -- Never use raw `kubectl patch`, `kubectl set env`, `kubectl edit`, or direct database queries as the first resort. Treat them as escape hatches. Use one only when the documented configuration path is broken, the user explicitly approves the operation, and the change and rationale are recorded for rollback or migration into supported configuration during the next deployment. +- Use the Admin Console for documented deployment settings and the V1 API for documented application settings. Use KOTS ConfigValues only under a version-matched OpenHands Support procedure. +- Do not patch or edit Kubernetes resources, restart workloads, query databases directly, or rotate installer-managed secrets unless OpenHands Support directs the specific operation and the administrator approves it. - Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support. - Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them. - Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements. @@ -26,8 +30,10 @@ Guide a customer or field engineer from installation scoping to a usable OpenHan Record: - OHE target release and installer/Embedded Cluster version shown by the dashboard; +- trial or rollout intent and expected peak concurrent sandboxes; - AWS Terraform or manual VM path; - base domain, DNS owner, TLS owner, and hostname mode; +- sandbox isolation mode and whether Docker-in-sandbox is required; - LLM provider and authentication owner; - Git provider and optional integrations; - embedded or external PostgreSQL and backup expectations; @@ -37,13 +43,18 @@ Copy `assets/install-plan.yaml` outside the skill repository and populate only n ### 2. Provision or Inspect Infrastructure -Use the current OpenHands AWS Terraform module when AWS Terraform is selected. For every fresh installation, explicitly set Terraform `hostname_mode = "wildcard"`; this maps to `Simple` in the Admin Console. Do not select Terraform `legacy` or Admin Console `Legacy` unless the task is to reproduce an existing Legacy installation. Before applying, confirm the plan creates `*.` rather than `auth.app.` or `*.runtime.`. +Size the VM from expected **peak concurrent sandboxes**, not user count. The Quick Start baseline is a trial starting point; use the current Sizing Guide for larger rollouts and place application data on a separate expandable volume rather than the boot disk. + +Use the current OpenHands AWS Terraform module when AWS Terraform is selected. Its default `hostname_mode = "wildcard"` maps to `Simple` in the Admin Console. Use `legacy` only to reproduce an existing Legacy installation; use manual infrastructure when every hostname must be customized. Review the complete Terraform plan before applying. -For a manual VM, require the documented CPU, memory, disk, latency, OS, systemd, root access, inbound ports, local ports, and outbound destinations. +For a manual VM, require the documented CPU, memory, disk, latency, Linux x86-64, systemd, root access, inbound ports, local ports, and outbound destinations. Ubuntu 24.04 LTS is recommended. If the default stronger sandbox isolation or Docker-in-sandbox is required, the host kernel must be 6.3 or newer; the standard isolation mode does not support Docker-in-sandbox. -Run read-only preflights on the target VM: +Run read-only preflights on the target VM, setting the planned data path and isolation mode: ```bash +DATA_PATH=/path/to/data-volume \ +MIN_DATA_DISK_GIB="${PLANNED_DATA_DISK_GIB:?set from approved sizing plan}" \ +SANDBOX_ISOLATION=sysbox \ scripts/check_host_preflight.sh scripts/check_dns.sh simple scripts/check_tls_files.sh wildcard @@ -54,12 +65,12 @@ Resolve failures before obtaining approval to run the installer. Read `reference ### 3. Review the Installer Operation -Use only commands copied from the customer's installer dashboard for the chosen release. Before execution: +Use only commands copied from the customer's installer dashboard for the chosen release. In the dashboard, name the instance and select **Outbound requests allowed** for Network Availability. Before execution: 1. Confirm the VM and base domain. 2. Confirm the installer-side instance name is not being confused with the cloud resource name. 3. Confirm the license and TLS file paths exist without printing their contents. -4. Confirm host, DNS, port, and outbound preflights passed. +4. Confirm host, DNS, port, outbound, sizing, disk, and isolation preflights passed. 5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console. 6. Obtain explicit approval to run the exact dashboard-provided install command. @@ -67,15 +78,19 @@ Run the interactive installer in a real PTY. Stop rather than scripting around a ### 4. Configure the Admin Console in Layers -Explicitly select `Simple` hostname mode for a fresh installation unless the customer requires manual hostnames. Confirm it matches Terraform `hostname_mode = "wildcard"`; never select `Legacy` merely because an older runbook or Terraform copy uses nested hostnames. Configure and validate only the minimum required layers before the baseline test: +Access the Admin Console at `https://admin.:30000` when TLS was supplied during installation, or `http://:30000` when it was not. For a single-node deployment, continue past the add-node screen. -1. domain and publicly trusted TLS; -2. one LLM provider; -3. database choice and storage durability; -4. core application deployment; -5. first login and organization. +Keep `Simple (default)` hostname mode for a fresh installation unless the customer requires Manual hostnames. Confirm it matches Terraform `hostname_mode = "wildcard"`; keep existing Legacy installations on Legacy. Configure and validate only the minimum required layers before the baseline test: -Read `references/admin-config.md` before applying settings. Treat ConfigValues files as potentially secret-bearing. Preview helper operations before execution. Defer Git provider authentication, integrations, analytics, automations, and advanced settings until the baseline passes. +1. domain, publicly trusted TLS, and any required additional trusted CA; +2. one administrator-managed LLM provider and its exact model identifiers; +3. bundled or prepared external PostgreSQL; +4. sandbox isolation, routing, resources, and lifecycle values sized for the planned peak; +5. GitHub App authentication when GitHub is the selected provider; +6. core application deployment; +7. first login and default organization behavior. + +Read `references/admin-config.md` before saving settings. Treat every populated configuration screen and ConfigValues file as potentially secret-bearing. Defer additional providers, SMTP, proxy overrides, integrations, analytics, automations, plugins, and advanced settings until the baseline passes. ### 5. Prove the Core Product @@ -117,33 +132,31 @@ Support-bundle command and approved support channel: Exclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps. -## Mutating Helper Gate - -Use `scripts/apply_kots_config.sh` in preview mode first: - -```bash -scripts/apply_kots_config.sh \ - --appslug openhands \ - --config-file ./config-values.patch.yaml \ - --current -``` +## Support-Directed ConfigValues Gate -After reviewing impact and obtaining explicit approval, add `--execute`; add `--deploy` only when an immediate deployment is approved. Re-run workload, readiness, storage, and user-path verification after deployment. +The current OpenHands installation workflow uses the Admin Console. Do not use `scripts/apply_kots_config.sh` unless a version-matched OpenHands Support procedure directs a KOTS ConfigValues change. The helper prints its command by default and requires both `--support-directed` and `--execute` before it can mutate configuration. Re-run workload, readiness, storage, and user-path verification after any approved deployment. ## Resources +- OpenHands Enterprise Quick Start: https://docs.openhands.dev/enterprise/quick-start +- OpenHands Enterprise Sizing Guide: https://docs.openhands.dev/enterprise/sizing-guide +- Admin Console Configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration +- Conversations and Sandboxes: https://docs.openhands.dev/enterprise/conversations-and-sandboxes +- Docker in the Agent Sandbox: https://docs.openhands.dev/enterprise/docker-in-sandbox +- Troubleshooting: https://docs.openhands.dev/enterprise/troubleshooting +- VM Log Collection: https://docs.openhands.dev/enterprise/vm-install/log-collection - `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria. -- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and guarded ConfigValues guidance. +- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and Support-directed ConfigValues guidance. - `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation. - `references/backup-and-durability.md`: persistence checks and recovery boundaries. - `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow. - `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates. - `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing. - `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues. -- `scripts/check_host_preflight.sh`: read-only Linux host and port checks. +- `scripts/check_host_preflight.sh`: read-only Linux, sizing, data-disk, isolation, and port checks. - `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks. - `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks. - `scripts/check_outbound.sh`: required outbound reachability checks. - `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary. -- `scripts/apply_kots_config.sh`: preview-first KOTS ConfigValues helper. +- `scripts/apply_kots_config.sh`: OpenHands Support-directed KOTS ConfigValues helper. - `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks. diff --git a/skills/install-openhands-replicated/assets/install-plan.yaml b/skills/install-openhands-replicated/assets/install-plan.yaml index e5a2201e..3843798f 100644 --- a/skills/install-openhands-replicated/assets/install-plan.yaml +++ b/skills/install-openhands-replicated/assets/install-plan.yaml @@ -3,6 +3,8 @@ installation: target_ohe_release: "" installer_version: "" + purpose: "trial-or-rollout" + expected_peak_concurrent_sandboxes: 0 infrastructure_path: "aws-terraform-or-manual-vm" environment_name: "" change_approver: "" @@ -12,11 +14,17 @@ infrastructure: cloud_or_datacenter: "" region_or_site: "" vm_identifier: "" + operating_system: "" + kernel_version: "" cpu_count: 0 memory_gib: 0 - disk_gib: 0 + boot_disk_gib: 0 + data_disk_path: "" + data_disk_gib: 0 + data_disk_expandable: false storage_type: "" disk_p99_write_latency_ms: null + storage_growth_owner: "" network: base_domain: "" @@ -32,6 +40,13 @@ application: llm_provider: "" git_provider: "" database_mode: "embedded-or-external" + sandbox_isolation: "stronger-or-standard" + docker_in_sandbox_required: false + sandbox_routing_mode: "subdomain-or-path" + per_sandbox_cpu_request: "" + per_sandbox_memory_request: "" + per_sandbox_persistent_storage: "" + per_sandbox_ephemeral_storage: "" optional_integrations: [] analytics_enabled: false automations_enabled: false @@ -43,7 +58,10 @@ recovery: restore_procedure: "" validation: + sizing_review: "pending" host_preflight: "pending" + data_disk_preflight: "pending" + isolation_preflight: "pending" dns_preflight: "pending" tls_preflight: "pending" outbound_preflight: "pending" diff --git a/skills/install-openhands-replicated/references/admin-config.md b/skills/install-openhands-replicated/references/admin-config.md index 24f26481..6a760702 100644 --- a/skills/install-openhands-replicated/references/admin-config.md +++ b/skills/install-openhands-replicated/references/admin-config.md @@ -4,7 +4,7 @@ Use the Admin Console for supported settings. Treat a saved configuration as a m ## Domain and TLS -Explicitly select `Simple` hostname mode for new installations unless DNS policy requires manual hostnames. The AWS Terraform module calls this same mode `hostname_mode = "wildcard"`; keep the Terraform and Admin Console choices aligned. Do not select `Legacy` merely because an older runbook or copied Terraform directory contains nested hostnames. +Keep `Simple (default)` hostname mode for new installations unless DNS or network policy requires a custom hostname for every service. The AWS Terraform module calls Simple `hostname_mode = "wildcard"`; keep the Terraform and Admin Console choices aligned. Use `Manual` for custom hostnames, and do not select `Legacy` merely because an older runbook or copied Terraform directory contains nested hostnames. In Simple mode, all service names sit directly under the base domain: @@ -20,9 +20,11 @@ runtime-api. Keep existing Legacy installations on their current layout unless hostname migration is the approved change. Legacy layouts can include `auth.app.` and `.runtime.`. +For Manual mode, record the application, analytics, authentication, LLM proxy, Runtime API, and runtime base hostnames. Provision DNS, certificates, OAuth callbacks, and webhook callbacks for the complete set. `Additional Permitted CORS Origins` must contain browser origins with scheme and host only, without a path or trailing slash. + Use a publicly trusted wildcard certificate for customer-facing installations whenever possible. Include intermediate certificates and verify that the private key matches the server certificate without printing either value. -Self-signed certificates are not supported for the OpenHands application. A private CA requires every browser, OAuth provider, and webhook sender to trust the CA; otherwise callbacks can fail TLS validation. +Self-signed certificates are not supported for the OpenHands application. Use `Additional Trusted CA Certificates` for a private CA or TLS-inspecting proxy, but every external OAuth and webhook provider that calls OpenHands must also trust that CA. If certificates are not passed during installation, use the Admin Console certificate upload flow. Store local certificate and key files outside repositories with restrictive permissions and remove temporary copies after use. @@ -32,7 +34,9 @@ Subdomain routing in Simple mode requires wildcard coverage for `*. ## LLM Provider -Configure one working provider first. For Bedrock, verify: +Configure one working administrator-managed provider first. Current documented choices include Anthropic, OpenAI, Google, DeepSeek, Mistral AI, Azure, Groq, OpenRouter, AWS Bedrock, and custom/local LLMs. Use exact provider model identifiers; prefix custom OpenAI-compatible model names with `openai/`. Enable BYOK only when users should be allowed to add their own provider credentials. + +For Bedrock, verify: - AWS auth mode is correct: access key/secret or EC2 instance profile. - Region has access to the chosen model. @@ -59,23 +63,40 @@ http://openhands-litellm:4000 ## Sandbox Settings -Common settings: +Current settings include: -- idle time: how long before idle conversations pause; -- deletion time: how long paused runtimes/PVCs are retained before deletion; -- storage size: PVC size per sandbox; -- memory request/limit and CPU request/limit; -- warm runtime count. +- sandbox isolation and routing mode; +- idle time before an inactive conversation pauses; +- deletion time before a paused conversation and its storage are permanently deleted; +- persistent and ephemeral storage size per sandbox; +- memory and CPU requests and limits; +- warm runtime count; +- additional host path mounts in `host_path:container_path[:ro|rw]` form; +- optional `/dev/kvm` passthrough when the node exposes KVM. Interpretation: -- A longer deletion time helps users resume old conversations, but it keeps runtime PVCs around longer. +- The default stronger isolation requires Linux kernel 6.3 or newer and supports Docker-in-sandbox; standard isolation does not support Docker-in-sandbox. +- A single running session is capped at 12 hours even when it is active. It is then force-paused, and resuming starts a new 12-hour window. +- A longer deletion time helps users resume old conversations, but it keeps runtime storage around longer. - A warm runtime can improve start latency, but it must match the environment needed by the conversation. If a warm runtime lacks required secrets/env vars, the request may cold-start anyway. -- More running sandboxes consume memory and CPU. On small single-node installs, too many active runtimes can indirectly make login and API paths feel unstable. +- Resource requests are scheduling reservations. Multiply per-sandbox requests by expected peak concurrent sandboxes and leave capacity for platform services. +- Host mounts and KVM expand sandbox access to host resources. Enable them only for a reviewed requirement. + +## Default Organization + +Decide whether the first signed-in user should create and own a default organization, whether later signed-in users should join it automatically, and whether personal workspaces should be hidden. These options are additive: disabling them later does not delete organizations, remove members, or delete hidden personal data. + +## SMTP and Proxy + +Configure SMTP only when budget alerts or administrator notifications are required. Match implicit SSL and STARTTLS to the mail server rather than enabling both by assumption. + +When outbound traffic uses a corporate proxy, configure `HTTP_PROXY`, `HTTPS_PROXY`, and any additional `NO_PROXY` hosts through the Admin Console. Keep SSL verification enabled and add the proxy CA under `Additional Trusted CA Certificates` instead of disabling certificate verification. + ## Declarative KOTS Config -Prefer the Admin Console for interactive customer configuration. Use a small KOTS `ConfigValues` merge patch only when the operator requires repeatable declarative configuration and the target release supports the referenced keys: +Use the Admin Console for the documented installation workflow. Use a KOTS `ConfigValues` merge patch only when a version-matched OpenHands Support procedure directs it and confirms the referenced keys: ```yaml apiVersion: kots.io/v1beta1 @@ -88,22 +109,24 @@ spec: Treat ConfigValues files as potentially secret-bearing. Keep them outside repositories, restrict permissions, avoid shell tracing, and do not paste their contents into chat or tickets. -Preview the command first: +After confirming the Support procedure, preview the command first: ```bash scripts/apply_kots_config.sh \ --appslug openhands \ --config-file ./config-values.patch.yaml \ - --current + --current \ + --support-directed ``` -After reviewing the preview and obtaining approval, execute without deployment: +After reviewing the preview and obtaining administrator approval, execute without deployment: ```bash scripts/apply_kots_config.sh \ --appslug openhands \ --config-file ./config-values.patch.yaml \ --current \ + --support-directed \ --execute ``` diff --git a/skills/install-openhands-replicated/references/backup-and-durability.md b/skills/install-openhands-replicated/references/backup-and-durability.md index a998ed15..7831ce04 100644 --- a/skills/install-openhands-replicated/references/backup-and-durability.md +++ b/skills/install-openhands-replicated/references/backup-and-durability.md @@ -1,8 +1,10 @@ # Backup And Durability +For a rollout, place application data on a separate expandable volume rather than the boot disk. Size the starting capacity from expected peak concurrent sandboxes, per-sandbox storage, retention, and growth. The current Sizing Guide starts the 15-sandbox Embedded Cluster tier at a 1 TiB SSD data disk. + At minimum, confirm the main OpenHands Postgres data directory is PVC-backed before production/demo use or any redeploy. -Run on the target VM or from an operator environment with cluster access: +Run on the target VM or from an operator environment with read-only cluster access: ```bash scripts/preflight_storage_guard.sh openhands diff --git a/skills/install-openhands-replicated/references/install-flow.md b/skills/install-openhands-replicated/references/install-flow.md index 51f5fd21..c90e4f61 100644 --- a/skills/install-openhands-replicated/references/install-flow.md +++ b/skills/install-openhands-replicated/references/install-flow.md @@ -7,8 +7,10 @@ Use this checklist for a new OpenHands Enterprise VM installation delivered thro Capture before changing infrastructure: - target OHE release and installer/Embedded Cluster version; +- trial or rollout intent and expected peak concurrent sandboxes; - AWS Terraform or manual VM path; - base domain, DNS owner, hostname mode, and TLS owner; +- sandbox isolation mode and whether Docker-in-sandbox is required; - LLM provider and authentication owner; - Git provider and optional integrations; - embedded or external PostgreSQL; @@ -19,9 +21,9 @@ Keep installer URLs, license files, private keys, and credentials out of tickets ## Phase 2: Infrastructure Requirements -The current OpenHands Enterprise quick start requires the following for a manual VM: +Size a rollout by expected **peak concurrent sandboxes**. One user can run multiple sandboxes, so user count is only a rough estimate. The current Quick Start trial baseline comfortably supports about 15 concurrent sandboxes: -| Resource | Requirement | +| Resource | Trial baseline | | --- | --- | | CPU | 16 vCPUs | | Memory | 64 GB | @@ -31,6 +33,10 @@ The current OpenHands Enterprise quick start requires the following for a manual | Init system | systemd | | Access | root or sudo | +Use the Sizing Guide for a larger rollout. Its current 15-sandbox starting recommendation is a 16 vCPU / 64 GiB VM with a 1 TiB SSD data disk. Put application data on a separate expandable volume, not the boot disk. Record the planned peak, per-sandbox resource overrides, data path, starting capacity, and growth owner. + +Ubuntu 24.04 LTS is recommended. The default stronger sandbox isolation, required for Docker-in-sandbox, needs Linux kernel 6.3 or newer. If Docker-in-sandbox is not required, the standard isolation runtime avoids the Sysbox kernel requirement. + Inbound TCP ports: ```text @@ -46,6 +52,9 @@ Local ports that must be available before installation: Run on the target VM: ```bash +DATA_PATH=/path/to/data-volume \ +MIN_DATA_DISK_GIB="${PLANNED_DATA_DISK_GIB:?set from approved sizing plan}" \ +SANDBOX_ISOLATION=sysbox \ scripts/check_host_preflight.sh scripts/check_outbound.sh ``` @@ -106,12 +115,14 @@ Resolve all preflight failures before running the installer. Obtain the version-specific commands from the customer's installer dashboard. The normal sequence is: -1. select the OHE version; -2. download the installation assets with the dashboard-provided command; -3. extract the assets, including the license file; -4. review the exact install command and TLS paths; -5. obtain explicit approval; -6. run the install command in a real interactive PTY. +1. register or sign in to the installer dashboard; +2. name the instance and select **Outbound requests allowed** for Network Availability; +3. select the OHE version; +4. download the installation assets with the dashboard-provided command; +5. extract the assets, including the license file; +6. review the exact install command and TLS paths; +7. obtain explicit approval; +8. run the install command in a real interactive PTY. A representative command shape is: @@ -123,13 +134,19 @@ sudo ./openhands install --license \ Do not substitute a representative command for the dashboard-provided command. Do not expose the dashboard download URL or license contents. -If installation fails after preflights pass, collect a support bundle with the installed application binary: +If installation did not complete, collect a support bundle with the original installer from its extracted directory: ```bash sudo ./openhands support-bundle ``` -Treat the bundle as sensitive and share it only through the approved support channel. +After installation, use the installed application binary: + +```bash +sudo /var/lib/embedded-cluster/bin/openhands support-bundle +``` + +Treat the bundle as sensitive. Open a support ticket through the approved portal and attach the archive, or mention a **Send bundle to vendor** upload. Do not change Kubernetes resources while investigating unless directed by OpenHands Support. ## Headless and Declarative Boundary @@ -138,23 +155,26 @@ Do not claim a fully headless installation unless the target OHE release exposes - use the installer dashboard for version-specific download and license commands; - run the interactive installer in a real PTY; - complete required Admin Console steps with guided ClickOps; -- use KOTS ConfigValues only for documented keys and preview each merge; +- use KOTS ConfigValues only under a version-matched OpenHands Support procedure; - keep `assets/install-plan.yaml` as a non-secret planning record, not deployment input. When headless installation is required, collect the target binary's `install --help`, the release-specific schema, secret-injection method, and rollback procedure from official documentation or OpenHands Support before implementation. ## Phase 6: Admin Console Configuration -For a single-node deployment, continue past the add-node screen. Configure in layers: +Open `https://admin.:30000` when TLS was supplied during installation, or `http://:30000` when it was omitted. In the latter case, upload the Admin Console certificate before configuring OpenHands. For a single-node deployment, continue past the add-node screen. + +Configure in layers: -1. Simple hostname mode and base domain; -2. certificate and private key; -3. one LLM provider; -4. database choice; -5. core application deployment; -6. first login and organization; -7. Git provider authentication; -8. optional integrations, analytics, and automations. +1. `Simple (default)` hostname mode and base domain; +2. certificate, private key, and optional additional trusted CA; +3. one administrator-managed LLM provider and exact model IDs; +4. bundled or prepared external PostgreSQL; +5. sandbox isolation, routing, resources, and lifecycle settings; +6. GitHub App authentication when GitHub is selected; +7. core application deployment; +8. first login and default organization behavior; +9. optional integrations, SMTP, proxy, analytics, automations, plugins, and advanced options. Wait for deployment status to reach Ready and inspect resource details before moving to user-path validation. @@ -180,7 +200,12 @@ Provide versions, topology, hostnames, enabled features, smoke-test evidence, ba ## Official References -- OpenHands Enterprise quick start: https://docs.openhands.dev/enterprise/quick-start -- Admin Console configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration +- OpenHands Enterprise Quick Start: https://docs.openhands.dev/enterprise/quick-start +- OpenHands Enterprise Sizing Guide: https://docs.openhands.dev/enterprise/sizing-guide +- Admin Console Configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration +- Conversations and Sandboxes: https://docs.openhands.dev/enterprise/conversations-and-sandboxes +- Docker in the Agent Sandbox: https://docs.openhands.dev/enterprise/docker-in-sandbox +- Troubleshooting: https://docs.openhands.dev/enterprise/troubleshooting +- VM Log Collection: https://docs.openhands.dev/enterprise/vm-install/log-collection - Replicated Embedded Cluster installation: https://docs.replicated.com/enterprise/installing-embedded - Replicated requirements: https://docs.replicated.com/enterprise/installing-embedded-requirements diff --git a/skills/install-openhands-replicated/references/operator-requests.md b/skills/install-openhands-replicated/references/operator-requests.md index 00e72798..7d71a066 100644 --- a/skills/install-openhands-replicated/references/operator-requests.md +++ b/skills/install-openhands-replicated/references/operator-requests.md @@ -58,18 +58,30 @@ Required by: ```text Subject: VM prerequisites for OpenHands Enterprise -Please provide a dedicated Linux x86-64 VM with: +Expected peak concurrent sandboxes: +Sandbox isolation: +Docker-in-sandbox required: + +Please provide a dedicated Linux x86-64 VM sized from the current OpenHands Enterprise Sizing Guide. For the Quick Start trial baseline: - 16 vCPUs - 64 GB memory -- 200 GB disk +- 200 GB disk minimum - disk P99 write latency no greater than 10 ms - systemd - root or sudo access for the installation operator +Ubuntu 24.04 LTS is recommended. If the default stronger sandbox isolation or Docker-in-sandbox is required, provide Linux kernel 6.3 or newer. + +For rollout use, provide a separate expandable SSD data volume rather than storing application data on the boot disk. The current 15-sandbox starting recommendation is 1 TiB. + Please identify: - VM hostname and environment - cloud region or datacenter +- operating system and kernel version +- boot disk and data disk sizes +- planned data mount path - storage class/type and provisioned IOPS/throughput +- data-volume growth owner - administrator access method - backup/snapshot owner diff --git a/skills/install-openhands-replicated/scripts/apply_kots_config.sh b/skills/install-openhands-replicated/scripts/apply_kots_config.sh index 9ae04172..f3c4d326 100755 --- a/skills/install-openhands-replicated/scripts/apply_kots_config.sh +++ b/skills/install-openhands-replicated/scripts/apply_kots_config.sh @@ -5,8 +5,9 @@ usage() { cat >&2 <<'EOF' usage: apply_kots_config.sh --appslug --config-file (--current | --sequence ) [options] -Prints the KOTS ConfigValues command by default without executing it. Add ---execute only after the specific operation has been reviewed and approved. +Use only under a version-matched OpenHands Support procedure. Pass +--support-directed to attest that requirement, then review the printed command. +Add --execute only after the administrator approves the specific operation. Add --deploy only when an immediate rollout is also approved. Options: @@ -14,6 +15,7 @@ Options: --app-namespace OpenHands app namespace for guard checks. Default: openhands --current Use the currently deployed version as the base --sequence Use a specific app sequence as the base + --support-directed Confirm a version-matched Support procedure directs this change --execute Execute the config merge; otherwise print a preview --deploy Deploy the resulting sequence after setting config --skip-guard Skip storage guard before/after an approved deployment @@ -28,6 +30,7 @@ KOTS_NAMESPACE="kotsadm" APP_NAMESPACE="openhands" APPSLUG="" CONFIG_FILE="" +SUPPORT_DIRECTED=0 EXECUTE=0 DEPLOY=0 RUN_GUARD=1 @@ -60,6 +63,10 @@ while [[ $# -gt 0 ]]; do SEQUENCE="${2:-}" shift 2 ;; + --support-directed) + SUPPORT_DIRECTED=1 + shift + ;; --execute) EXECUTE=1 shift @@ -99,6 +106,11 @@ if [[ "${CURRENT}" != "1" && -z "${SEQUENCE}" ]]; then exit 1 fi +if [[ "${SUPPORT_DIRECTED}" != "1" ]]; then + echo "refusing KOTS configuration: a version-matched OpenHands Support procedure is required; rerun with --support-directed after confirming it" >&2 + exit 1 +fi + if [[ ! -f "${CONFIG_FILE}" ]]; then echo "config file not found: ${CONFIG_FILE}" >&2 exit 1 diff --git a/skills/install-openhands-replicated/scripts/check_host_preflight.sh b/skills/install-openhands-replicated/scripts/check_host_preflight.sh index dfca7dae..32b60b1a 100755 --- a/skills/install-openhands-replicated/scripts/check_host_preflight.sh +++ b/skills/install-openhands-replicated/scripts/check_host_preflight.sh @@ -4,18 +4,34 @@ set -u MIN_CPUS="${MIN_CPUS:-16}" MIN_MEMORY_GIB="${MIN_MEMORY_GIB:-64}" MIN_DISK_GIB="${MIN_DISK_GIB:-200}" +MIN_DATA_DISK_GIB="${MIN_DATA_DISK_GIB:-0}" +MIN_SYSBOX_KERNEL="${MIN_SYSBOX_KERNEL:-6.3}" MAX_DISK_USE_PERCENT="${MAX_DISK_USE_PERCENT:-80}" INSTALL_PATH="${INSTALL_PATH:-/}" +DATA_PATH="${DATA_PATH:-/var/lib}" +SANDBOX_ISOLATION="${SANDBOX_ISOLATION:-sysbox}" local_ports=(2379 7443 9099 10248 10257 10259) edge_ports=(80 443 30000) installer_paths=( + /etc/cni /etc/k0s + /opt/cni /opt/containerd + /run/calico + /run/containerd /run/k0s + /usr/libexec/k0s /usr/local/bin/k0s + /var/lib/calico + /var/lib/cni + /var/lib/containers /var/lib/embedded-cluster /var/lib/kubelet + /var/log/calico + /var/log/containers + /var/log/embedded-cluster + /var/log/pods ) failed=0 @@ -23,12 +39,49 @@ ok() { printf 'OK %s\n' "$*"; } warn() { printf 'WARN %s\n' "$*" >&2; } fail() { printf 'FAIL %s\n' "$*" >&2; failed=1; } + +version_at_least() { + local actual="$1" + local minimum="$2" + local actual_major actual_minor minimum_major minimum_minor + IFS=. read -r actual_major actual_minor _ <<<"${actual}" + IFS=. read -r minimum_major minimum_minor _ <<<"${minimum}" + (( actual_major > minimum_major || (actual_major == minimum_major && actual_minor >= minimum_minor) )) +} + +case "${SANDBOX_ISOLATION}" in + sysbox|stronger|standard) ;; + *) fail "SANDBOX_ISOLATION must be sysbox, stronger, or standard; found ${SANDBOX_ISOLATION}" ;; +esac + if [[ "$(uname -s)" == "Linux" ]]; then ok "operating system is Linux" else fail "target must run Linux; found $(uname -s)" fi + +if [[ -r /etc/os-release ]]; then + # shellcheck disable=SC1091 + source /etc/os-release + if [[ "${ID:-}" == "ubuntu" && "${VERSION_ID:-}" == "24.04" ]]; then + ok "Ubuntu 24.04 LTS detected" + else + warn "Ubuntu 24.04 LTS is recommended; found ${PRETTY_NAME:-unknown distribution}" + fi +else + warn "cannot read /etc/os-release; verify the supported Linux distribution manually" +fi + +kernel_version="$(uname -r | cut -d- -f1)" +if [[ "${SANDBOX_ISOLATION}" == "standard" ]]; then + ok "standard sandbox isolation selected; Docker-in-sandbox is not supported" +elif version_at_least "${kernel_version}" "${MIN_SYSBOX_KERNEL}"; then + ok "kernel ${kernel_version} meets the ${MIN_SYSBOX_KERNEL}+ requirement for stronger sandbox isolation" +else + fail "kernel ${kernel_version} is below ${MIN_SYSBOX_KERNEL}; use a supported newer kernel or select standard isolation when Docker-in-sandbox is not required" +fi + arch="$(uname -m)" if [[ "${arch}" == "x86_64" || "${arch}" == "amd64" ]]; then ok "architecture is ${arch}" @@ -72,6 +125,40 @@ else fail "INSTALL_PATH does not exist: ${INSTALL_PATH}" fi +if [[ -e "${DATA_PATH}" ]]; then + read -r data_disk_kib data_disk_used_percent < <(df -Pk "${DATA_PATH}" | awk 'NR == 2 {gsub(/%/, "", $5); print $2, $5}') + data_disk_gib=$((data_disk_kib / 1024 / 1024)) + if (( MIN_DATA_DISK_GIB == 0 )); then + warn "filesystem containing ${DATA_PATH} has ${data_disk_gib} GiB total; set MIN_DATA_DISK_GIB from the approved sizing plan" + elif (( data_disk_gib < MIN_DATA_DISK_GIB )); then + fail "filesystem containing ${DATA_PATH} has ${data_disk_gib} GiB total; planned minimum is ${MIN_DATA_DISK_GIB} GiB" + else + ok "filesystem containing ${DATA_PATH} has ${data_disk_gib} GiB total; planned minimum is ${MIN_DATA_DISK_GIB} GiB" + fi + if (( data_disk_used_percent < MAX_DISK_USE_PERCENT )); then + ok "filesystem containing ${DATA_PATH} is ${data_disk_used_percent}% full" + else + fail "filesystem containing ${DATA_PATH} is ${data_disk_used_percent}% full; required maximum is below ${MAX_DISK_USE_PERCENT}%" + fi + + if command -v findmnt >/dev/null 2>&1; then + root_source="$(findmnt -n -o SOURCE --target / 2>/dev/null || true)" + data_source="$(findmnt -n -o SOURCE --target "${DATA_PATH}" 2>/dev/null || true)" + if [[ -n "${root_source}" && "${data_source}" == "${root_source}" ]]; then + warn "${DATA_PATH} is on the boot filesystem; rollout guidance recommends a separate expandable data volume" + elif [[ -n "${data_source}" ]]; then + ok "${DATA_PATH} is mounted from ${data_source}, separate from the boot filesystem" + else + warn "could not identify the mount source for ${DATA_PATH}" + fi + else + warn "findmnt is unavailable; verify ${DATA_PATH} uses a separate expandable data volume" + fi +else + fail "DATA_PATH does not exist: ${DATA_PATH}" +fi + + if command -v systemctl >/dev/null 2>&1 && [[ -d /run/systemd/system ]]; then ok "systemd is available" for service in k0scontroller kubelet containerd docker; do From e945ed649aa78500c393bccee4390e72e6add991 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Wed, 26 Aug 2026 13:17:04 -0500 Subject: [PATCH 6/6] docs: focus install skill on operational workflow Co-authored-by: openhands --- skills/index.js | 2 +- skills/install-openhands-replicated/README.md | 4 +- skills/install-openhands-replicated/SKILL.md | 36 +++--- .../references/admin-config.md | 96 +++------------ .../references/backup-and-durability.md | 2 +- .../references/install-flow.md | 110 +++--------------- .../references/operator-requests.md | 23 ++-- 7 files changed, 61 insertions(+), 212 deletions(-) diff --git a/skills/index.js b/skills/index.js index 2d5cad6d..eb4f1d18 100644 --- a/skills/index.js +++ b/skills/index.js @@ -291,7 +291,7 @@ export const SKILLS_CATALOG = [ "name": "install-openhands-replicated", "description": "This skill should be used when the user asks to \"install OpenHands Enterprise\", \"set up OHE on a VM\", \"run an OHE install preflight\", \"configure the Replicated Admin Console\", \"prepare DNS and TLS for OpenHands Enterprise\", or \"validate a Replicated Embedded Cluster installation\". It guides supported AWS Terraform or manual VM installations from scoping through end-to-end validation.", "triggers": [], - "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n> **Failed-install troubleshooting must remain read-only**\n>\n> 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.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, save Admin Console configuration, or deploy a new sequence without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Use the Admin Console for documented deployment settings and the V1 API for documented application settings. Use KOTS ConfigValues only under a version-matched OpenHands Support procedure.\n- Do not patch or edit Kubernetes resources, restart workloads, query databases directly, or rotate installer-managed secrets unless OpenHands Support directs the specific operation and the administrator approves it.\n- Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- trial or rollout intent and expected peak concurrent sandboxes;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- sandbox isolation mode and whether Docker-in-sandbox is required;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nSize the VM from expected **peak concurrent sandboxes**, not user count. The Quick Start baseline is a trial starting point; use the current Sizing Guide for larger rollouts and place application data on a separate expandable volume rather than the boot disk.\n\nUse the current OpenHands AWS Terraform module when AWS Terraform is selected. Its default `hostname_mode = \"wildcard\"` maps to `Simple` in the Admin Console. Use `legacy` only to reproduce an existing Legacy installation; use manual infrastructure when every hostname must be customized. Review the complete Terraform plan before applying.\n\nFor a manual VM, require the documented CPU, memory, disk, latency, Linux x86-64, systemd, root access, inbound ports, local ports, and outbound destinations. Ubuntu 24.04 LTS is recommended. If the default stronger sandbox isolation or Docker-in-sandbox is required, the host kernel must be 6.3 or newer; the standard isolation mode does not support Docker-in-sandbox.\n\nRun read-only preflights on the target VM, setting the planned data path and isolation mode:\n\n```bash\nDATA_PATH=/path/to/data-volume \\\nMIN_DATA_DISK_GIB=\"${PLANNED_DATA_DISK_GIB:?set from approved sizing plan}\" \\\nSANDBOX_ISOLATION=sysbox \\\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. In the dashboard, name the instance and select **Outbound requests allowed** for Network Availability. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, outbound, sizing, disk, and isolation preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nAccess the Admin Console at `https://admin.:30000` when TLS was supplied during installation, or `http://:30000` when it was not. For a single-node deployment, continue past the add-node screen.\n\nKeep `Simple (default)` hostname mode for a fresh installation unless the customer requires Manual hostnames. Confirm it matches Terraform `hostname_mode = \"wildcard\"`; keep existing Legacy installations on Legacy. Configure and validate only the minimum required layers before the baseline test:\n\n1. domain, publicly trusted TLS, and any required additional trusted CA;\n2. one administrator-managed LLM provider and its exact model identifiers;\n3. bundled or prepared external PostgreSQL;\n4. sandbox isolation, routing, resources, and lifecycle values sized for the planned peak;\n5. GitHub App authentication when GitHub is the selected provider;\n6. core application deployment;\n7. first login and default organization behavior.\n\nRead `references/admin-config.md` before saving settings. Treat every populated configuration screen and ConfigValues file as potentially secret-bearing. Defer additional providers, SMTP, proxy overrides, integrations, analytics, automations, plugins, and advanced settings until the baseline passes.\n\n### 5. Prove the Core Product\n\nOn a fresh install, validate the baseline before adding optional configuration. Create one simple conversation through the UI or V1 API and confirm that its sandbox reaches `READY`. If the baseline is broken, report it as a platform or product issue rather than patching around it with infrastructure changes. Treat a fresh install that cannot start a sandbox as a bug, not a configuration task.\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation reaches `READY` and finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Support-Directed ConfigValues Gate\n\nThe current OpenHands installation workflow uses the Admin Console. Do not use `scripts/apply_kots_config.sh` unless a version-matched OpenHands Support procedure directs a KOTS ConfigValues change. The helper prints its command by default and requires both `--support-directed` and `--execute` before it can mutate configuration. Re-run workload, readiness, storage, and user-path verification after any approved deployment.\n\n## Resources\n\n- OpenHands Enterprise Quick Start: https://docs.openhands.dev/enterprise/quick-start\n- OpenHands Enterprise Sizing Guide: https://docs.openhands.dev/enterprise/sizing-guide\n- Admin Console Configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration\n- Conversations and Sandboxes: https://docs.openhands.dev/enterprise/conversations-and-sandboxes\n- Docker in the Agent Sandbox: https://docs.openhands.dev/enterprise/docker-in-sandbox\n- Troubleshooting: https://docs.openhands.dev/enterprise/troubleshooting\n- VM Log Collection: https://docs.openhands.dev/enterprise/vm-install/log-collection\n- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria.\n- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and Support-directed ConfigValues guidance.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux, sizing, data-disk, isolation, and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: OpenHands Support-directed KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", + "content": "# Install OpenHands Enterprise on Replicated\n\nGuide a customer or field engineer from installation scoping to a usable OpenHands Enterprise deployment. Treat a green Replicated deployment as an intermediate milestone; prove the user workflows that are in scope.\n\n> **Failed-install troubleshooting must remain read-only**\n>\n> 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.\n\n## Documentation Source of Truth\n\nThis version was synchronized with the latest available official OpenHands Enterprise installation, sizing, Admin Console, sandbox, troubleshooting, and VM log-collection documentation. Before acting, use the linked official pages and the customer's installer dashboard as the source of truth for release-specific values and UI steps. This skill intentionally focuses on decisions, safety gates, reusable checks, and completion evidence rather than reproducing the documentation.\n\n## Safety Contract\n\n- Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, save Admin Console configuration, or deploy a new sequence without explicit approval for that exact operation.\n- Obtain the current installer command, license bundle, release channel, and target OHE version from the customer's installer dashboard. Treat download URLs, license files, tokens, private keys, and provider credentials as secrets. Never paste or log their values.\n- State the command category, expected impact, prerequisites, rollback boundary, and verification plan before each mutating phase.\n- Use the Admin Console for documented deployment settings and the V1 API for documented application settings. Use KOTS ConfigValues only under a version-matched OpenHands Support procedure.\n- Do not patch or edit Kubernetes resources, restart workloads, query databases directly, or rotate installer-managed secrets unless OpenHands Support directs the specific operation and the administrator approves it.\n- Do not bypass host preflights except under a version-matched procedure from OpenHands or Replicated Support.\n- Keep temporary secret-bearing files permission-restricted and outside repositories. Remove them after the supported configuration surface has consumed them.\n- Use supported defaults first. Add integrations and operational overrides only when they are explicit requirements.\n- Stop when the installed version differs from the documentation or command help, storage safety is unclear, or the requested recovery path can destroy state.\n\n## Installation Workflow\n\n### 1. Establish the Contract\n\nRecord:\n\n- OHE target release and installer/Embedded Cluster version shown by the dashboard;\n- trial or rollout intent and expected peak concurrent sandboxes;\n- AWS Terraform or manual VM path;\n- base domain, DNS owner, TLS owner, and hostname mode;\n- sandbox isolation mode and whether Docker-in-sandbox is required;\n- LLM provider and authentication owner;\n- Git provider and optional integrations;\n- embedded or external PostgreSQL and backup expectations;\n- change approver, maintenance window, and support contact.\n\nCopy `assets/install-plan.yaml` outside the skill repository and populate only non-secret scope and validation state. Do not represent it as a deployable headless configuration file. Draft missing DNS, firewall, certificate, or access requests from `references/operator-requests.md` before changing infrastructure.\n\n### 2. Provision or Inspect Infrastructure\n\nUse the current Quick Start and Sizing Guide to size for **peak concurrent sandboxes**. Record the approved capacity, data-volume path, isolation choice, and growth owner in `assets/install-plan.yaml`; do not cache sizing tables in this skill.\n\nFor AWS, use the Terraform module linked from the current Quick Start and review the complete plan before applying. For a manual VM, verify the documented host, storage, port, and outbound requirements. Run the reusable read-only checks with the approved data capacity and isolation mode:\n\n```bash\nDATA_PATH=/path/to/data-volume \\\nMIN_DATA_DISK_GIB=\"${PLANNED_DATA_DISK_GIB:?set from approved sizing plan}\" \\\nSANDBOX_ISOLATION=sysbox \\\nscripts/check_host_preflight.sh\nscripts/check_dns.sh simple\nscripts/check_tls_files.sh wildcard\nscripts/check_outbound.sh \n```\n\nResolve failures before obtaining approval to run the installer. Read `references/install-flow.md` for the current requirements and phased checklist.\n\n### 3. Review the Installer Operation\n\nUse only commands copied from the customer's installer dashboard for the chosen release. Before execution:\n\n1. Confirm the VM and base domain.\n2. Confirm the installer-side instance name is not being confused with the cloud resource name.\n3. Confirm the license and TLS file paths exist without printing their contents.\n4. Confirm host, DNS, port, outbound, sizing, disk, and isolation preflights passed.\n5. Explain that installation creates system services, Kubernetes state, storage, and an Admin Console.\n6. Obtain explicit approval to run the exact dashboard-provided install command.\n\nRun the interactive installer in a real PTY. Stop rather than scripting around an unexpected password or terminal prompt. Do not claim a headless installation from the non-secret planning asset; require a documented release-specific schema and secret-input method before automating ClickOps.\n\n### 4. Configure the Admin Console in Layers\n\nFollow the target release's Admin Console documentation and configure only the baseline needed for validation:\n\n1. domain and TLS;\n2. one administrator-managed LLM provider;\n3. database and sandbox settings sized from the approved plan;\n4. required Git authentication;\n5. deployment, first login, and organization behavior.\n\nBefore saving, review the intended values, expected restarts, rollback boundary, and verification plan, then obtain explicit approval. Treat populated screens as secret-bearing and defer optional integrations and advanced settings until the baseline passes. Use `references/admin-config.md` for the approval checklist and Support-only escape hatch, not as a substitute for the official field reference.\n\n### 5. Prove the Core Product\n\nOn a fresh install, validate the baseline before adding optional configuration. Create one simple conversation through the UI or V1 API and confirm that its sandbox reaches `READY`. If the baseline is broken, report it as a platform or product issue rather than patching around it with infrastructure changes. Treat a fresh install that cannot start a sandbox as a bug, not a configuration task.\n\nDo not declare completion from pod readiness alone. Verify:\n\n- Admin Console and application TLS validate for the configured hostnames;\n- deployment status is Ready and workloads have no new warning events;\n- login works in a clean browser session;\n- the first organization and bounded API key work;\n- the configured model completes one tiny request;\n- one no-repository conversation reaches `READY` and finishes with an expected marker;\n- repository search and one repository-backed conversation work when a Git provider is in scope.\n\nRun `scripts/preflight_storage_guard.sh ` before declaring the deployment durable. Record what the backup does and does not cover.\n\n### 6. Add Optional Integrations\n\nValidate integrations one at a time after core login, LLM, and conversation paths pass. Use `references/integrations.md` and the focused checklist scripts. Prove a real event or linked account; a reachable callback URL is not sufficient.\n\n### 7. Produce the Handoff\n\nRecord:\n\n```text\nOHE release:\nEmbedded Cluster/installer version:\nInfrastructure path and region/site:\nHostname mode and base domain:\nDatabase and storage class:\nEnabled integrations:\nPreflight evidence:\nCore smoke-test evidence:\nBackup and restore boundary:\nKnown limitations:\nSupport-bundle command and approved support channel:\n```\n\nExclude credentials, license contents, private keys, unredacted ConfigValues, and complete environment dumps.\n\n## Support-Directed ConfigValues Gate\n\nThe current OpenHands installation workflow uses the Admin Console. Do not use `scripts/apply_kots_config.sh` unless a version-matched OpenHands Support procedure directs a KOTS ConfigValues change. The helper prints its command by default and requires both `--support-directed` and `--execute` before it can mutate configuration. Re-run workload, readiness, storage, and user-path verification after any approved deployment.\n\n## Resources\n\n- OpenHands Enterprise Quick Start: https://docs.openhands.dev/enterprise/quick-start\n- OpenHands Enterprise Sizing Guide: https://docs.openhands.dev/enterprise/sizing-guide\n- Admin Console Configuration: https://docs.openhands.dev/enterprise/vm-install/admin-console-configuration\n- Conversations and Sandboxes: https://docs.openhands.dev/enterprise/conversations-and-sandboxes\n- Docker in the Agent Sandbox: https://docs.openhands.dev/enterprise/docker-in-sandbox\n- Troubleshooting: https://docs.openhands.dev/enterprise/troubleshooting\n- VM Log Collection: https://docs.openhands.dev/enterprise/vm-install/log-collection\n- `references/install-flow.md`: phase gates, approval checkpoints, support-bundle routing, and completion criteria.\n- `references/admin-config.md`: Admin Console save checklist and Support-directed ConfigValues escape hatch.\n- `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation.\n- `references/backup-and-durability.md`: persistence checks and recovery boundaries.\n- `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow.\n- `references/operator-requests.md`: customer-ready DNS, firewall, TLS, and access request templates.\n- `references/git-provider-auth.md`: provider-specific application setup, approval, and validation routing.\n- `assets/install-plan.yaml`: non-secret scoping and validation record; never use it as deployable ConfigValues.\n- `scripts/check_host_preflight.sh`: read-only Linux, sizing, data-disk, isolation, and port checks.\n- `scripts/check_dns.sh`: Simple or Legacy hostname resolution checks.\n- `scripts/check_tls_files.sh`: certificate dates, key matching, SAN coverage, and trust-chain checks.\n- `scripts/check_outbound.sh`: required outbound reachability checks.\n- `scripts/summarize_terraform_outputs.sh`: allowlisted, non-sensitive Terraform output summary.\n- `scripts/apply_kots_config.sh`: OpenHands Support-directed KOTS ConfigValues helper.\n- `scripts/preflight_storage_guard.sh`: Postgres PVC, DiskPressure, host-space, and ClickHouse checks.", "category": "environment" }, { diff --git a/skills/install-openhands-replicated/README.md b/skills/install-openhands-replicated/README.md index db54e701..882f914e 100644 --- a/skills/install-openhands-replicated/README.md +++ b/skills/install-openhands-replicated/README.md @@ -21,9 +21,9 @@ Installer download URLs, license files, private keys, provider credentials, Conf ## Current scope -The skill covers sizing by peak concurrent sandboxes, host and network preflight, provider setup guidance, guided Admin Console configuration, post-install verification, and customer-ready IT requests. +This version was synchronized with the latest available official OpenHands Enterprise installation documentation. Those pages and the customer's installer dashboard remain authoritative for release-specific values and UI steps. -Fresh installations use `Simple` hostname mode. In the AWS Terraform module, the matching default is `hostname_mode = "wildcard"`; Legacy is reserved for reproducing an existing Legacy installation. Ubuntu 24.04 LTS is recommended, and the default stronger sandbox isolation requires Linux kernel 6.3 or newer. +The skill adds the durable agent workflow around those docs: scoping decisions, read-only preflights, approval gates, reusable scripts, support escalation, end-to-end validation, and handoff evidence. It deliberately avoids maintaining a second copy of sizing tables, field catalogs, and installer screens. A fully headless install remains conditional on a documented, release-specific installer schema and supported secret-input mechanism. The skill does not infer or invent those interfaces. diff --git a/skills/install-openhands-replicated/SKILL.md b/skills/install-openhands-replicated/SKILL.md index df64b552..25adcb30 100644 --- a/skills/install-openhands-replicated/SKILL.md +++ b/skills/install-openhands-replicated/SKILL.md @@ -11,6 +11,10 @@ Guide a customer or field engineer from installation scoping to a usable OpenHan > > 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. +## Documentation Source of Truth + +This version was synchronized with the latest available official OpenHands Enterprise installation, sizing, Admin Console, sandbox, troubleshooting, and VM log-collection documentation. Before acting, use the linked official pages and the customer's installer dashboard as the source of truth for release-specific values and UI steps. This skill intentionally focuses on decisions, safety gates, reusable checks, and completion evidence rather than reproducing the documentation. + ## Safety Contract - Start with planning and read-only preflight checks. Do not create infrastructure, modify DNS or firewall rules, run the installer, save Admin Console configuration, or deploy a new sequence without explicit approval for that exact operation. @@ -43,13 +47,9 @@ Copy `assets/install-plan.yaml` outside the skill repository and populate only n ### 2. Provision or Inspect Infrastructure -Size the VM from expected **peak concurrent sandboxes**, not user count. The Quick Start baseline is a trial starting point; use the current Sizing Guide for larger rollouts and place application data on a separate expandable volume rather than the boot disk. - -Use the current OpenHands AWS Terraform module when AWS Terraform is selected. Its default `hostname_mode = "wildcard"` maps to `Simple` in the Admin Console. Use `legacy` only to reproduce an existing Legacy installation; use manual infrastructure when every hostname must be customized. Review the complete Terraform plan before applying. +Use the current Quick Start and Sizing Guide to size for **peak concurrent sandboxes**. Record the approved capacity, data-volume path, isolation choice, and growth owner in `assets/install-plan.yaml`; do not cache sizing tables in this skill. -For a manual VM, require the documented CPU, memory, disk, latency, Linux x86-64, systemd, root access, inbound ports, local ports, and outbound destinations. Ubuntu 24.04 LTS is recommended. If the default stronger sandbox isolation or Docker-in-sandbox is required, the host kernel must be 6.3 or newer; the standard isolation mode does not support Docker-in-sandbox. - -Run read-only preflights on the target VM, setting the planned data path and isolation mode: +For AWS, use the Terraform module linked from the current Quick Start and review the complete plan before applying. For a manual VM, verify the documented host, storage, port, and outbound requirements. Run the reusable read-only checks with the approved data capacity and isolation mode: ```bash DATA_PATH=/path/to/data-volume \ @@ -65,7 +65,7 @@ Resolve failures before obtaining approval to run the installer. Read `reference ### 3. Review the Installer Operation -Use only commands copied from the customer's installer dashboard for the chosen release. In the dashboard, name the instance and select **Outbound requests allowed** for Network Availability. Before execution: +Use only commands copied from the customer's installer dashboard for the chosen release. Before execution: 1. Confirm the VM and base domain. 2. Confirm the installer-side instance name is not being confused with the cloud resource name. @@ -78,19 +78,15 @@ Run the interactive installer in a real PTY. Stop rather than scripting around a ### 4. Configure the Admin Console in Layers -Access the Admin Console at `https://admin.:30000` when TLS was supplied during installation, or `http://:30000` when it was not. For a single-node deployment, continue past the add-node screen. - -Keep `Simple (default)` hostname mode for a fresh installation unless the customer requires Manual hostnames. Confirm it matches Terraform `hostname_mode = "wildcard"`; keep existing Legacy installations on Legacy. Configure and validate only the minimum required layers before the baseline test: +Follow the target release's Admin Console documentation and configure only the baseline needed for validation: -1. domain, publicly trusted TLS, and any required additional trusted CA; -2. one administrator-managed LLM provider and its exact model identifiers; -3. bundled or prepared external PostgreSQL; -4. sandbox isolation, routing, resources, and lifecycle values sized for the planned peak; -5. GitHub App authentication when GitHub is the selected provider; -6. core application deployment; -7. first login and default organization behavior. +1. domain and TLS; +2. one administrator-managed LLM provider; +3. database and sandbox settings sized from the approved plan; +4. required Git authentication; +5. deployment, first login, and organization behavior. -Read `references/admin-config.md` before saving settings. Treat every populated configuration screen and ConfigValues file as potentially secret-bearing. Defer additional providers, SMTP, proxy overrides, integrations, analytics, automations, plugins, and advanced settings until the baseline passes. +Before saving, review the intended values, expected restarts, rollback boundary, and verification plan, then obtain explicit approval. Treat populated screens as secret-bearing and defer optional integrations and advanced settings until the baseline passes. Use `references/admin-config.md` for the approval checklist and Support-only escape hatch, not as a substitute for the official field reference. ### 5. Prove the Core Product @@ -145,8 +141,8 @@ The current OpenHands installation workflow uses the Admin Console. Do not use ` - Docker in the Agent Sandbox: https://docs.openhands.dev/enterprise/docker-in-sandbox - Troubleshooting: https://docs.openhands.dev/enterprise/troubleshooting - VM Log Collection: https://docs.openhands.dev/enterprise/vm-install/log-collection -- `references/install-flow.md`: current VM requirements, hostname layouts, installer sequence, and completion criteria. -- `references/admin-config.md`: TLS, LLM, database, sandbox, proxy, and Support-directed ConfigValues guidance. +- `references/install-flow.md`: phase gates, approval checkpoints, support-bundle routing, and completion criteria. +- `references/admin-config.md`: Admin Console save checklist and Support-directed ConfigValues escape hatch. - `references/integrations.md`: GitHub, GitLab, Bitbucket, Jira, Slack, analytics, and automation validation. - `references/backup-and-durability.md`: persistence checks and recovery boundaries. - `references/blue-green-reinstall.md`: separately approved rebuild and cutover workflow. diff --git a/skills/install-openhands-replicated/references/admin-config.md b/skills/install-openhands-replicated/references/admin-config.md index 6a760702..2511c0fc 100644 --- a/skills/install-openhands-replicated/references/admin-config.md +++ b/skills/install-openhands-replicated/references/admin-config.md @@ -1,97 +1,35 @@ # Admin Console Configuration -Use the Admin Console for supported settings. Treat a saved configuration as a mutating operation that can restart components. Review the intended values, impact, and verification plan before selecting Deploy. +This version was synchronized with the latest available official Admin Console documentation. Use that documentation as the field reference; this file defines the review and approval boundary. -## Domain and TLS +Treat every save or deployment as a mutating operation that can restart components. Before approval, record: -Keep `Simple (default)` hostname mode for new installations unless DNS or network policy requires a custom hostname for every service. The AWS Terraform module calls Simple `hostname_mode = "wildcard"`; keep the Terraform and Admin Console choices aligned. Use `Manual` for custom hostnames, and do not select `Legacy` merely because an older runbook or copied Terraform directory contains nested hostnames. +- the target release and authoritative field reference; +- changed fields and why they are required; +- affected hostnames, callbacks, trust chains, or external systems; +- expected restarts and user impact; +- rollback boundary and post-save verification; +- the administrator who approves the exact operation. -In Simple mode, all service names sit directly under the base domain: +## Domain, TLS, and Routing -```text -admin. -app. -auth. -analytics. -llm-proxy. -runtime-api. --runtime. -``` - -Keep existing Legacy installations on their current layout unless hostname migration is the approved change. Legacy layouts can include `auth.app.` and `.runtime.`. - -For Manual mode, record the application, analytics, authentication, LLM proxy, Runtime API, and runtime base hostnames. Provision DNS, certificates, OAuth callbacks, and webhook callbacks for the complete set. `Additional Permitted CORS Origins` must contain browser origins with scheme and host only, without a path or trailing slash. - -Use a publicly trusted wildcard certificate for customer-facing installations whenever possible. Include intermediate certificates and verify that the private key matches the server certificate without printing either value. - -Self-signed certificates are not supported for the OpenHands application. Use `Additional Trusted CA Certificates` for a private CA or TLS-inspecting proxy, but every external OAuth and webhook provider that calls OpenHands must also trust that CA. - -If certificates are not passed during installation, use the Admin Console certificate upload flow. Store local certificate and key files outside repositories with restrictive permissions and remove temporary copies after use. +Choose the documented hostname and routing mode for the installation. Preserve existing modes unless migration is the approved task. Record and validate the complete DNS, certificate, CORS, OAuth callback, and webhook callback set; do not infer it from an older runbook. -## Runtime Routing - -Subdomain routing in Simple mode requires wildcard coverage for `*.`. If wildcard certificates are unavailable, use the target release's supported path-based routing mode and provision the complete SAN set from its documentation. +Keep certificate and key files outside repositories, do not print their contents, and validate them with `scripts/check_tls_files.sh`. Use the documented trusted-CA mechanism rather than disabling certificate verification. ## LLM Provider -Configure one working administrator-managed provider first. Current documented choices include Anthropic, OpenAI, Google, DeepSeek, Mistral AI, Azure, Groq, OpenRouter, AWS Bedrock, and custom/local LLMs. Use exact provider model identifiers; prefix custom OpenAI-compatible model names with `openai/`. Enable BYOK only when users should be allowed to add their own provider credentials. - -For Bedrock, verify: - -- AWS auth mode is correct: access key/secret or EC2 instance profile. -- Region has access to the chosen model. -- Model ID is the exact Bedrock or inference-profile ID exposed by AWS. -- LiteLLM model alias is visible through `/v1/models`. - -For current Bedrock model IDs, query AWS rather than relying on stale notes: - -```bash -aws bedrock list-foundation-models --region -``` - -If OpenHands profiles use the internal proxy, model names should normally look like: - -```text -litellm_proxy/ -``` - -and the base URL should be: - -```text -http://openhands-litellm:4000 -``` - -## Sandbox Settings - -Current settings include: - -- sandbox isolation and routing mode; -- idle time before an inactive conversation pauses; -- deletion time before a paused conversation and its storage are permanently deleted; -- persistent and ephemeral storage size per sandbox; -- memory and CPU requests and limits; -- warm runtime count; -- additional host path mounts in `host_path:container_path[:ro|rw]` form; -- optional `/dev/kvm` passthrough when the node exposes KVM. - -Interpretation: - -- The default stronger isolation requires Linux kernel 6.3 or newer and supports Docker-in-sandbox; standard isolation does not support Docker-in-sandbox. -- A single running session is capped at 12 hours even when it is active. It is then force-paused, and resuming starts a new 12-hour window. -- A longer deletion time helps users resume old conversations, but it keeps runtime storage around longer. -- A warm runtime can improve start latency, but it must match the environment needed by the conversation. If a warm runtime lacks required secrets/env vars, the request may cold-start anyway. -- Resource requests are scheduling reservations. Multiply per-sandbox requests by expected peak concurrent sandboxes and leave capacity for platform services. -- Host mounts and KVM expand sandbox access to host resources. Enable them only for a reviewed requirement. +Configure one administrator-managed provider for the baseline. Resolve provider, authentication, region, model identifier, and BYOK choices from the current documentation and provider API rather than copied examples. Verify the configured model appears through the supported model-discovery path and completes one minimal request before adding another provider. -## Default Organization +## Sandbox and Organization Decisions -Decide whether the first signed-in user should create and own a default organization, whether later signed-in users should join it automatically, and whether personal workspaces should be hidden. These options are additive: disabling them later does not delete organizations, remove members, or delete hidden personal data. +Derive isolation, routing, per-sandbox resources, lifecycle, and warm-capacity values from the approved plan and current sandbox documentation. Confirm the aggregate fits the host. Treat host mounts, device passthrough, extended retention, and weaker isolation as explicit risk decisions that require a documented need. -## SMTP and Proxy +Record intended first-user, default-organization, membership, and personal-workspace behavior before deployment. Validate the resulting behavior with a clean first login; do not assume disabling an option reverses previously created state. -Configure SMTP only when budget alerts or administrator notifications are required. Match implicit SSL and STARTTLS to the mail server rather than enabling both by assumption. +## Optional Settings -When outbound traffic uses a corporate proxy, configure `HTTP_PROXY`, `HTTPS_PROXY`, and any additional `NO_PROXY` hosts through the Admin Console. Keep SSL verification enabled and add the proxy CA under `Additional Trusted CA Certificates` instead of disabling certificate verification. +Defer SMTP, proxy, analytics, automations, plugins, and other optional settings until the baseline passes. For required proxies or private CAs, keep certificate verification enabled and use the documented trust configuration. ## Declarative KOTS Config diff --git a/skills/install-openhands-replicated/references/backup-and-durability.md b/skills/install-openhands-replicated/references/backup-and-durability.md index 7831ce04..316b8986 100644 --- a/skills/install-openhands-replicated/references/backup-and-durability.md +++ b/skills/install-openhands-replicated/references/backup-and-durability.md @@ -1,6 +1,6 @@ # Backup And Durability -For a rollout, place application data on a separate expandable volume rather than the boot disk. Size the starting capacity from expected peak concurrent sandboxes, per-sandbox storage, retention, and growth. The current Sizing Guide starts the 15-sandbox Embedded Cluster tier at a 1 TiB SSD data disk. +For a rollout, use the current Sizing Guide to select an approved starting capacity from expected peak concurrent sandboxes, per-sandbox storage, retention, and growth. Place application data on a separate expandable volume rather than the boot disk. At minimum, confirm the main OpenHands Postgres data directory is PVC-backed before production/demo use or any redeploy. diff --git a/skills/install-openhands-replicated/references/install-flow.md b/skills/install-openhands-replicated/references/install-flow.md index c90e4f61..3780133e 100644 --- a/skills/install-openhands-replicated/references/install-flow.md +++ b/skills/install-openhands-replicated/references/install-flow.md @@ -1,6 +1,6 @@ # Install Flow -Use this checklist for a new OpenHands Enterprise VM installation delivered through Replicated Embedded Cluster. Confirm current values against the target OHE release and the customer's installer dashboard. +Use this checklist for a new OpenHands Enterprise VM installation delivered through Replicated Embedded Cluster. This version was synchronized with the latest available official Enterprise documentation, but the target release documentation and customer's installer dashboard remain authoritative. ## Phase 1: Scope and Approval @@ -21,35 +21,9 @@ Keep installer URLs, license files, private keys, and credentials out of tickets ## Phase 2: Infrastructure Requirements -Size a rollout by expected **peak concurrent sandboxes**. One user can run multiple sandboxes, so user count is only a rough estimate. The current Quick Start trial baseline comfortably supports about 15 concurrent sandboxes: +Use the current Quick Start, Sizing Guide, and installer host requirements. Record the approved peak concurrent sandboxes, capacity, data path, isolation mode, ports, outbound endpoints, and growth owner in the non-secret install plan. -| Resource | Trial baseline | -| --- | --- | -| CPU | 16 vCPUs | -| Memory | 64 GB | -| Disk | 200 GB | -| Disk P99 write latency | 10 ms maximum | -| Architecture | Linux x86-64 | -| Init system | systemd | -| Access | root or sudo | - -Use the Sizing Guide for a larger rollout. Its current 15-sandbox starting recommendation is a 16 vCPU / 64 GiB VM with a 1 TiB SSD data disk. Put application data on a separate expandable volume, not the boot disk. Record the planned peak, per-sandbox resource overrides, data path, starting capacity, and growth owner. - -Ubuntu 24.04 LTS is recommended. The default stronger sandbox isolation, required for Docker-in-sandbox, needs Linux kernel 6.3 or newer. If Docker-in-sandbox is not required, the standard isolation runtime avoids the Sysbox kernel requirement. - -Inbound TCP ports: - -```text -80 443 30000 -``` - -Local ports that must be available before installation: - -```text -2379 7443 9099 10248 10257 10259 -``` - -Run on the target VM: +Run the read-only checks on the target VM: ```bash DATA_PATH=/path/to/data-volume \ @@ -59,80 +33,36 @@ scripts/check_host_preflight.sh scripts/check_outbound.sh ``` -Pass each customer-approved LLM, cloud-model, or corporate gateway HTTPS endpoint required by the selected authentication mode. - -The host script cannot prove P99 storage latency without a write benchmark. Rely on the installer host preflight for the final latency check. Do not bypass a failed latency preflight; increase disk IOPS/throughput or use faster storage. +Pass every required customer-approved endpoint to the outbound checker. Rely on the installer preflight for checks this helper cannot safely perform, including storage latency; do not bypass a failure. -For AWS Terraform, use the current module linked by the OpenHands Enterprise quick start. On a fresh installation, explicitly set `hostname_mode = "wildcard"`, which is the Terraform name for Admin Console `Simple` mode. Reserve `hostname_mode = "legacy"` for reproducing an existing Legacy installation. - -Review `terraform plan` before requesting approval for `apply`. Confirm a fresh Simple-mode plan provisions `*.` and does not provision `auth.app.` or `*.runtime.`. Use the allowlisted output helper after apply: +For AWS, use the Terraform module linked from the current Quick Start. Review `terraform plan` before approval and use the allowlisted output helper after apply: ```bash scripts/summarize_terraform_outputs.sh ``` -Do not print the full Terraform output set because it can include sensitive values or local key paths. +Do not print complete Terraform outputs because they can contain sensitive values or local key paths. ## Phase 3: DNS and TLS -The current default is `Simple` hostname mode. A wildcard DNS record and certificate for `*.` cover: +Select the hostname and routing mode from the current Admin Console documentation. Preserve an existing installation's mode unless migration is the approved task, and record the complete hostname, callback, DNS, certificate, and trust requirements before requesting changes. -```text -admin. -app. -auth. -analytics. -llm-proxy. -runtime-api. --runtime. -``` - -Validate the wildcard route with a synthetic runtime name: +Run the matching checks: ```bash scripts/check_dns.sh simple +scripts/check_tls_files.sh wildcard ``` -Older installations can use `Legacy` hostnames such as `auth.app.` and `.runtime.`. Do not migrate an existing installation's hostname mode during unrelated work. For a confirmed Legacy installation, run: - -```bash -scripts/check_dns.sh legacy -``` - -Use a publicly trusted wildcard certificate whenever possible. Self-signed certificates are not supported for the OpenHands application. A private CA requires every browser, OAuth provider, and webhook sender to trust the chain. - -If wildcard certificates are unavailable, select path-based sandbox routing and obtain the complete SAN set documented for the target release. +Use `legacy` only for a confirmed Legacy installation. For Manual hostnames or path-based routing, validate the complete documented host and SAN set rather than assuming wildcard coverage. ## Phase 4: Outbound Preflight -Run outbound checks from the target VM. Required destinations currently include Replicated control-plane endpoints, OpenHands image/chart/update endpoints, GitHub, Traefik charts, Docker Hub, GHCR, and each endpoint required by the selected LLM provider or corporate gateway. - -Treat HTTP responses such as 301, 401, 403, or 405 as reachable. Treat HTTP `000` as a DNS, timeout, proxy, or firewall failure. - -Resolve all preflight failures before running the installer. +Build the endpoint list from the current installation documentation and the selected providers, then run the checks from the target VM. Resolve DNS, timeout, proxy, or firewall failures before running the installer; an authentication or method error can still prove network reachability. ## Phase 5: Installer -Obtain the version-specific commands from the customer's installer dashboard. The normal sequence is: - -1. register or sign in to the installer dashboard; -2. name the instance and select **Outbound requests allowed** for Network Availability; -3. select the OHE version; -4. download the installation assets with the dashboard-provided command; -5. extract the assets, including the license file; -6. review the exact install command and TLS paths; -7. obtain explicit approval; -8. run the install command in a real interactive PTY. - -A representative command shape is: - -```bash -sudo ./openhands install --license \ - --tls-cert \ - --tls-key -``` - -Do not substitute a representative command for the dashboard-provided command. Do not expose the dashboard download URL or license contents. +Use the customer's installer dashboard for the target release. Review the exact download, license, TLS, and install commands without exposing sensitive values; explain the impact and rollback boundary; obtain explicit approval; then run the dashboard-provided installer in a real interactive PTY. Stop on unexpected prompts or version differences rather than inventing flags or workarounds. If installation did not complete, collect a support bundle with the original installer from its extracted directory: @@ -162,21 +92,7 @@ When headless installation is required, collect the target binary's `install --h ## Phase 6: Admin Console Configuration -Open `https://admin.:30000` when TLS was supplied during installation, or `http://:30000` when it was omitted. In the latter case, upload the Admin Console certificate before configuring OpenHands. For a single-node deployment, continue past the add-node screen. - -Configure in layers: - -1. `Simple (default)` hostname mode and base domain; -2. certificate, private key, and optional additional trusted CA; -3. one administrator-managed LLM provider and exact model IDs; -4. bundled or prepared external PostgreSQL; -5. sandbox isolation, routing, resources, and lifecycle settings; -6. GitHub App authentication when GitHub is selected; -7. core application deployment; -8. first login and default organization behavior; -9. optional integrations, SMTP, proxy, analytics, automations, plugins, and advanced options. - -Wait for deployment status to reach Ready and inspect resource details before moving to user-path validation. +Follow the target release's Admin Console field reference. Configure the minimum baseline in layers: domain and TLS, one LLM provider, database and sandbox settings, required Git authentication, deployment, then first login and organization behavior. Review impact and obtain approval before each save or deployment. Defer optional configuration until core validation passes. ## Phase 7: Core Validation diff --git a/skills/install-openhands-replicated/references/operator-requests.md b/skills/install-openhands-replicated/references/operator-requests.md index 7d71a066..8a5d4891 100644 --- a/skills/install-openhands-replicated/references/operator-requests.md +++ b/skills/install-openhands-replicated/references/operator-requests.md @@ -59,27 +59,26 @@ Required by: Subject: VM prerequisites for OpenHands Enterprise Expected peak concurrent sandboxes: -Sandbox isolation: +Sandbox isolation: Docker-in-sandbox required: - -Please provide a dedicated Linux x86-64 VM sized from the current OpenHands Enterprise Sizing Guide. For the Quick Start trial baseline: -- 16 vCPUs -- 64 GB memory -- 200 GB disk minimum -- disk P99 write latency no greater than 10 ms +Sizing Guide reviewed on: + +Please provide a dedicated Linux x86-64 VM that meets the attached approved sizing plan and current OpenHands Enterprise host requirements: +- vCPUs: +- memory: +- boot disk: +- separate expandable data disk: +- data mount path: +- storage latency/IOPS/throughput: +- operating system and kernel: - systemd - root or sudo access for the installation operator -Ubuntu 24.04 LTS is recommended. If the default stronger sandbox isolation or Docker-in-sandbox is required, provide Linux kernel 6.3 or newer. - -For rollout use, provide a separate expandable SSD data volume rather than storing application data on the boot disk. The current 15-sandbox starting recommendation is 1 TiB. - Please identify: - VM hostname and environment - cloud region or datacenter - operating system and kernel version - boot disk and data disk sizes -- planned data mount path - storage class/type and provisioned IOPS/throughput - data-volume growth owner - administrator access method