@openhands/extensions 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/custom-codereview-guide.md +25 -0
- package/.github/pull_request_template.md +38 -0
- package/.github/release.yml +14 -0
- package/.github/workflows/check-extensions.yml +72 -0
- package/.github/workflows/npm-publish.yml +89 -0
- package/.github/workflows/pr.yml +30 -0
- package/.github/workflows/release.yml +24 -0
- package/.github/workflows/tests.yml +25 -0
- package/.github/workflows/vulnerability-scan.yml +87 -0
- package/.release-please-manifest.json +3 -0
- package/AGENTS.md +132 -0
- package/README.md +10 -0
- package/analysis_results.md +162 -0
- package/marketplaces/large-codebase.json +66 -0
- package/marketplaces/openhands-extensions.json +682 -0
- package/package.json +4 -10
- package/plugins/README.md +30 -0
- package/plugins/city-weather/.plugin/plugin.json +13 -0
- package/plugins/city-weather/README.md +145 -0
- package/plugins/city-weather/commands/now.md +56 -0
- package/plugins/cobol-modernization/.plugin/plugin.json +19 -0
- package/plugins/cobol-modernization/README.md +201 -0
- package/plugins/cobol-modernization/references/troubleshooting.md +18 -0
- package/plugins/cobol-modernization/skills/build-setup/SKILL.md +78 -0
- package/plugins/cobol-modernization/skills/build-setup/scripts/install-gnucobol.sh +32 -0
- package/plugins/cobol-modernization/skills/cobol-modernization-overview/SKILL.md +113 -0
- package/plugins/cobol-modernization/skills/mainfraime-removal/SKILL.md +62 -0
- package/plugins/cobol-modernization/skills/mainfraime-removal/references/cics-transformation-examples.md +45 -0
- package/plugins/cobol-modernization/skills/mainframe-planning/SKILL.md +78 -0
- package/plugins/cobol-modernization/skills/to-java-migration/SKILL.md +59 -0
- package/plugins/cobol-modernization/skills/to-java-migration/references/cobol-to-java-example.md +58 -0
- package/plugins/cobol-modernization/skills/to-java-migration/references/datatype-mappings.md +19 -0
- package/plugins/issue-duplicate-checker/.plugin/plugin.json +13 -0
- package/plugins/issue-duplicate-checker/README.md +51 -0
- package/plugins/issue-duplicate-checker/action.yml +349 -0
- package/plugins/issue-duplicate-checker/scripts/auto_close_duplicate_issues.py +569 -0
- package/plugins/issue-duplicate-checker/scripts/issue_duplicate_check_openhands.py +681 -0
- package/plugins/issue-duplicate-checker/scripts/post_duplicate_notice.js +220 -0
- package/plugins/issue-duplicate-checker/scripts/remove_duplicate_candidate_label.js +27 -0
- package/plugins/magic-test/.plugin/plugin.json +13 -0
- package/plugins/magic-test/skills/magic-word/SKILL.md +33 -0
- package/plugins/migration-scoring/.plugin/plugin.json +19 -0
- package/plugins/migration-scoring/README.md +244 -0
- package/plugins/migration-scoring/skills/migration-mapping/SKILL.md +72 -0
- package/plugins/migration-scoring/skills/migration-report/SKILL.md +118 -0
- package/plugins/migration-scoring/skills/migration-scoring-overview/SKILL.md +126 -0
- package/plugins/migration-scoring/skills/score-quality/SKILL.md +54 -0
- package/plugins/migration-scoring/skills/score-quality/references/scoring-criteria.md +30 -0
- package/plugins/migration-scoring/skills/score-style/SKILL.md +106 -0
- package/plugins/onboarding/.plugin/plugin.json +20 -0
- package/plugins/onboarding/README.md +30 -0
- package/plugins/onboarding/references/criteria.md +144 -0
- package/plugins/onboarding/skills/agent-readiness-report/README.md +23 -0
- package/plugins/onboarding/skills/agent-readiness-report/SKILL.md +122 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_agent_instructions.sh +88 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_build_env.sh +114 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_feedback_loops.sh +133 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_policy.sh +113 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_workflows.sh +127 -0
- package/plugins/onboarding/skills/improve-agent-readiness/README.md +19 -0
- package/plugins/onboarding/skills/improve-agent-readiness/SKILL.md +167 -0
- package/plugins/onboarding/skills/setup-agents-md/README.md +15 -0
- package/plugins/onboarding/skills/setup-agents-md/SKILL.md +150 -0
- package/plugins/onboarding/skills/setup-openhands/README.md +20 -0
- package/plugins/onboarding/skills/setup-openhands/SKILL.md +56 -0
- package/plugins/onboarding/skills/setup-pr-review/README.md +23 -0
- package/plugins/onboarding/skills/setup-pr-review/SKILL.md +72 -0
- package/plugins/openhands/.plugin/plugin.json +13 -0
- package/plugins/openhands/README.md +52 -0
- package/plugins/openhands/SKILL.md +61 -0
- package/plugins/openhands/commands/create.md +55 -0
- package/plugins/openhands/commands/openhands-cloud.md +8 -0
- package/plugins/openhands/scripts/run.sh +69 -0
- package/plugins/pr-review/.plugin/plugin.json +13 -0
- package/plugins/pr-review/README.md +393 -0
- package/plugins/pr-review/action.yml +298 -0
- package/plugins/pr-review/scripts/agent_script.py +1282 -0
- package/plugins/pr-review/scripts/evaluate_review.py +655 -0
- package/plugins/pr-review/scripts/prompt.py +260 -0
- package/plugins/pr-review/workflows/pr-review-by-openhands.yml +51 -0
- package/plugins/pr-review/workflows/pr-review-evaluation.yml +85 -0
- package/plugins/qa-changes/.plugin/plugin.json +11 -0
- package/plugins/qa-changes/README.md +185 -0
- package/plugins/qa-changes/action.yml +181 -0
- package/plugins/qa-changes/scripts/agent_script.py +406 -0
- package/plugins/qa-changes/scripts/evaluate_qa_changes.py +385 -0
- package/plugins/qa-changes/scripts/prompt.py +174 -0
- package/plugins/qa-changes/workflows/qa-changes-by-openhands.yml +50 -0
- package/plugins/qa-changes/workflows/qa-changes-evaluation.yml +85 -0
- package/plugins/release-notes/.plugin/plugin.json +19 -0
- package/plugins/release-notes/README.md +283 -0
- package/plugins/release-notes/SKILL.md +83 -0
- package/plugins/release-notes/action.yml +117 -0
- package/plugins/release-notes/commands/release-notes.md +8 -0
- package/plugins/release-notes/scripts/agent_script.py +292 -0
- package/plugins/release-notes/scripts/generate_release_notes.py +733 -0
- package/plugins/release-notes/scripts/prompt.py +90 -0
- package/plugins/release-notes/scripts/validate_release_notes.py +328 -0
- package/plugins/release-notes/workflows/release-notes.yml +76 -0
- package/plugins/vulnerability-remediation/.plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/README.md +217 -0
- package/plugins/vulnerability-remediation/action.yml +187 -0
- package/plugins/vulnerability-remediation/scripts/scan_and_remediate.py +561 -0
- package/plugins/vulnerability-remediation/workflows/vulnerability-scan.yml +87 -0
- package/pyproject.toml +12 -0
- package/release-please-config.json +16 -0
- package/scripts/sync_extensions.py +494 -0
- package/scripts/sync_openhands_sdk_skill.py +264 -0
- package/skills/README.md +159 -0
- package/skills/add-javadoc/.plugin/plugin.json +18 -0
- package/skills/add-javadoc/README.md +40 -0
- package/skills/add-javadoc/SKILL.md +35 -0
- package/skills/add-javadoc/references/example.md +32 -0
- package/skills/add-skill/.plugin/plugin.json +18 -0
- package/skills/add-skill/README.md +67 -0
- package/skills/add-skill/SKILL.md +47 -0
- package/skills/add-skill/scripts/fetch_skill.py +259 -0
- package/skills/agent-creator/.plugin/plugin.json +20 -0
- package/skills/agent-creator/README.md +104 -0
- package/skills/agent-creator/SKILL.md +190 -0
- package/skills/agent-creator/commands/agent-creator.md +8 -0
- package/skills/agent-creator/references/fallback.md +117 -0
- package/skills/agent-memory/.plugin/plugin.json +18 -0
- package/skills/agent-memory/README.md +35 -0
- package/skills/agent-memory/SKILL.md +30 -0
- package/skills/agent-memory/commands/remember.md +8 -0
- package/skills/agent-sdk-builder/.plugin/plugin.json +18 -0
- package/skills/agent-sdk-builder/README.md +40 -0
- package/skills/agent-sdk-builder/SKILL.md +37 -0
- package/skills/agent-sdk-builder/commands/agent-builder.md +8 -0
- package/skills/azure-devops/.plugin/plugin.json +18 -0
- package/skills/azure-devops/README.md +55 -0
- package/skills/azure-devops/SKILL.md +50 -0
- package/skills/bitbucket/.plugin/plugin.json +17 -0
- package/skills/bitbucket/README.md +50 -0
- package/skills/bitbucket/SKILL.md +45 -0
- package/skills/code-review/.plugin/plugin.json +19 -0
- package/skills/code-review/README.md +18 -0
- package/skills/code-review/SKILL.md +208 -0
- package/skills/code-review/commands/codereview-roasted.md +8 -0
- package/skills/code-review/commands/codereview.md +8 -0
- package/skills/code-review/references/risk-evaluation.md +41 -0
- package/skills/code-review/references/supply-chain-security.md +31 -0
- package/skills/code-simplifier/.plugin/plugin.json +21 -0
- package/skills/code-simplifier/README.md +30 -0
- package/skills/code-simplifier/SKILL.md +91 -0
- package/skills/code-simplifier/commands/simplify.md +8 -0
- package/skills/code-simplifier/references/code-quality-review.md +86 -0
- package/skills/code-simplifier/references/code-reuse-review.md +63 -0
- package/skills/code-simplifier/references/efficiency-review.md +81 -0
- package/skills/datadog/.plugin/plugin.json +19 -0
- package/skills/datadog/README.md +100 -0
- package/skills/datadog/SKILL.md +95 -0
- package/skills/deno/.plugin/plugin.json +18 -0
- package/skills/deno/README.md +5 -0
- package/skills/deno/SKILL.md +99 -0
- package/skills/deno/references/README.md +6 -0
- package/skills/discord/.plugin/plugin.json +18 -0
- package/skills/discord/README.md +31 -0
- package/skills/discord/SKILL.md +109 -0
- package/skills/discord/__init__.py +0 -0
- package/skills/discord/references/REFERENCE.md +78 -0
- package/skills/discord/scripts/__init__.py +0 -0
- package/skills/discord/scripts/_http.py +127 -0
- package/skills/discord/scripts/post_webhook.py +106 -0
- package/skills/discord/scripts/send_message.py +102 -0
- package/skills/docker/.plugin/plugin.json +17 -0
- package/skills/docker/README.md +34 -0
- package/skills/docker/SKILL.md +29 -0
- package/skills/evidence-based-citations/.plugin/plugin.json +20 -0
- package/skills/evidence-based-citations/README.md +31 -0
- package/skills/evidence-based-citations/SKILL.md +59 -0
- package/skills/flarglebargle/.plugin/plugin.json +16 -0
- package/skills/flarglebargle/README.md +14 -0
- package/skills/flarglebargle/SKILL.md +9 -0
- package/skills/frontend-design/.plugin/plugin.json +21 -0
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/README.md +42 -0
- package/skills/frontend-design/SKILL.md +42 -0
- package/skills/github/.plugin/plugin.json +19 -0
- package/skills/github/README.md +42 -0
- package/skills/github/SKILL.md +106 -0
- package/skills/github-pr-review/.plugin/plugin.json +18 -0
- package/skills/github-pr-review/README.md +145 -0
- package/skills/github-pr-review/SKILL.md +148 -0
- package/skills/github-pr-review/commands/github-pr-review.md +8 -0
- package/skills/github-pr-reviewer/.plugin/plugin.json +20 -0
- package/skills/github-pr-reviewer/README.md +34 -0
- package/skills/github-pr-reviewer/SKILL.md +89 -0
- package/skills/github-pr-reviewer/commands/pr-reviewer:setup.md +8 -0
- package/skills/github-repo-monitor/.plugin/plugin.json +22 -0
- package/skills/github-repo-monitor/README.md +70 -0
- package/skills/github-repo-monitor/SKILL.md +316 -0
- package/skills/github-repo-monitor/commands/github-monitor:poll.md +8 -0
- package/skills/github-repo-monitor/references/github-api.md +241 -0
- package/skills/github-repo-monitor/references/state-schema.md +160 -0
- package/skills/github-repo-monitor/scripts/main.py +915 -0
- package/skills/github-repo-monitor/tests/test_main.py +400 -0
- package/skills/gitlab/.plugin/plugin.json +17 -0
- package/skills/gitlab/README.md +37 -0
- package/skills/gitlab/SKILL.md +32 -0
- package/skills/incident-retrospective/.plugin/plugin.json +21 -0
- package/skills/incident-retrospective/README.md +34 -0
- package/skills/incident-retrospective/SKILL.md +98 -0
- package/skills/incident-retrospective/commands/incident-retro:setup.md +8 -0
- package/skills/iterate/.plugin/plugin.json +13 -0
- package/skills/iterate/README.md +25 -0
- package/skills/iterate/SKILL.md +399 -0
- package/skills/iterate/commands/babysit.md +8 -0
- package/skills/iterate/commands/iterate.md +8 -0
- package/skills/iterate/commands/verify.md +8 -0
- package/skills/iterate/references/heuristics.md +58 -0
- package/skills/iterate/references/verification.md +96 -0
- package/skills/jupyter/.plugin/plugin.json +18 -0
- package/skills/jupyter/README.md +55 -0
- package/skills/jupyter/SKILL.md +50 -0
- package/skills/kubernetes/.plugin/plugin.json +18 -0
- package/skills/kubernetes/README.md +53 -0
- package/skills/kubernetes/SKILL.md +48 -0
- package/skills/learn-from-code-review/.plugin/plugin.json +19 -0
- package/skills/learn-from-code-review/README.md +64 -0
- package/skills/learn-from-code-review/SKILL.md +186 -0
- package/skills/learn-from-code-review/commands/learn-from-reviews.md +8 -0
- package/skills/linear/.plugin/plugin.json +19 -0
- package/skills/linear/README.md +58 -0
- package/skills/linear/SKILL.md +213 -0
- package/skills/linear-triage/.plugin/plugin.json +21 -0
- package/skills/linear-triage/README.md +34 -0
- package/skills/linear-triage/SKILL.md +91 -0
- package/skills/linear-triage/commands/linear-triage:setup.md +8 -0
- package/skills/notion/.plugin/plugin.json +17 -0
- package/skills/notion/README.md +114 -0
- package/skills/notion/SKILL.md +109 -0
- package/skills/npm/.plugin/plugin.json +17 -0
- package/skills/npm/README.md +14 -0
- package/skills/npm/SKILL.md +9 -0
- package/skills/openhands-api/.plugin/plugin.json +22 -0
- package/skills/openhands-api/README.md +48 -0
- package/skills/openhands-api/SKILL.md +399 -0
- package/skills/openhands-api/references/README.md +33 -0
- package/skills/openhands-api/references/TROUBLESHOOTING.md +81 -0
- package/skills/openhands-api/references/example_prompt.md +12 -0
- package/skills/openhands-api/scripts/openhands_api.py +606 -0
- package/skills/openhands-api/scripts/openhands_api.ts +252 -0
- package/skills/openhands-automation/.plugin/plugin.json +19 -0
- package/skills/openhands-automation/README.md +89 -0
- package/skills/openhands-automation/SKILL.md +875 -0
- package/skills/openhands-automation/commands/automation:create.md +8 -0
- package/skills/openhands-automation/references/ab-testing.md +185 -0
- package/skills/openhands-automation/references/custom-automation.md +644 -0
- package/skills/openhands-sdk/.plugin/plugin.json +20 -0
- package/skills/openhands-sdk/README.md +22 -0
- package/skills/openhands-sdk/SKILL.md +229 -0
- package/skills/openhands-sdk/commands/sdk.md +8 -0
- package/skills/pdflatex/.plugin/plugin.json +18 -0
- package/skills/pdflatex/README.md +39 -0
- package/skills/pdflatex/SKILL.md +34 -0
- package/skills/prd/.plugin/plugin.json +19 -0
- package/skills/prd/README.md +28 -0
- package/skills/prd/SKILL.md +237 -0
- package/skills/prd/commands/prd.md +8 -0
- package/skills/qa-changes/README.md +18 -0
- package/skills/qa-changes/SKILL.md +229 -0
- package/skills/qa-changes/commands/qa-changes.md +8 -0
- package/skills/release-notes/README.md +24 -0
- package/skills/release-notes/SKILL.md +19 -0
- package/skills/release-notes/commands/release-notes.md +8 -0
- package/skills/research-brief/.plugin/plugin.json +20 -0
- package/skills/research-brief/README.md +34 -0
- package/skills/research-brief/SKILL.md +99 -0
- package/skills/research-brief/commands/research-brief:setup.md +8 -0
- package/skills/security/.plugin/plugin.json +18 -0
- package/skills/security/README.md +38 -0
- package/skills/security/SKILL.md +33 -0
- package/skills/skill-creator/.plugin/plugin.json +17 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/README.md +182 -0
- package/skills/skill-creator/SKILL.md +545 -0
- package/skills/skill-creator/references/output-patterns.md +82 -0
- package/skills/skill-creator/references/workflows.md +28 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/skills/slack-channel-monitor/.plugin/plugin.json +21 -0
- package/skills/slack-channel-monitor/README.md +91 -0
- package/skills/slack-channel-monitor/SKILL.md +276 -0
- package/skills/slack-channel-monitor/commands/slack-monitor:poll.md +8 -0
- package/skills/slack-channel-monitor/references/slack-api.md +207 -0
- package/skills/slack-channel-monitor/references/state-schema.md +180 -0
- package/skills/slack-channel-monitor/scripts/main.py +962 -0
- package/skills/slack-standup-digest/.plugin/plugin.json +21 -0
- package/skills/slack-standup-digest/README.md +34 -0
- package/skills/slack-standup-digest/SKILL.md +92 -0
- package/skills/slack-standup-digest/commands/standup-digest:setup.md +8 -0
- package/skills/spark-version-upgrade/.plugin/plugin.json +20 -0
- package/skills/spark-version-upgrade/README.md +54 -0
- package/skills/spark-version-upgrade/SKILL.md +233 -0
- package/skills/ssh/.plugin/plugin.json +18 -0
- package/skills/ssh/README.md +140 -0
- package/skills/ssh/SKILL.md +135 -0
- package/skills/swift-linux/.plugin/plugin.json +17 -0
- package/skills/swift-linux/README.md +86 -0
- package/skills/swift-linux/SKILL.md +81 -0
- package/skills/theme-factory/.plugin/plugin.json +19 -0
- package/skills/theme-factory/LICENSE.txt +202 -0
- package/skills/theme-factory/README.md +58 -0
- package/skills/theme-factory/SKILL.md +59 -0
- package/skills/theme-factory/theme-showcase.pdf +0 -0
- package/skills/theme-factory/themes/arctic-frost.md +19 -0
- package/skills/theme-factory/themes/botanical-garden.md +19 -0
- package/skills/theme-factory/themes/desert-rose.md +19 -0
- package/skills/theme-factory/themes/forest-canopy.md +19 -0
- package/skills/theme-factory/themes/golden-hour.md +19 -0
- package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
- package/skills/theme-factory/themes/modern-minimalist.md +19 -0
- package/skills/theme-factory/themes/ocean-depths.md +19 -0
- package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
- package/skills/theme-factory/themes/tech-innovation.md +19 -0
- package/skills/uv/.plugin/plugin.json +18 -0
- package/skills/uv/README.md +5 -0
- package/skills/uv/SKILL.md +95 -0
- package/skills/uv/references/README.md +5 -0
- package/skills/vercel/.plugin/plugin.json +18 -0
- package/skills/vercel/README.md +108 -0
- package/skills/vercel/SKILL.md +103 -0
- package/tests/test_add_skill_installs_to_agents_dir.py +42 -0
- package/tests/test_catalogs.py +109 -0
- package/tests/test_code_review_risk_evaluation.py +94 -0
- package/tests/test_issue_duplicate_checker.py +240 -0
- package/tests/test_openhands_api_python.py +152 -0
- package/tests/test_plugin_manifest.py +83 -0
- package/tests/test_pr_review_diff_payload.py +202 -0
- package/tests/test_pr_review_feedback.py +263 -0
- package/tests/test_pr_review_prompt.py +152 -0
- package/tests/test_pr_review_review_context.py +253 -0
- package/tests/test_qa_changes.py +232 -0
- package/tests/test_qa_changes_evaluation.py +259 -0
- package/tests/test_release_notes_generator.py +990 -0
- package/tests/test_sdk_loading.py +150 -0
- package/tests/test_skill_plugin_loading.py +149 -0
- package/tests/test_skills_have_readme.py +66 -0
- package/tests/test_sync_extensions.py +292 -0
- package/tests/test_workflow_sync.py +46 -0
- package/utils/analysis/README.md +7 -0
- package/utils/analysis/laminar_signals/README.md +211 -0
- package/utils/analysis/laminar_signals/analyze.py +780 -0
- package/utils/analysis/laminar_signals/templates/default.j2 +49 -0
- package/utils/analysis/laminar_signals/templates/pr_review.j2 +61 -0
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openhands-automation
|
|
3
|
+
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.
|
|
4
|
+
triggers:
|
|
5
|
+
- automation
|
|
6
|
+
- automations
|
|
7
|
+
- scheduled task
|
|
8
|
+
- cron job
|
|
9
|
+
- cron schedule
|
|
10
|
+
- webhook
|
|
11
|
+
- webhooks
|
|
12
|
+
- event trigger
|
|
13
|
+
- github event
|
|
14
|
+
- pull request automation
|
|
15
|
+
- issue automation
|
|
16
|
+
- /automation:create
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# OpenHands Automations
|
|
20
|
+
|
|
21
|
+
Create and manage automations that run inside an OpenHands agent server — triggered by cron schedules or webhook events (GitHub, custom services).
|
|
22
|
+
|
|
23
|
+
## Automation Creation Process
|
|
24
|
+
The agent must follow these steps when creating an automation:
|
|
25
|
+
* Quickly check that you can access the correct automations backend using the auth mechanism below
|
|
26
|
+
* Quickly check that you can access any necessary integrations (e.g. GitHub, Slack); if access fails, inform the user and stop
|
|
27
|
+
* Ask the user for any necessary information, e.g. if you need the name of a Slack channel or GitHub repo to proceed
|
|
28
|
+
* Write the code or prompt that will be sent to the automations backend _inside the current workspace_
|
|
29
|
+
* Show the code to the user with the `canvas_ui` tool if available, otherwise present it in a fenced code block in your reply
|
|
30
|
+
* Message the user with a concise summary of how the automation will behave, and ask if they are ready to deploy it
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
Two components work together to run automations:
|
|
35
|
+
|
|
36
|
+
**Automation Service** (API at `OPENHANDS_HOST/api/automation/v1`)
|
|
37
|
+
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.
|
|
38
|
+
|
|
39
|
+
**Agent Server** (accessible as `AGENT_SERVER_URL` inside script runs)
|
|
40
|
+
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.
|
|
41
|
+
|
|
42
|
+
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.
|
|
43
|
+
|
|
44
|
+
**Key environment variables:**
|
|
45
|
+
|
|
46
|
+
| Variable | Availability | Description |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `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). |
|
|
49
|
+
| `AGENT_SERVER_URL` | Injected into scripts at run time only | Internal URL of the agent server. Available inside script execution context; **not** an ambient environment variable outside of a running script. |
|
|
50
|
+
| `OPENHANDS_HOST` | Shell convention only — set manually | Base URL for the automation service API. **Not a real environment variable.** Set it from the `<HOST>` system-prompt value, or default to `https://app.all-hands.dev`. Used in all `curl` examples throughout this skill. |
|
|
51
|
+
|
|
52
|
+
> **⚠️ CRITICAL — Agent behavior rules:**
|
|
53
|
+
>
|
|
54
|
+
> 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.
|
|
55
|
+
>
|
|
56
|
+
> **Instant-recognition patterns — these are always deterministic, never use an LLM preset:**
|
|
57
|
+
> - "post a quote / message / fact every N minutes" (rotating from a list)
|
|
58
|
+
> - "send a scheduled reminder / standup / digest"
|
|
59
|
+
> - "ping a health-check URL on a schedule"
|
|
60
|
+
> - "post to Slack / webhook every N minutes"
|
|
61
|
+
> - Any task where the full output could be written as a static template right now
|
|
62
|
+
>
|
|
63
|
+
> 1. **For LLM-appropriate work, default to preset endpoints.** They handle all SDK boilerplate, tarball packaging, and upload automatically:
|
|
64
|
+
> - **Prompt preset** (`POST /v1/preset/prompt`) — for tasks expressed as a natural language prompt that benefit from agent reasoning
|
|
65
|
+
> - **Plugin preset** (`POST /v1/preset/plugin`) — when plugins with skills, MCP configs, or commands are needed
|
|
66
|
+
> 2. **Do not silently create custom scripts.** Do not generate Python code, `setup.sh` files, or tarball uploads without user consent. But *do* proactively recommend the custom path (per rule 0) when the task is deterministic or high-frequency — surface the option and let the user choose.
|
|
67
|
+
> 3. **If neither preset is the right fit**, do NOT silently fall back to custom automation. Instead, explain the available options to the user:
|
|
68
|
+
> - **Prompt preset** — natural language prompt execution (LLM-driven)
|
|
69
|
+
> - **Plugin preset** — load plugins with extended capabilities (skills, MCP, hooks, commands)
|
|
70
|
+
> - **Custom script** — full control over code, with or without LLM; point them to `references/custom-automation.md`
|
|
71
|
+
> - Let the user choose which approach to use.
|
|
72
|
+
> 4. **Only create custom scripts after the user agrees to that path.** Refer to `references/custom-automation.md` for the full reference.
|
|
73
|
+
> 5. **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:
|
|
74
|
+
> - **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.
|
|
75
|
+
> - 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."
|
|
76
|
+
|
|
77
|
+
### No-LLM Script Helpers
|
|
78
|
+
|
|
79
|
+
When building a deterministic custom script, these two stdlib-only functions are required. Copy them verbatim — they use `AGENT_SERVER_URL` and `SESSION_API_KEY` injected by the automation service.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import json, os, urllib.request
|
|
83
|
+
|
|
84
|
+
def get_secret(name):
|
|
85
|
+
"""Fetch a named secret stored in the agent server."""
|
|
86
|
+
url = os.environ.get("AGENT_SERVER_URL", "").rstrip("/")
|
|
87
|
+
key = os.environ.get("SESSION_API_KEY") or os.environ.get("OH_SESSION_API_KEYS_0", "")
|
|
88
|
+
with urllib.request.urlopen(urllib.request.Request(
|
|
89
|
+
f"{url}/api/settings/secrets/{name}", headers={"X-Session-API-Key": key}
|
|
90
|
+
)) as r:
|
|
91
|
+
return r.read().decode().strip()
|
|
92
|
+
|
|
93
|
+
def fire_callback(status="COMPLETED", error=None):
|
|
94
|
+
"""Signal run completion. MUST be called on every exit path — success AND error."""
|
|
95
|
+
url = os.environ.get("AUTOMATION_CALLBACK_URL", "")
|
|
96
|
+
if not url: return
|
|
97
|
+
body = {"status": status, "run_id": os.environ.get("AUTOMATION_RUN_ID", "")}
|
|
98
|
+
if error: body["error"] = error
|
|
99
|
+
try:
|
|
100
|
+
urllib.request.urlopen(urllib.request.Request(url, data=json.dumps(body).encode(), headers={
|
|
101
|
+
"Content-Type": "application/json",
|
|
102
|
+
"Authorization": f"Bearer {os.environ.get('AUTOMATION_CALLBACK_API_KEY', '')}",
|
|
103
|
+
}))
|
|
104
|
+
except Exception as e: print(f"Callback error: {e}")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
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.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Authentication
|
|
112
|
+
|
|
113
|
+
All requests require Bearer authentication:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## API Endpoints
|
|
120
|
+
|
|
121
|
+
### Determining the API Host
|
|
122
|
+
|
|
123
|
+
**Before making API calls, determine the correct host:**
|
|
124
|
+
|
|
125
|
+
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:
|
|
126
|
+
|
|
127
|
+
- Look for a `<HOST>` value in the system prompt. If present, use that URL.
|
|
128
|
+
- Otherwise default to `https://app.all-hands.dev`.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
OPENHANDS_HOST="https://app.all-hands.dev" # replace with <HOST> if provided
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
### Automation Endpoints
|
|
136
|
+
|
|
137
|
+
| Endpoint | Method | Description |
|
|
138
|
+
|----------|--------|-------------|
|
|
139
|
+
| `/api/automation/v1/preset/prompt` | POST | **Create automation from a prompt (recommended)** |
|
|
140
|
+
| `/api/automation/v1/preset/plugin` | POST | **Create automation with plugins** |
|
|
141
|
+
| `/api/automation/v1` | GET | List automations |
|
|
142
|
+
| `/api/automation/v1/{id}` | GET | Get automation details |
|
|
143
|
+
| `/api/automation/v1/{id}` | PATCH | Update automation |
|
|
144
|
+
| `/api/automation/v1/{id}` | DELETE | Delete automation |
|
|
145
|
+
| `/api/automation/v1/{id}/dispatch` | POST | Trigger a run manually |
|
|
146
|
+
| `/api/automation/v1/{id}/runs` | GET | List automation runs |
|
|
147
|
+
|
|
148
|
+
### Custom Webhook Endpoints
|
|
149
|
+
|
|
150
|
+
| Endpoint | Method | Description |
|
|
151
|
+
|----------|--------|-------------|
|
|
152
|
+
| `/api/automation/v1/webhooks` | POST | Register a custom webhook source |
|
|
153
|
+
| `/api/automation/v1/webhooks` | GET | List all custom webhooks |
|
|
154
|
+
| `/api/automation/v1/webhooks/{id}` | GET | Get webhook details |
|
|
155
|
+
| `/api/automation/v1/webhooks/{id}` | PATCH | Update webhook settings |
|
|
156
|
+
| `/api/automation/v1/webhooks/{id}` | DELETE | Delete a webhook |
|
|
157
|
+
| `/api/automation/v1/webhooks/{id}/rotate-secret` | POST | Rotate signing secret |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Trigger Types
|
|
162
|
+
|
|
163
|
+
Automations support two trigger types:
|
|
164
|
+
|
|
165
|
+
| Trigger Type | Use Case |
|
|
166
|
+
|--------------|----------|
|
|
167
|
+
| **Cron** | Run on a schedule (daily, weekly, hourly, etc.) |
|
|
168
|
+
| **Event** | Run when a webhook event occurs (GitHub PR opened, issue commented, etc.) — **requires a publicly reachable deployment** |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Creating Automations
|
|
173
|
+
|
|
174
|
+
Two preset endpoints simplify automation creation by handling SDK boilerplate, tarball packaging, and upload automatically:
|
|
175
|
+
|
|
176
|
+
1. **Prompt Preset** — Execute a natural language prompt (simple tasks)
|
|
177
|
+
2. **Plugin Preset** — Load plugins with skills, MCP configs, and commands (extended capabilities)
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### Prompt Preset
|
|
182
|
+
|
|
183
|
+
Use the **preset/prompt endpoint** for simple automations. Provide a natural language prompt describing the task.
|
|
184
|
+
|
|
185
|
+
#### How It Works
|
|
186
|
+
|
|
187
|
+
1. Send a prompt describing the task (e.g., "Generate a weekly status report")
|
|
188
|
+
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
|
|
189
|
+
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
|
|
190
|
+
|
|
191
|
+
#### Request
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
195
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
196
|
+
-H "Content-Type: application/json" \
|
|
197
|
+
-d '{
|
|
198
|
+
"name": "My Automation Name",
|
|
199
|
+
"prompt": "What the automation should do",
|
|
200
|
+
"trigger": {
|
|
201
|
+
"type": "cron",
|
|
202
|
+
"schedule": "0 9 * * *",
|
|
203
|
+
"timezone": "UTC"
|
|
204
|
+
}
|
|
205
|
+
}'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### Request Fields
|
|
209
|
+
|
|
210
|
+
| Field | Required | Description |
|
|
211
|
+
|-------|----------|-------------|
|
|
212
|
+
| `name` | Yes | Name of the automation (1-500 characters) |
|
|
213
|
+
| `prompt` | Yes | Natural language instructions (1-50,000 characters) |
|
|
214
|
+
| `trigger` | Yes | Trigger configuration — either `cron` or `event` (see below) |
|
|
215
|
+
| `timeout` | No | Max execution time in seconds (default: system maximum) |
|
|
216
|
+
| `repos` | No | Repositories to clone (see [Repository Cloning](#repository-cloning)) |
|
|
217
|
+
|
|
218
|
+
**Cron Trigger Fields:**
|
|
219
|
+
|
|
220
|
+
| Field | Required | Description |
|
|
221
|
+
|-------|----------|-------------|
|
|
222
|
+
| `trigger.type` | Yes | `"cron"` |
|
|
223
|
+
| `trigger.schedule` | Yes | Cron expression (5 fields: min hour day month weekday) |
|
|
224
|
+
| `trigger.timezone` | No | IANA timezone (default: `"UTC"`) |
|
|
225
|
+
|
|
226
|
+
**Event Trigger Fields:**
|
|
227
|
+
|
|
228
|
+
| Field | Required | Description |
|
|
229
|
+
|-------|----------|-------------|
|
|
230
|
+
| `trigger.type` | Yes | `"event"` |
|
|
231
|
+
| `trigger.source` | Yes | Event source: `"github"` or custom webhook source name |
|
|
232
|
+
| `trigger.on` | Yes | Event key pattern(s) to match (see Event Keys below) |
|
|
233
|
+
| `trigger.filter` | No | JMESPath expression for payload filtering (see Filter Expressions below) |
|
|
234
|
+
|
|
235
|
+
#### Prompt Tips
|
|
236
|
+
|
|
237
|
+
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:
|
|
238
|
+
|
|
239
|
+
- `"Generate a weekly status report summarizing the team's GitHub activity and post it to Slack"`
|
|
240
|
+
- `"Check the production API health endpoint every hour and alert if it returns non-200"`
|
|
241
|
+
- `"Pull the latest data from our analytics API and update the dashboard spreadsheet"`
|
|
242
|
+
|
|
243
|
+
#### Cron Schedule
|
|
244
|
+
|
|
245
|
+
| Field | Values | Description |
|
|
246
|
+
|-------|--------|-------------|
|
|
247
|
+
| Minute | 0-59 | Minute of the hour |
|
|
248
|
+
| Hour | 0-23 | Hour of the day (24-hour) |
|
|
249
|
+
| Day | 1-31 | Day of the month |
|
|
250
|
+
| Month | 1-12 | Month of the year |
|
|
251
|
+
| Weekday | 0-6 | Day of week (0=Sun, 6=Sat) |
|
|
252
|
+
|
|
253
|
+
Common schedules: `0 9 * * *` (daily 9 AM), `0 9 * * 1-5` (weekdays 9 AM), `0 9 * * 1` (Mondays 9 AM), `0 0 1 * *` (first of month), `*/15 * * * *` (every 15 min), `0 */6 * * *` (every 6 hours).
|
|
254
|
+
|
|
255
|
+
#### Response (HTTP 201)
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"id": "123e4567-e89b-12d3-a456-426614174000",
|
|
260
|
+
"name": "My Automation Name",
|
|
261
|
+
"trigger": {"type": "cron", "schedule": "0 9 * * *", "timezone": "UTC"},
|
|
262
|
+
"enabled": true,
|
|
263
|
+
"created_at": "2025-03-25T10:00:00Z"
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Prompt Preset Examples
|
|
268
|
+
|
|
269
|
+
**Daily report:**
|
|
270
|
+
```bash
|
|
271
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
272
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
273
|
+
-H "Content-Type: application/json" \
|
|
274
|
+
-d '{
|
|
275
|
+
"name": "Daily Report",
|
|
276
|
+
"prompt": "Generate a daily status report and save it to a file in the workspace",
|
|
277
|
+
"trigger": {"type": "cron", "schedule": "0 9 * * 1-5", "timezone": "America/New_York"}
|
|
278
|
+
}'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Weekly cleanup:**
|
|
282
|
+
```bash
|
|
283
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
284
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
285
|
+
-H "Content-Type: application/json" \
|
|
286
|
+
-d '{
|
|
287
|
+
"name": "Weekly Cleanup",
|
|
288
|
+
"prompt": "Clean up temporary files older than 7 days and send a summary of what was removed",
|
|
289
|
+
"trigger": {"type": "cron", "schedule": "0 2 * * 0", "timezone": "UTC"},
|
|
290
|
+
"timeout": 300
|
|
291
|
+
}'
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Polling as a Webhook Alternative
|
|
297
|
+
|
|
298
|
+
When the deployment cannot receive inbound webhook traffic (see rule 5), use a cron-triggered automation that calls the external service’s API on a schedule to check for new events.
|
|
299
|
+
|
|
300
|
+
### Polling vs. Webhooks at a Glance
|
|
301
|
+
|
|
302
|
+
| | Webhooks (Event trigger) | Polling (Cron trigger) |
|
|
303
|
+
|---|---|---|
|
|
304
|
+
| **Requires public URL** | Yes | No — works locally |
|
|
305
|
+
| **Latency** | Near-instant | Up to one poll interval |
|
|
306
|
+
| **API calls** | Only on real events | Every poll interval |
|
|
307
|
+
| **Best for** | Cloud / public deployments | Local or private deployments |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Event-Triggered Automations (Webhooks)
|
|
312
|
+
|
|
313
|
+
Event-triggered automations run when a webhook event occurs — like a GitHub PR being opened, an issue receiving a comment, or a custom service sending a notification.
|
|
314
|
+
|
|
315
|
+
### Built-in Integrations
|
|
316
|
+
|
|
317
|
+
**GitHub** is a built-in integration — no webhook registration needed. Just create automations with `"source": "github"`.
|
|
318
|
+
|
|
319
|
+
### GitHub Event Keys
|
|
320
|
+
|
|
321
|
+
Events use the format `{event_type}.{action}` or just `{event_type}` (for events without actions like `push`).
|
|
322
|
+
|
|
323
|
+
| Event Type | Event Keys | Description |
|
|
324
|
+
|------------|------------|-------------|
|
|
325
|
+
| `pull_request` | `pull_request.opened`, `pull_request.closed`, `pull_request.synchronize`, `pull_request.labeled`, `pull_request.unlabeled`, `pull_request.reopened`, `pull_request.edited`, `pull_request.ready_for_review` | PR activity |
|
|
326
|
+
| `issues` | `issues.opened`, `issues.closed`, `issues.reopened`, `issues.labeled`, `issues.unlabeled`, `issues.edited`, `issues.assigned` | Issue activity |
|
|
327
|
+
| `issue_comment` | `issue_comment.created`, `issue_comment.edited`, `issue_comment.deleted` | Comments on issues/PRs |
|
|
328
|
+
| `push` | `push` | Code pushed to a branch |
|
|
329
|
+
| `release` | `release.published`, `release.created`, `release.released`, `release.prereleased` | Release activity |
|
|
330
|
+
| `pull_request_review` | `pull_request_review.submitted`, `pull_request_review.edited`, `pull_request_review.dismissed` | PR review activity |
|
|
331
|
+
|
|
332
|
+
**Wildcards:** Use `*` to match any action — e.g., `pull_request.*` matches all PR events.
|
|
333
|
+
|
|
334
|
+
**Multiple patterns:** The `on` field can be a string or array — e.g., `["push", "pull_request.opened"]`.
|
|
335
|
+
|
|
336
|
+
### Filter Expressions (JMESPath)
|
|
337
|
+
|
|
338
|
+
Filters let you match events based on payload content using JMESPath expressions.
|
|
339
|
+
|
|
340
|
+
#### Available Functions
|
|
341
|
+
|
|
342
|
+
| Function | Description | Example |
|
|
343
|
+
|----------|-------------|---------|
|
|
344
|
+
| `glob(str, pattern)` | Wildcard pattern matching | `glob(repository.full_name, 'myorg/*')` |
|
|
345
|
+
| `icontains(str, substr)` | Case-insensitive substring | `icontains(comment.body, '@openhands')` |
|
|
346
|
+
| `contains(array, value)` | Array contains value | `contains(pull_request.labels[].name, 'bug')` |
|
|
347
|
+
| `regex(str, pattern)` | Regular expression match | `regex(ref, '^refs/tags/v\\d+')` |
|
|
348
|
+
| `starts_with(str, prefix)` | String starts with | `starts_with(ref, 'refs/heads/')` |
|
|
349
|
+
| `ends_with(str, suffix)` | String ends with | `ends_with(ref, '/main')` |
|
|
350
|
+
| `lower(str)` / `upper(str)` | Case conversion | `lower(sender.login) == 'admin'` |
|
|
351
|
+
|
|
352
|
+
#### Boolean Operators
|
|
353
|
+
|
|
354
|
+
- `&&` — AND
|
|
355
|
+
- `||` — OR
|
|
356
|
+
- `!` — NOT
|
|
357
|
+
|
|
358
|
+
#### Filter Examples
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
// Exact match on label name
|
|
362
|
+
"contains(pull_request.labels[].name, 'openhands')"
|
|
363
|
+
|
|
364
|
+
// Case-insensitive mention in comment
|
|
365
|
+
"icontains(comment.body, '@openhands')"
|
|
366
|
+
|
|
367
|
+
// Match specific repository
|
|
368
|
+
"repository.full_name == 'myorg/myrepo'"
|
|
369
|
+
|
|
370
|
+
// Match any repo in an org
|
|
371
|
+
"glob(repository.full_name, 'myorg/*')"
|
|
372
|
+
|
|
373
|
+
// PR with 'bug' label in any org repo
|
|
374
|
+
"glob(repository.full_name, 'myorg/*') && contains(pull_request.labels[].name, 'bug')"
|
|
375
|
+
|
|
376
|
+
// Push to main or release branches
|
|
377
|
+
"glob(ref, 'refs/heads/main') || glob(ref, 'refs/heads/release/*')"
|
|
378
|
+
|
|
379
|
+
// Issue opened by a specific user
|
|
380
|
+
"sender.login == 'dependabot[bot]'"
|
|
381
|
+
|
|
382
|
+
// Not a draft PR
|
|
383
|
+
"!pull_request.draft"
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
### Event-Triggered Examples
|
|
389
|
+
|
|
390
|
+
#### GitHub: Respond to @openhands mentions in comments
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
394
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
395
|
+
-H "Content-Type: application/json" \
|
|
396
|
+
-d '{
|
|
397
|
+
"name": "OpenHands Mention Responder",
|
|
398
|
+
"prompt": "Analyze the issue or PR context and provide a helpful response to the user'\''s question. The comment body and context are available in the event payload.",
|
|
399
|
+
"trigger": {
|
|
400
|
+
"type": "event",
|
|
401
|
+
"source": "github",
|
|
402
|
+
"on": "issue_comment.created",
|
|
403
|
+
"filter": "icontains(comment.body, '\''@openhands'\'')"
|
|
404
|
+
},
|
|
405
|
+
"timeout": 300
|
|
406
|
+
}'
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
#### GitHub: Auto-review PRs with the "openhands" label
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
413
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
414
|
+
-H "Content-Type: application/json" \
|
|
415
|
+
-d '{
|
|
416
|
+
"name": "Auto Review PRs",
|
|
417
|
+
"prompt": "Review this pull request for code quality, potential bugs, and best practices. Provide constructive feedback.",
|
|
418
|
+
"trigger": {
|
|
419
|
+
"type": "event",
|
|
420
|
+
"source": "github",
|
|
421
|
+
"on": "pull_request.labeled",
|
|
422
|
+
"filter": "contains(pull_request.labels[].name, '\''openhands'\'')"
|
|
423
|
+
}
|
|
424
|
+
}'
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
#### GitHub: Run tests on push to main
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
431
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
432
|
+
-H "Content-Type: application/json" \
|
|
433
|
+
-d '{
|
|
434
|
+
"name": "Run Tests on Main",
|
|
435
|
+
"prompt": "Clone the repository and run the test suite. Report any failures.",
|
|
436
|
+
"trigger": {
|
|
437
|
+
"type": "event",
|
|
438
|
+
"source": "github",
|
|
439
|
+
"on": "push",
|
|
440
|
+
"filter": "ref == '\''refs/heads/main'\''"
|
|
441
|
+
}
|
|
442
|
+
}'
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### GitHub: Triage new issues in specific repos
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
449
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
450
|
+
-H "Content-Type: application/json" \
|
|
451
|
+
-d '{
|
|
452
|
+
"name": "Issue Triage Bot",
|
|
453
|
+
"prompt": "Analyze this new issue and suggest appropriate labels. If it looks like a bug, try to identify the root cause.",
|
|
454
|
+
"trigger": {
|
|
455
|
+
"type": "event",
|
|
456
|
+
"source": "github",
|
|
457
|
+
"on": "issues.opened",
|
|
458
|
+
"filter": "glob(repository.full_name, '\''myorg/*'\'')"
|
|
459
|
+
}
|
|
460
|
+
}'
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
#### GitHub: Respond to multiple event types
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
467
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
468
|
+
-H "Content-Type: application/json" \
|
|
469
|
+
-d '{
|
|
470
|
+
"name": "PR Activity Bot",
|
|
471
|
+
"prompt": "Process the PR event and take appropriate action based on the event type.",
|
|
472
|
+
"trigger": {
|
|
473
|
+
"type": "event",
|
|
474
|
+
"source": "github",
|
|
475
|
+
"on": ["pull_request.opened", "pull_request.synchronize", "pull_request.ready_for_review"]
|
|
476
|
+
}
|
|
477
|
+
}'
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Custom Webhooks
|
|
483
|
+
|
|
484
|
+
For services other than GitHub (Linear, Stripe, Slack, etc.), register a custom webhook first.
|
|
485
|
+
|
|
486
|
+
> **Agent behavior:**
|
|
487
|
+
> - **Always provide the curl request** to the user — do not attempt to register webhooks yourself.
|
|
488
|
+
> - **Ask the user:** "Do you have a webhook signing secret from [service], or should the system generate one?"
|
|
489
|
+
> - If they have one → include `webhook_secret` in the request
|
|
490
|
+
> - If not → omit it; the response will contain a generated secret they must configure in their service
|
|
491
|
+
|
|
492
|
+
### Register a Custom Webhook
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/webhooks" \
|
|
496
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
497
|
+
-H "Content-Type: application/json" \
|
|
498
|
+
-d '{
|
|
499
|
+
"name": "Linear Issues",
|
|
500
|
+
"source": "linear",
|
|
501
|
+
"event_key_expr": "type",
|
|
502
|
+
"signature_header": "Linear-Signature",
|
|
503
|
+
"webhook_secret": "your-linear-webhook-secret"
|
|
504
|
+
}'
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
#### Webhook Fields
|
|
508
|
+
|
|
509
|
+
| Field | Required | Description |
|
|
510
|
+
|-------|----------|-------------|
|
|
511
|
+
| `name` | Yes | Human-readable name for the webhook |
|
|
512
|
+
| `source` | Yes | Unique source identifier (lowercase, alphanumeric with hyphens, 1-50 chars) |
|
|
513
|
+
| `event_key_expr` | No | JMESPath expression to extract event type from payload (default: `"type"`) |
|
|
514
|
+
| `signature_header` | No | HTTP header containing HMAC signature (default: `"X-Signature-256"`) |
|
|
515
|
+
| `webhook_secret` | No | Signing secret — provide your own (from the external service) or let the system generate one |
|
|
516
|
+
|
|
517
|
+
#### Response
|
|
518
|
+
|
|
519
|
+
```json
|
|
520
|
+
{
|
|
521
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
522
|
+
"webhook_url": "https://app.all-hands.dev/v1/events/{org_id}/linear",
|
|
523
|
+
"source": "linear",
|
|
524
|
+
"enabled": true
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Note:** When you provide your own `webhook_secret`, it won't be echoed back in the response. If you don't provide one, the system generates a secret and returns it once — store it securely.
|
|
529
|
+
|
|
530
|
+
### Manage Custom Webhooks
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
# List all webhooks
|
|
534
|
+
curl "${OPENHANDS_HOST}/api/automation/v1/webhooks" \
|
|
535
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
536
|
+
|
|
537
|
+
# Update a webhook
|
|
538
|
+
curl -X PATCH "${OPENHANDS_HOST}/api/automation/v1/webhooks/{webhook_id}" \
|
|
539
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
540
|
+
-H "Content-Type: application/json" \
|
|
541
|
+
-d '{"enabled": false}'
|
|
542
|
+
|
|
543
|
+
# Rotate the signing secret
|
|
544
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/webhooks/{webhook_id}/rotate-secret" \
|
|
545
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
546
|
+
|
|
547
|
+
# Delete a webhook
|
|
548
|
+
curl -X DELETE "${OPENHANDS_HOST}/api/automation/v1/webhooks/{webhook_id}" \
|
|
549
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Custom Webhook Example: Linear
|
|
553
|
+
|
|
554
|
+
Linear sends webhooks with:
|
|
555
|
+
- Signature header: `Linear-Signature`
|
|
556
|
+
- Event type in payload: `type` field (e.g., `Issue`, `Comment`, `Project`)
|
|
557
|
+
- Action in payload: `action` field (e.g., `create`, `update`, `remove`)
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
# 1. Register the Linear webhook
|
|
561
|
+
# - Get your webhook signing secret from Linear's webhook settings
|
|
562
|
+
# - Use "Linear-Signature" as the signature header
|
|
563
|
+
# - Use "type" to extract the event type from the payload
|
|
564
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/webhooks" \
|
|
565
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
566
|
+
-H "Content-Type: application/json" \
|
|
567
|
+
-d '{
|
|
568
|
+
"name": "Linear Issues",
|
|
569
|
+
"source": "linear",
|
|
570
|
+
"event_key_expr": "type",
|
|
571
|
+
"signature_header": "Linear-Signature",
|
|
572
|
+
"webhook_secret": "lin_wh_xxxxxxxxxxxxx"
|
|
573
|
+
}'
|
|
574
|
+
|
|
575
|
+
# Response includes webhook_url — configure this in Linear:
|
|
576
|
+
# Settings → API → Webhooks → New webhook → paste the webhook_url
|
|
577
|
+
|
|
578
|
+
# 2. Create an automation for new Linear issues
|
|
579
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
580
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
581
|
+
-H "Content-Type: application/json" \
|
|
582
|
+
-d '{
|
|
583
|
+
"name": "Triage New Linear Issues",
|
|
584
|
+
"prompt": "A new issue was created in Linear. Analyze the issue title and description, suggest appropriate labels, and add a comment with initial triage notes.",
|
|
585
|
+
"trigger": {
|
|
586
|
+
"type": "event",
|
|
587
|
+
"source": "linear",
|
|
588
|
+
"on": "Issue",
|
|
589
|
+
"filter": "action == '\''create'\''"
|
|
590
|
+
}
|
|
591
|
+
}'
|
|
592
|
+
|
|
593
|
+
# 3. Create an automation for high-priority issue updates
|
|
594
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
595
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
596
|
+
-H "Content-Type: application/json" \
|
|
597
|
+
-d '{
|
|
598
|
+
"name": "High Priority Issue Alert",
|
|
599
|
+
"prompt": "A high-priority issue was updated. Review the changes and notify the team if action is needed.",
|
|
600
|
+
"trigger": {
|
|
601
|
+
"type": "event",
|
|
602
|
+
"source": "linear",
|
|
603
|
+
"on": "Issue",
|
|
604
|
+
"filter": "action == '\''update'\'' && data.priority == `1`"
|
|
605
|
+
}
|
|
606
|
+
}'
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Common Signature Headers by Service
|
|
610
|
+
|
|
611
|
+
| Service | Signature Header | Event Key Expression |
|
|
612
|
+
|---------|-----------------|---------------------|
|
|
613
|
+
| Linear | `Linear-Signature` | `type` |
|
|
614
|
+
| Stripe | `Stripe-Signature` | `type` |
|
|
615
|
+
| Slack | `X-Slack-Signature` | `type` |
|
|
616
|
+
| Twilio | `X-Twilio-Signature` | `type` |
|
|
617
|
+
| Generic | `X-Signature-256` | `type` |
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
### Plugin Preset
|
|
622
|
+
|
|
623
|
+
Use the **preset/plugin endpoint** when you need to load one or more plugins that provide extended capabilities like skills, MCP configurations, hooks, and commands.
|
|
624
|
+
|
|
625
|
+
> **💡 Finding plugins:** Browse the [OpenHands/extensions](https://github.com/OpenHands/extensions) repository for available skills and plugins. When given a broad use case, check this directory first to see if something already exists that fits your needs.
|
|
626
|
+
|
|
627
|
+
#### How It Works
|
|
628
|
+
|
|
629
|
+
1. Specify one or more plugins (from GitHub repos, git URLs, or monorepo subdirectories)
|
|
630
|
+
2. Provide a prompt that can invoke plugin commands (e.g., `/plugin-name:command`)
|
|
631
|
+
3. The service generates SDK boilerplate that loads all plugins at runtime, creates a conversation with plugin capabilities, and executes the prompt
|
|
632
|
+
4. The service packages everything into a tarball, uploads it, and creates the automation
|
|
633
|
+
|
|
634
|
+
#### Request
|
|
635
|
+
|
|
636
|
+
```bash
|
|
637
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/plugin" \
|
|
638
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
639
|
+
-H "Content-Type: application/json" \
|
|
640
|
+
-d '{
|
|
641
|
+
"name": "My Plugin Automation",
|
|
642
|
+
"plugins": [
|
|
643
|
+
{"source": "github:owner/repo", "ref": "v1.0.0"},
|
|
644
|
+
{"source": "github:owner/another-plugin"}
|
|
645
|
+
],
|
|
646
|
+
"prompt": "Use the plugin commands to perform the task",
|
|
647
|
+
"trigger": {
|
|
648
|
+
"type": "cron",
|
|
649
|
+
"schedule": "0 9 * * 1",
|
|
650
|
+
"timezone": "UTC"
|
|
651
|
+
}
|
|
652
|
+
}'
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### Request Fields
|
|
656
|
+
|
|
657
|
+
| Field | Required | Description |
|
|
658
|
+
|-------|----------|-------------|
|
|
659
|
+
| `name` | Yes | Name of the automation (1-500 characters) |
|
|
660
|
+
| `plugins` | Yes | List of plugin sources (at least one required) |
|
|
661
|
+
| `plugins[].source` | Yes | Plugin source: `github:owner/repo`, git URL, or local path |
|
|
662
|
+
| `plugins[].ref` | No | Git ref: branch, tag, or commit SHA |
|
|
663
|
+
| `plugins[].repo_path` | No | Subdirectory path for monorepos |
|
|
664
|
+
| `prompt` | Yes | Instructions for the automation (1-50,000 characters) |
|
|
665
|
+
| `trigger` | Yes | Trigger configuration — either `cron` or `event` (same as Prompt Preset) |
|
|
666
|
+
| `timeout` | No | Max execution time in seconds (default: system maximum) |
|
|
667
|
+
| `repos` | No | Repositories to clone (see [Repository Cloning](#repository-cloning)) |
|
|
668
|
+
|
|
669
|
+
#### Plugin Source Formats
|
|
670
|
+
|
|
671
|
+
| Format | Example | Description |
|
|
672
|
+
|--------|---------|-------------|
|
|
673
|
+
| GitHub shorthand | `github:owner/repo` | Fetches from GitHub |
|
|
674
|
+
| Git URL | `https://github.com/owner/repo.git` | Any git repository |
|
|
675
|
+
| With ref | `{"source": "github:owner/repo", "ref": "v1.0.0"}` | Specific branch/tag/commit |
|
|
676
|
+
| Monorepo | `{"source": "github:org/monorepo", "repo_path": "plugins/my-plugin"}` | Subdirectory in repo |
|
|
677
|
+
|
|
678
|
+
#### Response (HTTP 201)
|
|
679
|
+
|
|
680
|
+
```json
|
|
681
|
+
{
|
|
682
|
+
"id": "123e4567-e89b-12d3-a456-426614174000",
|
|
683
|
+
"name": "My Plugin Automation",
|
|
684
|
+
"trigger": {"type": "cron", "schedule": "0 9 * * 1", "timezone": "UTC"},
|
|
685
|
+
"enabled": true,
|
|
686
|
+
"created_at": "2025-03-25T10:00:00Z"
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
#### Plugin Preset Examples
|
|
691
|
+
|
|
692
|
+
**Single plugin with version:**
|
|
693
|
+
```bash
|
|
694
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/plugin" \
|
|
695
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
696
|
+
-H "Content-Type: application/json" \
|
|
697
|
+
-d '{
|
|
698
|
+
"name": "Code Review Automation",
|
|
699
|
+
"plugins": [
|
|
700
|
+
{"source": "github:owner/code-review-plugin", "ref": "v2.0.0"}
|
|
701
|
+
],
|
|
702
|
+
"prompt": "Review all Python files in the repository for code quality issues",
|
|
703
|
+
"trigger": {"type": "cron", "schedule": "0 9 * * 1-5", "timezone": "UTC"}
|
|
704
|
+
}'
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
**Multiple plugins:**
|
|
708
|
+
```bash
|
|
709
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/plugin" \
|
|
710
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
711
|
+
-H "Content-Type: application/json" \
|
|
712
|
+
-d '{
|
|
713
|
+
"name": "Security Scan Automation",
|
|
714
|
+
"plugins": [
|
|
715
|
+
{"source": "github:owner/security-scanner"},
|
|
716
|
+
{"source": "github:owner/report-generator", "ref": "main"}
|
|
717
|
+
],
|
|
718
|
+
"prompt": "Run a security scan on the codebase and generate a report",
|
|
719
|
+
"trigger": {"type": "cron", "schedule": "0 2 * * 0", "timezone": "UTC"},
|
|
720
|
+
"timeout": 600
|
|
721
|
+
}'
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
**Monorepo plugin:**
|
|
725
|
+
```bash
|
|
726
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/plugin" \
|
|
727
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
728
|
+
-H "Content-Type: application/json" \
|
|
729
|
+
-d '{
|
|
730
|
+
"name": "Style Guide Enforcement",
|
|
731
|
+
"plugins": [
|
|
732
|
+
{"source": "github:company/monorepo", "repo_path": "plugins/style-guide", "ref": "main"}
|
|
733
|
+
],
|
|
734
|
+
"prompt": "Check all files against the company style guide",
|
|
735
|
+
"trigger": {"type": "cron", "schedule": "0 8 * * 1", "timezone": "America/Los_Angeles"}
|
|
736
|
+
}'
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## Repository Cloning
|
|
742
|
+
|
|
743
|
+
Both presets support an optional `repos` field to clone repositories into the sandbox before execution. Cloned repos have their skills (AGENTS.md, `.agents/skills/`) automatically loaded.
|
|
744
|
+
|
|
745
|
+
### Repo Source Formats
|
|
746
|
+
|
|
747
|
+
| Format | Example | Description |
|
|
748
|
+
|--------|---------|-------------|
|
|
749
|
+
| Full URL | `"https://github.com/owner/repo"` | Provider auto-detected |
|
|
750
|
+
| Full URL + ref | `{"url": "https://github.com/owner/repo", "ref": "main"}` | With branch/tag/SHA |
|
|
751
|
+
| Short URL | `{"url": "owner/repo", "provider": "github"}` | Requires `provider` field |
|
|
752
|
+
|
|
753
|
+
**Supported providers:** `github`, `gitlab`, `bitbucket`
|
|
754
|
+
|
|
755
|
+
> **Note:** Short URLs (`owner/repo`) require an explicit `provider` field. Full URLs auto-detect the provider.
|
|
756
|
+
|
|
757
|
+
### Examples
|
|
758
|
+
|
|
759
|
+
**Single repo (full URL):**
|
|
760
|
+
```json
|
|
761
|
+
{
|
|
762
|
+
"repos": ["https://github.com/OpenHands/openhands-cli"]
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
**Multiple repos with refs:**
|
|
767
|
+
```json
|
|
768
|
+
{
|
|
769
|
+
"repos": [
|
|
770
|
+
{"url": "https://github.com/owner/repo1", "ref": "main"},
|
|
771
|
+
{"url": "https://gitlab.com/owner/repo2", "ref": "v1.0.0"}
|
|
772
|
+
]
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
**Short URL with provider:**
|
|
777
|
+
```json
|
|
778
|
+
{
|
|
779
|
+
"repos": [
|
|
780
|
+
{"url": "owner/repo", "provider": "github", "ref": "main"}
|
|
781
|
+
]
|
|
782
|
+
}
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Complete Automation Example
|
|
786
|
+
|
|
787
|
+
```bash
|
|
788
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/preset/prompt" \
|
|
789
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
790
|
+
-H "Content-Type: application/json" \
|
|
791
|
+
-d '{
|
|
792
|
+
"name": "Analyze Codebase",
|
|
793
|
+
"prompt": "Analyze the openhands-cli codebase and generate a summary report",
|
|
794
|
+
"trigger": {"type": "cron", "schedule": "0 9 * * 1"},
|
|
795
|
+
"repos": [
|
|
796
|
+
{"url": "https://github.com/OpenHands/openhands-cli", "ref": "main"}
|
|
797
|
+
]
|
|
798
|
+
}'
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
---
|
|
802
|
+
|
|
803
|
+
## Managing Automations
|
|
804
|
+
|
|
805
|
+
### List Automations
|
|
806
|
+
|
|
807
|
+
```bash
|
|
808
|
+
curl "${OPENHANDS_HOST}/api/automation/v1?limit=20" \
|
|
809
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### Get / Update / Delete
|
|
813
|
+
|
|
814
|
+
```bash
|
|
815
|
+
# Get details
|
|
816
|
+
curl "${OPENHANDS_HOST}/api/automation/v1/{automation_id}" \
|
|
817
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
818
|
+
|
|
819
|
+
# Update (fields: name, trigger, enabled, timeout)
|
|
820
|
+
curl -X PATCH "${OPENHANDS_HOST}/api/automation/v1/{automation_id}" \
|
|
821
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}" \
|
|
822
|
+
-H "Content-Type: application/json" \
|
|
823
|
+
-d '{"enabled": false}'
|
|
824
|
+
|
|
825
|
+
# Delete
|
|
826
|
+
curl -X DELETE "${OPENHANDS_HOST}/api/automation/v1/{automation_id}" \
|
|
827
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
### Trigger and Monitor Runs
|
|
831
|
+
|
|
832
|
+
```bash
|
|
833
|
+
# Manually trigger a run
|
|
834
|
+
curl -X POST "${OPENHANDS_HOST}/api/automation/v1/{automation_id}/dispatch" \
|
|
835
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
836
|
+
|
|
837
|
+
# List runs
|
|
838
|
+
curl "${OPENHANDS_HOST}/api/automation/v1/{automation_id}/runs?limit=20" \
|
|
839
|
+
-H "Authorization: Bearer ${OPENHANDS_API_KEY}"
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
Run status values: `PENDING` (waiting for dispatch), `RUNNING` (in progress), `COMPLETED` (success), `FAILED` (check `error_detail`).
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## Run Lifecycle
|
|
847
|
+
|
|
848
|
+
When a run completes, the automation service receives a callback and marks the run done. Any conversations started during the run remain accessible in the OpenHands UI — users can view the history and continue interacting. The agent server persists until it times out or is manually deleted.
|
|
849
|
+
|
|
850
|
+
The automation script itself controls when the callback fires (signalling completion). For simple synchronous scripts this happens naturally on exit. For scripts that start asynchronous conversations, the callback should be deferred until the conversation reaches an idle state (see `references/custom-automation.md` for patterns).
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## Choosing the Right Preset
|
|
855
|
+
|
|
856
|
+
Pick based on **what the task needs**, not just **what is technically possible**. An LLM-driven preset can do almost anything, so "the preset can satisfy this" is not by itself a good reason to pick it — every run costs tokens and sandbox time.
|
|
857
|
+
|
|
858
|
+
| Use Case | Recommended |
|
|
859
|
+
|----------|-------------|
|
|
860
|
+
| Reasoning, summarization, triage, code review, or open-ended tool use | **Prompt Preset** |
|
|
861
|
+
| Needs plugin commands / skills / MCP configs / hooks | **Plugin Preset** |
|
|
862
|
+
| Compare plugin versions or configurations across runs | **Plugin Preset with A/B testing** — see `references/ab-testing.md` |
|
|
863
|
+
| **Deterministic task** (fixed data + scheduled action, e.g. healthcheck, Slack notification, rotating from a known list) — especially if it runs frequently | **Custom script, no LLM** — see `references/custom-automation.md#deterministic-script-no-llm` |
|
|
864
|
+
| Custom Python dependencies, multi-file project, or direct SDK lifecycle control | **Custom script with SDK** — see `references/custom-automation.md#sdk-based-scripts` |
|
|
865
|
+
|
|
866
|
+
The **prompt preset** is the right default for genuinely agent-shaped work — anything that benefits from reasoning over context, calling tools dynamically, or producing a non-templated output. Use the **plugin preset** when you need extended capabilities from plugins (skills, MCP configurations, hooks, commands).
|
|
867
|
+
|
|
868
|
+
**Watch for deterministic, high-frequency patterns.** Requests like "send a daily standup reminder", "ping a healthcheck URL every minute", "post a random quote every 5 minutes", or "rotate a fact-of-the-day message" do not need an LLM. Surface this to the user explicitly with a rough cost framing (e.g. "this schedule will invoke your LLM ~288 times/day") before defaulting to a preset. As a rule of thumb, any cron tighter than hourly deserves a deliberate "should this really be agent-driven?" check.
|
|
869
|
+
|
|
870
|
+
**When neither preset is the right fit** (deterministic task, custom Python dependencies, non-Python entrypoint, multi-file project structure, direct SDK lifecycle control), explain the options to the user and let them decide. Do not attempt custom automation without explicit user agreement. If they choose the custom route, refer to `references/custom-automation.md`.
|
|
871
|
+
|
|
872
|
+
## Reference Files
|
|
873
|
+
|
|
874
|
+
- **`references/custom-automation.md`** — Detailed guide for custom automations: tarball uploads, code structure (SDK and no-LLM), environment variables, validation rules, and complete examples. Consult this whenever you need to evaluate or recommend the custom path (including for deterministic / cost-sensitive tasks per rule 0). Only *implement* a custom automation after the user agrees to that path.
|
|
875
|
+
- **`references/ab-testing.md`** — A/B testing for plugin automations: defining variants with weights, experiment configuration, variant selection logic, observability via conversation tags, and complete examples. Consult this when a user wants to compare plugin versions or configurations.
|