# Where results go

hushrun reads earlier results from one place and records new ones there: your organization's backend, shared by everyone who works on the repository, or this machine when there is none.

## The order

hushrun takes the first of these:

1. **`HUSHRUN_BACKEND`**, when it is set. Set to nothing (`HUSHRUN_BACKEND=`), it turns results off: every check runs, and nothing is recorded.
2. **The repository's backend**, which `package.json` at the repository's root names. `npx hushrun init` adds it:

   ```json title="package.json"
   "hushrun": {
     "backend": "https://api.hushrun.com/o/acme"
   }
   ```

   Committed with the code, it tells CI, your teammates and their agents where results go, with no variable to set.
3. **The backend you signed in to** with `hushrun login`, for repositories that name none.
4. **This machine**, with no setup: hushrun's cache directory, `~/.cache/hushrun/results` on Linux, `~/Library/Caches/hushrun/results` on macOS and `%LOCALAPPDATA%\hushrun\results` on Windows. `HUSHRUN_CACHE_DIR` moves it.

A backend's URL is an organization's address on a server, `https://<host>/o/<org>`. It must use `https://`; `http://` works only on `localhost`, for a server in development.

`hushrun whoami` shows which backend applies here, what named it, and the credential that goes with it:

```console
$ hushrun whoami
backend   https://api.hushrun.com/o/acme (this repository's package.json names it)
token     none: sign in with hushrun login, or set HUSHRUN_TOKEN
…
```

It exits 0 when the backend answered, 1 when it refused the credential, and 6 when it couldn't be reached.

## Signing in

On a laptop, a backend needs your sign-in:

```bash
npx hushrun login
```

hushrun shows a code and opens a page where you approve it, for one of your organizations; `--no-browser` prints the page's address instead. Once you approve, hushrun keeps a token that only you can read, and the organization's URL becomes your backend for repositories that name none. In a repository that names a backend, `login` signs in there.

- **Another server:** `hushrun login https://hushrun.example/o/acme` signs in to an organization on a server you run.
- **This machine:** signing in registers the machine. hushrun makes a key the first time, kept beside the token and never in a repository, and signs your results with it: the server records none without that signature. The dashboard lists your machines; once you revoke one there, the server records nothing it signs. A machine unused for 90 days is revoked too, until you sign in on it again, and you can have 20 in an organization.
- **Signing out:** `hushrun logout` revokes the token and this machine's registration. Results then stay on this machine again.

The token and the machine key live in hushrun's configuration directory: `~/.config/hushrun/` on Linux, `~/Library/Application Support/hushrun/` on macOS and `%APPDATA%\hushrun\` on Windows. `HUSHRUN_CREDENTIALS` names another file.

Until you sign in, checks in a repository that names a backend still run, and at a terminal hushrun ends with one line:

```text
hushrun: sign in to share results with acme: npx hushrun login
```

## Which credential goes where

hushrun sends the first of these that applies:

1. **`HUSHRUN_TOKEN`**, but only to the backend `HUSHRUN_BACKEND` names. An agent token, which starts with `hra_`, also goes to the repository's or your login's backend when it is on hushrun's hosted service, `https://api.hushrun.com`, and its results carry the signature of the key it came with, `HUSHRUN_MACHINE_KEY` ([Agents and sandboxes](https://hushrun.com/docs/agents.md#sandboxes)).
2. **Your login's token**, only to the server you signed in to.
3. **In GitHub Actions**, when the job has `id-token: write`: an ID token made for that backend alone.

A repository's `package.json` is part of the code, so anyone who changes it could point it at another server. That is why a CI secret in `HUSHRUN_TOKEN` never follows it, and hushrun says so instead:

```text
hushrun: HUSHRUN_TOKEN isn't sent to https://hushrun.example/o/acme: it goes only to the backend HUSHRUN_BACKEND names, and an agent token (hra_…) to hushrun's host, https://api.hushrun.com
```

Set `HUSHRUN_BACKEND` alongside the token when the backend is somewhere else.

## On this machine only

With no backend, results stay in hushrun's cache directory, where nothing leaves the machine and only it reads them. A pass still skips the next run on the same files, which is useful for an agent working alone. `hushrun repository stats --local` sums up this machine's results and sends nothing.

## Turning results off

```bash
HUSHRUN_BACKEND= npm test
```

Every check runs, and nothing is read or recorded. An empty `HUSHRUN_CACHE_DIR` turns off the cache on this machine in the same way.

## Your own server

Any server that speaks hushrun's results protocol, `hushrun-results/v0`, can be a backend: name its organization URL in `package.json` or `HUSHRUN_BACKEND`. It is three requests under the organization's URL, `{base}`, each with `Authorization: Bearer <token>`:

| Request | Answer |
|---|---|
| `GET {base}/v0` | `200 {"protocol": "hushrun-results/v0", "org": "acme", "as": "<who the token is>"}`. `hushrun login` checks access with it, and `hushrun whoami` shows it |
| `GET {base}/v0/results/{key}` | `200 {"result": <the newest pass or fail recorded for the key>}`, or `{"result": null}` |
| `POST {base}/v0/results/{key}` | `2xx` once it keeps the result in the body |

- `{key}` is 64 lowercase hex characters, the run key hushrun computes. The server keeps results by key; it never computes one.
- Each result is a JSON object. hushrun decides what it means; the server keeps it, and who sent it:

  ```json
  {"schema": "hushrun.run-result/v0", "check": "unit", "result": "pass", "exitCode": 0,
   "command": ["vitest", "run"], "cwd": "", "scope": "default", "digest": "sha256:…",
   "revision": "<commit>", "repository": "github.com/acme/shop",
   "startedAt": "2026-10-16T14:05:10.123Z", "durationMs": 41000, "provider": "github",
   "runUrl": "https://github.com/acme/shop/actions/runs/1", "tool": "hushrun 0.1.0"}
  ```

- hushrun also records skips, `"result": "skip"`, with the time each saved in `savedMs`. A server keeps them for its own counts, and never answers a lookup with one.
- Errors are `{"error": {"code": "…", "message": "…"}}`, and hushrun shows the message.
- hushrun sends requests to that origin only, follows no redirect, and gives all of a run's requests 10 seconds. Anything else it gets back means it runs the check.

Which tokens a server accepts, and whose results count, is the server's to decide. A token from `HUSHRUN_TOKEN` and `HUSHRUN_BACKEND` works with any server; `hushrun login` needs the server to offer its sign-in at `{origin}/cli/login`.
