Skip to main content

openhands-automation

This skill should be used when the user asks to "create an automation", "schedule a task", "set up a cron job", "webhook integration", "event-triggered automation", or mentions automations, scheduled tasks, cron scheduling, or webhook events in OpenHands Cloud.

ソース情報

リポジトリ
OpenHands/extensions
ソースの最終更新活動
2026年10月5日 15:05
検出された SKILL.md の言語
英語
スター
157
フォーク
102

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
10 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
openhands-automation
description
This skill should be used when the user asks to "create an automation", "schedule a task", "set up a cron job", "webhook integration", "event-triggered automation", or mentions automations, scheduled tasks, cron scheduling, or webhook events in OpenHands Cloud.
triggers
["automation","automations","scheduled task","cron job","cron schedule","webhook","webhooks","event trigger","github event","pull request automation","issue automation","/automation:create"]
# OpenHands Automations Create and manage automations that run inside an OpenHands agent server — triggered by cron schedules or webhook events (GitHub, custom services). Windows PowerShell equivalents for the automation API `curl` examples and shell-variable conventions are in `references/windows.md`. ## Automation Creation Process The agent must follow these steps when creating an automation: * Quickly check that you can access the correct automations backend using the auth mechanism below * Quickly check that you can access any necessary integrations (e.g. GitHub, Slack); if access fails, inform the user and stop * Ask the user for any necessary information, e.g. if you need the name of a Slack channel or GitHub repo to proceed * Write the code or prompt that will be sent to the automations backend _inside the current workspace_ * Show the code to the user with the `canvas_ui` tool if available, otherwise present it in a fenced code block in your reply * Message the user with a concise summary of how the automation will behave, and ask if they are ready to deploy it ## Architecture Two components work together to run automations: **Automation Service** (API at `OPENHANDS_HOST/api/automation/v1`) Manages the *when*: holds automation definitions, schedules cron-triggered runs, dispatches webhook-triggered runs, and receives completion callbacks to mark runs as done. This is the API you call to create, update, and manage automations. **Agent Server** (accessible as `AGENT_SERVER_URL` inside script runs) Manages the *what*: the runtime environment where automation scripts execute and where conversations (AI agent interactions with tools, bash, file editing, etc.) run. When a run is triggered, the automation service uploads the automation's tarball to the agent server, which unpacks and runs the entrypoint script. The script connects back to the agent server using `AGENT_SERVER_URL` and a session API key to start, monitor, and stop conversations. The agent server typically runs inside a **sandbox** (a Docker or Kubernetes container). Some deployments use sandboxless mode, where the agent server runs directly on a host. **Key environment variables:** | Variable | Availability | Description | |---|---|---| | `RUNTIME_URL` | Ambient in cloud environments | Public-facing URL of the **agent server** sandbox. Use this to determine whether external webhook delivery is possible — if unset or local, webhooks cannot be received. The automation service may run at a separate URL (see Determining the API Host). | | `AGENT_SERVER_URL` | Injected into scripts at run time, local Agent Canvas only | Internal URL of the agent server. Available inside script execution context; **not** an ambient environment variable outside of a running script, and not set on OpenHands Cloud or Enterprise. | | `OPENHANDS_HOST` | Shell convention only — set manually | Base URL for the automation service API. **Not a real environment variable.** Set it from an explicit host, a detected local Agent Canvas server, or the cloud default. Used in all `curl` examples throughout this skill. | > **⚠️ CRITICAL — Agent behavior rules:** > > 0. **Does this task need an LLM at all? Check first.** Before picking a preset, ask whether the task actually requires reasoning, judgment, summarization, or open-ended tool use. If it is fully deterministic — fixed data transforms, scheduled HTTP calls, healthcheck pings, file rotation, picking from a known list, posting a templated message — an LLM-driven preset is overkill. Every run will consume LLM tokens, which adds up fast at high frequencies (every 5 min ≈ 288 runs/day). Surface the trade-off to the user and offer the custom-script path (see `references/custom-automation.md`) as the cheaper, more reliable option. Be especially careful for cron schedules tighter than hourly. > > **Instant-recognition patterns — these are always deterministic, never use an LLM preset:** > - "post a quote / message / fact every N minutes" (rotating from a list) > - "send a scheduled reminder / standup / digest" > - "ping a health-check URL on a schedule" > - "post to Slack / webhook every N minutes" > - Any task where the full output could be written as a static template right now > > 1. **For LLM-appropriate work, default to preset endpoints.** They handle all SDK boilerplate, tarball packaging, and upload automatically: > - **Prompt preset** (`POST /v1/preset/prompt`) — for tasks expressed as a natural language prompt that benefit from agent reasoning > - **Plugin preset** (`POST /v1/preset/plugin`) — when plugins with skills, MCP configs, or commands are needed > 2. **Present the options, then build the one the user picks.** Whenever rule 0 applies, or neither preset is a clean fit (custom Python dependencies, a non-Python entrypoint, a multi-file project, direct SDK lifecycle control), lay the choices out side by side with a one-line note on cost and reliability for each, and let the user choose: > - **Prompt preset** - natural language prompt execution (LLM-driven) > - **Plugin preset** - load plugins with extended capabilities (skills, MCP, hooks, commands) > - **Custom script** - full control over code, with or without an LLM; see `references/custom-automation.md` > > Do not silently fall back to either side. The "ready to deploy?" confirmation in the creation process applies to every path equally; a custom script needs no extra permission beyond it, and a preset gets no pass on it. > 3. **Building a custom script:** follow `references/custom-automation.md` for tarball packaging, validation, and upload. The *Custom Script Example (No LLM)* below shows the whole flow end to end. > 4. **Before suggesting event-triggered (webhook) automations, check whether the deployment is publicly reachable.** Check `RUNTIME_URL`. Webhooks require an internet-accessible URL so that external services (GitHub, Slack, Linear, etc.) can deliver events to the automation service. If `RUNTIME_URL` is unset, empty, or resolves to a local or private address (`localhost`, `127.0.0.1`, `0.0.0.0`, or any RFC 1918 range: `10.x.x.x`, `192.168.x.x`, `172.16–31.x.x`), the service cannot receive inbound webhook traffic from the public internet. In that case: > - **Recommend a cron-based polling automation instead.** Have the automation run on a schedule and call the external service's API (e.g., the GitHub REST API) to check for new events since the last run. > - Explain the limitation clearly to the user: "Because this is a local deployment, external services can't reach the webhook endpoint. I'll set up a polling automation using a cron schedule instead." ### No-LLM Script Helpers When building a deterministic custom script, these two stdlib-only functions are required. Copy them verbatim - they use variables injected by the automation service: `SESSION_API_KEY`, plus `AGENT_SERVER_URL` on a local Agent Canvas or `OPENHANDS_CLOUD_API_URL` and `SANDBOX_ID` on OpenHands Cloud and Enterprise. ```python import json, os, urllib.request def get_secret(name): """Fetch a named secret: from the agent server when AGENT_SERVER_URL is set, else from the OpenHands API.""" url = os.environ.get("AGENT_SERVER_URL", "").rstrip("/") key = os.environ.get("SESSION_API_KEY") or os.environ.get("OH_SESSION_API_KEYS_0", "") if url: # local Agent Canvas url = f"{url}/api/settings/secrets/{name}" else: # OpenHands Cloud / Enterprise api = os.environ["OPENHANDS_CLOUD_API_URL"].rstrip("/") url = f"{api}/api/v1/sandboxes/{os.environ['SANDBOX_ID']}/settings/secrets/{name}" with urllib.request.urlopen(urllib.request.Request( url, headers={"X-Session-API-Key": key} )) as r: return r.read().decode().strip() def fire_callback(status="COMPLETED", error=None): """Signal run completion. MUST be called on every exit path — success AND error.""" url = os.environ.get("AUTOMATION_CALLBACK_URL", "") if not url: return body = {"status": status, "run_id": os.environ.get("AUTOMATION_RUN_ID", "")} if error: body["error"] = error try: urllib.request.urlopen(urllib.request.Request(url, data=json.dumps(body).encode(), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {os.environ.get('AUTOMATION_CALLBACK_API_KEY', '')}", })) except Exception as e: print(f"Callback error: {e}") ``` Entrypoint must be `python3 main.py` (no `setup.sh` needed). Wrap your main logic in `try/except` and call `fire_callback("FAILED", str(e))` in the except block. **State persistence between runs** — polling automations that track a "last processed" timestamp or active conversation IDs must use the built-in KV store rather than local files. Local files are lost when a run ends on a cloud pod. The KV store is available when `AUTOMATION_KV_TOKEN` is injected into the run environment. See `references/custom-automation.md#state-persistence-kv-store` for ready-to-copy `kv_get` / `kv_set` / `load_state` / `save_state` helpers. --- ## Authentication All requests require authentication: - Cloud (default `https://app.all-hands.dev`): Bearer token: `-H "Authorization: Bearer ${OPENHANDS_API_KEY}"` - Local Agent Canvas (`http://localhost:8001`): session API key through `X-Session-API-Key`: `-H "X-Session-API-Key: ${OPENHANDS_AUTOMATION_API_KEY:-${SESSION_API_KEY}}"` The curl examples below show cloud Bearer authentication. For local Agent Canvas, replace that header with the `X-Session-API-Key` header above. ## API Endpoints ### Determining the API Host **Before making API calls, determine the correct host:** The automation service may run at a different URL from the agent server. In the examples throughout this skill, `${OPENHANDS_HOST}` is a shell-variable convention for the automation service base URL — it is **not** a real environment variable. Set it from context before running any curl command: - Look for a `<HOST>` value in the system prompt or runtime-services block. If present, use that URL. - If running inside a local Agent Canvas stack and no explicit host is provided, use `http://localhost:8001` for the local automation/agent-server API. - Otherwise default to `https://app.all-hands.dev`. For a local Agent Canvas server, validate the endpoint before making a mutating request and authenticate with the session key through `X-Session-API-Key` when that API requires it. Do not use the cloud default merely because no `<HOST>` value is present. ```bash # Choose the host that matches the detected environment: OPENHANDS_HOST="http://localhost:8001" # local Agent Canvas # OPENHANDS_HOST="https://app.all-hands.dev" # OpenHands Cloud ``` ### Automation Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/api/automation/v1/preset/prompt` | POST | **Create automation from a prompt (recommended)** | | `/api/automation/v1/preset/plugin` | POST | **Create automation with plugins** | | `/api/automation/v1` | GET | List automations | | `/api/automation/v1/{id}` | GET | Get automation details | | `/api/automation/v1/{id}` | PATCH | Update automation | | `/api/automation/v1/{id}` | DELETE | Delete automation | | `/api/automation/v1/{id}/dispatch` | POST | Trigger a run manually | | `/api/automation/v1/{id}/runs` | GET | List automation runs | ### Custom Webhook Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/api/automation/v1/webhooks` | POST | Register a custom webhook source | | `/api/automation/v1/webhooks` | GET | List all custom webhooks | | `/api/automation/v1/webhooks/{id}` | GET | Get webhook details | | `/api/automation/v1/webhooks/{id}` | PATCH | Update webhook settings | | `/api/automation/v1/webhooks/{id}` | DELETE | Delete a webhook | | `/api/automation/v1/webhooks/{id}/rotate-secret` | POST | Rotate signing secret | --- ## Trigger Types Automations support two trigger types: | Trigger Type | Use Case | |--------------|----------| | **Cron** | Run on a schedule (daily, weekly, hourly, etc.) | | **Event** | Run when a webhook event occurs (GitHub PR opened, issue commented, etc.) — **requires a publicly reachable deployment** | --- ## Creating Automations Two preset endpoints simplify automation creation by handling SDK boilerplate, tarball packaging, and upload automatically: 1. **Prompt Preset** — Execute a natural language prompt (simple tasks) 2. **Plugin Preset** — Load plugins with skills, MCP configs, and commands (extended capabilities) --- ### Prompt Preset Use the **preset/prompt endpoint** for simple automations. Provide a natural language prompt describing the task. #### How It Works 1. Send a prompt describing the task (e.g., "Generate a weekly status report") 2. The automation service generates a Python script that: fetches LLM config and secrets from the agent server, starts an AI agent conversation with your prompt, and sends a completion callback when done 3. The script is packaged as a tarball and the automation is registered; on each trigger, the automation service uploads the tarball to the agent server, which unpacks and runs the script inside its environment #### Request ```bash curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "name": "My Automation Name", "prompt": "What the automation should do", "trigger": { "type": "cron", "schedule": "0 9 * * *", "timezone": "UTC" } }' ``` #### Request Fields | Field | Required | Description | |-------|----------|-------------| | `name` | Yes | Name of the automation (1-500 characters) | | `prompt` | Yes | Natural language instructions (1-50,000 characters) | | `trigger` | Yes | Trigger configuration — either `cron` or `event` (see below) | | `timeout` | No | Max execution time in seconds (default: system maximum) | | `repos` | No | Repositories to clone (see [Repository Cloning](#repository-cloning)) | **Cron Trigger Fields:** | Field | Required | Description | |-------|----------|-------------| | `trigger.type` | Yes | `"cron"` | | `trigger.schedule` | Yes | Cron expression (5 fields: min hour day month weekday) | | `trigger.timezone` | No | IANA timezone (default: `"UTC"`) | **Event Trigger Fields:** | Field | Required | Description | |-------|----------|-------------| | `trigger.type` | Yes | `"event"` | | `trigger.source` | Yes | Event source: `"github"` or custom webhook source name | | `trigger.on` | Yes | Event key pattern(s) to match (see Event Keys below) | | `trigger.filter` | No | JMESPath expression for payload filtering (see Filter Expressions below) | #### Prompt Tips Write the prompt as an instruction to an AI agent. The prompt executes inside a sandbox with full tool access (bash, file editing, etc.), the user's configured LLM, stored secrets, and MCP server integrations. Examples: - `"Generate a weekly status report summarizing the team's GitHub activity and post it to Slack"` - `"Read yesterday's new error reports in Sentry, group them by likely root cause, and open one GitHub issue per new failure pattern with a proposed fix"`
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る