Runtime Api Configs
Manage warm sandbox pools on OpenHands Enterprise by driving the runtime-api admin endpoints (lis…
by openhands · MIT
The skill
Manage warm sandbox pools on OpenHands Enterprise by driving the runtime-api admin endpoints (list, save, delete warm runtime configurations) from a Python CLI. Use when an OpenHands Enterprise administrator asks to add, update, delete, or inspect custom sandbox images, warm pools, or `warm-runtime-configs`, or when the docs point to `enterprise/custom-sandbox-images/multiple-images-warm-pools`.
Runtime API - Warm Runtime Configurations
This plugin manages the warm sandbox pools used by OpenHands Enterprise. It
replaces the ad-hoc warm-runtime-configs.sh shell script embedded in the
docs and gives administrators a single, testable Python CLI for the same
workflow.
The CLI talks HTTP to the runtime-api service. It never modifies the cluster
directly, and it uses only the Python standard library, so it runs anywhere
python3 is available.
When to use this skill
Reach for this skill whenever the user wants to:
- List the effective warm-runtime configurations on an OHE install.
- Add or update a custom sandbox image (e.g.
openhands-php:8.4-v1) so users can select it from the Settings → Application → Default Sandbox dropdown. - Delete a database-managed configuration, restoring an installer-managed entry with the same name.
- Refresh configurations after upgrading OHE, when API-managed frozen snapshots need to be re-derived from the new installer template.
- Bootstrap credentials (
RUNTIME_API_URL,API_KEY,ADMIN_PASSWORD) from Kubernetes secrets so subsequent runs need no cluster access.
If the user is instead asking how to build a custom sandbox image (Dockerfile, versioning), point them at Building a Custom Image
- image building is out of scope for this skill.
Prerequisites
-
OpenHands Enterprise 0.64.0 or later.
-
Python 3.9+ on the machine running the CLI. No third-party packages.
-
The Runtime API Admin Password:
- VM (Replicated) installs: set via Admin Console → Config → Sandbox Configuration → Runtime API Admin Password.
- Helm installs: the value stored in the
admin-passwordKubernetes secret in the runtime-api namespace. Helm has no Admin Console.
-
Helm installs only: the runtime-api chart must be running in overlay mode and have warm pools enabled, so
v1_currentshows up inlistand can be used as atemplatesource. Set both in your umbrella values:runtime-api: warmRuntimes: enabled: true env: WARM_RUNTIME_CONFIG_OVERLAY: "1"Overlay mode is on by default on Replicated VM installs. Without it on Helm,
listreturns[]on a fresh install andtemplate v1_currentfails.
Setup
On any machine with HTTPS reachability to the runtime-api, export two env vars:
export RUNTIME_API_URL=https://runtime-api.<your-base-domain>
export ADMIN_PASSWORD=<runtime-api-admin-password> # see Prerequisites above
That is the full setup on any install where the runtime-api ingress is
reachable from the machine running the CLI. No kubectl, no SSH, no
cluster access. If the runtime-api is cluster-internal (Helm default), see
the Helm entry in the Advanced section below to port-forward first.
Under the hood, the CLI uses the admin password directly for save and
delete (via the PBKDF2 handshake), and for list and template it logs
in as admin and fetches the default read-only API key over HTTPS from
/api/admin/api-keys.
If you already know the read-only API key (for example, from an operator runbook), export it too and the CLI will skip the extra admin-login round trip on reads:
export API_KEY=<default api key>
If you have kubectl access to the cluster and prefer to pull all three
env vars from Kubernetes secrets in one step, see
Advanced: bootstrap from Kubernetes
at the bottom of this file.
CLI reference
Run with python3 scripts/warm_runtime_configs.py <subcommand>. Each
subcommand exits non-zero on error and prints the runtime-api's HTTP body
on failure.
| Subcommand | Auth | Purpose |
|---|---|---|
list |
API_KEY if set, else admin login |
Print the effective set of configurations. |
template <source> |
API_KEY if set, else admin login |
Fetch a config, strip identity fields, override image/count, print JSON ready to save. |
save <name> [--file F] |
Admin password | Upsert a configuration. Reads JSON from --file or stdin. |
delete <name> |
Admin password | Delete a database-managed configuration. |
bootstrap |
kubectl | Print export lines for RUNTIME_API_URL, API_KEY, ADMIN_PASSWORD. Optional; see Advanced below. |
Full help: python3 scripts/warm_runtime_configs.py --help and
python3 scripts/warm_runtime_configs.py <subcommand> --help.
Typical workflow
Register a new PHP sandbox image once credentials are in the environment:
# 1. Derive a config JSON from the current default, changing only the image
python3 scripts/warm_runtime_configs.py template v1_current \
--image ghcr.io/your-org/openhands-php:8.4-v1 --count 1 \
--output php-web.json
# 2. Save it
python3 scripts/warm_runtime_configs.py save php-web --file php-web.json
# 3. Confirm
python3 scripts/warm_runtime_configs.py list
Within about a minute the pool is ready and php-web appears in
Settings → Application → Default Sandbox.
Deleting an API-managed configuration removes it from the effective set:
python3 scripts/warm_runtime_configs.py delete php-web
delete operates on database rows only, so it 404s for names that have
never been saved through this CLI (installer-managed entries like
v1_current on a fresh install fall in that bucket). In overlay mode, if
you had previously saved a database row that shadowed a same-named
ConfigMap entry, deleting the row reverts to the ConfigMap entry on the
next reconciler cycle.
After an OHE upgrade
Frozen API-managed configurations do not follow release bumps. After every OHE upgrade, re-derive each API-managed configuration from the refreshed default template, keeping each configuration's current image tag and pool size unless you deliberately change them:
# One "name image count" tuple per API-managed config; edit for your fleet.
# Preserving the existing pool count matters: hardcoding it would silently
# shrink pools on every refresh.
while read -r name image count; do
[ -z "$name" ] && continue
python3 scripts/warm_runtime_configs.py template v1_current \
--image "$image" --count "$count" \
| python3 scripts/warm_runtime_configs.py save "$name" --file -
done <<'EOF'
php-web ghcr.io/your-org/openhands-php:8.4-v2 3
ruby-app ghcr.io/your-org/openhands-ruby:3.3-v2 2
node-monorepo ghcr.io/your-org/openhands-node:24-v2 1
EOF
Two caveats worth spelling out:
templaterefreshes the command and environment to match the newv1_current, but it keeps whatever image tag you pass. To actually pick up a new agent-server version, the image itself must be rebuilt against the matching agent-server base. This loop alone does not do that.- Skipping this step leaves configurations pointing at the previous agent-server command/environment, and new conversations fail with a version mismatch until the configurations are updated.
Environment variables
| Variable | Used by | Notes |
|---|---|---|
RUNTIME_API_URL |
all HTTP subcommands | e.g. https://runtime-api.example.com or http://localhost:5000. |
ADMIN_PASSWORD |
save, delete; also list/template when API_KEY is unset |
Runs the PBKDF2 challenge-response handshake. |
ADMIN_TOKEN |
Anywhere ADMIN_PASSWORD is used |
Pre-obtained admin JWT. When set, it wins over ADMIN_PASSWORD and skips the handshake. |
API_KEY |
list, template (optional) |
Sent as X-API-Key. Optional: when unset, the CLI fetches the default key over HTTPS via admin login. |
NAMESPACE |
bootstrap |
Defaults to openhands. Overridable via --namespace. |
Advanced: bootstrap from Kubernetes
bootstrap extracts all three env vars from Kubernetes secrets in one
step. Handy for cluster operators and CI, but the default HTTPS-only
workflow above is preferred for interactive admin use.
VM (Replicated) install
The k0s kubeconfig is root-owned, so the invocation runs under sudo:
eval "$(sudo -E python3 scripts/warm_runtime_configs.py bootstrap --namespace openhands)"
Helm install
The runtime-api is cluster-internal on Helm (chart default is
ingress.enabled: false). The Kubernetes service name is release-prefixed
via include "runtime-api.fullname", so it is not literally runtime-api
- discover it and port-forward, then bootstrap without touching
RUNTIME_API_URL:
SVC=$(kubectl -n openhands get svc \
-l app.kubernetes.io/name=runtime-api \
-o jsonpath='{.items[0].metadata.name}')
kubectl -n openhands port-forward "svc/$SVC" 5000:5000 &
export RUNTIME_API_URL=http://localhost:5000
eval "$(python3 scripts/warm_runtime_configs.py bootstrap --namespace openhands --skip-url)"
--skip-url leaves RUNTIME_API_URL alone. If the operator set
nameOverride on the runtime-api subchart, adjust the label selector to
match.
See also
- Docs: Configuring Custom Sandbox Images
- Docs: Using Custom Images
Use this skill
Connect your agent to the Skill Store MCP server and ask for it by ref: openhands/runtime-api-configs-71595506564.
Details
- Publisher
- openhands
- Category
- Software Development › DevOps & cloud
- License
- MIT
- Updated
- 2026-10-19
References
More from openhands
- Build Setup Set up build environment and test fixtures for COBOL-to-Java migrations.
- Cobol Modernization End-to-end COBOL to Java migration workflow.
- Mainframe Planning Create a transformation guide for replacing mainframe-specific COBOL constructs with standard COB…
- Mainframe Removal Apply mainframe dependency transformations to COBOL code using a pre-generated transformation guide.