# The `bucker` CLI

The `bucker` command line: releases, deploys, source maps, cron check-ins, issues, config as
code, and a local envelope sink for development. One file, no runtime dependencies, Node 22+.

```bash
npx @bucker/cli login                  # device code in the browser; stored under ~/.config/bucker
npx @bucker/cli whoami
```

Every command takes `--json`: stdout then carries exactly one JSON document and progress goes
to stderr, so an agent or a CI step can pipe it.

## Context

Each value comes from the first of: a flag, the environment, `.bucker/cli.json` (nearest
ancestor directory).

| Flag | Environment | `.bucker/cli.json` |
| --- | --- | --- |
| `--api-url` | `BUCKER_API_URL` | `apiUrl` (default `https://api.bucker.io`) |
| `--token` | `BUCKER_TOKEN` | never; see below |
| `--org` | `BUCKER_ORG` | `org` |
| `--project` | `BUCKER_PROJECT` | `project` |
| `--dsn` | `BUCKER_DSN` | `dsn` |

`.bucker/cli.json` is meant to be committed: an org slug and a DSN are not secrets. A token is
never read from it. A `token` key is an error, because a file that works with a token in it
gets committed with one. `bucker login` stores its credential in
`$XDG_CONFIG_HOME/bucker/credentials.json` (else `~/.config/bucker/`), mode 0600, outside every
working tree. The CLI refreshes and rotates that credential before it expires.

`login` asks for `org:read project:read project:write event:read issue:read release:write`.
This is the most a first-party login can hold (`OAUTH_API_CEILING`). `issues resolve` and
`config apply` need scopes outside it. For those, use a personal access token with the scope
(Settings → Tokens) as `BUCKER_TOKEN`. In CI, use an org token (`bkr_org_…`): it keeps working
after the person who set up the pipeline leaves.

## Releases and source maps (CI)

```bash
bucker releases new "$VERSION" --auto            # --auto: HEAD's sha; Bucker walks the commits
bucker sourcemaps upload dist --release "$VERSION"   # inject debug ids, upload, verify
bucker releases finalize "$VERSION"
bucker deploys new "$VERSION" --env production
```

`sourcemaps inject|upload|verify` run the bundler plugin's own code. It is bundled in, not
copied, so a tsc, esbuild or webpack build gets the same debug ids the Vite plugin would derive.
Injecting is idempotent: a file that already carries a `//# debugId=` keeps it. `upload` fails
the step unless every shipped id resolves server-side. `--no-verify` turns that off. Doing so
trades a red build for frames that silently stay minified.

The posts are upserts, so re-running a CI step changes nothing it already recorded. Recipes for
GitHub Actions, GitLab CI and AWS CodeBuild are in `docs/releases.md`, under "CI recipes".

## Events and cron

```bash
bucker send-event -m "nightly import failed" --logfile import.log --tag job:import
bucker monitors run nightly-import --schedule "0 3 * * *" -- ./import.sh
```

`monitors run` sends `in_progress`, runs the command, then sends `ok` or `error` with the
duration. All three share one check-in id. A `--schedule` (or `--interval`) creates the monitor
on its first check-in. The CLI exits with the command's own exit code. A check-in that cannot be
sent only warns on stderr, so a network blip never fails a successful job.

## Issues

```bash
bucker issues list --json
bucker issues essence CHECKOUT-42        # the ≤500-token essence, the document MCP issue_essence returns
bucker issues rca CHECKOUT-42 [--run]
bucker issues resolve CHECKOUT-42 --in-release 1.4.0
```

## Config as code

```bash
bucker config export > bucker.json       # JSON is valid YAML: this is also a working bucker.yml
bucker config plan                       # bucker.yml / bucker.yaml / bucker.json, or a path, or -
bucker config apply --yes
```

`apply` plans again and sends that plan's hash. If the organization changed between the two, the
server answers 409 and nothing is applied. `--plan-hash <h>` pins a hash from an earlier `plan`,
so CI can apply on merge exactly what was reviewed on the pull request. The schema is in
`docs/config-as-code.md`.

## `bucker dev`: local errors, locally

```bash
bucker dev                               # http://127.0.0.1:8969
BUCKER_DSN=http://bucker_dev@127.0.0.1:8969/0 node app.js
```

`bucker dev` accepts envelopes from any SDK on `/api/<id>/envelope/`. It also accepts them on
Spotlight's sidecar path `/stream`, so a Sentry SDK with `spotlight: true` works unchanged. It
prints one line per error and serves a list at `/`, each issue's page at `/issues/<id>`, and the
same as JSON under `/api/issues`. Data stays in an in-memory ring buffer and is never forwarded
anywhere.

Grouping and scrubbing are a **local approximation; production grouping happens on Bucker.**
`bucker dev` groups by the SDK's `fingerprint` when one is sent, else by the exception type and
its innermost in-app frame (not the line number), else by the message. Before anything is
stored, shown or handed to an agent, it replaces credential headers (`Authorization`, `Cookie`,
`X-Api-Key`, …), cookies, values under secret-shaped keys (`password`, `api_key`,
`access_token`, …) and query parameters of those names inside any string, such as a breadcrumb's
URL, with `[Filtered]`. It does not build the issue essence: that is computed by
Bucker's hosted pipeline, which is not part of this package. Two errors that share a local issue
may still be separate issues on Bucker, and the other way round.

To give a coding agent the local errors over MCP:

```json
{ "mcpServers": { "bucker-dev": { "command": "npx", "args": ["@bucker/cli", "dev", "--mcp"] } } }
```

The tools are `issues_list` and `issue_details`. `issue_details` returns the local summary
(exception chain, innermost frames, last breadcrumbs, tags, release), labelled as a local
approximation, with every string marked as data from the application under test. There is no
local `issue_essence`: a call to it returns an error that names `issue_details`.

## Licence

Apache-2.0, like the SDKs — decided by the owner on 2026-10-17; copyright Atilan LLC (see the
package's `LICENSE` and `NOTICE`). The published file is the CLI's own code, the bundler plugin's and the
public wire protocol (the same envelope and DSN code `@bucker/sdk-core` ships), plus third-party
code. It carries no Bucker server code, and its build refuses to produce a file that does.
