# OpenHands Automation Service
> ⚠️ **Beta**: This project is currently in beta. APIs and features may change without notice.
Scheduled and event-driven automation execution for OpenHands Cloud. This service allows users to create automations that run on a schedule (cron) or in response to events (webhooks).
## Features
- **Scheduled Automations**: Run OpenHands conversations on a cron schedule
- **Event-Driven**: Trigger automations via webhooks (e.g., GitHub events)
- **API Key Management**: Per-user API keys for secure automation access
- **Run History**: Track automation runs with status and results
## Repository boundaries
The Automation Service owns automation definitions, cron scheduling, webhooks, run history, dispatch, and sandbox lifecycle orchestration. It manages when work runs; the Agent Server and [`OpenHands/software-agent-sdk`](https://github.com/OpenHands/software-agent-sdk) execute the agent conversations and own agent/tool behavior, workspaces, events, and API endpoints.
[`OpenHands/typescript-client`](https://github.com/OpenHands/typescript-client) provides typed browser access to the Agent Server API, while [`OpenHands/OpenHands`](https://github.com/OpenHands/OpenHands) owns Agent Canvas UI and frontend integration. If a change belongs in one of those repositories, open the PR there rather than duplicating the logic here.
## Development
### Prerequisites
- Python 3.12+
- [uv](https://github.com/astral-sh/uv) for dependency management
- PostgreSQL (or use testcontainers for testing)
### Setup
```bash
# Install dependencies
uv sync --group dev
# Run the service locally (requires PostgreSQL)
uv run uvicorn openhands.automation.app:app --host 0.0.0.0 --port 8000 --reload
```
### Testing
```bash
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=openhands/automation --cov-report=term-missing
```
### Code Quality
```bash
# Run pre-commit hooks
uv run pre-commit run --all-files
# Format code
uv run ruff format
# Lint code
uv run ruff check --fix
# Type check
uv run pyright
```
### Database Migrations
```bash
# Create a new migration
uv run alembic revision --autogenerate -m "description"
# Apply migrations
uv run alembic upgrade head
```
SQLite databases are migrated on startup. PostgreSQL databases are not, unless
`AUTOMATION_RUN_MIGRATIONS_ON_STARTUP=true` (or `1`). With it set, each replica runs
`alembic upgrade head` before it serves requests, and a failed migration stops it from
starting. Replicas that start at the same time take turns through an advisory lock.
Set `AUTOMATION_CREATE_DATABASE_IF_MISSING=true` (or `1`) to have the migrations create the
PostgreSQL database first if it does not exist. This works both on startup and with
`alembic upgrade head`. The migrations connect to the `postgres` database to create it, so
the database user needs the `CREATEDB` privilege.
## Docker
```bash
# Build the image
docker build -t automation -f containers/Dockerfile .
# Run the container
docker run -p 8000:8000 automation
```
## Project Structure
```
openhands/
└── automation/ # Main application package (openhands.automation namespace)
├── app.py # FastAPI application entry point
├── router.py # API routes for CRUD operations
├── scheduler.py # Background scheduler for cron jobs
├── dispatcher.py # Dispatches pending runs to OpenHands
├── models.py # SQLAlchemy models
├── schemas.py # Pydantic schemas for API
└── utils/ # Utility functions
migrations/ # Alembic database migrations
tests/ # Unit tests
containers/ # Docker configuration
```
## Deployment
This service is deployed via the [deploy repository](https://github.com/All-Hands-AI/deploy). Docker images are automatically built and pushed to `ghcr.io/openhands/automation` on every push to main and on tags.