Usage
Listing and filtering
wk projects list --page-size 5
wk projects list --json | jq '.projects[].name'
wk annotations list accepts filters that map onto the same query parameters as the platform API:
wk annotations list <project-id> --label end_of_turn --review-status approved
Available filters: --label, --review-status, --file-id, --created-by. Combine with --json 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:
# 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:
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))
Smart-turn adapter rules
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.
Phone calls
wk voice places and manages real phone calls through the WaveKat Voice desktop app. Install the app, open it, and turn on Settings → Automation; then:
wk voice status # is the app reachable? lists your SIP accounts
wk voice call +14155550123 --wait # dial, follow the call, exit with its outcome
wk voice call list # calls happening right now
wk voice call hangup <call-id>
wk voice call transcript <call-id>
wk voice --help # every command
Calls go through your own SIP account and may cost money. wk voice doesn’t need wk login: it runs the calling engine bundled inside the installed app and passes every argument to it unchanged, so its commands, --json output and exit codes always match your app version.
wk voice call <number> --wait exits with the call’s outcome: 0 answered then ended normally, 1 couldn’t place the call (app not reachable, bad input), 2 busy or declined, 3 the call failed or dropped, 4 no answer.
wk voice uses the engine you installed with wk voice install, if any (see below). Otherwise it finds the engine on PATH (the app’s Install command-line tool button), then in the app’s install folder (macOS app, .deb, Snap), then through Flatpak. Set WK_VOICE_BIN to point at it anywhere else.
On macOS, the Mac App Store version’s engine only runs inside the app, so wk voice can’t use it and says so; use the direct download from wavekat.com, or the engine on its own (below).
Without the app
The calling engine also runs on its own, with no app window: on a server, on a machine an AI assistant works from, or on a Mac whose only install is the App Store app. It runs on Apple Silicon Macs and on x86_64 / arm64 Linux (Ubuntu 24.04 or a similarly recent distribution):
wk voice install # install the engine
wk voice service install # keep it running in the background
wk voice setup # agree to the terms, add your phone line
wk voice call +14155550123 --wait
wk voice install also gets the engine ready: it starts it (in the background on a computer with no service manager, such as most containers), signs it in with your wk login, and asks about anything left. Your WaveKat account already agreed to the terms of service when you created it, so signing in covers them here too; otherwise install asks once (press Enter to agree), and --accept-terms agrees without asking. Ordinary calls work either way; only automated calls need the terms. On a server with no sound library, install downloads the engine built without audio devices, so nothing else needs installing.
Your line’s password is never typed on the command line. wk voice setup and wk voice accounts add ask for it, hidden. A script or an AI assistant can pass it with --password-file <path>, --password-command '<cmd>' (to read it from a password manager, for example op read op://Private/SIP/password), --password-stdin, or the WAVEKAT_SIP_PASSWORD environment variable. Without a terminal, wk voice setup asks nothing and lists what’s left to do, with the command for each step.
To use call flows and automated calls, the engine also signs in to WaveKat. wk voice login does that with your wk login, with no browser. If you added a phone line before signing in, it asks whether to add that line (and earlier calls) to your account; --claim adds them without asking.
wk voice update gets the newest engine and restarts it; wk voice uninstall removes it (your lines and call history stay). If the WaveKat Voice app is installed, wk voice install uses the app’s engine instead of downloading another, and the app keeps it up to date; its Settings → Automation → “Keep running in the background” switch does the same as wk voice service install. To try preview builds, run wk voice install --beta; wk voice update then stays on previews (falling back to the latest release where a preview isn’t built for your computer) until wk voice install --force takes you back. With the app installed, the app’s Settings → About → Preview updates decides instead. To install wk and the engine in one go:
curl -fsSL https://dl.wavekat.com/wk/install.sh | sh -s -- --with-voice
If you install the app later, it connects to the engine that’s already running, with the same lines and history.
Call flows
A call flow is a YAML document that scripts a call: greet, offer a menu, take a message, book a time, hang up. wk flows writes, checks, voices and publishes them (wk login first); they show up in the web editor too.
# reminder.yaml
schema_version: 1
name: Appointment reminder
entry: hello
nodes:
hello:
kind: greeting
prompt: Hi, this is a reminder about your appointment tomorrow at ten.
exits: { next: bye }
bye:
kind: hangup
prompt: Thanks, goodbye.
wk flows validate reminder.yaml # exits 1 and lists the issues if it can't be published
wk flows create reminder.yaml # saves the draft, prints its id
wk flows publish <flow-id> --render # voice the text prompts, then publish
wk flows show <flow-id> --yaml > reminder.yaml
wk flows update <flow-id> reminder.yaml
Leave id out of a new file; create assigns it. Calls play recorded clips, not text. wk flows render <id> (or publish --render) generates a phone-quality clip for each text prompt — pick the voice with --voice, from wk flows voices — and sets the prompt in the draft to {audio: vprompt_…, transcript: …}. Prompts that already have audio are skipped. Voicing uses your monthly voice character allowance and each prompt has a length cap; render --dry-run shows the cost first. Your plan caps how many flows can be published at once.
To use your own recording instead, write the prompt as {audio: ./intro.wav, transcript: "…"} (the path is relative to the YAML file): create and update upload each local file and point the prompt at the new clip. validate checks the files but doesn’t upload them. wk flows upload <file.wav> uploads one by hand and prints its vprompt_… id. Uploads must be WAV (convert with e.g. ffmpeg -i in.mp3 -ar 8000 -ac 1 out.wav; a temporary flow run with wk voice call --flow-file plays MP3/OGG/FLAC/M4A directly), up to 10 MB and 2 minutes. Your account holds up to 100 uploaded clips by default, and booking steps can’t use them.
create, update and render save the flow in its canonical form, the same text the web editor writes: keys in a fixed order, standard quoting, and no YAML comments (wk tells you how many it dropped). Put notes in a note: field, on the flow or on any step; those are kept. A file with a field this version of wk doesn’t know is refused rather than saved, since saving would delete it. validate reports both.
Pagination
Every list command paginates with --page and --page-size (default 20). When more pages exist, the CLI prints a ready-to-paste Next: line you can run verbatim. Or, in JSON mode, read the next_page field.
Output modes
- Default — human-readable table, with an ASR snippet under each annotation row.
--json— raw API payload, suitable for piping intojqor another tool.