From c3f622ee2652b4dae7bf9a74f75c55b4e4180103 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 25 Mar 2026 14:44:39 +0000 Subject: [PATCH 1/6] Add automation-creation plugin Add a new plugin that helps users create OpenHands automations through a guided slash command interface. Features: - /automation:create slash command for interactive automation setup - Collects name, cron schedule, tarball path, entrypoint, and timeout - Validates inputs before API call - Provides helpful cron schedule examples - Supports timeout configuration (1-600 seconds) Plugin structure follows Claude Code marketplace format: - .claude-plugin/plugin.json: Plugin manifest - commands/create.md: Slash command definition - README.md: Documentation with API reference Co-authored-by: openhands --- .../.claude-plugin/plugin.json | 13 ++ plugins/automation-creation/README.md | 181 ++++++++++++++++++ .../automation-creation/commands/create.md | 155 +++++++++++++++ 3 files changed, 349 insertions(+) create mode 100644 plugins/automation-creation/.claude-plugin/plugin.json create mode 100644 plugins/automation-creation/README.md create mode 100644 plugins/automation-creation/commands/create.md diff --git a/plugins/automation-creation/.claude-plugin/plugin.json b/plugins/automation-creation/.claude-plugin/plugin.json new file mode 100644 index 0000000..5f47cb0 --- /dev/null +++ b/plugins/automation-creation/.claude-plugin/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "automation-creation", + "version": "1.0.0", + "description": "Create and manage OpenHands automations - scheduled tasks that run in sandboxes", + "author": { + "name": "OpenHands", + "email": "contact@all-hands.dev" + }, + "homepage": "https://github.com/OpenHands/extensions", + "repository": "https://github.com/OpenHands/extensions", + "license": "MIT", + "keywords": ["automation", "scheduling", "cron", "sandbox", "openhands"] +} diff --git a/plugins/automation-creation/README.md b/plugins/automation-creation/README.md new file mode 100644 index 0000000..11dc584 --- /dev/null +++ b/plugins/automation-creation/README.md @@ -0,0 +1,181 @@ +# Automation Creation Plugin + +Create and manage OpenHands automations - scheduled tasks that run SDK scripts in sandboxes on a cron schedule. + +## Features + +- **Slash command**: `/automation:create` - Create a new automation interactively +- **Cron scheduling**: Schedule automations to run on any cron schedule +- **Tarball uploads**: Upload your SDK code as a tarball +- **Configurable timeout**: Set execution timeout (up to 10 minutes) +- **Setup scripts**: Optional setup.sh for environment preparation + +## Usage + +### Create an Automation + +``` +/automation:create +``` + +The agent will guide you through: +1. Providing a name for your automation +2. Setting up a cron schedule (e.g., `0 9 * * 5` for every Friday at 9 AM) +3. Specifying your code tarball path +4. Defining the entrypoint command +5. Optionally setting a timeout and setup script + +### Example Interaction + +``` +User: /automation:create + +Agent: I'll help you create a new automation. Please provide the following details: + +1. **Name**: What would you like to call this automation? + +User: Weekly Report Generator + +Agent: 2. **Cron Schedule**: When should this run? (e.g., "0 9 * * 5" for Fridays at 9 AM UTC) + +User: 0 9 * * 1 + +Agent: 3. **Tarball Path**: Where is your code? This can be: + - An uploaded tarball: `oh-internal://uploads/{uuid}` + - An external URL: `https://...`, `s3://...`, or `gs://...` + +User: s3://my-bucket/automations/weekly-report.tar.gz + +Agent: 4. **Entrypoint**: What command runs your automation? (e.g., "uv run main.py") + +User: python generate_report.py + +Agent: Creating your automation... + +✅ Automation created successfully! +- ID: 550e8400-e29b-41d4-a716-446655440000 +- Name: Weekly Report Generator +- Schedule: Every Monday at 9:00 AM UTC +- Status: Enabled +``` + +## API Reference + +The automation service exposes a REST API at `/api/v1/automations`: + +### Create Automation + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "My Automation", + "trigger": { + "type": "cron", + "schedule": "0 9 * * 5", + "timezone": "UTC" + }, + "tarball_path": "s3://bucket/code.tar.gz", + "entrypoint": "uv run main.py", + "timeout": 300 + }' +``` + +### Request Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | Name of the automation (1-500 characters) | +| `trigger.type` | Yes | Must be `"cron"` | +| `trigger.schedule` | Yes | Cron expression (e.g., `"0 9 * * 5"`) | +| `trigger.timezone` | No | IANA timezone (default: `"UTC"`) | +| `tarball_path` | Yes | Path to code tarball (`oh-internal://`, `s3://`, `gs://`, `https://`) | +| `entrypoint` | Yes | Command to execute (e.g., `"uv run main.py"`) | +| `setup_script_path` | No | Relative path to setup script inside tarball | +| `timeout` | No | Max execution time in seconds (1-600, default: 600) | + +### List Automations + +```bash +curl "https://automations.all-hands.dev/api/v1/automations" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Update Automation + +```bash +curl -X PATCH "https://automations.all-hands.dev/api/v1/automations/{id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "enabled": false + }' +``` + +### Manually Trigger a Run + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/automations/{id}/dispatch" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +## Cron Schedule Examples + +| Schedule | Description | +|----------|-------------| +| `0 9 * * *` | Every day at 9:00 AM | +| `0 9 * * 1` | Every Monday at 9:00 AM | +| `0 9 * * 5` | Every Friday at 9:00 AM | +| `0 0 1 * *` | First day of each month at midnight | +| `*/15 * * * *` | Every 15 minutes | +| `0 */6 * * *` | Every 6 hours | + +## Tarball Structure + +Your automation tarball should contain: + +``` +my-automation/ +├── main.py # Your entrypoint script +├── setup.sh # Optional setup script +├── requirements.txt # Dependencies (if using pip) +└── pyproject.toml # Or use uv/poetry +``` + +### Environment Variables + +Your script receives these environment variables: + +| Variable | Description | +|----------|-------------| +| `OPENHANDS_API_KEY` | API key for OpenHands services | +| `OPENHANDS_CLOUD_API_URL` | Base URL for the OpenHands Cloud API | +| `AUTOMATION_EVENT_PAYLOAD` | JSON with trigger info, automation ID, and name | +| `AUTOMATION_RUN_ID` | Unique ID for this run | +| `AUTOMATION_CALLBACK_URL` | URL to POST completion status | + +## Validation Rules + +- **Name**: 1-500 characters, required +- **Cron schedule**: Must be a valid cron expression +- **Entrypoint**: Must be a relative path, no shell metacharacters (`;&|` etc.) +- **Setup script path**: Must be relative, no path traversal (`..`) +- **Timeout**: 1-600 seconds (10 minutes max) + +## Plugin Structure + +``` +automation-creation/ +├── .claude-plugin/ +│ └── plugin.json # Plugin manifest +├── commands/ +│ └── create.md # Slash command definition +└── README.md # This file +``` + +## Related Resources + +- [OpenHands SDK Documentation](https://docs.openhands.dev/sdk) +- [OpenHands Cloud](https://app.all-hands.dev) +- [Cron Expression Reference](https://crontab.guru/) diff --git a/plugins/automation-creation/commands/create.md b/plugins/automation-creation/commands/create.md new file mode 100644 index 0000000..ac3c6df --- /dev/null +++ b/plugins/automation-creation/commands/create.md @@ -0,0 +1,155 @@ +--- +allowed-tools: Bash(curl:*) +description: Create a new OpenHands automation with cron scheduling +--- + +# Create OpenHands Automation + +Guide the user through creating a new automation that runs on a cron schedule. + +## Instructions + +Help the user create an automation by collecting the required information interactively. + +### Step 1: Collect Required Information + +Ask the user for each of these fields one at a time: + +1. **Name** (required): A descriptive name for the automation (1-500 characters) + +2. **Cron Schedule** (required): When the automation should run + - Examples: `0 9 * * *` (daily at 9 AM), `0 9 * * 5` (Fridays at 9 AM) + - Provide helpful examples based on what the user describes + +3. **Timezone** (optional): IANA timezone name (default: UTC) + - Examples: `America/New_York`, `Europe/London`, `Asia/Tokyo` + +4. **Tarball Path** (required): Location of the code to run + - Internal upload: `oh-internal://uploads/{uuid}` + - External URL: `https://...`, `s3://...`, or `gs://...` + +5. **Entrypoint** (required): Command to execute + - Examples: `uv run main.py`, `python script.py`, `./run.sh` + - Must be a relative path, no shell metacharacters + +6. **Setup Script Path** (optional): Relative path to setup script inside tarball + - Example: `setup.sh` + +7. **Timeout** (optional): Maximum execution time in seconds + - Range: 1-600 seconds (default: 600 = 10 minutes) + - Only positive integers allowed + +### Step 2: Validate the Information + +Before creating, validate: +- Name is not empty and ≤ 500 characters +- Cron schedule is valid (5 fields: minute hour day month weekday) +- Tarball path starts with `oh-internal://`, `s3://`, `gs://`, `http://`, or `https://` +- Entrypoint is a relative path without `..` or shell metacharacters (`;`, `&`, `|`, etc.) +- Timeout (if provided) is between 1 and 600 + +### Step 3: Create the Automation + +Use the OpenHands Automations API to create the automation: + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "USER_PROVIDED_NAME", + "trigger": { + "type": "cron", + "schedule": "USER_PROVIDED_SCHEDULE", + "timezone": "USER_PROVIDED_TIMEZONE_OR_UTC" + }, + "tarball_path": "USER_PROVIDED_TARBALL_PATH", + "entrypoint": "USER_PROVIDED_ENTRYPOINT", + "setup_script_path": "USER_PROVIDED_OR_NULL", + "timeout": USER_PROVIDED_OR_NULL + }' +``` + +Replace placeholders with actual values. Omit `setup_script_path` and `timeout` if not provided. + +### Step 4: Present the Result + +On success (HTTP 201), display: +- ✅ Automation created successfully! +- **ID**: The automation UUID +- **Name**: The name provided +- **Schedule**: Human-readable description of the cron schedule +- **Timezone**: The timezone +- **Status**: Enabled + +On error (HTTP 4xx/5xx), display: +- ❌ Failed to create automation +- The error message from the API response + +## Cron Schedule Reference + +Help users construct cron schedules: + +| Field | Values | Description | +|-------|--------|-------------| +| Minute | 0-59 | Minute of the hour | +| Hour | 0-23 | Hour of the day (24-hour format) | +| Day | 1-31 | Day of the month | +| Month | 1-12 | Month of the year | +| Weekday | 0-6 | Day of week (0=Sunday, 1=Monday, ..., 6=Saturday) | + +Common patterns: +- `0 9 * * *` → Every day at 9:00 AM +- `0 9 * * 1-5` → Weekdays at 9:00 AM +- `0 9 * * 0` → Every Sunday at 9:00 AM +- `0 0 1 * *` → First day of each month at midnight +- `*/30 * * * *` → Every 30 minutes + +## Example Conversation + +**User**: I want to create an automation that generates weekly reports every Monday morning. + +**Agent**: I'll help you create that automation. Let's go through the details: + +**1. Name**: What would you like to call this automation? + +**User**: Weekly Report Generator + +**Agent**: **2. Cron Schedule**: You mentioned Monday mornings. What time would you like it to run? (in UTC) + +**User**: 9 AM + +**Agent**: So `0 9 * * 1` for every Monday at 9:00 AM UTC. + +**3. Tarball Path**: Where is your automation code stored? + +**User**: s3://my-bucket/automations/weekly-report.tar.gz + +**Agent**: **4. Entrypoint**: What command runs your report generator? + +**User**: python generate_report.py + +**Agent**: **5. Setup Script** (optional): Do you need a setup script to run first? + +**User**: No + +**Agent**: **6. Timeout** (optional): How long should it be allowed to run? (max 600 seconds) + +**User**: 5 minutes should be enough + +**Agent**: Creating your automation with: +- Name: Weekly Report Generator +- Schedule: Every Monday at 9:00 AM UTC +- Code: s3://my-bucket/automations/weekly-report.tar.gz +- Command: python generate_report.py +- Timeout: 300 seconds + +[Executes API call] + +✅ Automation created successfully! +- **ID**: 550e8400-e29b-41d4-a716-446655440000 +- **Name**: Weekly Report Generator +- **Schedule**: Every Monday at 9:00 AM UTC +- **Status**: Enabled + +Your automation will run for the first time next Monday at 9:00 AM UTC. From 02c045b4fd1b537e36cfd6ee2ff3934ee2f7db53 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 25 Mar 2026 14:51:49 +0000 Subject: [PATCH 2/6] Add automation skill and update plugin with upload instructions Add skills/automation/: - SKILL.md with full API reference for uploads and automations - README.md with quick start guide - Triggers: automation, scheduled task, cron job, cron schedule Update plugins/automation-creation/: - Add tarball upload step before automation creation - Document upload constraints (1MB max, allowed content types) - Update create.md command with upload workflow - Add allowed-tools for tar, jq operations Co-authored-by: openhands --- plugins/automation-creation/README.md | 87 ++++- .../automation-creation/commands/create.md | 51 ++- skills/automation/README.md | 65 ++++ skills/automation/SKILL.md | 359 ++++++++++++++++++ 4 files changed, 542 insertions(+), 20 deletions(-) create mode 100644 skills/automation/README.md create mode 100644 skills/automation/SKILL.md diff --git a/plugins/automation-creation/README.md b/plugins/automation-creation/README.md index 11dc584..94205c8 100644 --- a/plugins/automation-creation/README.md +++ b/plugins/automation-creation/README.md @@ -5,8 +5,8 @@ Create and manage OpenHands automations - scheduled tasks that run SDK scripts i ## Features - **Slash command**: `/automation:create` - Create a new automation interactively +- **Tarball uploads**: Upload your SDK code as a tarball (up to 1MB) - **Cron scheduling**: Schedule automations to run on any cron schedule -- **Tarball uploads**: Upload your SDK code as a tarball - **Configurable timeout**: Set execution timeout (up to 10 minutes) - **Setup scripts**: Optional setup.sh for environment preparation @@ -19,9 +19,9 @@ Create and manage OpenHands automations - scheduled tasks that run SDK scripts i ``` The agent will guide you through: -1. Providing a name for your automation -2. Setting up a cron schedule (e.g., `0 9 * * 5` for every Friday at 9 AM) -3. Specifying your code tarball path +1. Uploading your code as a tarball (if needed) +2. Providing a name for your automation +3. Setting up a cron schedule (e.g., `0 9 * * 5` for every Friday at 9 AM) 4. Defining the entrypoint command 5. Optionally setting a timeout and setup script @@ -30,7 +30,20 @@ The agent will guide you through: ``` User: /automation:create -Agent: I'll help you create a new automation. Please provide the following details: +Agent: I'll help you create a new automation. First, do you: +1. Have local code that needs to be uploaded? +2. Already have a tarball URL (S3, GCS, HTTPS)? + +User: I have local code in ./my-automation/ + +Agent: I'll help you upload that. Let me create and upload the tarball... + +[Creates tarball and uploads] + +✅ Upload successful! +- Tarball path: oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000 + +Now let's configure the automation: 1. **Name**: What would you like to call this automation? @@ -40,26 +53,72 @@ Agent: 2. **Cron Schedule**: When should this run? (e.g., "0 9 * * 5" for Friday User: 0 9 * * 1 -Agent: 3. **Tarball Path**: Where is your code? This can be: - - An uploaded tarball: `oh-internal://uploads/{uuid}` - - An external URL: `https://...`, `s3://...`, or `gs://...` - -User: s3://my-bucket/automations/weekly-report.tar.gz - -Agent: 4. **Entrypoint**: What command runs your automation? (e.g., "uv run main.py") +Agent: 3. **Entrypoint**: What command runs your automation? (e.g., "uv run main.py") User: python generate_report.py Agent: Creating your automation... ✅ Automation created successfully! -- ID: 550e8400-e29b-41d4-a716-446655440000 +- ID: 123e4567-e89b-12d3-a456-426614174000 - Name: Weekly Report Generator - Schedule: Every Monday at 9:00 AM UTC - Status: Enabled ``` -## API Reference +--- + +## Uploading Tarballs + +Before creating an automation with local code, you must upload it as a tarball. + +### Upload Endpoint + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code&description=My%20automation%20code" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/gzip" \ + --data-binary @automation.tar.gz +``` + +### Upload Constraints + +| Constraint | Value | +|------------|-------| +| Max file size | 1 MB | +| Content types | `application/gzip`, `application/x-tar`, `application/x-gzip`, `application/x-compressed-tar`, `application/octet-stream` | + +### Upload Response + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "my-code", + "status": "COMPLETED", + "tarball_path": "oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000", + "size_bytes": 12345 +} +``` + +**Important:** Use the `tarball_path` value when creating your automation. + +### List Uploads + +```bash +curl "https://automations.all-hands.dev/api/v1/uploads" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Delete Upload + +```bash +curl -X DELETE "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +--- + +## Automation API Reference The automation service exposes a REST API at `/api/v1/automations`: diff --git a/plugins/automation-creation/commands/create.md b/plugins/automation-creation/commands/create.md index ac3c6df..03f8120 100644 --- a/plugins/automation-creation/commands/create.md +++ b/plugins/automation-creation/commands/create.md @@ -1,5 +1,5 @@ --- -allowed-tools: Bash(curl:*) +allowed-tools: Bash(curl:*), Bash(tar:*), Bash(cat:*), Bash(echo:*), Bash(jq:*) description: Create a new OpenHands automation with cron scheduling --- @@ -11,9 +11,46 @@ Guide the user through creating a new automation that runs on a cron schedule. Help the user create an automation by collecting the required information interactively. -### Step 1: Collect Required Information +### Step 0: Ask About Code Location -Ask the user for each of these fields one at a time: +First, ask the user if they: +1. **Have code to upload** - They have local files that need to be uploaded as a tarball +2. **Have an existing tarball URL** - They already have code hosted somewhere (S3, GCS, HTTPS, or a previous upload) + +If they need to upload code, guide them through the upload process first (see Step 1a). +If they have an existing URL, skip to Step 1b. + +### Step 1a: Upload Code (if needed) + +If the user has local code to upload: + +1. Help them create a tarball from their code: + ```bash + tar -czf automation.tar.gz -C /path/to/code . + ``` + +2. Upload the tarball (max 1MB): + ```bash + curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=UPLOAD_NAME" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/gzip" \ + --data-binary @automation.tar.gz + ``` + +3. Extract the `tarball_path` from the response: + ```bash + # Response includes: "tarball_path": "oh-internal://uploads/{uuid}" + ``` + +4. Verify the upload status is `COMPLETED` before proceeding. + +**Upload Constraints:** +- Maximum file size: 1MB +- Allowed content types: `application/gzip`, `application/x-tar`, `application/x-gzip`, `application/x-compressed-tar`, `application/octet-stream` + +### Step 1b: Collect Automation Details + +Ask the user for each of these fields: 1. **Name** (required): A descriptive name for the automation (1-500 characters) @@ -24,9 +61,11 @@ Ask the user for each of these fields one at a time: 3. **Timezone** (optional): IANA timezone name (default: UTC) - Examples: `America/New_York`, `Europe/London`, `Asia/Tokyo` -4. **Tarball Path** (required): Location of the code to run - - Internal upload: `oh-internal://uploads/{uuid}` - - External URL: `https://...`, `s3://...`, or `gs://...` +4. **Tarball Path** (required if not uploaded): Location of the code to run + - Internal upload: `oh-internal://uploads/{uuid}` (from Step 1a) + - S3: `s3://bucket/path/file.tar.gz` + - GCS: `gs://bucket/path/file.tar.gz` + - HTTPS: `https://example.com/file.tar.gz` 5. **Entrypoint** (required): Command to execute - Examples: `uv run main.py`, `python script.py`, `./run.sh` diff --git a/skills/automation/README.md b/skills/automation/README.md new file mode 100644 index 0000000..7796d3b --- /dev/null +++ b/skills/automation/README.md @@ -0,0 +1,65 @@ +# Automation Skill + +Create and manage OpenHands automations - scheduled tasks that run SDK scripts in sandboxes on a cron schedule. + +## Triggers + +This skill is activated by keywords: +- `automation` / `automations` +- `scheduled task` +- `cron job` / `cron schedule` + +## Features + +- **Tarball Upload**: Upload your code (up to 1MB) for use in automations +- **Automation Creation**: Create cron-scheduled automations +- **Automation Management**: List, update, enable/disable, and delete automations +- **Manual Dispatch**: Trigger automation runs on-demand + +## Quick Start + +### 1. Upload Your Code + +```bash +# Create tarball +tar -czf automation.tar.gz -C /path/to/code . + +# Upload (max 1MB) +curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/gzip" \ + --data-binary @automation.tar.gz +``` + +### 2. Create Automation + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "My Automation", + "trigger": {"type": "cron", "schedule": "0 9 * * 1"}, + "tarball_path": "oh-internal://uploads/{upload_id}", + "entrypoint": "python main.py" + }' +``` + +## API Endpoints + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/api/v1/uploads` | POST | Upload a tarball | +| `/api/v1/uploads` | GET | List uploads | +| `/api/v1/uploads/{id}` | GET | Get upload details | +| `/api/v1/uploads/{id}` | DELETE | Delete upload | +| `/api/v1/automations` | POST | Create automation | +| `/api/v1/automations` | GET | List automations | +| `/api/v1/automations/{id}` | GET | Get automation | +| `/api/v1/automations/{id}` | PATCH | Update automation | +| `/api/v1/automations/{id}` | DELETE | Delete automation | +| `/api/v1/automations/{id}/dispatch` | POST | Trigger run | + +## See Also + +- [SKILL.md](SKILL.md) - Full API reference and examples diff --git a/skills/automation/SKILL.md b/skills/automation/SKILL.md new file mode 100644 index 0000000..aa76370 --- /dev/null +++ b/skills/automation/SKILL.md @@ -0,0 +1,359 @@ +--- +name: automation +description: Create and manage OpenHands automations - scheduled tasks that run SDK scripts in sandboxes. Use when creating cron-scheduled automations, uploading tarballs, or managing automation runs. +triggers: +- automation +- automations +- scheduled task +- cron job +- cron schedule +--- + +# OpenHands Automations + +This skill helps you create and manage OpenHands automations - scheduled tasks that run your code in sandboxes on a cron schedule. + +## API Base URL + +All automation endpoints are at: `https://automations.all-hands.dev/api/v1/` + +## Authentication + +Use Bearer authentication with your OpenHands API key: + +```bash +-H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +The `OPENHANDS_API_KEY` environment variable should be available in your session. + +--- + +## Uploading a Tarball + +Before creating an automation, you need to upload your code as a tarball. The upload endpoint streams directly to cloud storage with a **1MB size limit**. + +### Create a Tarball + +```bash +# Create a tarball from your automation code +tar -czf automation.tar.gz -C /path/to/your/code . +``` + +Your tarball should contain: +``` +automation.tar.gz +├── main.py # Your entrypoint script +├── setup.sh # Optional setup script (install deps, etc.) +├── requirements.txt # Dependencies (if using pip) +└── pyproject.toml # Or use uv/poetry for dependency management +``` + +### Upload the Tarball + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-automation&description=Weekly%20report%20generator" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/gzip" \ + --data-binary @automation.tar.gz +``` + +**Query Parameters:** +| Parameter | Required | Description | +|-----------|----------|-------------| +| `name` | Yes | Name for the upload (1-255 characters) | +| `description` | No | Description (max 2000 characters) | + +**Allowed Content-Types:** +- `application/x-tar` +- `application/gzip` +- `application/x-gzip` +- `application/x-compressed-tar` +- `application/octet-stream` + +**Response (HTTP 201):** +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "user_id": "...", + "org_id": "...", + "name": "my-automation", + "description": "Weekly report generator", + "status": "COMPLETED", + "error_message": null, + "size_bytes": 12345, + "tarball_path": "oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000", + "created_at": "2025-03-25T10:00:00Z", + "updated_at": "2025-03-25T10:00:00Z" +} +``` + +**Important:** Save the `tarball_path` value - you'll need it when creating the automation. + +### Upload Status Values + +| Status | Description | +|--------|-------------| +| `UPLOADING` | Upload in progress | +| `COMPLETED` | Upload successful, `tarball_path` is available | +| `FAILED` | Upload failed, check `error_message` | + +### List Uploads + +```bash +curl "https://automations.all-hands.dev/api/v1/uploads?limit=10" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Get Upload Details + +```bash +curl "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Delete Upload + +```bash +curl -X DELETE "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +--- + +## Creating an Automation + +Once you have a tarball uploaded (or an external URL), create the automation: + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Weekly Report Generator", + "trigger": { + "type": "cron", + "schedule": "0 9 * * 1", + "timezone": "UTC" + }, + "tarball_path": "oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000", + "entrypoint": "python main.py", + "timeout": 300 + }' +``` + +### Request Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | Name of the automation (1-500 characters) | +| `trigger.type` | Yes | Must be `"cron"` | +| `trigger.schedule` | Yes | Cron expression (5 fields: min hour day month weekday) | +| `trigger.timezone` | No | IANA timezone (default: `"UTC"`) | +| `tarball_path` | Yes | Path to code tarball (see Tarball Path Formats below) | +| `entrypoint` | Yes | Command to execute (e.g., `"python main.py"`, `"uv run script.py"`) | +| `setup_script_path` | No | Relative path to setup script inside tarball | +| `timeout` | No | Max execution time in seconds (1-600, default: 600) | + +### Tarball Path Formats + +| Format | Example | Description | +|--------|---------|-------------| +| Internal upload | `oh-internal://uploads/{uuid}` | Uploaded via `/api/v1/uploads` | +| S3 | `s3://bucket/path/file.tar.gz` | AWS S3 bucket | +| GCS | `gs://bucket/path/file.tar.gz` | Google Cloud Storage | +| HTTPS | `https://example.com/file.tar.gz` | Public HTTPS URL | + +### Response (HTTP 201) + +```json +{ + "id": "123e4567-e89b-12d3-a456-426614174000", + "name": "Weekly Report Generator", + "triggers": { + "type": "cron", + "schedule": "0 9 * * 1", + "timezone": "UTC" + }, + "tarball_path": "oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000", + "entrypoint": "python main.py", + "setup_script_path": null, + "timeout": 300, + "enabled": true, + "created_at": "2025-03-25T10:00:00Z", + "updated_at": "2025-03-25T10:00:00Z" +} +``` + +--- + +## Managing Automations + +### List Automations + +```bash +curl "https://automations.all-hands.dev/api/v1/automations?limit=20" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Get Automation Details + +```bash +curl "https://automations.all-hands.dev/api/v1/automations/{automation_id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Update Automation + +```bash +curl -X PATCH "https://automations.all-hands.dev/api/v1/automations/{automation_id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "enabled": false + }' +``` + +**Updatable Fields:** +- `name` +- `trigger` (schedule, timezone) +- `tarball_path` +- `entrypoint` +- `setup_script_path` +- `timeout` +- `enabled` + +### Delete Automation + +```bash +curl -X DELETE "https://automations.all-hands.dev/api/v1/automations/{automation_id}" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### Manually Trigger a Run + +```bash +curl -X POST "https://automations.all-hands.dev/api/v1/automations/{automation_id}/dispatch" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +--- + +## Cron Schedule Reference + +| Field | Values | Description | +|-------|--------|-------------| +| Minute | 0-59 | Minute of the hour | +| Hour | 0-23 | Hour of the day (24-hour) | +| Day | 1-31 | Day of the month | +| Month | 1-12 | Month of the year | +| Weekday | 0-6 | Day of week (0=Sun, 6=Sat) | + +### Common Patterns + +| Schedule | Description | +|----------|-------------| +| `0 9 * * *` | Every day at 9:00 AM | +| `0 9 * * 1-5` | Weekdays at 9:00 AM | +| `0 9 * * 1` | Every Monday at 9:00 AM | +| `0 0 1 * *` | First day of month at midnight | +| `*/15 * * * *` | Every 15 minutes | +| `0 */6 * * *` | Every 6 hours | + +--- + +## Environment Variables in Your Script + +Your automation script receives these environment variables: + +| Variable | Description | +|----------|-------------| +| `OPENHANDS_API_KEY` | API key for OpenHands services | +| `OPENHANDS_CLOUD_API_URL` | Base URL for the OpenHands Cloud API | +| `AUTOMATION_RUN_ID` | Unique ID for this run | +| `AUTOMATION_EVENT_PAYLOAD` | JSON with trigger info, automation ID, and name | +| `AUTOMATION_CALLBACK_URL` | URL to POST completion status | + +--- + +## Validation Rules + +- **Name**: 1-500 characters +- **Cron schedule**: Valid 5-field cron expression +- **Entrypoint**: Relative path, no shell metacharacters (`;`, `&`, `|`, etc.) +- **Setup script path**: Relative path, no path traversal (`..`) +- **Timeout**: 1-600 seconds (10 minutes max) +- **Tarball size**: 1MB max for uploads + +--- + +## Complete Example: Create Automation from Scratch + +```bash +# 1. Create your automation code +mkdir my-automation && cd my-automation + +cat > main.py << 'EOF' +import os +import json + +print("Running automation!") +print(f"Run ID: {os.environ.get('AUTOMATION_RUN_ID')}") + +payload = json.loads(os.environ.get('AUTOMATION_EVENT_PAYLOAD', '{}')) +print(f"Automation: {payload.get('automation_name')}") +EOF + +# 2. Create the tarball +tar -czf ../my-automation.tar.gz . +cd .. + +# 3. Upload the tarball +UPLOAD_RESPONSE=$(curl -s -X POST \ + "https://automations.all-hands.dev/api/v1/uploads?name=my-automation" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/gzip" \ + --data-binary @my-automation.tar.gz) + +TARBALL_PATH=$(echo "$UPLOAD_RESPONSE" | jq -r '.tarball_path') +echo "Uploaded: $TARBALL_PATH" + +# 4. Create the automation +curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d "{ + \"name\": \"My First Automation\", + \"trigger\": { + \"type\": \"cron\", + \"schedule\": \"0 9 * * 1\", + \"timezone\": \"UTC\" + }, + \"tarball_path\": \"$TARBALL_PATH\", + \"entrypoint\": \"python main.py\", + \"timeout\": 60 + }" +``` + +--- + +## Troubleshooting + +### Upload Failed: File too large +The upload limit is 1MB. Reduce your tarball size by: +- Excluding unnecessary files +- Not including `node_modules`, `.venv`, or other dependency directories +- Using `.tar.gz` compression + +### Upload Failed: Unsupported media type +Ensure your Content-Type header is one of: +- `application/gzip` +- `application/x-tar` +- `application/x-gzip` +- `application/x-compressed-tar` +- `application/octet-stream` + +### Automation Not Running +1. Check if the automation is enabled (`enabled: true`) +2. Verify the cron schedule is correct +3. Check for validation errors in the response From c1a3e29a179329e1d093684a06adecd1ee47448c Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 26 Mar 2026 21:01:56 +0000 Subject: [PATCH 3/6] Update automation skill/plugin with correct API endpoints - Change API base URL from automations.all-hands.dev/api/v1 to app.all-hands.dev/api/automation/v1 per infra middleware routing - Fix response field name from 'triggers' to 'trigger' in examples - Add List Automation Runs endpoint documentation - Update environment variables section with correct vars: - Add SANDBOX_ID and SESSION_API_KEY - Remove AUTOMATION_CALLBACK_URL and AUTOMATION_RUN_ID (internal) - Add user_id, org_id, and last_triggered_at to response examples - Note that completion callbacks are handled automatically by framework Co-authored-by: openhands --- plugins/automation-creation/README.md | 45 +++++++++++---- .../automation-creation/commands/create.md | 8 ++- skills/automation/README.md | 29 ++++++---- skills/automation/SKILL.md | 57 +++++++++++++------ 4 files changed, 97 insertions(+), 42 deletions(-) diff --git a/plugins/automation-creation/README.md b/plugins/automation-creation/README.md index 94205c8..b07ea91 100644 --- a/plugins/automation-creation/README.md +++ b/plugins/automation-creation/README.md @@ -68,6 +68,14 @@ Agent: Creating your automation... --- +## API Base URL + +All automation endpoints are available through the OpenHands Cloud API: +- **Automations**: `https://app.all-hands.dev/api/automation/v1` +- **Uploads**: `https://app.all-hands.dev/api/automation/v1/uploads` + +--- + ## Uploading Tarballs Before creating an automation with local code, you must upload it as a tarball. @@ -75,7 +83,7 @@ Before creating an automation with local code, you must upload it as a tarball. ### Upload Endpoint ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code&description=My%20automation%20code" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=my-code&description=My%20automation%20code" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/gzip" \ --data-binary @automation.tar.gz @@ -93,10 +101,16 @@ curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code&desc ```json { "id": "550e8400-e29b-41d4-a716-446655440000", + "user_id": "...", + "org_id": "...", "name": "my-code", + "description": "My automation code", "status": "COMPLETED", + "error_message": null, + "size_bytes": 12345, "tarball_path": "oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000", - "size_bytes": 12345 + "created_at": "2025-03-25T10:00:00Z", + "updated_at": "2025-03-25T10:00:00Z" } ``` @@ -105,14 +119,14 @@ curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code&desc ### List Uploads ```bash -curl "https://automations.all-hands.dev/api/v1/uploads" \ +curl "https://app.all-hands.dev/api/automation/v1/uploads" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Delete Upload ```bash -curl -X DELETE "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ +curl -X DELETE "https://app.all-hands.dev/api/automation/v1/uploads/{upload_id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` @@ -120,12 +134,12 @@ curl -X DELETE "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ ## Automation API Reference -The automation service exposes a REST API at `/api/v1/automations`: +The automation service exposes a REST API at `https://app.all-hands.dev/api/automation/v1`: ### Create Automation ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ @@ -157,14 +171,14 @@ curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ ### List Automations ```bash -curl "https://automations.all-hands.dev/api/v1/automations" \ +curl "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Update Automation ```bash -curl -X PATCH "https://automations.all-hands.dev/api/v1/automations/{id}" \ +curl -X PATCH "https://app.all-hands.dev/api/automation/v1/{id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ @@ -175,7 +189,14 @@ curl -X PATCH "https://automations.all-hands.dev/api/v1/automations/{id}" \ ### Manually Trigger a Run ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/automations/{id}/dispatch" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1/{id}/dispatch" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +### List Automation Runs + +```bash +curl "https://app.all-hands.dev/api/automation/v1/{id}/runs" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` @@ -211,8 +232,10 @@ Your script receives these environment variables: | `OPENHANDS_API_KEY` | API key for OpenHands services | | `OPENHANDS_CLOUD_API_URL` | Base URL for the OpenHands Cloud API | | `AUTOMATION_EVENT_PAYLOAD` | JSON with trigger info, automation ID, and name | -| `AUTOMATION_RUN_ID` | Unique ID for this run | -| `AUTOMATION_CALLBACK_URL` | URL to POST completion status | +| `SANDBOX_ID` | The sandbox ID where the automation is running | +| `SESSION_API_KEY` | Session API key for sandbox operations | + +**Note:** The automation framework automatically handles run completion callbacks. ## Validation Rules diff --git a/plugins/automation-creation/commands/create.md b/plugins/automation-creation/commands/create.md index 03f8120..87f5654 100644 --- a/plugins/automation-creation/commands/create.md +++ b/plugins/automation-creation/commands/create.md @@ -7,6 +7,10 @@ description: Create a new OpenHands automation with cron scheduling Guide the user through creating a new automation that runs on a cron schedule. +## API Base URL + +All automation endpoints are at: `https://app.all-hands.dev/api/automation/v1` + ## Instructions Help the user create an automation by collecting the required information interactively. @@ -31,7 +35,7 @@ If the user has local code to upload: 2. Upload the tarball (max 1MB): ```bash - curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=UPLOAD_NAME" \ + curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=UPLOAD_NAME" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/gzip" \ --data-binary @automation.tar.gz @@ -92,7 +96,7 @@ Before creating, validate: Use the OpenHands Automations API to create the automation: ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ diff --git a/skills/automation/README.md b/skills/automation/README.md index 7796d3b..6df6158 100644 --- a/skills/automation/README.md +++ b/skills/automation/README.md @@ -16,6 +16,10 @@ This skill is activated by keywords: - **Automation Management**: List, update, enable/disable, and delete automations - **Manual Dispatch**: Trigger automation runs on-demand +## API Base URL + +All automation endpoints are at: `https://app.all-hands.dev/api/automation/v1` + ## Quick Start ### 1. Upload Your Code @@ -25,7 +29,7 @@ This skill is activated by keywords: tar -czf automation.tar.gz -C /path/to/code . # Upload (max 1MB) -curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=my-code" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/gzip" \ --data-binary @automation.tar.gz @@ -34,7 +38,7 @@ curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-code" \ ### 2. Create Automation ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ @@ -49,16 +53,17 @@ curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ | Endpoint | Method | Description | |----------|--------|-------------| -| `/api/v1/uploads` | POST | Upload a tarball | -| `/api/v1/uploads` | GET | List uploads | -| `/api/v1/uploads/{id}` | GET | Get upload details | -| `/api/v1/uploads/{id}` | DELETE | Delete upload | -| `/api/v1/automations` | POST | Create automation | -| `/api/v1/automations` | GET | List automations | -| `/api/v1/automations/{id}` | GET | Get automation | -| `/api/v1/automations/{id}` | PATCH | Update automation | -| `/api/v1/automations/{id}` | DELETE | Delete automation | -| `/api/v1/automations/{id}/dispatch` | POST | Trigger run | +| `/api/automation/v1/uploads` | POST | Upload a tarball | +| `/api/automation/v1/uploads` | GET | List uploads | +| `/api/automation/v1/uploads/{id}` | GET | Get upload details | +| `/api/automation/v1/uploads/{id}` | DELETE | Delete upload | +| `/api/automation/v1` | POST | Create automation | +| `/api/automation/v1` | GET | List automations | +| `/api/automation/v1/{id}` | GET | Get automation | +| `/api/automation/v1/{id}` | PATCH | Update automation | +| `/api/automation/v1/{id}` | DELETE | Delete automation | +| `/api/automation/v1/{id}/dispatch` | POST | Trigger run | +| `/api/automation/v1/{id}/runs` | GET | List runs | ## See Also diff --git a/skills/automation/SKILL.md b/skills/automation/SKILL.md index aa76370..800f092 100644 --- a/skills/automation/SKILL.md +++ b/skills/automation/SKILL.md @@ -15,7 +15,9 @@ This skill helps you create and manage OpenHands automations - scheduled tasks t ## API Base URL -All automation endpoints are at: `https://automations.all-hands.dev/api/v1/` +All automation endpoints are available through the OpenHands Cloud API: +- **Automations**: `https://app.all-hands.dev/api/automation/v1` +- **Uploads**: `https://app.all-hands.dev/api/automation/v1/uploads` ## Authentication @@ -52,7 +54,7 @@ automation.tar.gz ### Upload the Tarball ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-automation&description=Weekly%20report%20generator" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=my-automation&description=Weekly%20report%20generator" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/gzip" \ --data-binary @automation.tar.gz @@ -101,21 +103,21 @@ curl -X POST "https://automations.all-hands.dev/api/v1/uploads?name=my-automatio ### List Uploads ```bash -curl "https://automations.all-hands.dev/api/v1/uploads?limit=10" \ +curl "https://app.all-hands.dev/api/automation/v1/uploads?limit=10" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Get Upload Details ```bash -curl "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ +curl "https://app.all-hands.dev/api/automation/v1/uploads/{upload_id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Delete Upload ```bash -curl -X DELETE "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ +curl -X DELETE "https://app.all-hands.dev/api/automation/v1/uploads/{upload_id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` @@ -126,7 +128,7 @@ curl -X DELETE "https://automations.all-hands.dev/api/v1/uploads/{upload_id}" \ Once you have a tarball uploaded (or an external URL), create the automation: ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ @@ -169,8 +171,10 @@ curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ ```json { "id": "123e4567-e89b-12d3-a456-426614174000", + "user_id": "...", + "org_id": "...", "name": "Weekly Report Generator", - "triggers": { + "trigger": { "type": "cron", "schedule": "0 9 * * 1", "timezone": "UTC" @@ -180,6 +184,7 @@ curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ "setup_script_path": null, "timeout": 300, "enabled": true, + "last_triggered_at": null, "created_at": "2025-03-25T10:00:00Z", "updated_at": "2025-03-25T10:00:00Z" } @@ -192,21 +197,21 @@ curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ ### List Automations ```bash -curl "https://automations.all-hands.dev/api/v1/automations?limit=20" \ +curl "https://app.all-hands.dev/api/automation/v1?limit=20" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Get Automation Details ```bash -curl "https://automations.all-hands.dev/api/v1/automations/{automation_id}" \ +curl "https://app.all-hands.dev/api/automation/v1/{automation_id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Update Automation ```bash -curl -X PATCH "https://automations.all-hands.dev/api/v1/automations/{automation_id}" \ +curl -X PATCH "https://app.all-hands.dev/api/automation/v1/{automation_id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ @@ -226,17 +231,32 @@ curl -X PATCH "https://automations.all-hands.dev/api/v1/automations/{automation_ ### Delete Automation ```bash -curl -X DELETE "https://automations.all-hands.dev/api/v1/automations/{automation_id}" \ +curl -X DELETE "https://app.all-hands.dev/api/automation/v1/{automation_id}" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` ### Manually Trigger a Run ```bash -curl -X POST "https://automations.all-hands.dev/api/v1/automations/{automation_id}/dispatch" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1/{automation_id}/dispatch" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" ``` +### List Automation Runs + +```bash +curl "https://app.all-hands.dev/api/automation/v1/{automation_id}/runs?limit=20" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" +``` + +**Run Status Values:** +| Status | Description | +|--------|-------------| +| `PENDING` | Run scheduled, waiting for dispatch | +| `RUNNING` | Execution in progress | +| `COMPLETED` | Run finished successfully | +| `FAILED` | Run failed, check `error_detail` | + --- ## Cron Schedule Reference @@ -270,9 +290,11 @@ Your automation script receives these environment variables: |----------|-------------| | `OPENHANDS_API_KEY` | API key for OpenHands services | | `OPENHANDS_CLOUD_API_URL` | Base URL for the OpenHands Cloud API | -| `AUTOMATION_RUN_ID` | Unique ID for this run | | `AUTOMATION_EVENT_PAYLOAD` | JSON with trigger info, automation ID, and name | -| `AUTOMATION_CALLBACK_URL` | URL to POST completion status | +| `SANDBOX_ID` | The sandbox ID where the automation is running | +| `SESSION_API_KEY` | Session API key for sandbox operations | + +**Note:** The automation framework automatically handles run completion callbacks. Your script does not need to manage these manually. --- @@ -298,10 +320,11 @@ import os import json print("Running automation!") -print(f"Run ID: {os.environ.get('AUTOMATION_RUN_ID')}") payload = json.loads(os.environ.get('AUTOMATION_EVENT_PAYLOAD', '{}')) print(f"Automation: {payload.get('automation_name')}") +print(f"Automation ID: {payload.get('automation_id')}") +print(f"Trigger: {payload.get('trigger')}") EOF # 2. Create the tarball @@ -310,7 +333,7 @@ cd .. # 3. Upload the tarball UPLOAD_RESPONSE=$(curl -s -X POST \ - "https://automations.all-hands.dev/api/v1/uploads?name=my-automation" \ + "https://app.all-hands.dev/api/automation/v1/uploads?name=my-automation" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/gzip" \ --data-binary @my-automation.tar.gz) @@ -319,7 +342,7 @@ TARBALL_PATH=$(echo "$UPLOAD_RESPONSE" | jq -r '.tarball_path') echo "Uploaded: $TARBALL_PATH" # 4. Create the automation -curl -X POST "https://automations.all-hands.dev/api/v1/automations" \ +curl -X POST "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d "{ From 0631ec80bbcaf4f4cf5ef9f003cd1ab5e8c9ef9c Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 26 Mar 2026 21:02:58 +0000 Subject: [PATCH 4/6] Add automation skill to default marketplace Co-authored-by: openhands --- marketplaces/default.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/marketplaces/default.json b/marketplaces/default.json index 1120ee8..53dfa46 100644 --- a/marketplaces/default.json +++ b/marketplaces/default.json @@ -46,6 +46,19 @@ "openhands" ] }, + { + "name": "automation", + "source": "./automation", + "description": "Create and manage OpenHands automations - scheduled tasks that run SDK scripts in sandboxes. Use when creating cron-scheduled automations, uploading tarballs, or managing automation runs.", + "category": "integration", + "keywords": [ + "automation", + "cron", + "scheduled-task", + "sandbox", + "openhands" + ] + }, { "name": "azure-devops", "source": "./azure-devops", From c1c1743e4b30aa69edb59c0203adbec54560a657 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 26 Mar 2026 21:12:07 +0000 Subject: [PATCH 5/6] Add SDK documentation and requirements to automation skill/plugin - Document that automations must use the OpenHands Software Agent SDK - Add link to SDK docs: https://docs.openhands.dev/sdk - Add setup.sh example that installs SDK packages - Include complete Python example using OpenHandsCloudWorkspace - Reference test_tarball example from automation repo - Make setup.sh REQUIRED (installs SDK dependencies) Co-authored-by: openhands --- plugins/automation-creation/README.md | 50 +++++++++- skills/automation/SKILL.md | 130 ++++++++++++++++++++++++-- 2 files changed, 165 insertions(+), 15 deletions(-) diff --git a/plugins/automation-creation/README.md b/plugins/automation-creation/README.md index b07ea91..4786ee6 100644 --- a/plugins/automation-creation/README.md +++ b/plugins/automation-creation/README.md @@ -211,18 +211,58 @@ curl "https://app.all-hands.dev/api/automation/v1/{id}/runs" \ | `*/15 * * * *` | Every 15 minutes | | `0 */6 * * *` | Every 6 hours | -## Tarball Structure +## Writing Automation Code + +Automations must use the **OpenHands Software Agent SDK** to create conversations and interact with OpenHands Cloud. + +**SDK Documentation:** https://docs.openhands.dev/sdk + +### Tarball Structure Your automation tarball should contain: ``` my-automation/ -├── main.py # Your entrypoint script -├── setup.sh # Optional setup script -├── requirements.txt # Dependencies (if using pip) -└── pyproject.toml # Or use uv/poetry +├── main.py # Your entrypoint script (uses SDK) +├── setup.sh # REQUIRED: installs SDK dependencies +├── pyproject.toml # Optional: for uv/poetry +└── requirements.txt # Optional: additional dependencies ``` +### Setup Script (Required) + +Your `setup.sh` must install the OpenHands SDK packages: + +```bash +#!/bin/bash +set -e +pip install openhands-sdk openhands-workspace openhands-tools +``` + +### Example Entrypoint + +```python +import os +from openhands.sdk import Conversation +from openhands.tools.preset.default import get_default_agent +from openhands.workspace import OpenHandsCloudWorkspace + +with OpenHandsCloudWorkspace( + local_agent_server_mode=True, + cloud_api_url=os.environ["OPENHANDS_CLOUD_API_URL"], + cloud_api_key=os.environ["OPENHANDS_API_KEY"], +) as workspace: + llm = workspace.get_llm() + agent = get_default_agent(llm=llm, cli_mode=True) + + conversation = Conversation(agent=agent, workspace=workspace) + conversation.send_message("Your automation prompt") + conversation.run() + conversation.close() +``` + +For a complete working example, see the [test_tarball](https://github.com/OpenHands/automation/tree/main/scripts/test_tarball) in the automation repository. + ### Environment Variables Your script receives these environment variables: diff --git a/skills/automation/SKILL.md b/skills/automation/SKILL.md index 800f092..bc76bca 100644 --- a/skills/automation/SKILL.md +++ b/skills/automation/SKILL.md @@ -13,6 +13,8 @@ triggers: This skill helps you create and manage OpenHands automations - scheduled tasks that run your code in sandboxes on a cron schedule. +**Important:** Automation code must use the [OpenHands Software Agent SDK](https://docs.openhands.dev/sdk) to create conversations and interact with OpenHands Cloud services. + ## API Base URL All automation endpoints are available through the OpenHands Cloud API: @@ -31,6 +33,75 @@ The `OPENHANDS_API_KEY` environment variable should be available in your session --- +## Writing Automation Code + +Automations run inside OpenHands Cloud sandboxes and use the **Software Agent SDK** to: +- Create and run AI agent conversations +- Access your configured LLM settings +- Use your stored secrets + +**SDK Documentation:** https://docs.openhands.dev/sdk + +### Required Dependencies + +Your automation must install the OpenHands SDK packages. Use a `setup.sh` script: + +```bash +#!/bin/bash +set -e + +# Install uv for fast dependency management (recommended) +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" + +# Install the OpenHands SDK packages +pip install openhands-sdk openhands-workspace openhands-tools +``` + +### Basic Automation Structure + +```python +"""Example automation using the OpenHands SDK.""" +import os + +from openhands.sdk import Conversation +from openhands.tools.preset.default import get_default_agent +from openhands.workspace import OpenHandsCloudWorkspace + +# Environment variables are automatically injected by the dispatcher +api_key = os.environ["OPENHANDS_API_KEY"] +api_url = os.environ["OPENHANDS_CLOUD_API_URL"] + +# Use OpenHandsCloudWorkspace to connect to your OpenHands Cloud account +with OpenHandsCloudWorkspace( + local_agent_server_mode=True, + cloud_api_url=api_url, + cloud_api_key=api_key, +) as workspace: + # Get your configured LLM from OpenHands Cloud + llm = workspace.get_llm() + + # Optionally get your stored secrets + secrets = workspace.get_secrets() + + # Create an agent and conversation + agent = get_default_agent(llm=llm, cli_mode=True) + conversation = Conversation(agent=agent, workspace=workspace) + + # Inject secrets if available + if secrets: + conversation.update_secrets(secrets) + + # Send a prompt and run the conversation + conversation.send_message("Your automation prompt here") + conversation.run() + conversation.close() + +# The workspace context manager automatically reports completion status +``` + +--- + ## Uploading a Tarball Before creating an automation, you need to upload your code as a tarball. The upload endpoint streams directly to cloud storage with a **1MB size limit**. @@ -42,15 +113,19 @@ Before creating an automation, you need to upload your code as a tarball. The up tar -czf automation.tar.gz -C /path/to/your/code . ``` +### Tarball Structure + Your tarball should contain: ``` automation.tar.gz -├── main.py # Your entrypoint script -├── setup.sh # Optional setup script (install deps, etc.) -├── requirements.txt # Dependencies (if using pip) -└── pyproject.toml # Or use uv/poetry for dependency management +├── main.py # Your entrypoint script (uses SDK) +├── setup.sh # Setup script (REQUIRED: installs uv + SDK) +├── pyproject.toml # Optional: for uv/poetry dependency management +└── requirements.txt # Optional: additional dependencies ``` +**Note:** The `setup.sh` script is critical - it must install `uv` and the OpenHands SDK packages before your entrypoint runs. + ### Upload the Tarball ```bash @@ -315,16 +390,48 @@ Your automation script receives these environment variables: # 1. Create your automation code mkdir my-automation && cd my-automation +# Create setup.sh to install dependencies +cat > setup.sh << 'EOF' +#!/bin/bash +set -e +echo "[setup] Installing OpenHands SDK..." +pip install -q openhands-sdk openhands-workspace openhands-tools +echo "[setup] Done" +EOF +chmod +x setup.sh + +# Create main.py using the SDK cat > main.py << 'EOF' +"""Weekly report automation using OpenHands SDK.""" import os import json -print("Running automation!") +from openhands.sdk import Conversation +from openhands.tools.preset.default import get_default_agent +from openhands.workspace import OpenHandsCloudWorkspace +# Log trigger info payload = json.loads(os.environ.get('AUTOMATION_EVENT_PAYLOAD', '{}')) -print(f"Automation: {payload.get('automation_name')}") -print(f"Automation ID: {payload.get('automation_id')}") -print(f"Trigger: {payload.get('trigger')}") +print(f"Running: {payload.get('automation_name')}") + +# Connect to OpenHands Cloud +api_key = os.environ["OPENHANDS_API_KEY"] +api_url = os.environ["OPENHANDS_CLOUD_API_URL"] + +with OpenHandsCloudWorkspace( + local_agent_server_mode=True, + cloud_api_url=api_url, + cloud_api_key=api_key, +) as workspace: + llm = workspace.get_llm() + agent = get_default_agent(llm=llm, cli_mode=True) + + conversation = Conversation(agent=agent, workspace=workspace) + conversation.send_message("Generate a weekly status report and save it to report.txt") + conversation.run() + conversation.close() + +print("Automation completed!") EOF # 2. Create the tarball @@ -346,7 +453,7 @@ curl -X POST "https://app.all-hands.dev/api/automation/v1" \ -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ -H "Content-Type: application/json" \ -d "{ - \"name\": \"My First Automation\", + \"name\": \"Weekly Report Generator\", \"trigger\": { \"type\": \"cron\", \"schedule\": \"0 9 * * 1\", @@ -354,10 +461,13 @@ curl -X POST "https://app.all-hands.dev/api/automation/v1" \ }, \"tarball_path\": \"$TARBALL_PATH\", \"entrypoint\": \"python main.py\", - \"timeout\": 60 + \"setup_script_path\": \"setup.sh\", + \"timeout\": 300 }" ``` +For a complete working example, see the [test_tarball](https://github.com/OpenHands/automation/tree/main/scripts/test_tarball) in the automation repository. + --- ## Troubleshooting From ba82a553ed41e7d0a127fa06ec87c7248752ad0c Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 26 Mar 2026 22:09:14 +0000 Subject: [PATCH 6/6] Deduplicate automation-creation plugin, reference skill for API docs Address review comments: - Reduce README from 303 lines to 39 lines by removing API duplication - Reduce create.md from 198 lines to 70 lines, focusing on workflow only - Add cross-references between plugin and skill - Add automation-creation plugin to marketplace - Keep production API URL hardcoded (https://app.all-hands.dev/api/automation/v1) Plugin now provides only the /automation:create slash command. Full API documentation remains in skills/automation/SKILL.md. Co-authored-by: openhands --- marketplaces/default.json | 13 + plugins/automation-creation/README.md | 283 +----------------- .../automation-creation/commands/create.md | 194 ++---------- skills/automation/SKILL.md | 4 +- 4 files changed, 58 insertions(+), 436 deletions(-) diff --git a/marketplaces/default.json b/marketplaces/default.json index 53dfa46..05b4283 100644 --- a/marketplaces/default.json +++ b/marketplaces/default.json @@ -484,6 +484,19 @@ "verification", "sample" ] + }, + { + "name": "automation-creation", + "source": "./plugins/automation-creation", + "description": "Interactive slash command for creating OpenHands automations. Provides /automation:create for guided cron-scheduled automation setup.", + "category": "integration", + "keywords": [ + "automation", + "cron", + "scheduling", + "openhands", + "slash-command" + ] } ] } diff --git a/plugins/automation-creation/README.md b/plugins/automation-creation/README.md index 4786ee6..a849afe 100644 --- a/plugins/automation-creation/README.md +++ b/plugins/automation-creation/README.md @@ -1,289 +1,23 @@ # Automation Creation Plugin -Create and manage OpenHands automations - scheduled tasks that run SDK scripts in sandboxes on a cron schedule. +Interactive slash command for creating OpenHands automations via guided prompts. -## Features - -- **Slash command**: `/automation:create` - Create a new automation interactively -- **Tarball uploads**: Upload your SDK code as a tarball (up to 1MB) -- **Cron scheduling**: Schedule automations to run on any cron schedule -- **Configurable timeout**: Set execution timeout (up to 10 minutes) -- **Setup scripts**: Optional setup.sh for environment preparation - -## Usage - -### Create an Automation +## Quick Start ``` /automation:create ``` -The agent will guide you through: +The agent guides you through: 1. Uploading your code as a tarball (if needed) -2. Providing a name for your automation -3. Setting up a cron schedule (e.g., `0 9 * * 5` for every Friday at 9 AM) -4. Defining the entrypoint command -5. Optionally setting a timeout and setup script - -### Example Interaction - -``` -User: /automation:create - -Agent: I'll help you create a new automation. First, do you: -1. Have local code that needs to be uploaded? -2. Already have a tarball URL (S3, GCS, HTTPS)? - -User: I have local code in ./my-automation/ - -Agent: I'll help you upload that. Let me create and upload the tarball... - -[Creates tarball and uploads] - -✅ Upload successful! -- Tarball path: oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000 - -Now let's configure the automation: - -1. **Name**: What would you like to call this automation? - -User: Weekly Report Generator - -Agent: 2. **Cron Schedule**: When should this run? (e.g., "0 9 * * 5" for Fridays at 9 AM UTC) - -User: 0 9 * * 1 - -Agent: 3. **Entrypoint**: What command runs your automation? (e.g., "uv run main.py") - -User: python generate_report.py - -Agent: Creating your automation... - -✅ Automation created successfully! -- ID: 123e4567-e89b-12d3-a456-426614174000 -- Name: Weekly Report Generator -- Schedule: Every Monday at 9:00 AM UTC -- Status: Enabled -``` - ---- - -## API Base URL - -All automation endpoints are available through the OpenHands Cloud API: -- **Automations**: `https://app.all-hands.dev/api/automation/v1` -- **Uploads**: `https://app.all-hands.dev/api/automation/v1/uploads` - ---- - -## Uploading Tarballs - -Before creating an automation with local code, you must upload it as a tarball. - -### Upload Endpoint - -```bash -curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=my-code&description=My%20automation%20code" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ - -H "Content-Type: application/gzip" \ - --data-binary @automation.tar.gz -``` - -### Upload Constraints - -| Constraint | Value | -|------------|-------| -| Max file size | 1 MB | -| Content types | `application/gzip`, `application/x-tar`, `application/x-gzip`, `application/x-compressed-tar`, `application/octet-stream` | - -### Upload Response - -```json -{ - "id": "550e8400-e29b-41d4-a716-446655440000", - "user_id": "...", - "org_id": "...", - "name": "my-code", - "description": "My automation code", - "status": "COMPLETED", - "error_message": null, - "size_bytes": 12345, - "tarball_path": "oh-internal://uploads/550e8400-e29b-41d4-a716-446655440000", - "created_at": "2025-03-25T10:00:00Z", - "updated_at": "2025-03-25T10:00:00Z" -} -``` - -**Important:** Use the `tarball_path` value when creating your automation. - -### List Uploads - -```bash -curl "https://app.all-hands.dev/api/automation/v1/uploads" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" -``` - -### Delete Upload - -```bash -curl -X DELETE "https://app.all-hands.dev/api/automation/v1/uploads/{upload_id}" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" -``` - ---- - -## Automation API Reference - -The automation service exposes a REST API at `https://app.all-hands.dev/api/automation/v1`: - -### Create Automation - -```bash -curl -X POST "https://app.all-hands.dev/api/automation/v1" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "My Automation", - "trigger": { - "type": "cron", - "schedule": "0 9 * * 5", - "timezone": "UTC" - }, - "tarball_path": "s3://bucket/code.tar.gz", - "entrypoint": "uv run main.py", - "timeout": 300 - }' -``` - -### Request Fields - -| Field | Required | Description | -|-------|----------|-------------| -| `name` | Yes | Name of the automation (1-500 characters) | -| `trigger.type` | Yes | Must be `"cron"` | -| `trigger.schedule` | Yes | Cron expression (e.g., `"0 9 * * 5"`) | -| `trigger.timezone` | No | IANA timezone (default: `"UTC"`) | -| `tarball_path` | Yes | Path to code tarball (`oh-internal://`, `s3://`, `gs://`, `https://`) | -| `entrypoint` | Yes | Command to execute (e.g., `"uv run main.py"`) | -| `setup_script_path` | No | Relative path to setup script inside tarball | -| `timeout` | No | Max execution time in seconds (1-600, default: 600) | - -### List Automations - -```bash -curl "https://app.all-hands.dev/api/automation/v1" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" -``` - -### Update Automation - -```bash -curl -X PATCH "https://app.all-hands.dev/api/automation/v1/{id}" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ - -H "Content-Type: application/json" \ - -d '{ - "enabled": false - }' -``` - -### Manually Trigger a Run - -```bash -curl -X POST "https://app.all-hands.dev/api/automation/v1/{id}/dispatch" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" -``` - -### List Automation Runs - -```bash -curl "https://app.all-hands.dev/api/automation/v1/{id}/runs" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" -``` - -## Cron Schedule Examples - -| Schedule | Description | -|----------|-------------| -| `0 9 * * *` | Every day at 9:00 AM | -| `0 9 * * 1` | Every Monday at 9:00 AM | -| `0 9 * * 5` | Every Friday at 9:00 AM | -| `0 0 1 * *` | First day of each month at midnight | -| `*/15 * * * *` | Every 15 minutes | -| `0 */6 * * *` | Every 6 hours | - -## Writing Automation Code - -Automations must use the **OpenHands Software Agent SDK** to create conversations and interact with OpenHands Cloud. - -**SDK Documentation:** https://docs.openhands.dev/sdk - -### Tarball Structure - -Your automation tarball should contain: - -``` -my-automation/ -├── main.py # Your entrypoint script (uses SDK) -├── setup.sh # REQUIRED: installs SDK dependencies -├── pyproject.toml # Optional: for uv/poetry -└── requirements.txt # Optional: additional dependencies -``` - -### Setup Script (Required) - -Your `setup.sh` must install the OpenHands SDK packages: - -```bash -#!/bin/bash -set -e -pip install openhands-sdk openhands-workspace openhands-tools -``` - -### Example Entrypoint - -```python -import os -from openhands.sdk import Conversation -from openhands.tools.preset.default import get_default_agent -from openhands.workspace import OpenHandsCloudWorkspace - -with OpenHandsCloudWorkspace( - local_agent_server_mode=True, - cloud_api_url=os.environ["OPENHANDS_CLOUD_API_URL"], - cloud_api_key=os.environ["OPENHANDS_API_KEY"], -) as workspace: - llm = workspace.get_llm() - agent = get_default_agent(llm=llm, cli_mode=True) - - conversation = Conversation(agent=agent, workspace=workspace) - conversation.send_message("Your automation prompt") - conversation.run() - conversation.close() -``` - -For a complete working example, see the [test_tarball](https://github.com/OpenHands/automation/tree/main/scripts/test_tarball) in the automation repository. - -### Environment Variables - -Your script receives these environment variables: - -| Variable | Description | -|----------|-------------| -| `OPENHANDS_API_KEY` | API key for OpenHands services | -| `OPENHANDS_CLOUD_API_URL` | Base URL for the OpenHands Cloud API | -| `AUTOMATION_EVENT_PAYLOAD` | JSON with trigger info, automation ID, and name | -| `SANDBOX_ID` | The sandbox ID where the automation is running | -| `SESSION_API_KEY` | Session API key for sandbox operations | +2. Setting a name, cron schedule, and entrypoint +3. Creating the automation via the OpenHands Cloud API -**Note:** The automation framework automatically handles run completion callbacks. +## Plugin vs Skill -## Validation Rules +This **plugin** provides the `/automation:create` slash command for interactive automation setup. -- **Name**: 1-500 characters, required -- **Cron schedule**: Must be a valid cron expression -- **Entrypoint**: Must be a relative path, no shell metacharacters (`;&|` etc.) -- **Setup script path**: Must be relative, no path traversal (`..`) -- **Timeout**: 1-600 seconds (10 minutes max) +For comprehensive API documentation (all endpoints, SDK examples, validation rules), see the **[automation skill](../../skills/automation/SKILL.md)**. ## Plugin Structure @@ -298,6 +32,7 @@ automation-creation/ ## Related Resources +- **[Automation Skill](../../skills/automation/SKILL.md)** - Full API reference and SDK examples - [OpenHands SDK Documentation](https://docs.openhands.dev/sdk) - [OpenHands Cloud](https://app.all-hands.dev) - [Cron Expression Reference](https://crontab.guru/) diff --git a/plugins/automation-creation/commands/create.md b/plugins/automation-creation/commands/create.md index 87f5654..ae63ce6 100644 --- a/plugins/automation-creation/commands/create.md +++ b/plugins/automation-creation/commands/create.md @@ -5,95 +5,47 @@ description: Create a new OpenHands automation with cron scheduling # Create OpenHands Automation -Guide the user through creating a new automation that runs on a cron schedule. +Guide the user through creating a new automation interactively. -## API Base URL +**API Base URL:** `https://app.all-hands.dev/api/automation/v1` -All automation endpoints are at: `https://app.all-hands.dev/api/automation/v1` +**Full API Reference:** See [skills/automation/SKILL.md](../../../skills/automation/SKILL.md) for complete documentation on endpoints, validation rules, SDK examples, and cron syntax. -## Instructions +## Workflow -Help the user create an automation by collecting the required information interactively. +### Step 1: Ask About Code Location -### Step 0: Ask About Code Location +Ask the user if they: +1. **Have local code** - Needs to be uploaded as a tarball first +2. **Have an existing URL** - Already hosted (S3, GCS, HTTPS, or previous upload) -First, ask the user if they: -1. **Have code to upload** - They have local files that need to be uploaded as a tarball -2. **Have an existing tarball URL** - They already have code hosted somewhere (S3, GCS, HTTPS, or a previous upload) +### Step 2: Upload Code (if needed) -If they need to upload code, guide them through the upload process first (see Step 1a). -If they have an existing URL, skip to Step 1b. - -### Step 1a: Upload Code (if needed) - -If the user has local code to upload: - -1. Help them create a tarball from their code: - ```bash - tar -czf automation.tar.gz -C /path/to/code . - ``` - -2. Upload the tarball (max 1MB): - ```bash - curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=UPLOAD_NAME" \ - -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ - -H "Content-Type: application/gzip" \ - --data-binary @automation.tar.gz - ``` - -3. Extract the `tarball_path` from the response: - ```bash - # Response includes: "tarball_path": "oh-internal://uploads/{uuid}" - ``` - -4. Verify the upload status is `COMPLETED` before proceeding. - -**Upload Constraints:** -- Maximum file size: 1MB -- Allowed content types: `application/gzip`, `application/x-tar`, `application/x-gzip`, `application/x-compressed-tar`, `application/octet-stream` - -### Step 1b: Collect Automation Details - -Ask the user for each of these fields: - -1. **Name** (required): A descriptive name for the automation (1-500 characters) - -2. **Cron Schedule** (required): When the automation should run - - Examples: `0 9 * * *` (daily at 9 AM), `0 9 * * 5` (Fridays at 9 AM) - - Provide helpful examples based on what the user describes - -3. **Timezone** (optional): IANA timezone name (default: UTC) - - Examples: `America/New_York`, `Europe/London`, `Asia/Tokyo` - -4. **Tarball Path** (required if not uploaded): Location of the code to run - - Internal upload: `oh-internal://uploads/{uuid}` (from Step 1a) - - S3: `s3://bucket/path/file.tar.gz` - - GCS: `gs://bucket/path/file.tar.gz` - - HTTPS: `https://example.com/file.tar.gz` - -5. **Entrypoint** (required): Command to execute - - Examples: `uv run main.py`, `python script.py`, `./run.sh` - - Must be a relative path, no shell metacharacters - -6. **Setup Script Path** (optional): Relative path to setup script inside tarball - - Example: `setup.sh` +If uploading local code: +```bash +# Create tarball +tar -czf automation.tar.gz -C /path/to/code . -7. **Timeout** (optional): Maximum execution time in seconds - - Range: 1-600 seconds (default: 600 = 10 minutes) - - Only positive integers allowed +# Upload (max 1MB) +curl -X POST "https://app.all-hands.dev/api/automation/v1/uploads?name=UPLOAD_NAME" \ + -H "Authorization: Bearer ${OPENHANDS_API_KEY}" \ + -H "Content-Type: application/gzip" \ + --data-binary @automation.tar.gz +``` -### Step 2: Validate the Information +Extract `tarball_path` from response (e.g., `oh-internal://uploads/{uuid}`). -Before creating, validate: -- Name is not empty and ≤ 500 characters -- Cron schedule is valid (5 fields: minute hour day month weekday) -- Tarball path starts with `oh-internal://`, `s3://`, `gs://`, `http://`, or `https://` -- Entrypoint is a relative path without `..` or shell metacharacters (`;`, `&`, `|`, etc.) -- Timeout (if provided) is between 1 and 600 +### Step 3: Collect Required Fields -### Step 3: Create the Automation +1. **Name**: Descriptive name (1-500 characters) +2. **Cron Schedule**: e.g., `0 9 * * 1` (Mondays at 9 AM UTC) +3. **Tarball Path**: `oh-internal://`, `s3://`, `gs://`, or `https://` +4. **Entrypoint**: e.g., `python main.py` or `uv run script.py` +5. **Timezone** (optional): IANA timezone (default: UTC) +6. **Setup Script** (optional): Relative path, e.g., `setup.sh` +7. **Timeout** (optional): 1-600 seconds (default: 600) -Use the OpenHands Automations API to create the automation: +### Step 4: Create the Automation ```bash curl -X POST "https://app.all-hands.dev/api/automation/v1" \ @@ -107,92 +59,12 @@ curl -X POST "https://app.all-hands.dev/api/automation/v1" \ "timezone": "USER_PROVIDED_TIMEZONE_OR_UTC" }, "tarball_path": "USER_PROVIDED_TARBALL_PATH", - "entrypoint": "USER_PROVIDED_ENTRYPOINT", - "setup_script_path": "USER_PROVIDED_OR_NULL", - "timeout": USER_PROVIDED_OR_NULL + "entrypoint": "USER_PROVIDED_ENTRYPOINT" }' ``` -Replace placeholders with actual values. Omit `setup_script_path` and `timeout` if not provided. - -### Step 4: Present the Result - -On success (HTTP 201), display: -- ✅ Automation created successfully! -- **ID**: The automation UUID -- **Name**: The name provided -- **Schedule**: Human-readable description of the cron schedule -- **Timezone**: The timezone -- **Status**: Enabled - -On error (HTTP 4xx/5xx), display: -- ❌ Failed to create automation -- The error message from the API response - -## Cron Schedule Reference - -Help users construct cron schedules: - -| Field | Values | Description | -|-------|--------|-------------| -| Minute | 0-59 | Minute of the hour | -| Hour | 0-23 | Hour of the day (24-hour format) | -| Day | 1-31 | Day of the month | -| Month | 1-12 | Month of the year | -| Weekday | 0-6 | Day of week (0=Sunday, 1=Monday, ..., 6=Saturday) | - -Common patterns: -- `0 9 * * *` → Every day at 9:00 AM -- `0 9 * * 1-5` → Weekdays at 9:00 AM -- `0 9 * * 0` → Every Sunday at 9:00 AM -- `0 0 1 * *` → First day of each month at midnight -- `*/30 * * * *` → Every 30 minutes - -## Example Conversation - -**User**: I want to create an automation that generates weekly reports every Monday morning. - -**Agent**: I'll help you create that automation. Let's go through the details: - -**1. Name**: What would you like to call this automation? - -**User**: Weekly Report Generator - -**Agent**: **2. Cron Schedule**: You mentioned Monday mornings. What time would you like it to run? (in UTC) - -**User**: 9 AM - -**Agent**: So `0 9 * * 1` for every Monday at 9:00 AM UTC. - -**3. Tarball Path**: Where is your automation code stored? - -**User**: s3://my-bucket/automations/weekly-report.tar.gz - -**Agent**: **4. Entrypoint**: What command runs your report generator? - -**User**: python generate_report.py - -**Agent**: **5. Setup Script** (optional): Do you need a setup script to run first? - -**User**: No - -**Agent**: **6. Timeout** (optional): How long should it be allowed to run? (max 600 seconds) - -**User**: 5 minutes should be enough - -**Agent**: Creating your automation with: -- Name: Weekly Report Generator -- Schedule: Every Monday at 9:00 AM UTC -- Code: s3://my-bucket/automations/weekly-report.tar.gz -- Command: python generate_report.py -- Timeout: 300 seconds - -[Executes API call] +### Step 5: Present Result -✅ Automation created successfully! -- **ID**: 550e8400-e29b-41d4-a716-446655440000 -- **Name**: Weekly Report Generator -- **Schedule**: Every Monday at 9:00 AM UTC -- **Status**: Enabled +**On success (HTTP 201):** Show automation ID, name, schedule, and status. -Your automation will run for the first time next Monday at 9:00 AM UTC. +**On error:** Show the error message from the API response. diff --git a/skills/automation/SKILL.md b/skills/automation/SKILL.md index bc76bca..68157b8 100644 --- a/skills/automation/SKILL.md +++ b/skills/automation/SKILL.md @@ -11,7 +11,9 @@ triggers: # OpenHands Automations -This skill helps you create and manage OpenHands automations - scheduled tasks that run your code in sandboxes on a cron schedule. +This skill provides comprehensive API documentation for creating and managing OpenHands automations - scheduled tasks that run your code in sandboxes on a cron schedule. + +**Interactive Setup:** For a guided slash command experience, use the [automation-creation plugin](../../plugins/automation-creation/README.md) with `/automation:create`. **Important:** Automation code must use the [OpenHands Software Agent SDK](https://docs.openhands.dev/sdk) to create conversations and interact with OpenHands Cloud services.