CLI Reference
Every command, flag, and environment variable in the newt CLI.
The newt CLI is the primary tool for authenticating, inspecting your API key, listing models, and installing the onboarding skill. It is a global command — installed once, used in any directory.
newt [command] [flags]Global flags
| Flag | Description |
|---|---|
-h, --help | Print usage and exit. Zero network calls, zero writes. |
-V, --version | Print newt <version> and exit. Also available as newt version. Zero network calls, zero writes. |
Help guard: newt --help and newt -h are safe to call anywhere — they make no network calls and write nothing to disk.
Commands
newt login
Authenticate with the New Theory console and save your API key.
newt login [--print]What it does: Opens an interactive browser pairing flow. Prints a URL and an 8-character code formatted XXXX-XXXX, then polls the console until you complete the authorization. On success, writes your API key to ~/.nt/credentials.
First-line output: Starting authentication…
The pairing URL and code appear on subsequent lines (~line 6). The load-bearing fact (the code itself) is not on line 1 — this is a known constraint of the interactive auth flow.
Flags:
| Flag | Description |
|---|---|
--print | Route auth output to stderr; print only the bare API key to stdout. Does not write ~/.nt/credentials. Use to pipe the key into another tool or capture it in a script. |
Exit codes:
| Code | Condition |
|---|---|
| 0 | Authentication succeeded |
| 1 | Network failure, pairing expired, or other error |
Network: POST to NT_CONSOLE_URL/api/cli/auth/start; polls NT_CONSOLE_URL/api/cli/auth/poll every 2 s for up to 10 minutes.
Writes: ~/.nt/credentials (mode 0600) on success — unless --print is set.
Help guard: newt login --help and newt login -h are safe — they print usage and exit 0 with zero network calls and zero writes. The guard shipped 2026-06-11 (commit 50004519, 44 tests).
newt logout
Remove your API key from disk.
newt logout [--json]What it does: Deletes ~/.nt/credentials and removes ~/.nt/ if it is now empty. Safe to call when already logged out.
First-line output (human): Logged out. or Already logged out — no credentials file found.
Flags:
| Flag | Description |
|---|---|
--json | Emit a JSON object instead of human-readable output. See output shape below. |
--json output shape:
{
"action": "removed" | "already_logged_out",
"credentials_path": "/Users/<user>/.nt/credentials",
"env_var_warning": true | false
}env_var_warning is true when NT_API_KEY is set in the environment — your key remains active even after logout.
Exit codes:
| Code | Condition |
|---|---|
| 0 | Always (idempotent) |
Network: None.
Writes: Deletes ~/.nt/credentials; removes ~/.nt/ if empty.
Help guard: newt logout --help and newt logout -h are safe — they print usage and exit 0 with zero network calls and zero writes. The guard shipped 2026-06-11 (commit 50004519, 44 tests).
newt models
List models available to your API key.
newt models [--json] [--ids]What it does: Calls the New Theory registry and prints the model families your key has access to. Human output leads with a Key line naming which credential produced the listing (masked — never the full key) and its source (environment or credentials file), then the catalog grouped by base with its fine-tunes indented underneath. Raw uids are left out by default — the tag is the identity you scan by; --ids brings them back alongside each name.
First-line output (human): Key nt_••••••••<last8> (<source>) — the masked key identity and where it came from (environment or credentials file). The model catalog follows below it. If your key has no models, a message appears on stdout.
Example (default):
Key nt_••••••••5bde16a3 (environment)
ft-64cad948c4e9f09c-red-cube-bowl [base: ft_base_so101_ft]
ft-64cad948c4e9f09c-svla-so101-pickplace-20260714213146 [base: ft_base_so101_ft]
ft-64cad948c4e9f09c-my-first-pickplace [base: ft_base_so101_ft]
molmoact2
so101Example (--ids):
Key nt_••••••••5bde16a3 (environment)
ft-64cad948c4e9f09c-red-cube-bowl ft_64cad948c4e9f09c_31ac23c75952 [base: ft_base_so101_ft]
ft-64cad948c4e9f09c-svla-so101-pickplace-20260714213146 ft_64cad948c4e9f09c_e4519e2a61d5 [base: ft_base_so101_ft]
ft-64cad948c4e9f09c-my-first-pickplace ft_64cad948c4e9f09c_4527340bb316 [base: ft_base_so101_ft]
molmoact2 ft_base_molmoact2
so101 ft_6341c5_d13da9Flags:
| Flag | Description |
|---|---|
--json | Emit the raw model array from the registry as JSON. |
--ids | Show each model's uid alongside its name. |
--json output shape: An array of model objects. Shape is determined by the registry API.
Exit codes:
| Code | Condition |
|---|---|
| 0 | Models listed successfully |
| 1 | No API key, authentication failure, or registry unreachable |
Network: Registry call via newt.list_models(api_key).
Writes: None.
Help guard: newt models --help and newt models -h are safe — they print usage and exit 0 with zero network calls and zero writes. The guard shipped 2026-06-11 (commit 50004519, 44 tests).
newt status
Show your current authentication state and registry connectivity.
newt status [--json]What it does: Reports your key source (environment variable or credentials file), any active URL overrides, and whether the registry is reachable. Prints an amber warning block if NT_BOOTSTRAP_URL or NT_INFERENCE_URL is set.
First-line output (human): Key source: env_var / Key source: credentials_file / Key source: none. Registry reachability appears on a subsequent line (~line 4).
Flags:
| Flag | Description |
|---|---|
--json | Emit a JSON status object. |
--json output shape:
{
"key_source": "env_var" | "credentials_file" | "none",
"overrides": {
"NT_BOOTSTRAP_URL": null | "<url>",
"NT_INFERENCE_URL": null | "<url>"
},
"registry_reachable": true | false,
"latency_ms": <int> | null
}Exit codes:
| Code | Condition |
|---|---|
| 0 | Status check completed without error |
| 1 | No key, bad key, registry unreachable, or other error |
Network: Registry call via newt.list_models(api_key). Skipped when no key is present.
Writes: None.
Help guard: newt status --help and newt status -h are safe — they print usage and exit 0 with zero network calls and zero writes. The guard shipped 2026-06-11 (commit 50004519, 44 tests).
newt run
Run one real inference against your model and print what came back.
newt run <tag> [--snapshot <name>] [--prompt <text>] [--json]What it does: Loads a bundled recorded observation and calls your model once against prod via Robot(model=<tag>).infer(obs) — no hardware involved. Prints the resolved model, the round-trip latency, and the action-chunk shape. No robot is connected and nothing moves — this is a live inference against your model, not a robot demo, and the output says so plainly.
First-line output (human): The resolved model name.
Flags:
| Flag | Description |
|---|---|
--snapshot <name> | Bundled observation to send. Options are red_cube (6-axis SO-101), cup_stacking (8-axis rig), and pour_coffee_beans (8-axis rig). Defaults to the snapshot matching your model's contract. |
--prompt <text> | Override the snapshot's recorded prompt. |
--json | Emit machine-readable JSON instead of human output. |
--json output shape:
{
"tag": "<tag>",
"model": "<resolved model>",
"snapshot": "<name>",
"prompt": "<prompt sent>",
"latency_ms": <float>,
"total_ms": <float>,
"retries": <int>,
"action_chunk": {
"shape": [<int>, ...],
"axes": ["<axis>", ...]
}
}Exit codes:
| Code | Condition |
|---|---|
| 0 | Inference completed and result printed |
| 1 | No model tag given, unknown --snapshot, no API key, or the call failed (authentication, model not found, model not deployable, registry unreachable, contract mismatch, server error, verifier unavailable, or protocol error) |
Network: One inference call against prod via Robot(model=<tag>).infer(obs).
Writes: None.
Help guard: newt run --help and newt run -h are safe — they print usage and exit 0 with zero network calls and zero writes.
newt skill
Manage Claude Code skills provided by New Theory.
newt skill <subcommand> [-h | --help]Subcommands:
| Subcommand | Description |
|---|---|
install | Install the newt-onboarding skill into .claude/skills/ in the current directory. |
Help guard: newt skill --help and newt skill -h are safe — they print usage and exit 0 with zero network calls and zero writes.
Exit codes:
| Code | Condition |
|---|---|
| 0 | --help flag; or subcommand succeeded |
| 1 | Unknown subcommand |
Network: None.
Writes: None (for the skill dispatcher itself; install writes — see below).
newt skill install
Install the newt-onboarding skill into the current directory.
newt skill install [--json]What it does: Writes .claude/skills/newt-onboarding/SKILL.md into the current working directory, creating the directory if needed. If the file already exists, it is updated in-place.
First-line output (human): Skill installed — <path> or Skill updated — <path>
Flags:
| Flag | Description |
|---|---|
--json | Emit a JSON result object. |
--json output shape:
{"ok": true, "path": "/path/to/.claude/skills/newt-onboarding/SKILL.md", "overwrite": false}On error:
{"ok": false, "error": "<message>"}Exit codes:
| Code | Condition |
|---|---|
| 0 | Skill written or updated successfully |
| 1 | Read or write error |
Network: None. The skill file is read from package resources, not fetched over the network.
Writes: .claude/skills/newt-onboarding/SKILL.md relative to the current working directory.
Help guard: newt skill install --help and newt skill install -h are safe — they print usage and exit 0 with zero network calls and zero writes. The guard shipped 2026-06-11 (commit 50004519, 44 tests).
newt record
Record NT episodes from a robot (or a simulated joint stream) — the keyboard capture frontend on newt.recording.Session.
newt record --task <text> [--dest <dir>] [--simulate | --source <module:factory>] [--target <n>] [--hz <n>] [--json]What it does: Reads keystrokes and drives a recording session. SPACE starts and stops an episode; at the stop, ENTER keeps it, D discards, R redoes. A live frame counter and joint readout print during capture, and Ctrl+H is the kill — it torques off and leaves no partial episode directory. Every decision about episode format, atomicity, and the kill lives in newt.recording.Session; this command is only the skin.
Requires the recording extra: pip install "newt[recording]". Without it, the command stands down with the exact install line.
Flags:
| Flag | Description |
|---|---|
--task <text> | Language task prompt recorded in every episode. Required. |
--dest <dir> | Episode output directory (default: ./episodes). |
--simulate | Record from a fake joint stream — no hardware. |
--source <module:factory> | Load a developer RecordingSource, MODULE:FACTORY (e.g. mypkg.rig:make_source). Mutually exclusive with --simulate. |
--target <n> | Stop after N kept episodes. |
--hz <n> | State sample rate (default: 30). |
--author <text> / --license <text> | Provenance written to each episode.json. |
--json | Agent mode: line-delimited JSON events on stdout, line-delimited commands on stdin. |
Exit codes:
| Code | Condition |
|---|---|
| 0 | Session ran and closed cleanly |
| 130 | Ctrl+H kill (no partial episode left behind) |
| 1 | Missing --task, no writable destination, or the recording extra is not installed |
Network: None. Writes: episode_<id> directories under --dest.
Non-TTY without --json: stands down loudly — there is no keyboard to read.
newt finetune
Launch a training run on New Theory's GPUs with your API key, then watch it to completion.
newt finetune (--dataset <name> | --handle <job> | --list) [--status] [--steps <int>] [--name <slug>] [--fresh] [--json]What it does: Sends your dataset to the New Theory console, which launches the training job server-side on New Theory's GPUs and returns a job handle. No infrastructure credential ever reaches your machine. The CLI then polls the run until it reaches a terminal state, printing the resulting model tag and report-card pointer on success, or the pipeline gate that failed. --handle re-attaches to a run you already launched (poll only, no new launch); --status prints that run's current state once and exits; --list prints your recent runs.
First-line output (human): Launched fine-tune on dataset '<name>'. followed by the job handle. When re-attaching, the first line is Watching <job> ….
Flags:
| Flag | Description |
|---|---|
--dataset <name> | The staged dataset to fine-tune on. Launches a new run. |
--handle <job> | Re-attach to a run already launched, and poll it. |
--status | With --handle, print the run's current state once and exit instead of watching. |
--list | List your recent runs — handle, dataset, last recorded state, and when. |
--steps <int> | Advanced. Total training steps for this run, used with --dataset. A whole number between 2000 and 100000. Optional; omit it for the default. |
--name <slug> | Advanced. Name for the model this run produces, used with --dataset. A slug — lowercase letters, digits, and hyphens, 3–40 characters. Optional; omit it to name the model after the dataset. |
--fresh | Advanced. Ignore any existing checkpoint and retrain from scratch, used with --dataset. Optional; omit it to resume a completed run's finishing steps. |
--json | Emit machine-readable JSON instead of human output. |
--steps bounds: A value outside 2000–100000 is rejected with an error naming the bounds, never clamped into range. The value is recorded on the run. Leave --steps off for the default step count.
--name validation and collision: A name is validated as a slug — lowercase letters, digits, and hyphens, 3–40 characters — before any network call; anything else is rejected with an error, never reshaped to fit. If a model of that name already exists under your account, the launch is refused with a 409 naming the tag, before any training starts and before any GPU time is spent. Omit --name to name the model after its dataset (the default).
--fresh behavior: By default a re-run resumes a completed run's finishing steps instead of retraining. --fresh forces the full retrain from scratch, ignoring any checkpoint. Either way, the launch output names which path ran — resume or forced retrain — so the choice is never silent.
--json output shape (launch, --handle, --status):
{
"job_handle": "<id>",
"status": "succeeded" | "failed",
"gate": null | "<failing gate>",
"tag": null | "<model tag>",
"report_card": null | "<pointer>",
"steps": null | <int>,
"name": null | "<slug>"
}steps is the value set with --steps, or null when none was set (the server default is in force). name is the value set with --name, or null when none was set (the model is named after its dataset).
--list --json output shape:
[
{
"job_handle": "<id>",
"dataset": "<name>",
"status": "<last recorded state>",
"created_at": "<ISO 8601>",
"model_status": null | "pending" | "probed" | "live" | "dead"
}
]model_status is each run's model lifecycle state: null before the model registers, pending/probed while New Theory verifies the weights load, live once they do, and dead if they don't. A dead model is recoverable and stays listed.
Each run also carries a stable model identity (uid), assigned at launch and returned by the finetune status and jobs APIs. Bring it to the support table if you need help with a specific run.
Exit codes:
| Code | Condition |
|---|---|
| 0 | Run reached succeeded (or --status/--list completed) |
| 1 | No API key, launch rejected, run failed, or the poll gave up |
| 130 | You stopped watching with Ctrl-C (the run keeps going) |
Network: POST /api/finetune to launch, GET /api/finetune/status to poll a handle, and GET /api/finetune/jobs for --list. The console holds the training credentials; the CLI only ever sees a job handle.
Writes: None.
newt promote
Keep a fine-tune's checkpoint band and serve it — the CLI twin of the console's promote button.
newt promote <job-handle> --band <token> [--json]What it does: Registers one of a run's evaluated checkpoint bands as a served model, over the same route the console's promote button calls. The model is born pending; New Theory's admission chain runs a safety check and takes it live, usually within a few minutes. The output names the new model and points at newt models to watch it. Handle-only: list your runs with newt finetune --list.
First-line output (human): Promoted — your checkpoint is registered as a model. followed by the model tag and its pending status.
Flags:
| Flag | Description |
|---|---|
<job-handle> | The run whose checkpoint to serve (required, first argument). |
--band <token> | Which checkpoint band to serve — the evaluated step, passed verbatim (e.g. 010000). Required. |
--json | Emit the route's JSON response body on stdout (the registered model, or the server's refusal detail). |
Refusals: Every server refusal prints its plain reason verbatim — a band whose eval hasn't completed, a checkpoint whose location the training pipeline hasn't reported yet, or a run that already has a registered model (with that model's identity). A refusal is never collapsed into a generic failure.
Exit codes:
| Code | Condition |
|---|---|
| 0 | The band was registered (model born pending) |
| 1 | No API key, a bad argument, or the server refused the promote |
Network: POST /api/finetune/runs/<job-handle>/promote. Writes: None.
newt episodes
Inspect recorded episodes, and pull a staged dataset back down.
newt episodes validate <dir> [--json]
newt episodes pull <dataset> [--dest DIR] [--json]validate calls newt.recording.validate on an episode_<id> directory and renders the verdict — a PASS/FAIL line plus one line per invariant check. Frontend only: the checks themselves are the library's. Requires the recording extra: pip install "newt[recording]".
pull downloads a staged dataset from your NT namespace. It fetches the owner-scoped download manifest (authed with your nt_ key), then downloads each object straight from storage over signed links — the bytes go GCS → your machine, never through the console. Files land under --dest (default ./<dataset>), recreating the dataset's relative layout. Progress is reported by files completed, never a percentage. Reruns are resumable: a file already present at the manifest's size is skipped, so an interrupted pull resumes cleanly.
Subcommands:
| Subcommand | Description |
|---|---|
validate <dir> | Validate an episode_<id> directory. |
pull <dataset> | Download a staged dataset into --dest (default ./<dataset>). |
Flags:
| Flag | Description |
|---|---|
--dest <dir> | (pull) Where to write the dataset. Default: ./<dataset>. |
--json | Emit machine-readable JSON (validate: the verdict; pull: total_files, downloaded, skipped, bytes). |
Exit codes:
| Code | Condition |
|---|---|
| 0 | Episode is valid / the pull completed |
| 1 | A check failed, no argument given, an unknown subcommand, the recording extra is missing (validate), or the download failed / no key / dataset not found (pull) |
Network: validate none; pull reads the console manifest + downloads from storage. Writes: validate none; pull writes files under --dest.
Help guard: newt episodes --help and newt episodes -h print usage and exit 0.
newt upgrade
newt upgrade [--print]Upgrade the CLI to the latest version. When newt was installed as a uv tool (the documented install), this runs uv tool upgrade newt for you and streams its output. When the install method can't be confirmed, it prints the command instead of running it — it never guess-runs a package manager against the wrong environment.
Flags:
| Flag | Description |
|---|---|
--print | Print the upgrade command and exit — never runs it. |
Passive update notice: After any command succeeds, the CLI may print one quiet line to stderr when a newer version is available — newt <latest> available — run 'newt upgrade'. It runs at most once a day, never blocks or slows a command, is silent on any network failure, and is skipped entirely under --json. Disable it with NEWT_NO_UPDATE_CHECK=1.
Exit codes:
| Code | Condition |
|---|---|
| 0 | The upgrade ran and succeeded, or the command was printed (unconfirmed install) |
| 1 | The upgrade command failed, or uv was not found |
Network: GET /api/cli/version (public, to source the command). Writes: ~/.nt/update-check.json (the once-a-day timestamp cache).
newt version
newt versionPrints newt <version> and exits. Identical to newt --version and newt -V.
| Exit code | Meaning |
|---|---|
| 0 | Always |
Network: None. Writes: None.
Environment and credentials
API key resolution
The CLI and SDK resolve your API key in this order, stopping at the first hit:
NT_API_KEYenvironment variable~/.nt/credentialsfile
NT_API_KEY always wins over the credentials file.
~/.nt/credentials
Written by newt login. Deleted by newt logout.
| Property | Value |
|---|---|
| Path | ~/.nt/credentials |
| Mode | 0600 |
| Format | api_key = nt_<hex> |
Environment variables
| Variable | Scope | Behavior | Default |
|---|---|---|---|
NT_API_KEY | CLI + SDK | API key; takes precedence over ~/.nt/credentials | — |
NT_CONSOLE_URL | login | Console URL for the pairing flow | https://newtheory-console.vercel.app |
NT_BOOTSTRAP_URL | status, SDK | Override the registry discovery base URL | https://nt-registry-production.up.railway.app |
NT_INFERENCE_URL | status, SDK | Override the inference endpoint; bypasses per-model routing via /v1/models | — |
NT_CONSOLE_URL | upgrade | Console URL the version check + newt upgrade read | https://newtheory-console.vercel.app |
NEWT_NO_UPDATE_CHECK | CLI | Set to 1 to disable the passive once-a-day "update available" notice | — |
Override warnings:
- CLI (
newt status): An amberOverrides active:block is printed whenNT_BOOTSTRAP_URLorNT_INFERENCE_URLis set, showing the active values. - SDK (
import newt):EnvOverrideWarningis emitted viawarnings.warn()whenNT_INFERENCE_URLis set. Warning text:NT_INFERENCE_URL is set to <url> — this overrides dynamic /v1/models discovery for ALL models. Unset it to use per-model cross-app routing.
Override variables are intended for development and testing against local or staging infrastructure. Unset them before running production workloads.
Related
- Getting started — install
newtand run your first inference - Authentication — credentials, key rotation, and team access