---
title: "CLI"
description: "Complete reference for the oneie / one command line — the bare journey, keys, wallets and test money, auth, API base resolution, JSON output, exit codes and known limits."
type: reference
audience: both
verified: 2026-09-06
canonical: https://one.ie/docs/cli
---
`@oneie/cli` is the operator and agent command line for ONE. It ships two bins, `oneie` and `one`, which are aliases for the same entry point, and is published twice under the same version: `@oneie/cli` and `oneie` (both 5.7.3 on 2026-11-08).

The bare journey, keys, wallets and test money were re-checked against the 5.7.3 source on 2026-11-08. The rest of the page is as measured on 2026-09-06; command counts in headings may be stale.

**Network: mainnet.** Since 2026-11-12, a money command below moves real money (Sui mainnet, Base) unless you name testnet. To practise, use `--net testnet` or `one network testnet`; `wallet faucet` is testnet only. Read it live: `curl -s https://pay.one.ie/status` → `"network"`.

## Install

```bash
npm i -g @oneie/cli     # installs both bins: oneie and one
npx oneie --help        # run without installing
```

| Package name | Version on npm | Notes |
| --- | --- | --- |
| `@oneie/cli` | 4.0.7 | The scoped package. `npm i -g @oneie/cli`. |
| `oneie` | 4.0.3 | The unscoped mirror. `npx oneie` resolves here, four patch releases behind. |

Runtime dependencies are exactly two: `commander` ^12 and `@oneie/sdk` ^0.14.12.

Licence: the ONE License (Version 1.0), in `LICENSE` in the package. `package.json` declares `SEE LICENSE IN LICENSE`.

## Bare invocation

`oneie` with no arguments runs the journey in the current folder (`oneie start`, `src/start.ts`): a key, a workspace, a shop with a product, a test sale, then one link that hands it over. A re-run resumes from the first step whose proof is not on disk.

```bash
npx -y oneie --json --name "My Shop"      # ~9–13 s on production, 2026-11-07
```

stdout is one JSON object: `{ ok, workspace, steps: [...], next }`. The workspace key is written to `./.one/agent.key` (0600, git-ignored before it is written), never to `~/.config/one/key`. Keys from the journey and from `init` come from `/api/provision/agent` and expire after 90 days (`init --ttl-days <n>`, at most 365); a key from `POST /api/auth/agent` does not expire. Journey flags: `--name`, `--email`, `--product "Name=12.50"` (repeatable, at least 0.50), `--currency`, `--wait <seconds>`, `--api`.

The journey seals its wallet in the Apple Keychain, or with a passphrase typed at a terminal. A shell with neither is refused by name, never downgraded to a plaintext file: `wallet: no Apple Keychain here and no terminal to type a passphrase into`. For a headless agent use `oneie init --no-wallet` (below) and make the signing key with `oneie key new`.

## Zero to live

The shortest path from an empty shell to an authenticated substrate call.

```bash
oneie init --write-env --name "My Agent"  # provision
one whoami                                # prove the key
one ask meta:catalog --data '{}'          # read it back
```

`init` POSTs `/api/provision/agent` with no credential, writes the key to `~/.config/one/key` at mode 0600 (`--dir <path>` writes it to `<path>/.one/agent.key` instead; `--no-wallet` skips the local wallet, `--yes-i-accept-plaintext-file` writes it as a 0600 file — one of the two is needed with no terminal), and with `--write-env` appends `ONE_API_KEY` and `ONE_API_URL` to `./.env.local`. It is idempotent when `--write-env` is set and `ONE_API_KEY` already resolves from `.env`, `.env.local` or the process env. `whoami` exits 1 on a missing or dead key.

The payload flag is `--data <json>`. `--data -` reads the JSON body from stdin. There is no positional payload argument.

## Auth

### Key resolution

There is no single ladder. `resolveKey()` (`src/lib/client.ts`) is the
canonical one and covers most of the surface:

```
--key > ONE_API_KEY > ONEIE_API_KEY
      > the folder's key (./.one/agent.key, or ./.oneie/agent.key)
      > ~/.config/one/key > ~/.config/oneie/key (legacy)
```

Five other shapes are in the tree. `--key` is declared on 13 of the 110 leaves,
never on the program, so it is not a global override.

| Ladder | Commands |
| --- | --- |
| `resolveKey()` — the block above | `agent` (19), `broadcast`, `chat`, `connect`, `doctor`, `group`, `links`, `newsletter`, `plugin`, `segment`, `social`, `staff`, `trail`, `whoami`, the 14 substrate commands |
| `ONEIE_API_KEY` > `ONE_API_KEY`. Process env only — no key file, no `--key` | `catalog`, `market`, `hire`, `bounty`, `earn`, `usage`, `recall`, `fn run` |
| `--key` > `ONEIE_API_KEY` > `ONE_API_KEY`, read through `.env` + `.env.local` + the process env — no key file | `client list`, `client add`, `client invite`, `push`, `setup`, `status`, `wallet get\|balances\|receive\|send\|request\|create\|transactions\|register` |
| `ONEIE_API_KEY` > `~/.config/oneie/key`. `ONE_API_KEY` is never read | `skill import`, `skill fork`, `skill list`, `skill unimport`, `skill eval` |
| `ONE_API_KEY` > `ONEIE_API_KEY`. No key file, no `--key` | `workflow` (7), `skill push` |
| `--key` > `ONEIE_API_KEY`, then the device flow | `auth login`, `login` |

So a shell that exports only `ONE_API_KEY` authenticates `agent` but not
`skill list`; a shell that exports only `ONEIE_API_KEY` authenticates both. The
key file written by `login` / `init` is read by the first and fourth ladders
only — the other four never look at it.

### Bearer form

The header is `Authorization: Bearer <key>` — the plain key. The `<slug>:<key>` form is wrong and 401s: `requireAuth` resolves a world key by its `one-` or `osk_` prefix, so prefixing a slug produces a string that matches no prefix. That form is still printed in `packages/cli/README.md:79` and `text/cli-reference.md:33`. Do not use it.

### Three doors to a key

| Command | Browser needed | Key class | Mechanism |
| --- | --- | --- | --- |
| `one init --write-env` | no | agent | `POST /api/provision/agent`, unauthenticated |
| `one onboard` | no | agent | Same provision call, plus a `lifecycle:mine` stage read-back |
| `one login` | yes | human | RFC 8628 device flow: `POST /api/auth/mcp/device/code`, approval at `https://one.ie/device`, poll `POST /api/auth/mcp/device/token` |

`one setup` also mints an agent-class key through the same provision route.

### The agent-class wall

Keys minted by `init`, `onboard` and `setup` are agent-class. Five receiver labels refuse them at dispatch (`one.ie/web/src/lib/receiver-envelope.ts:151-157`):

```
manage_workspace   manage_clients   manage_members
manage_groups      manage_actors
```

The refusal is not an HTTP error. The receiver door answers **200** with `outcome: "failure"`, and the result object carries `error: "forbidden"`, `forbidden: true`, the receiver name, the required label, and `callerRole: "agent"`. Code that branches on the status line will read it as a success.

The only self-service way past it is `one login`, which mints a human-class key and requires a person at a browser. An agent that cannot get one is capped at the non-management surface.

`one onboard` writes five keys to `.env.local`: `ONE_API_KEY`, `ONE_API_URL`, `ONE_REG_KEY`, `ONE_UID`, `AGENCY_WSID`. Receivers keyed on `ctx.ownerSlug === uid`, including `lifecycle:mine`, need `ONE_REG_KEY`. The workspace-scoped `ONE_API_KEY` resolves to the workspace actor, which has no stage-transition rows, so the call returns nothing rather than erroring.

## Testnet and mainnet

Every command that touches a chain acts on ONE network, chosen the same way everywhere:

1. `--net mainnet|testnet` on the command (`--network` on `key sweep` / `sweep-run`)
2. `ONE_NETWORK=mainnet|testnet` in the shell
3. `one network mainnet|testnet`, saved in `~/.config/one/network` until you change it
4. the deploy: whatever one.ie runs (`<meta name="one:network">`). Since 2026-11-12 that is mainnet, with no flag.

```bash
one network            # which network a command would use now, and why
one network testnet    # practise: every command uses testnet until you say otherwise
one network mainnet    # real money
one network auto       # forget the choice and follow the deploy again
```

If nothing names a network and the deploy cannot be read, a command that moves money refuses (`network_unknown`). It never guesses. Every money command prints the network it used, and a mainnet send says `MAINNET — real money`. `swap` is mainnet only (1Click has no testnet), `wallet faucet` is testnet only, and `hl` uses `--testnet` per call, because Hyperliquid is a separate venue.

## The API base

There is no single default. `--api` resolves per command:

```
--api  >  ONE_API_URL  >  ONEIE_BASE_URL  >  module fallback
```

That precedence holds inside `resolveBase()` (`src/lib/client.ts:12-16`). Ten modules bake their `--api` default at module load in the opposite order, and three groups bake a literal, so the env vars do not behave uniformly.

| Commands | Fallback base | Env behaviour |
| --- | --- | --- |
| `chat send`, `chat broadcast`, `connect`, `group`, `social`, `staff`, `trail`, `plugin`, `doctor`, `whoami` | `https://one.ie` | `ONE_API_URL` wins over `ONEIE_BASE_URL` |
| `broadcast`, `segment`, `newsletter`, `links`, and the 14 substrate commands | `https://api.one.ie` | `ONE_API_URL` wins over `ONEIE_BASE_URL` |
| `catalog`, `recall`, `market`, `hire`, `bounty`, `earn`, `usage`, `wallet`, `client`, `push`, `fn` | `https://api.one.ie` | `ONEIE_BASE_URL` wins over `ONE_API_URL` |
| `onboard`, `status` | `https://one.ie` | `ONEIE_BASE_URL` wins over `ONE_API_URL` |
| `auth login`, `auth logout`, `login`, `init` | `https://one.ie` | `ONE_API_URL` ignored; `ONEIE_BASE_URL` honoured |
| `setup`, keyless (the default path) | `https://one.ie` | `--api` **and** `ONE_API_URL` ignored — the provision call reads only `ONEIE_BASE_URL` (`src/setup.ts:54`) |
| `setup`, keyed (a key is already present) | `https://api.one.ie` | `--api`, then `ONEIE_BASE_URL` over `ONE_API_URL` |
| `agent` (19), `skill` (11) | `https://one.ie` | Both env vars ignored; use `--api`. `skill eval` reads `ONEIE_BASE_URL` |
| `workflow` (7) | `https://api.one.ie` | Both env vars ignored; use `--api` |

31 of the 110 leaves declare no `--api` at all; most of those are local (`agent
new`, `skill validate`, `create node`, `ship`, `dev`, `fn list`, …). Three of
them do reach the network, on a different host with their own flag:

| Command | Host | Flag | Env |
| --- | --- | --- | --- |
| `wallet faucet` | `https://pay.one.ie` | `--pay-url` | `ONEIE_PAY_URL` |
| `chat listen` | `https://channels.one.ie` | `--channels` | `CHANNELS_URL` |
| `eval` | `https://channels.one.ie` | `--channels` | `ONEIE_CHANNELS_URL` |

`eval` also takes `--events` for the substrate side, defaulting to
`ONEIE_BASE_URL` and then `https://one.ie`.

### Why the host matters

`api.one.ie` serves substrate operations at the short path form, `/ask/<receiver>`. `one.ie` serves only the long form, `/api/ask/<receiver>`. `src/lib/api-path.ts` picks the form from the hostname, so any command that routes through `askPath()` works against either host.

## Commands

110 leaf commands: 17 groups holding 74 leaves, plus 36 standalone commands. 53 entries appear in `oneie --help`.

### agent (19)

| Command | Does |
| --- | --- |
| `agent new <name>` | Scaffold from a template. `--profile core\|commerce\|asi` |
| `agent validate <path>` | Validate `agent.md` |
| `agent lint <path>` | Lint `agent.md` |
| `agent compile <path>` | Compile. `--target mcp \| uagents \| skillmd \| web`, default `mcp` |
| `agent serve <path>` | Stub. Prints `status=listening` and exits; no server is started (`src/agent.ts:84-90`). `--port 8000` |
| `agent publish <path>` | Publish. `--target oneie\|agentverse`, `--slug`, `--live` |
| `agent pull <name>` | Fetch a published agent to a file |
| `agent unpublish <name>` | Remove a published agent |
| `agent sign <path>` | Sign the agent file |
| `agent verify <path>` | Verify a signature |
| `agent eval <path>` | Run the frontmatter `evals:` block |
| `agent diff <a> <b>` | Diff two agent files |
| `agent dev <path>` | Local dev loop |
| `agent list` | List published agents. `--slug` required |
| `agent history <name>` | Version history. `--slug` required |
| `agent rollback <name>` | Roll back. `--slug` and `--to <epoch-ms>` required, `--yes` |
| `agent ai-edit <path>` | Edit via model. `--prompt`, `--model`, `--yes` |
| `agent templates` | List templates |
| `agent fork <template> <name>` | Copy a template locally |

`a2a` and `erc8004` are not implemented compile targets and fail loudly. The shipped `--target` help names four: `mcp | uagents | skillmd | web`.

See [Agents](/docs/agents) and [Publish an agent](/docs/agents-publish).

### skill (11)

| Command | Does |
| --- | --- |
| `skill new <name>` | Scaffold a skill file |
| `skill emit <path>` | Emit. `--out ./` |
| `skill publish <path>` | Publish a skill |
| `skill refresh <slug> [refs...]` | Refresh imported skills |
| `skill import <ref>` | Import. `--slug`, `--price 0.02`, `--yes` |
| `skill push <path>` | Push to a workspace. `--slug` required, `--name` |
| `skill fork <name>` | Copy an open skill into a workspace. `--slug` required. Refuses sealed, invoke-only skills |
| `skill list` | List workspace skills. `--slug` required |
| `skill unimport <name>` | Remove an imported skill. `--slug` required |
| `skill validate <path>` | Validate a skill file |
| `skill eval <path>` | Run the skill's evals. `--iteration 1` |

See [Skills](/docs/skills).

### workflow (7)

| Command | Does |
| --- | --- |
| `workflow list` | List workflows |
| `workflow pull <id>` | Write the workflow verbatim to `<name>/workflow.json`. `--out <dir>` |
| `workflow push <id> <file>` | Apply a diff file. Simulates by default; `--commit` persists |
| `workflow run <id>` | Start a run |
| `workflow validate <id> <file>` | Validate a diff without persisting |
| `workflow resolve <runId> <stepId>` | Resolve a suspended human step. `--decision approved\|rejected` |
| `workflow logs <id>` | Run history and per-run step events. `--run <runId>`, `--limit` |

Every one of the seven requires `--slug <workspace>`.

`workflow resolve` is the only CLI door into a suspended run. See [Workflows](/docs/workflows).

### key

| Command | Does |
| --- | --- |
| `key new` | Make a key on this machine: 24 words, no network. `--out <file> --yes-i-accept-plaintext-file` writes words + keys at 0600 and prints only addresses. Words on the command line (`--phrase`, `--mnemonic`) are refused |
| `key public` | The public identity and the chain addresses for words read on stdin. No network |
| `key recover` | Rebuild a key from its 24 words (stdin or `ONE_WALLET_MNEMONIC`). No network |
| `key verify` | Compare the words' public identity with what the server holds: `locked`, `verified`, `mismatch`, `unregistered` |

Plus `key lock`, `seal`, `open`, `identity`, `publish-lock`, `lock-of`, `sweep-rule`, `sweep`, `sweep-run`. Recovery is paper: ONE never holds the words and cannot recover a lost key.

Your key and your agent's key, on one Mac — the ceremony walked 2026-11-09:

```bash
npx oneie wallet new --dir ~/.one/me --keychain          # your vault: sealed to Touch ID, addresses only
npx oneie wallet paper --dir ~/.one/me                   # the 24 words, once, for paper
npx oneie wallet new --dir ~/.one/agents/scout --keychain  # the agent's own vault — its key, not yours
npx oneie staff add-agent scout --workspace acme         # the agent joins; its actor id prints once
npx oneie wallet register --dir ~/.one/agents/scout --kind agent --actor <aid> --workspace acme --yes
npx oneie key sweep-rule --agent <aid> --workspace acme --chain sui \
  --threshold 1000000000 --float 100000000 --dir ~/.one/me   # above 1 SUI sweeps to you; it keeps 0.1
npx oneie wallet file --dir ~/.one/me                     # a passphrase copy to drop on /w/restore
npx oneie wallet key --chain evm --clipboard --dir ~/.one/me  # the Ethereum key for MetaMask, clipboard only
```

`--threshold` and `--float` are base units (Sui: MIST, 1 SUI = 1,000,000,000). The sweep rule is how you own an agent: its key stays its own, its money above the line is yours. `sweep-rule` and `wallet file` open the vault through Touch ID and print nothing secret; `paper` is the one command that shows the words, and only to a person at a terminal.

```bash
npx oneie key new --out key.json --yes-i-accept-plaintext-file --json
# {"ok":true,"out":"key.json","addresses":{"sui":"0x…","evm":"0x…","sol":"…","btc":"…","asi":"…"},"userIdPub":"…"}
jq -r .mnemonic key.json | npx oneie key public --json   # check, offline
```

### wallet (18)

| Command | Does |
| --- | --- |
| `wallet get` | Credits, spend ceiling, wallet rows, live chain balances (`wallet:get`). `--workspace`, `--actor` |
| `wallet list` | Every wallet in the workspace, treasury first, with its tags, limit and sweep rule |
| `wallet limit <agent> <credits>` | An agent's spending limit in credits a month (1,000 credits = $1); `0` pauses it (`wallet:update`). Anyone who controls the workspace may lower it; only a person may raise it |
| `wallet create` | Provision a wallet row. `--kind human\|agent` |
| `wallet transactions` | List transactions. `--limit 100`, max 500 |
| `wallet faucet <address>` | Test money from pay.one.ie's faucet. `--chain sui\|sol\|eth\|usdc\|btc\|all` required, `--network testnet\|devnet`. Sui pays 0.05 test SUI, one ask per address per 24 h; ETH/USDC/BTC answer a manual faucet URL |
| `wallet balances [address]` | Every balance of your wallet on one network (`--net mainnet` by default: real money; `--net testnet`): ETH and USDC on Ethereum, Base and Arbitrum, USDT on mainnet, SUI and USDC on Sui, SOL, BTC, Hyperliquid perps and spot (never summed). `wallet:get` answers first; a row it read on another network is dropped, never shown under the wrong label, and that chain is read directly. A failed read prints `unavailable`, never 0 |
| `wallet receive --chain <c>` | Your address on ONE chain, with a terminal QR (`--no-qr` for the address only). `--chain` is required: one 0x address is Ethereum, Base and Arbitrum at once, and the EVM QR carries the chain id (`ethereum:0x…@8453`). `hl` is refused: a plain transfer does not reach Hyperliquid, so use `swap … hl` |
| `wallet send <amount> <asset>[@chain] <to>` | Send from your wallet: ETH or USDC on Ethereum, Base and Arbitrum, or SUI and USDC on Sui. **Dry by default.** The dry run prints the exact transaction that would be signed (chain id, nonce, to, value, data, gas, the fee ceiling) and the `--live` command. A bare `ETH` or `USDC` picks the one chain you hold it on and says so; held on two chains, or a read fails, it refuses and lists them. `<to>` is an address, a workspace slug or an agent id (the resolved address is printed; pin it with `--to-address`). `--live --dir <vault>` opens the sealed vault (Touch ID), rebuilds the transaction from your own words and compares (R16), checks that the key derives the sending address and that the node's chain id matches, signs on this machine, and broadcasts once, never re-sending. An agent shell signs only with its OWN vault, on a row tagged `agent`, with `--yes`. Live Sui needs `--rpc <json-rpc>`, because public Sui JSON-RPC is switched off. The old form, `send <to> --chain --amount --payment-tx`, still records a transfer signed elsewhere |
| `wallet request <amount> USD\|USDC` | A `wallet:invoice` payment link to be paid. `--from <slug>` names who you are asking; the receiver has no payer field, so you hand them the link. The link pays on the deploy's network. one.ie production is on mainnet, so it takes real money |
| `wallet new` · `open` · `paper` · `keychain` · `file` · `key` | The local vault, a person at a terminal: `new --keychain` makes it sealed to Touch ID and prints only addresses; `open` shows the addresses; `paper` prints the 24 words once for paper (an agent shell is refused); `keychain` moves a passphrase vault behind Touch ID; `file` writes a browser copy re-sealed with a passphrase you type, for the Key file door on `/w/restore`; `key --chain evm --clipboard` puts one chain's private key on the clipboard for MetaMask, Phantom, Slush or Sparrow — clipboard only, never printed, cleared after 60 s. Both `file` and `key` refuse a shell an agent drives and refuse a pipe: a person, at a terminal |
| `wallet register` | Register PUBLIC receiving addresses. First write per chain is permanent; a later write returns `address_conflict`. Prompts unless `--yes` |
| `wallet keygen` | Generate or recover a wallet offline for Sui, EVM, Solana and Bitcoin. `--out <file>` writes the mnemonic and private keys unencrypted at mode 0600 and requires `--yes-i-accept-plaintext-file`. `--recover` reads a 24-word BIP-39 mnemonic from `ONE_WALLET_MNEMONIC` or stdin |

Your money, from the terminal (read on mainnet 2026-11-09):

```bash
npx oneie wallet balances --net mainnet          # ethereum ETH 0.00492583640882 · hyperliquid spot 6.040423 USDC
npx oneie wallet receive --chain base            # the address + a QR that names Base (chain id 8453)
npx oneie wallet send 0.0003 ETH 0x…             # DRY: chain picked, nonce, fee ceiling, the --live line
npx oneie wallet send 0.0003 ETH@ethereum 0x… --live --dir ~/.one/tony   # Touch ID, signed here, sent once
npx oneie wallet request 25 USD                  # a payment link
```

Test money for practice, end to end (walk 8, 2026-11-07, testnet: 3.14 s):

```bash
npx oneie --json wallet faucet 0x<your sui> --chain sui --network testnet
# {"ok":true,"results":[{"chain":"sui","success":true,"txHash":"…","amount":"0.05 SUI",…}]}
```

A refusal is `success: false` with `reason`: `rate_limited`, `treasury_empty` or `not_configured`. There is no `oneie pay` or `oneie x402` command: an agent buys credits by POSTing `https://one.ie/api/x402` and signing the payment itself — the steps are in [https://one.ie/llms.txt](https://one.ie/llms.txt).

See [Wallets and custody](/docs/wallets).

### client (4)

| Command | Does |
| --- | --- |
| `client new <slug>` | Scaffold a client locally. `--name` |
| `client list` | List clients. Declares its own `--json` |
| `client add <slug>` | Provision a client workspace. `--dry-run` |
| `client invite <email>` | Invite a client owner. `--slug` required, `--dry-run` |

### plugin (4)

| Command | Does |
| --- | --- |
| `plugin list` | List available plugins |
| `plugin add <name>` | Install into a workspace |
| `plugin buy <name>` | Purchase. `--credits` |
| `plugin grant <name>` | Grant to a client. `--to <client>` required |

The program-level `--json` is inert for all four (`src/plugin.ts:6-7` checks the retired `ONEIE_JSON` env var).

### chat (3)

| Command | Does |
| --- | --- |
| `chat send <text>` | Post to a Space. `--to <space>`. This is the group's default subcommand, so `one chat "text"` routes here |
| `chat broadcast <text>` | Fan out to several Spaces. `--spaces <csv>` |
| `chat listen <space>` | Stream inbound messages from `channels.one.ie` |

The built-in `--spaces` default is a fixed list of three space slugs carried over from an internal deployment. It is not a general-purpose default. Pass `--to` or `--spaces` explicitly.

### social (3)

| Command | Does |
| --- | --- |
| `social list` | List posts. `--group <groupId>` required, `--status draft\|scheduled\|publishing\|published\|failed`, `--limit 50` |
| `social create` | Create a post. `--group <groupId>`, `--content` and `--platforms <csv>` all required, `--schedule <epoch>` |
| `social accounts` | List connected accounts |

### create (2)

| Command | Does |
| --- | --- |
| `create node [name]` | Scaffold a workspace. Default subcommand, so `one create my-agency` routes here. `--ref main` |
| `create partner [name]` | Scaffold a partner workspace. `--ref main` |

On a non-TTY, `create` prints directory and launch instructions instead of starting anything.

### fn (2)

| Command | Does |
| --- | --- |
| `fn list` | List the allowlisted functions and their return kinds |
| `fn run <name>` | Execute one. `--args <json>` (keys are prefixed with `$` for you), `--workspace`. Exits 1 on a name outside the allowlist |

### Smaller groups

| Command | Does |
| --- | --- |
| `auth login` | Device flow, or `--key <k>` to store a key directly |
| `auth logout` | Delete the machine key (`~/.config/one/key`) |
| `group bulk-create` | Bulk-provision from CSV. `--csv` required, `--segment`, `--plan`, `--parent`, `--batch-size 50`, `--dry-run` |
| `broadcast list` | List broadcasts. `--limit 20` |
| `broadcast send <id>` | Send a broadcast |
| `segment list` | List segments |
| `segment preview <id>` | Preview a segment's members |
| `newsletter pull <broadcastId>` | Pull newsletter content |
| `newsletter push <broadcastId> <file>` | Push content. `--test` |
| `links create <actorId>` | Create a tracked link. `--to /`, `--context`, `--greeting`, `--campaign`, `--expires <days>` |
| `staff invite [email]` | Invite a person. `--role owner\|admin\|member\|viewer`, default `admin` |
| `staff add-agent <name>` | Add an agent as staff. `--role member` |

### Substrate commands (14, standalone)

| Command | Does |
| --- | --- |
| `signal <receiver>` | Fire-and-forget signal. `--data <json\|->` |
| `ask <receiver>` | Request-response. `--data <json\|->`, `--timeout 10000` |
| `mark <edge>` | Strengthen a path. Edge format: `source>target`. `--strength 1` |
| `warn <edge>` | Raise resistance on a path. Edge format: `source>target`. `--strength 1` |
| `fade` | Apply the group fade rate. `--rate <0-1>` |
| `sub <tag> <actor>` | Subscribe an actor to a tag. `--scope private\|public` |
| `follow <type>` | Follow a tag |
| `select <type>` | Weighted selection. `--exploration <0-1>` |
| `groups` | List groups. `--type`, `--limit 20`, `--after <cursor>` |
| `actors` | List actors. `--type`, `--tag`, `--limit`, `--after` |
| `things` | List things. `--type`, `--tag`, `--limit`, `--after` |
| `paths` | List paths. `--source`, `--target`, `--min-strength`, `--limit`, `--after` |
| `events` | List events. `--actor`, `--tag`, `--from <iso>`, `--to <iso>`, `--limit` |
| `learning` | List hypotheses. `--status pending\|testing\|confirmed\|rejected`, `--actor`, `--tag` |

Since 5.7.3 each of these spells its path the way its host serves it (`src/lib/api-path.ts`), so the default host works. `message <text...>` sends words to `world:route` and prints the answer; it costs credits. Receiver names are listed in [Receivers](/docs/receivers).

### Lifecycle and diagnostics (9, standalone)

| Command | Does |
| --- | --- |
| `init` | Provision a workspace. `--name`, `--email`, `--skills <csv>`, `--no-content`, `--write-env` |
| `onboard` | Provision and walk the lifecycle stages: registered, bootstrapped, active, settled, adopted. `--write-env` defaults to true |
| `login` | Root alias of `auth login`, same implementation |
| `setup` | Provision a workspace and write the key to `./.env.local` (not to `~/.config/oneie/key`). No-op if `ONE_API_KEY` or `AGENCY_WSID`+`CC_ACTOR_ID` are already set. `--key` switches it to the keyed agency flow |
| `doctor` | Three checks — config file, key present, substrate reachable — each under a 5s abort. Exits 0 or 1 |
| `whoami` | Prints workspace, masked key and base. Proves the key with an authenticated `dashboard:usage` call. Exits 1 on a dead key |
| `status` | Billing and client status. Declares its own `--json` |
| `connect [channel]` | Connect a channel with `--token <t>`. With no argument, lists connection status. The token is never echoed back |
| `trail <tags>` | Path trail for a tag set. `--workspace global`, `--limit 10` |

There is no `auth:whoami` receiver. `whoami` proves liveness with `dashboard:usage`.

### Build and ship (5, standalone)

| Command | Does |
| --- | --- |
| `dev` | Local dev server. `-p 8787`, `--ip 127.0.0.1`, `--remote`, `--skip-build`, `--skip-migrate`, `--cwd` |
| `deploy [path]` | Deploy a built site. Default path `site/dist`, `--project <name>` |
| `push [path]` | Push content to a workspace. `--client <slug>`, `--dry-run` |
| `ship [message]` | Stages every untracked and modified file in the working tree, commits with the message, and pushes. See the irreversible-commands table below |
| `eval [path]` | Run `*.eval.ts` through `@oneie/evals`. Default path `evals`. Exits 1 when any eval fails |

### Market and memory (8, standalone)

| Command | Does |
| --- | --- |
| `catalog` | The receiver catalog grouped by recipe. `--goal <text>`. Own `--json` |
| `market` | List the skill market. `--query <text>`. Own `--json` |
| `hire <skillId>` | Hire a peer agent. `--provider <uid>`, `--budget 0`, `--dry-run` |
| `bounty <skillId>` | Post a bounty. `--price 0`, `--dry-run` |
| `earn` | Earnings. Own `--json` |
| `usage` | Metering. Own `--json` |
| `recall` | Cross-session memory. `--about <term>`, `--limit 20`. Own `--json` |
| `reputation` | Registered and reachable. Its own help reads "Agent reputation standing (pending)" and it prints a pending notice — `meta:reputation` is not shipped |

## JSON output

Four tiers, sorted by what the flag actually does. 56 + 4 + 27 + 23 = 110.

| Tier | Count | Behaviour |
| --- | --- | --- |
| 1 | 56 | Honour the program-level `--json` |
| 2 | 4 | Declare and honour their own `--json`, emitting raw JSON rather than the `{ok, …}` envelope |
| 3 | 27 | Emit JSON unconditionally, flag or not |
| 4 | 23 | Never emit JSON |

### Tier 1 — program-level `--json` (59)

Whole groups: `skill` (11), `workflow` (7), `wallet` (10, with `balances`, `receive` and `request`), `social` (3), `auth` (2), `staff` (2) — 35. Plus 18 of the 19 `agent` leaves: every one except `agent dev`, which prints watch output through `console.log` and never reaches the JSON writer.

Six more leaves: `login`, `connect`, `group bulk-create`, `init`, `onboard`, `trail`.

32 + 18 + 6 = 56.

`agent compile` is a half case that belongs here anyway: with `--out <file>` it emits a `{ok, written, bytes}` receipt that honours the flag, but with no `--out` it writes the compiled artifact to stdout raw, so the flag changes nothing.

Flag position does not matter. `jsonMode()` walks `cmd.parent` to the root, so both of these emit one JSON line:

```bash
one agent templates --json
one --json agent templates
```

Without the flag the same command prints `✓ templates=[…]`.

### Tier 2 — own `--json`, honoured (4)

`catalog`, `client list`, `recall`, `status`.

`market`, `earn` and `usage` also declare a `--json` option, but none of the three reads it — they print pretty JSON either way, so they sit in tier 3.

### Tier 3 — always JSON (27)

The 14 substrate commands, `broadcast list`, `broadcast send`, `segment list`, `segment preview`, `newsletter push`, `links create`, `eval`, `market`, `earn`, `usage`, `hire`, `bounty`, `fn run`.

All but `eval` pretty-print with a two-space indent; `eval` writes one compact line. `newsletter push` and the two `--dry-run` trade commands print a human summary line before the JSON.

### Tier 4 — no JSON (23)

`fn list`, `doctor`, `whoami`, `chat send`, `chat broadcast`, `chat listen`, `newsletter pull`, `plugin list`, `plugin add`, `plugin buy`, `plugin grant`, `push`, `setup`, `create node`, `create partner`, `deploy`, `dev`, `ship`, `client new`, `client add`, `client invite`, `reputation`, `agent dev`.

`newsletter pull` prints markdown, not JSON — it is the round-trip half of `newsletter push`. `chat send` is the one leaf here that can emit JSON: given `--to <space>` it prints the raw receiver reply, while the fan-out form prints human lines.

Apart from that, no flag or env var makes these emit JSON.

## Exit codes

Measured 2026-09-06 by running each case unpiped and reading `$?`.

| Case | Code | Stream |
| --- | --- | --- |
| Success | 0 | stdout |
| `--help`, `--version`, bare `oneie` | 0 | stdout |
| Unknown command | 1 | stderr |
| Missing required option | 1 | stderr |
| `{ok:false}` from a tier-1 command | 1 | `error  <msg>` on stderr; under `--json`, the object on stdout |
| Substrate command, non-2xx response | 1 | `METHOD url → status` then the body on stderr, then exit |
| `fn run` with a name outside the allowlist | 1 | stderr |
| `doctor` with any failing check | 1 | check lines on stdout |
| `whoami` with a missing or dead key | 1 | stderr / stdout |
| `eval` with any failing eval | 1 | stdout |
| Unhandled error, no `--json` | 1 | message on stderr |
| Unhandled error, `--json` anywhere in argv | 1 | `{"ok":false,"error":"…"}` on stdout |

`ship` propagates the exit status of the underlying commands, except that a commit returning 1 (nothing to commit) is not treated as a failure.

## Reading a refusal

| Status | Meaning | Fix |
| --- | --- | --- |
| 401 | The Bearer matched no `world_keys` row — wrong key, or not a key | Check the key ladder; send the plain key, not `<slug>:<key>` |
| 403 | The key is real and the authority walk refused it for that workspace | Use a key that owns the workspace, or a human-class key for a management label |
| 404 on `api.one.ie/api/*` | Wrong path form for that host | Pass `--api https://one.ie` |

On the receiver door the same split reads as `callerRole: "anonymous"` versus any other role. See [Authority and access](/docs/authority) and [Errors and limits](/docs/errors).

## Environment variables

| Variable | Read by |
| --- | --- |
| `ONE_API_KEY` | Key, canonical. Not read at all by the `skill import\|fork\|list\|unimport\|eval` ladder — see [Key resolution](#key-resolution) |
| `ONEIE_API_KEY` | Key, legacy. The only variable every key ladder reads |
| `ONE_API_URL` | Base, canonical. See the per-module table above |
| `ONEIE_BASE_URL` | Base, legacy. `ONE_BASE_URL` is retired |
| `ONE_REG_KEY`, `ONE_UID`, `AGENCY_WSID` | Written by `onboard`; `ONE_REG_KEY` is needed by uid-scoped receivers |
| `AGENCY_SLUG` | Default `--workspace` for `wallet` |
| `ONEIE_WORKSPACE` | Default `--workspace` for `plugin` |
| `CHANNELS_URL`, `ONEIE_CHANNELS_URL` | `chat listen`, `eval` |
| `ONEIE_PAY_URL` | `wallet faucet` |
| `ONE_WALLET_MNEMONIC` | `wallet keygen --recover` |
| `AGENTVERSE_API_KEY`, `ANTHROPIC_API_KEY` | `agent publish --target agentverse --hosted` (the default endpoint mode needs neither) |
| `GROQ_API_KEY` | `eval` |
| `WORKSPACE_OWNER_EMAIL`, `WORKSPACE_ID`, `WORKSPACE_SLUG`, `AGENCY_NAME`, `CC_ACTOR_ID` | `src/env.ts` merge |
| `ONEIE_JSON` | Retired everywhere except `plugin`, where it is still the only JSON switch |
| `CLAUDECODE`, `CLAUDE_CODE`, `CURSOR_TRACE_ID`, `WINDSURF`, `GITHUB_COPILOT_CLI`, `CI` | Agent-environment detection |

`.env` and `.env.local` are merged in that order, and `process.env` overrides both.

## Commands that change things irreversibly

| Command | What it does |
| --- | --- |
| `ship` | Runs `add -A`, then a commit, then a push, as git child processes in the current working directory (`src/ship.ts`). It stages every untracked and modified file in the tree, including work it did not create. A shell-level git guard does not see it, because it is a child process rather than a shell string |
| `wallet register` | Writes public receiving addresses to a workspace. First write per chain is permanent; a later write returns `address_conflict`. There is no undo. It prints the exact addresses and prompts unless `--yes` |
| `wallet keygen --out <file>` | Writes the mnemonic and every private key to disk unencrypted at mode 0600. Refuses without `--yes-i-accept-plaintext-file` |
| `wallet send … --live` | Signs and broadcasts a transfer. A sent coin does not come back. It prints the transaction and asks y/N first (`--yes` skips the prompt; an agent shell needs `--yes` AND its own vault). Without `--live` nothing is signed |

## What does not work yet

**Fixed in 5.7.3: the substrate commands no longer 404 on their default host.** `src/lib/api-path.ts` maps each long `/api/*` path to the gateway's short form when the host is `api.one.ie` (walk 6, 2026-11-06: mark 3.78 s, warn 1.80 s, follow 0.36 s). `signal` itself is the server's door (401); an agent fires the same receivers through `ask`.

**`agent compile --target a2a` and `--target erc8004` are not implemented** and fail loudly. Four targets ship: `mcp`, `uagents`, `skillmd`, `web`.

**`agent publish --target agentverse --hosted` forwards `ANTHROPIC_API_KEY`** to a third-party host, announced by variable name on stderr. The injected `ONEIE_API_KEY` is not yet consumed by the generated agent, and it has not been verified that the Agentverse sandbox permits importing the Anthropic client.

**`one eval` degrades outside the monorepo.** `@oneie/evals` is a devDependency, deliberately not bundled, because shipping it as a runtime dependency broke `npm i -g`. It is published — `npm view @oneie/evals version` returns 0.1.1 — so `npm i -g @oneie/evals` alongside the CLI is a real fix; the package's own source comment calling it unpublished is stale. From a global install without it, the command returns `{ok:false, error:"The \`eval\` command needs the @oneie/evals package, which is not bundled in the published CLI…"}`.

**`one reputation` is a stub.** It is registered and reachable and prints a pending notice; `meta:reputation` is not shipped.

**`agent serve` is a stub.** It checks the path exists, prints `status=listening`, and exits. No port is bound and no A2A or MCP server starts.

**`--json` is inert for `plugin`.** All four verbs read the retired `ONEIE_JSON` env var instead, because no call site passes the command object.

**Two published files carry wrong statements about this package.** `packages/cli/README.md:79` and `text/cli-reference.md:33` both give the Bearer token as `<slug>:<key>`, which 401s. `README.md` also closes with an MIT licence line; the shipped licence is the ONE License v1.0, and the MIT claim is wrong. `README.md` further shows a positional payload after the receiver name — the flag is `--data`.

**The two npm names are published in lockstep since 5.7.3.** `npm view oneie version` and `npm view @oneie/cli version` both answer 5.7.3 (2026-11-08).