# CLI

The `cronpad` binary is both the server and a command-line client. Server commands (`serve`, `migrate`, `user`, `secrets`) work on the local database and config. Client commands (`jobs`) talk to any cronpad server over the API. `schedule` commands work entirely offline. Schedule and jobs commands accept `--json` for machine-readable output; `user create-key` also supports it.

## Install

Download a release binary for Linux or macOS (amd64, arm64) from the GitHub releases page, or use the Docker image (`docker run --rm cronpad:<version> <command>`).

## Client configuration

| Variable | Flag | Description |
|---|---|---|
| `CRONPAD_URL` | `--url` | Server base URL, e.g. `https://app.cronpad.com` |
| `CRONPAD_API_KEY` | `--api-key` | API key (`cp_…`) |

## Commands

### `cronpad serve`

Starts the server: HTTP, dispatcher, workers and background tasks. Reads `cronpad.toml` from the working directory, or `--config <path>`. Environment variables override the file. See [Configuration](../self-hosting/configuration.md).

### `cronpad migrate`

Applies database migrations and exits. `serve` does this automatically unless `database.run_migrations = false`.

### `cronpad schedule validate <expr>`

```sh
$ cronpad schedule validate "0 0 9 ? * 3#2"
valid   quartz   At 09:00 on the second Tuesday of the month
```

### `cronpad schedule next <expr>`

```sh
$ cronpad schedule next "every weekday at 6:30pm" --tz America/New_York -n 3
2026-11-02 18:30 EST   (2026-11-02T23:30:00Z)
2026-11-03 18:30 EST   (2026-11-03T23:30:00Z)
2026-11-04 18:30 EST   (2026-11-04T23:30:00Z)
```

Flags: `--tz` (default `UTC`), `-n` / `--count` (default 10, range 1–100),
`--after <RFC3339>`, `--kind` (default `auto`), and `--json`. `validate` also
accepts `--tz`, `--kind`, and `--json`. Invalid schedules exit nonzero; JSON
validation output includes the structured parser errors. These commands do not
load configuration or open databases. An explicit `--after`
also anchors relative expressions and recurrence phases. Offline validation
checks syntax; the server additionally applies its configured minimum interval.

### `cronpad jobs …`

| Command | Description |
|---|---|
| `cronpad jobs list [--state active] [--tag t]` | List jobs |
| `cronpad jobs get <id>` | Show a job and its next runs |
| `cronpad jobs create --name n --schedule s [--tz z] (--url u \| --command c [--arg a]…)` | Create a simple job |
| `cronpad jobs create -f job.json` | Create from a full JSON body (same as the API) |
| `cronpad jobs pause <id>` / `resume <id>` / `enable <id>` | Change state |
| `cronpad jobs trigger <id>` | Run now |
| `cronpad jobs runs <id> [--status failed]` | Recent runs |

Jobs flags override environment variables. For `create`, `--url` is the webhook
URL; put a server override before the subcommand:

```sh
cronpad jobs --url https://cronpad.example.com create --name report \
  --schedule 'every weekday at 9am' --tz Asia/Kolkata \
  --url https://example.com/hook --retries 5 --tag reports --json
cronpad jobs create --name backup --schedule 'every day at 2am' \
  --command /usr/local/bin/backup.sh --arg daily --json
cronpad jobs list --query report --limit 20 --json
```

`--retries` sets maximum attempts including the first attempt. `--tag` accepts
repeated flags or comma-separated tags. `-f -` reads a JSON body from stdin;
file mode cannot be combined with simple creation flags. List and runs accept
`--limit`; list also accepts `--cursor`. Table output reports `next_cursor`
when another page is available. API errors print their code and message to
stderr and exit nonzero.

### `cronpad mcp`

Bridges the server's MCP endpoint to stdio for AI clients that launch local processes. Uses `CRONPAD_URL` and `CRONPAD_API_KEY`, overridden by `--url` and `--api-key`. Use `--path` for a custom `mcp.path`. See [MCP server](../ai/mcp-server.md).

### `cronpad user create-key --email <email> --name <name>`

Creates an API key for that user's personal workspace directly in the local database and prints it once. Useful for bootstrapping automation on a fresh self-hosted server. The user must have signed in at least once.

### `cronpad secrets rekey --new-key <base64>`

Re-encrypts all stored secrets with a new encryption key. Stop the server first, run this, then start it with the new `secrets.encryption_key`.

### `cronpad healthcheck`

Calls the local `/readyz` and exits `0` or `1`. Used as the Docker healthcheck, since the image has no `curl`.

### `cronpad version`

Prints version, commit and edition (`oss` or `cloud`).