# The attn CLI

> The attn command: push flows, start runs and wait for them in CI with exit codes, read a run's steps and outputs, share a screen, and run MCP for local agents.

`attn` is a thin client: it talks to a hub over HTTP and nothing else, so it runs anywhere Node.js does, with no native code and no browser. It isn't published to npm yet; in a checkout of the attention.run repository, `npx attn` runs it.

## Connecting to a hub

`attn` finds the hub in `--hub <url>` or `ATTN_HUB` (default `http://127.0.0.1:7300`, a local hub), and sends `ATTN_TOKEN` as its API token when it is set. A local hub needs no token. Elsewhere, make one in the web app under **Settings → API tokens**: it is shown once. The examples name the hosted app; until its API is open to the CLI ([Status](https://attention.run/docs#status)), point `ATTN_HUB` at a local hub instead.

```sh
export ATTN_HUB=https://app.attention.run
export ATTN_TOKEN=attn_api_…
attn status
```

```text
https://app.attention.run: ok, hub 0.0.0, protocol 0.1
```

## Flows

`attn flows push <file>` checks a flow file the way the hub does (the schema, placeholders, the steps), then saves it: a new flow, or a new version of the flow with that slug. An unchanged file saves nothing, so pushing on every CI build doesn't pile up versions. With errors it prints them with their paths and sends nothing.

```json
{
  "flow": "docs/hello",
  "description": "Opens the fixture's sign-in page and waits for its button.",
  "steps": [
    { "navigate": "http://127.0.0.1:7310/login" },
    { "waitFor": { "visible": "login/sign-in" } }
  ]
}
```

```sh
attn flows push hello.json --message "first version"
attn flows push hello.json
attn flows list
```

```text
docs/hello v1 (new flow)
docs/hello v1 (unchanged)
FLOW             VERSION  UPDATED               ID
docs/hello       v1       2026-10-15 09:12 UTC  flw_…
fixture/sign-in  v1       2026-10-15 09:05 UTC  flw_…
```

A broken file is refused before anything is sent, with exit status 2:

```json
{ "flow": "docs/broken", "steps": [{ "click": "login/sign-in", "button": "back" }] }
```

```sh
attn flows push broken.json
```

## Runs

`attn run <flow> --target <target>` starts a run of a flow (its slug or id) on a target (its name or id) and prints the run's id. `--wait` follows it: a line per step as it ends, then a summary, the `pass` step's message and the run's outputs.

```sh
attn run fixture/sign-in --target "Fixture app" --wait
```

`--param name=value` gives a param; values are typed by the flow's declarations, so `--param count=3` fills a number. `--version <n>` runs a stored version instead of the latest.

### Exit codes

`attn run --wait` exits with the run's result, so a CI job fails when its flow fails:

| Exit | The run |
|---|---|
| 0 | passed |
| 1 | failed: a step failed, or the flow's `fail` |
| 2 | error (the target or the setup broke), or `attn` itself failed: a bad argument, a hub it can't reach, a refusal |
| 3 | cancelled; Ctrl+C while waiting cancels the run (a second Ctrl+C stops waiting) |

Signing in as someone the fixture doesn't know fails the flow: the welcome heading never appears.

```sh
attn run fixture/sign-in --target "Fixture app" --param user=nobody --wait
```

```text
run_…: fixture/sign-in v1 on Fixture app (tgt_…)
✓ steps[0] navigate http://127.0.0.1:7310/login (36 ms)
✓ steps[1] type params.user into login/username (84 ms)
✓ steps[2] type "demo" into login/password (62 ms)
✓ steps[3] click login/sign-in (33 ms)
✗ steps[4] waitFor visible welcome/heading (5.0 s) — TIMEOUT: "welcome/heading" visible did not hold within 5000 ms; "welcome/heading": best candidate 0.7767 at (516, 154), threshold 0.9: add a variant for this look or lower the threshold, best 0.78/0.90
failed: fixture/sign-in v1 in 5.7 s (4 passed, 1 failed, 0 skipped)
  at steps[4]: TIMEOUT: "welcome/heading" visible did not hold within 5000 ms; …
```

The best candidate is the sign-in page's own "Welcome back" heading, in the same place: close to the element's pixels, but under its threshold, so the flow didn't take it for the welcome page. A failure always says what it was waiting for and what came closest.

### Reading a run

Without `--wait`, `attn run` prints the run's id and returns at once; `attn runs get <run>` shows it later: its status, params, the steps from its report, the error, the message and the outputs.

```sh
run=$(attn run fixture/sign-in --target "Fixture app")
attn runs get "$run"
```

```text
run_… leased: fixture/sign-in v1 on tgt_… (cli, 2026-10-15 09:13 UTC)
params: user=demo
No report until the run ends.
```

### JSON for scripts

`--json` prints one JSON document instead: for `run` and `runs get`, `{ status, error?, message?, outputs, run, report }`, with the run's result first.

```sh
attn run fixture/sign-in --target "Fixture app" --wait --json > result.json
node -e 'const r = require("./result.json"); console.log(r.status, r.report.steps.length, "steps")'
```

## Sharing a screen

`attn share` makes a VNC server or a Chrome on this machine a target of the hub, over SSH inside a WebSocket to the hub's normal port, and `--run` runs a flow on it. See [SSH targets](https://attention.run/docs/ssh-targets).

## MCP

`attn mcp` is a stdio MCP server for local agents (Claude Code, Claude Desktop): a proxy to the hub's MCP endpoint with `ATTN_TOKEN`. See [MCP](https://attention.run/docs/mcp).

## Commands

| Command | What it does |
|---|---|
| `attn status` | The hub's health and version |
| `attn flows push <file> [--message <text>] [--json]` | Check a flow file, then save it as a new flow or a new version |
| `attn flows list [--json]` | Flows: slug, latest version, last update, id |
| `attn run <flow> --target <t> [options]` | Start a run. Options: `--version <n>`, `--param k=v` (repeatable), `--wait` (follow it and exit with its result), `--json`, `--junit <file>` and `--html <file>` (with `--wait`, its JUnit XML or a self-contained HTML report) |
| `attn runs get <run> [--json]` | A run's status, steps, error and outputs |
| `attn runs report <run> [--junit <file>] [--html <file>]` | An ended run's report: JUnit XML, HTML, or its JSON on stdout |
| `attn library pull <library> <dir>` | Write a library to a folder: `library.json`, and each element's file with its variants' PNGs |
| `attn library push <dir> [<library>] [--dry-run] [--prune]` | Push a library folder back: new and changed elements and variants; conflicts listed and skipped |
| `attn share (--vnc \| --chrome) …` | Share this machine's screen as targets: `--vnc [host:]port`, `--chrome [host:]port` or `--chrome launch`; `--run <flow>` runs a flow on it |
| `attn mcp` | A stdio MCP server proxying the hub's MCP endpoint |
| `attn help` | Every command and option |

Not built yet: `attn login` (storing a hub and a token), `attn runs tail`, `attn flows pull`, and pushing TypeScript flows.

---

Canonical: https://attention.run/docs/cli · Updated 2026-10-15
