CLI
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.
Reading this as an agent? The same page in raw markdown: /docs/cli.md
claude "Read https://one.ie/docs/cli.md. Explain CLI back to me in five lines, then name the one thing on that page I am most likely to get wrong."
@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: testnet. Every money command below moves test money (Sui testnet, Stripe test mode). Read it live: curl -s https://pay.one.ie/status → "network".
Install
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.
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.
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.
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 and Publish an agent.
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.
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.
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:
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.
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, and one.ie production is on testnet today |
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):
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, end to end (walk 8, 2026-11-07: 3.14 s):
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.
See Wallets and custody.
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.
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:
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 and Errors and limits.
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 |
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).