wavekat-cli 0.0.25

Command-line client for the WaveKat platform (wk)
<p align="center">
  <a href="https://github.com/wavekat/wavekat-cli">
    <img src="https://github.com/wavekat/wavekat-brand/raw/main/assets/banners/wavekat-cli-narrow.svg" alt="WaveKat CLI">
  </a>
</p>

[![Crates.io](https://img.shields.io/crates/v/wavekat-cli.svg)](https://crates.io/crates/wavekat-cli)

Command-line client (`wk`) for the [WaveKat platform](https://platform.wavekat.com).
Sign in once with your browser and inspect projects and annotations from the
terminal.

Full docs: <https://wavekat.com/docs/cli/>

## Quick start

```sh
curl -fsSL https://github.com/wavekat/wavekat-cli/releases/latest/download/install.sh | sh
wk login
wk projects list
```

That's it — you're signed in and looking at your projects. Run any command
with `--help` to see all flags, or jump to the [Examples](#examples).

## What you can do today

| Command | What it shows |
|---------|---------------|
| `wk login` / `wk logout`                          | sign in via your browser, or sign out |
| `wk me`                                           | who you're signed in as |
| `wk projects list`                                | projects you can see, with your role, file/record counts, and review progress |
| `wk projects show <id>`                           | details for one project (`--json` for raw) |
| `wk annotations list <project-id>`                | paginated annotations with inline ASR text |
| `wk exports list <project-id>`                    | exports for a project (status, clip count, size, owner, writer progress) |
| `wk exports show <export-id>`                     | one export's filter, split policy, counts |
| `wk exports create <project-id> --name …`         | snapshot the current label set into a frozen export |
| `wk exports download <export-id>`                 | fetch `manifest.jsonl` + every clip into `./<id>/` |
| `wk exports delete <export-id> --yes`             | soft-delete an export (cleanup sweep purges later) |
| `wk exports adapt smart-turn …`                   | convert a downloaded export into HF `datasets` Parquet shards |
| `wk config telemetry on\|off\|status`              | toggle crash / error reporting (see [Crash reporting]#crash-reporting) |
| `wk admin …`                                      | root-only platform analytics — users, Voice installs, usage funnel, downloads, prompt usage, geography — as JSON (see [Admin analytics]#admin-analytics) |
| `wk api <path>`                                   | GET any platform endpoint and print its JSON, like `gh api` |

Every list command supports `--page` / `--page-size` (default 20) and prints a
ready-to-paste `Next:` line when more pages exist. `wk annotations list`
also takes `--label`, `--review-status`, `--file-id`, and `--created-by`
filters. Add `--json` to any command for machine-readable output you can pipe
into `jq`.

Supported on macOS (Apple Silicon + Intel) and Linux (x86_64 + aarch64).

## Install

### curl | sh (recommended)

```sh
curl -fsSL https://github.com/wavekat/wavekat-cli/releases/latest/download/install.sh | sh
```

Pin a specific version with `WK_VERSION=vX.Y.Z` or pick the install directory
with `WK_INSTALL_DIR=$HOME/bin`. Defaults to `/usr/local/bin` if writable, else
`$HOME/.local/bin`.

### Prebuilt binaries

Each [release](https://github.com/wavekat/wavekat-cli/releases) attaches
tarballs and `.sha256` checksums for the four supported targets — drop the
`wk` binary anywhere on your `PATH`.

### From source

```sh
cargo install --git https://github.com/wavekat/wavekat-cli wavekat-cli
# or, from a clone:
git clone https://github.com/wavekat/wavekat-cli && cd wavekat-cli
cargo install --path .
wk --version
```

## Sign in

```sh
wk login
```

`wk` opens your browser to the WaveKat platform, you click **Authorize**, and
the terminal confirms you're signed in. The browser tab will say "You can
close this tab" when it's done.

You can list and revoke tokens any time from your platform profile page.
`wk logout` revokes the current token before clearing the local file.

### Headless / SSH

Over SSH (or on a Linux box with no display) `wk login` doesn't try to open a
browser — it prints the sign-in URL instead. Force this anywhere with
`wk login --no-browser`.

1. Open the printed URL in a browser on any machine (e.g. your laptop) and
   click **Authorize**.
2. The browser then redirects to `http://127.0.0.1:<port>/callback?…`, which
   won't load because that port lives on the remote host. Copy the full URL
   from the address bar and paste it at the `Redirect URL:` prompt.

Alternatively, forward the port (`ssh -L <port>:127.0.0.1:<port> remote-host`)
and the redirect completes on its own.

### CI / pre-minted token

Pre-mint a token from your platform profile, then:

```sh
WK_TOKEN='wk_…' WK_BASE_URL='https://platform.wavekat.com' wk login
```

### Where credentials are stored

| Platform | Path |
|----------|------|
| macOS    | `~/Library/Application Support/wavekat/auth.json` |
| Linux    | `~/.config/wavekat/auth.json` |
| Windows  | `%APPDATA%\wavekat\auth.json` |

Mode is `0600` on Unix. Run `wk logout` to remove it.

## Crash reporting

`wk` sends anonymous crash and error reports to help us catch bugs we
wouldn't otherwise see (a server response shape that breaks an older
CLI, a panic in `exports adapt`, network errors). It's **on by
default** in the shipped binary.

What we collect:

- CLI version and build SHA, OS / arch, subcommand name.
- A short error category (`http_4xx`, `decode`, `network`,
  `auth_missing`, `panic`, …) and a 200-char snippet of the error.
- For HTTP failures, a **templated** endpoint path
  (`/api/projects/:id/annotations`, never the real ID).
- A random anonymous install ID, generated once and stored alongside
  `auth.json`.

What we never collect:

- Request bodies or response bodies (beyond the 200-char snippet).
- Full URLs containing IDs, command-line arguments, file paths,
  environment variables, auth tokens, cookies, or anything you've
  typed at a prompt.

The scrubber is in source at `src/telemetry.rs` — you can read
exactly what's filtered before sending. See also the
[privacy policy](https://wavekat.com/privacy/#telemetry).

To opt out:

```sh
wk config telemetry off          # persistent, until you re-enable
WK_TELEMETRY=0 wk projects list  # per-invocation
wk config telemetry status       # show current setting
```

Source builds without the `telemetry` cargo feature compile out the
SDK entirely.

## Examples

```sh
wk me
# login: somebody
# id:    42
# role:  user

wk projects list --page-size 5

wk projects list --json | jq '.projects[].name'

# Default: human-readable table with the ASR snippet under each row.
wk annotations list <project-id> --label end_of_turn --review-status approved

# Pipe raw JSON into jq for scripting.
wk annotations list <project-id> --label end_of_turn --review-status approved --json \
  | jq '.annotations | length'
```

## Datasets — end-to-end

Producing a HuggingFace-loadable training set from a labelled project is
three commands:

```sh
# 1. Snapshot the current labels into a frozen export.
wk exports create <project-id> \
  --name "smart-turn-zh 2026-04-28" \
  --review-status approved \
  --label-key end_of_turn \
  --label-key continuation \
  --split random --seed 42 --ratios 0.8,0.1,0.1

# 2. Download the resulting snapshot (manifest + every clip).
wk exports download <export-id> --out ./snapshots/smart-turn-zh

# 3. Convert it into Parquet shards consumable by HF datasets.
wk exports adapt smart-turn \
  --export-dir ./snapshots/smart-turn-zh \
  --out ./datasets/smart-turn-zh \
  --language zh
```

Then on the trainer side:

```python
from datasets import load_dataset, Audio
ds = load_dataset(
    "parquet",
    data_files={
        "train":      "./datasets/smart-turn-zh/train.parquet",
        "validation": "./datasets/smart-turn-zh/validation.parquet",
        "test":       "./datasets/smart-turn-zh/test.parquet",
    },
).cast_column("audio", Audio(sampling_rate=16000))
```

The smart-turn adapter only knows two label keys — `end_of_turn` (→ 1)
and `continuation` (→ 0). Anything richer is rejected; binary collapse
of a richer label set must be an explicit user decision via the export
filter, not a silent default in the adapter.

Every clip is decoded, downmixed to mono, resampled to 16 kHz, and
re-encoded as 16-bit PCM WAV before being written into the parquet.
This both validates the source bytes (corrupt or non-WAV clips fail at
adapt time, with the failing path in the error) and guarantees the
shards contain a uniform shape downstream notebooks can rely on.

## Admin analytics

For people with the global `root` role on the platform. `wk admin` wraps
the platform's root-only read endpoints so you (or an AI agent) can pull
real customer and product data from the terminal:

```sh
wk admin users list -q pageSize=100          # users + headline stats
wk admin users show <user-id>                # one user's activity summary
wk admin installs metrics -q days=30         # Voice fleet: active installs, versions, channels
wk admin installs events <install-id>        # one install's usage events
wk admin usage                               # usage-event funnel
wk admin downloads metrics                   # download numbers
wk admin prompts callers                     # voice-prompt spend per caller
wk admin geo -q days=90                      # where customers sign in from
wk admin spec > openapi.json                 # every endpoint and its parameters
```

Every `wk admin` command, and `wk api`, prints the endpoint's JSON
unchanged — there is no table view. Filters and pagination go through
`-q key=value` (repeatable) instead of per-command flags; `wk admin spec`
lists what each endpoint accepts. For anything without a named command,
use `wk api`:

```sh
wk api /api/admin/voice/installs -q channel=beta -q pageSize=50
```

Both are GET-only. A token from a non-root account gets a `403`. Errors
from these two commands are never sent to crash reporting, because their
URLs and response bodies can identify customers.

## API reference

Each command maps to a single platform endpoint:

| Command | Endpoint |
|---------|----------|
| `wk login`                                  | loopback OAuth + `GET /api/me` |
| `wk logout`                                 | `POST /api/auth/cli/tokens/revoke-current` |
| `wk me`                                     | `GET /api/me` |
| `wk projects list`                          | `GET /api/projects` |
| `wk projects show <id>`                     | `GET /api/projects/{id}` |
| `wk annotations list <project-id>`          | `GET /api/projects/{id}/annotations` |
| `wk exports list <project-id>`              | `GET /api/projects/{id}/exports` |
| `wk exports show <export-id>`               | `GET /api/exports/{id}` |
| `wk exports create <project-id>`            | `POST /api/projects/{id}/exports` |
| `wk exports download <export-id>`           | `GET /api/exports/{id}/manifest` + per-clip `GET /api/exports/{id}/clips/{annotation-id}` |
| `wk exports delete <export-id>`             | `DELETE /api/exports/{id}` |
| `wk exports adapt smart-turn`               | local-only; reads a downloaded snapshot |
| `wk config telemetry`                       | local-only; writes `auth.json` |
| `wk admin users list` / `show <id>`         | `GET /api/users` / `GET /api/users/{id}` |
| `wk admin installs metrics` / `list`        | `GET /api/admin/voice/installs/metrics` / `GET /api/admin/voice/installs` |
| `wk admin installs show <id>`               | `GET /api/admin/voice/installs/{id}` (`--install-id`: `…/installs/by-install-id/{installId}`) |
| `wk admin installs events <install-id>`     | `GET /api/admin/voice/installs/by-install-id/{installId}/events` |
| `wk admin usage`                            | `GET /api/admin/voice/usage` |
| `wk admin downloads metrics` / `list`       | `GET /api/admin/voice/downloads/metrics` / `GET /api/admin/voice/downloads` |
| `wk admin prompts usage` / `callers` / `events` | `GET /api/admin/voice/prompt-usage` / `prompt-callers` / `prompt-events` |
| `wk admin geo`                              | `GET /api/admin/geo` |
| `wk admin cli-usage`                        | `GET /api/admin/cli-usage` |
| `wk admin spec`                             | `GET /api/openapi.json` |
| `wk api <path>`                             | `GET <path>` (the `/api` prefix is optional) |

## Help and feedback

- `wk --help` (or `wk <command> --help`) for usage details.
- File issues at <https://github.com/wavekat/wavekat-cli/issues>.

## About WaveKat

WaveKat is an open-source ecosystem for building real-time voice pipelines, plus a platform for working with voice data. `wavekat-cli` (`wk`) is the command-line client for that platform.

See [wavekat.com](https://wavekat.com) for the full project.

## License

Apache-2.0. See [LICENSE](LICENSE).