# Voidnet CLI (/docs/cli/overview)



The Voidnet CLI (`voidnet`) manages publisher apps from the terminal. It calls the same publisher API as the Console, using bearer-token auth instead of browser cookies.

```bash
npm i -g openvoidnet
voidnet login
voidnet apps list
```

## Credentials [#credentials]

Voidnet uses three credential types:

| Credential            | Prefix      | Held by                         | Used for                                                                    | Accepted at                                              |
| --------------------- | ----------- | ------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------- |
| Buyer key             | `vnb-sk-*`  | Buyers and agents               | Live tool and chat calls                                                    | `https://api.openvoidnet.com/v1-beta/*`                  |
| Per-app publisher key | `vnp-sk-*`  | Your server config, one per app | The gateway presents it to your server so incoming calls are verifiable     | Validated by your server; no Voidnet endpoint accepts it |
| Machine token         | `vnp-pub-*` | Terminal, CI, scripts           | Publisher management: list apps, read usage, rotate keys, refresh snapshots | `https://openvoidnet.com/api/publisher/v1/*`             |

Per-app keys travel gateway-to-server. Machine tokens travel client-to-Voidnet. They are not interchangeable.

## Sign-in [#sign-in]

**Browser sign-in (recommended):**

```bash
voidnet login
```

The CLI starts a one-shot listener on `127.0.0.1`, opens Void Accounts in your browser, and waits up to 5 minutes. After approval, the token is stored at `~/.config/voidnet/cli.json` (mode 600).

Approval happens on a consent screen showing the requesting client, the granted permissions in plain language, and an app picker: **All apps** (including apps created later) or **Certain apps** (selected checkboxes). The issued token carries read and verify permissions with a 30-day expiry. Publishing and key rotation require a token created in the Console.

To preselect apps:

```bash
voidnet login --app "$APP_ID_1" --app "$APP_ID_2"
```

The selection is recorded at approval time and enforced on every call. A token cannot exceed what was approved.

**Token sign-in (headless and CI):**

```bash
voidnet login --token vnp-pub-...
```

Create the token at Console → Machine Tokens. The full value is shown once at creation. Prefer piping the value over typing it.

**Sign out:**

```bash
voidnet logout
```

Revokes the token server-side and removes the local config.

## Commands [#commands]

```bash
voidnet apps list
voidnet apps list --format=json
voidnet logs tail --app "$APP_ID"
voidnet logs tail --app "$APP_ID" --request-id "$REQUEST_ID"
voidnet keys list "$APP_ID"
voidnet keys rotate "$APP_ID"
```

`logs tail --request-id` filters Usage Logs by request ID. The gateway forwards the same value as `X-Voidnet-Request-Id` on every routed call, so a publisher's own server logs join to console records on that value.

`keys rotate` revokes all keys for the app and prints the new full value once.

## Scopes [#scopes]

| Scope                             | Grants                                                           |
| --------------------------------- | ---------------------------------------------------------------- |
| `apps:read`                       | List apps and status                                             |
| `apps:write`                      | Create drafts, edit descriptions                                 |
| `apps:verify`                     | Verify servers, refresh snapshots                                |
| `apps:publish`                    | Publish to marketplace (console-issued tokens only)              |
| `keys:read`                       | List key fingerprints                                            |
| `keys:rotate`                     | Revoke app keys and issue a new one (console-issued tokens only) |
| `domains:write`, `domains:verify` | Domain verification lifecycle                                    |
| `metering:read`                   | Usage logs with request IDs                                      |
| `billing:read`                    | Payout visibility                                                |

Unknown scope strings are rejected. Calls outside a token's scopes fail with `insufficient_scope`; calls outside its bound apps fail with `insufficient_binding`.

## Token rules [#token-rules]

* Full values appear once at creation. Lists show name, last 4 characters, scopes, bound apps, expiry, and last use.
* Tokens support an app binding: all apps or a fixed list. A compromised token affects only its listed apps.
* Suspended publishers lose machine access the same way they lose browser access.
* Revoke unused tokens. `last_used_at` on each token shows whether it is active or dormant.

## Troubleshooting [#troubleshooting]

| Symptom                                    | Meaning                                                                                                                     |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `Timed out waiting for browser approval`   | No approval arrived in 5 minutes. Run `voidnet login` again.                                                                |
| `state mismatch (possible CSRF — aborted)` | The callback did not match this session. Never approve a login you did not start.                                           |
| `Invalid grant: code already used`         | Each code redeems once. Start a fresh `voidnet login`.                                                                      |
| `no_publisher`                             | The signed-in account holds no active publisher. Complete publisher onboarding first.                                       |
| `insufficient_scope`                       | The token lacks the operation scope. Browser logins grant read + verify; use a console-issued token for publish and rotate. |

## For AI coding agents [#for-ai-coding-agents]

Agents driving this CLI (Claude Code, Cursor, Copilot, Opencode, or any other coding agent) need two things: the machine contract (see [CLI Output Contract](https://docs.openvoidnet.com/docs/cli/output)), and Voidnet platform knowledge. Both agent endpoints below are plain text over HTTPS — any LLM harness fetches them with a single GET, no special protocol needed. Fetch them instead of guessing:

* **Map first:** `https://docs.openvoidnet.com/llms.txt` — every page with one-line scope notes. Cheap context; find the right page, then fetch it.
* **Full detail when needed:** `https://docs.openvoidnet.com/llms-full.txt` — the complete documentation text. Ground truth for protocol versions, error catalogs, and billing rules.

Agent rules that hold for every run:

1. Run `voidnet` against production. Keep credentials in the environment or secret manager, never in files or chat.
2. Parse `--json` output, never tables. Never retry blindly on named errors.
3. Named errors are instructions: `insufficient_scope` means request a console-issued token, `insufficient_binding` means the token lacks that app, `invalid_grant` means start a fresh login. Never retry blindly.
4. Secrets appear once (rotate/create output). Store them in the environment or secret manager immediately; never echo them into logs, plans, or chat.
5. Destructive commands (`keys rotate`, `publish` flows) require explicit human approval in the task — an agent never runs them on inferred intent.

## Updates and host discovery [#updates-and-host-discovery]

The CLI checks `/.well-known/voidnet.json` on the management host at most once per day (cached in the OS config dir) and prints a one-line notice on stderr when a newer release exists. Unreachable metadata never fails a command. Versions below the published minimum fail loud with exit code 3 and the upgrade command. Disable with `VOIDNET_NO_UPDATE_CHECK=1` or `--no-update-check`.
