# CLI

> Create, inspect and cancel jobs, follow runs, and turn any program into a worker, from your terminal.

`emit` is the command line for your cluster: everything the API does, from a shell. It's one static binary, built with Go 1.23 or later:

```bash
git clone https://github.com/emit-run/cli
cd cli && go build -o emit .
```

## Connecting to a cluster

Save your cluster's endpoint and a token as a **profile**:

```bash
emit config set prod --url https://<your cluster's endpoint> --token emit_... --space orders
emit config use prod
emit config show   # what's in force, and where each value came from
```

Profiles live in `~/.config/emit/config.json` (set `EMIT_CONFIG` to use another file). The environment variables `EMIT_URL`, `EMIT_TOKEN` and `EMIT_SPACE` override the profile, and the flags `--url`, `--token` and `--space` (`-s`) override both. Every command takes `--profile` to pick a profile, and `--json` for output a script can read.

## Jobs

```bash
emit jobs create send-receipt -p '{"orderId": "ord_123"}' --key receipt-ord_123
emit jobs create send-receipt -p @order.json --delay 5m --max-attempts 3
emit jobs get 01M3QSJH9501P52NWMNZR5AF8A
emit jobs list --name send-receipt --status failed --from 2h
emit jobs follow 01M3QSJH9501P52NWMNZR5AF8A      # its events as they happen, until it ends
emit jobs result 01M3QSJH9501P52NWMNZR5AF8A      # waits, prints the result; exits 1 if it didn't complete
emit jobs lines 01M3QSJH9501P52NWMNZR5AF8A --min-level warn
emit jobs cancel 01M3QSJH9501P52NWMNZR5AF8A      # needs the admin scope
```

`-p` takes JSON, `@file` to read a file, or `-` to read standard input. `jobs create` also takes `--run-at`, `--timeout`, `--backoff`, `--callback` with `--callback-header`, and `--count` to make many alike in one call.

## Workers from any program

`emit work` turns a program into a worker. For each job it runs the program with the payload as JSON on standard input, and `EMIT_JOB_ID`, `EMIT_JOB_NAME` and `EMIT_ATTEMPT` in its environment:

```bash
emit work --names send-receipt --concurrency 4 -- ./send-receipt.sh
```

| The program | The job |
| --- | --- |
| exits 0 | completes, with what the program printed as its result (JSON if it's JSON, text otherwise) |
| exits 75 | goes back to the queue; the attempt isn't counted |
| exits 65 | fails for good |
| exits with any other code | fails this attempt, with what it printed to standard error |

Ctrl-C stops the program and gives its job back. `--once` stops after one job, which is handy for testing:

```bash
emit work --names send-receipt --once -- jq -c '{sent: true, orderId}'
```

## Workflow runs

```bash
emit runs list --name checkout --status waiting   # runs waiting, and what for
emit runs tree 01M3QSR386017JCY0DC11GTG7D --follow  # the run and its steps, redrawn as it changes
emit runs signal 01M3QSR386017JCY0DC11GTG7D delivered '{"at": "2026-10-02"}'
emit runs cancel 01M3QSR386017JCY0DC11GTG7D         # the run and everything it started; needs admin
```

`runs signal` exits 1 if no unfinished run took the signal.

## Spaces and tokens

These need a token with the `admin` scope.

```bash
emit spaces list
emit spaces get orders
emit spaces counts orders            # jobs by status, and when each name was last claimed
emit spaces configure orders --max-attempts 6 --timeout 10m --unclaimed 48h

emit tokens create --name api-server --spaces orders --scopes create,read   # the secret is shown once
emit tokens list
emit tokens revoke 01M3QT78EK010RWSN8YGR8YG00
```

`spaces configure` sets the space's settings whole: a setting you leave out goes back to its default, except the webhook secret, the retry growth and the unclaimed window, which stay as they are. Its flags are `--fifo`, `--max-attempts`, `--backoff`, `--timeout`, `--backoff-kind`, `--backoff-max`, `--backoff-multiplier`, `--backoff-jitter`, `--max-unfinished`, `--public signed|unsigned|disabled`, `--webhook-secret`, `--unclaimed` (a duration, or `never`) and `--wake-url` with `--wake-names` and `--wake-per`.

## Webhooks and browser tokens

```bash
# Is this callback genuine? Pass the raw body on standard input.
echo -n "$body" | emit sign verify --secret "$EMIT_WEBHOOK_SECRET" --header "$EMIT_SIGNATURE"

# A token that lets a browser follow one job for an hour.
emit sign subscription 01M3QSJH9501P52NWMNZR5AF8A --expires 1h
```

## Watching everything

`emit watch` streams every job change in the cluster from the firehose, filtered:

```bash
emit config set prod --firehose-url https://<your cluster's endpoint>/firehose --firehose-token ...
emit watch --spaces orders --to failed
```

Shell completion: `emit completion bash`, `zsh` or `fish`.
