# Veyl CLI

The CLI prints JSON results and newline-delimited JSON events. `src/commands.js` generates CLI paths, help, and persistent-session dispatch, so every operation has one canonical path and no aliases.

Run `veyl help` for the live inventory. The command families are summarized below.

## Reserved namespace owner

```bash
veyl namespace init
```

This one-time owner command creates `~/.veyl/namespace.seed` with mode `0600` and prints only its public key and fingerprint. It never prints the private seed. `veyl account create @name --reserved` signs a short-lived reserved-name claim for the exact new machine credential. The explicit flag prevents ordinary account creation from disclosing an unnecessary namespace-owner signature. The fleet owner detects the same file under its `homeDir` because a Veyl-managed fleet is already public operator context. Ordinary installations without the trusted seed cannot claim a reserved username.

The namespace seed is not accepted through a command argument, environment variable, profile, or fleet manifest. Back up the file offline; losing it removes the ability to authorize another reserved account.

## Account and vault

```bash
veyl account create @name [--passkey] [--reserved]
veyl account login [@name] [--passkey]
veyl account show
veyl account terms
veyl account accept-terms
veyl account logout
veyl account logout-all
veyl account delete --confirm [--key VALUE]

veyl vault create [--key VALUE] [--no-save-key]
veyl vault unlock [--key VALUE] [--no-save-key]
veyl vault lock
veyl vault export [--key VALUE]
```

Creating an account accepts Veyl's [Terms](https://veyl.glyphteck.com/terms#terms), which include the community rules. `account accept-terms` accepts the current Terms for an existing account. `account terms` reports the canonical link and whether the account's acceptance is current without unlocking the vault.

`vault export` returns the Spark mnemonic. Treat its JSON output as a secret.

## Profile, settings, and cache

```bash
veyl profile show
veyl profile avatar-set ./avatar.webp
veyl profile avatar-delete

veyl settings show
veyl settings update '{"moneyFormat":"btc"}'

veyl cache show
veyl cache clear
```

Avatar input must already be a WebP file within the shared avatar byte limit. The CLI supplies bytes to the same avatar upload owner used by the visual clients; it does not add a second image-processing pipeline.

## Peers

```bash
veyl peers show @alice
veyl peers search ali
veyl peers list [--count 30] [--all-peers]
veyl peers blocked
veyl peers block @alice
veyl peers unblock @alice
```

Blocking yourself is rejected. Blocking independently submits a narrow user report, deletes the canonical direct chat, and leaves every decrypted group containing that UID. Report failure does not prevent the block and is exposed separately in the command result. A future successor containing the block is dropped locally; no readable server membership graph exists.

## Chat

```bash
veyl chat list [--count 30]
veyl chat get CHAT_ID
veyl chat notes
veyl chat open-direct @alice
veyl chat create-group @alice,@bob --title "builders"
veyl chat add-members CHAT_ID @carol
veyl chat kick-member CHAT_ID MEMBER_CHAT_PK
veyl chat update-settings CHAT_ID '{"title":"night builders"}'
veyl chat messages-by-id CHAT_ID [--count 30]
veyl chat enter-by-id CHAT_ID [--read-policy auto|manual|none]
veyl chat mark-read-by-id CHAT_ID [MESSAGE_ID]
veyl chat send-to CHAT_ID "hello everyone"
veyl chat reply-in CHAT_ID MESSAGE_ID "got it"
veyl chat react-in CHAT_ID MESSAGE_ID "+1"
veyl chat unreact-in CHAT_ID MESSAGE_ID
veyl chat save-in CHAT_ID MESSAGE_ID
veyl chat unsave-in CHAT_ID MESSAGE_ID
veyl chat edit-in CHAT_ID MESSAGE_ID "corrected text"
veyl chat delete-message-in CHAT_ID MESSAGE_ID
veyl chat send-file-to CHAT_ID ./photo.webp
veyl chat download-by-id CHAT_ID MESSAGE_ID ./downloaded-file
veyl chat leave-membership CHAT_ID
veyl chat delete-by-id CHAT_ID

# Canonical-direct convenience commands:
veyl chat enter @alice [--count 30] [--read-policy auto|manual|none]
veyl chat entered
veyl chat leave @alice
veyl chat messages @alice [--count 30]
veyl chat mark-read @alice
veyl chat send @alice "hello" [--cid AGENT_ACTION_ID]
veyl chat retry @alice FAILED_CID
veyl chat reply @alice MESSAGE_ID "got it"
veyl chat react @alice MESSAGE_ID "+1"
veyl chat unreact @alice MESSAGE_ID
veyl chat save @alice MESSAGE_ID
veyl chat unsave @alice MESSAGE_ID
veyl chat edit @alice MESSAGE_ID "corrected text"
veyl chat delete-message @alice MESSAGE_ID
veyl chat delete @alice [--no-cleanup]
veyl chat retention @alice seen
veyl chat retention @alice 24h
```

Attachments use filesystem paths in the CLI while the shared owners still perform encryption, upload, message creation, sharing, and decryption:

```bash
veyl chat send-file @alice ./photo.webp --mime image/webp --caption "caption"
veyl chat send-file-many @alice,@bob ./document.pdf --name document.pdf
veyl chat forward @alice MESSAGE_ID @bob,@carol
veyl chat download @alice MESSAGE_ID ./downloaded-file
```

The `*-by-id`, `*-to`, and `*-in` commands are the primary notes/direct/group surface. Direct peer commands first resolve the canonical private direct alias. A chat that once became a group remains a separate group-lineage object even if reduced to two members.

`chat messages-by-id` and `chat messages` page the same epoch-spanning older-history loader used by the app, then mark the newest applicable message read. `chat mark-read-by-id` is the stable-chat latest-only write. Explicit message delete is immediate; retention expiry remains held in an already-mounted route until release.

`chat enter-by-id` and `chat enter` emit mounted snapshots as newline-delimited JSON. A one-off process owns the route until exit. With `--session`, the foreground runtime retains it after output disconnect; `chat entered` inspects retained routes and `chat exit-by-id` releases any chat by stable id. `manual` requires an explicit mark-read; `none` suppresses read writes.

## Wallet

Amounts are integer sats.

```bash
veyl wallet balance
veyl wallet address
veyl wallet claim [--count 100]
veyl wallet send @alice 10 [--operation-id AGENT_JOB_ID] [--token-identifier id]
veyl wallet request @alice 10 [--token-identifier id]
veyl wallet pay-request REQUEST_ID [--operation-id AGENT_JOB_ID]
veyl wallet pay-invoice INVOICE [--amount SATS] [--operation-id AGENT_JOB_ID]
veyl wallet transactions [--count 50] [--offset 0]
veyl wallet transaction TX_ID
veyl wallet search QUERY [--count 50] [--exact]
veyl wallet search @alice
```

## encrypted exit backup

```sh
veyl wallet refresh-exit-backup
veyl wallet export-exit-backup
veyl wallet restore-exit-backup
veyl wallet import-exit-backup /private/path/exit-backup.json
```

refresh needs spark connectivity; reading/exporting the retained copy and restoring its encrypted cloud mirror do not. `wallet exit-backup` returns private decoded transaction material instead of an encrypted envelope. keep the separately exported mnemonic private; it is required to decrypt the backup. a different retained device snapshot is not overwritten by importing a file or restoring cloud state. use the standalone sdk recovery helper for independent inspection. the backup commands do not broadcast. independent execution uses:

```sh
veyl wallet exit-status
veyl wallet prepare-exit bitcoin-address 2
veyl wallet start-exit 'the exact json review returned by prepare-exit'
veyl wallet resume-exit
```

review preparation is retained across command invocations and expires after five minutes until authorization. starting retires spark spending on this installation, persists the destination and signed bytes, and resumes the same withdrawal after interruption. approval must cover the explicit excluded amount, fixed fee rate/cap, separate fee funding and timelocks. never run independent writers against one wallet. `exit-status` does not prove fresh confirmation by itself; `resume-exit` checks bitcoin and may progress an already-authorized withdrawal. [the recovery contract](../../../guidelines/wallet-recovery.md) records coverage, fee and remaining live checks.

## Lightning and withdrawals

```bash
veyl lightning invoice 10 --memo "coffee" --expiry 3600
veyl lightning quote INVOICE [--amount SATS]
veyl lightning pay INVOICE [--amount SATS] [--max-fee SATS] [--transfer-id UUID]
veyl lightning receive ID
veyl lightning send ID

veyl withdrawal quote ADDRESS SATS
veyl withdrawal prepare ADDRESS SATS [--speed MEDIUM] [--no-deduct-fee]
veyl withdrawal confirm ADDRESS SATS --fee-quote-id ID --fee-amount SATS --operation-id REVIEW_OPERATION_ID [--speed MEDIUM] [--no-deduct-fee]
```

`withdrawal quote` and `withdrawal prepare` do not spend or broadcast, but the spark sdk may restructure wallet leaves while producing an exact quote. pass the reviewed `feeQuoteId`, `feeAmountSats` and generated `operationId` back to `withdrawal confirm`. confirmation never requests a new quote. reuse the same review to recover or read the original receipt without another submission; the operation id is the returned 32-character hexadecimal value, not an arbitrary job label. keep the installation's encrypted wallet state intact across retries.

Money commands print stable `code`, `operation`, `operationId`, `outcome`, and `retryable` fields when the SDK cannot determine whether a mutation committed. Do not replay a result with `code: "operation_outcome_unknown"` unless `retryable` is true. Today that is true only for Lightning: reuse the returned `operationId` as the exact same `--transfer-id`; otherwise reconcile wallet history first.

## Invites

```bash
veyl invite link [join|chat|send|request] [SATS]
veyl invite read URL
```

These commands create and parse the same public invite URLs used by web and iOS. The CLI reads and returns the URL string directly; it does not render or scan QR codes.

## Passkeys and support

```bash
veyl passkeys list
veyl passkeys link [--web-url ORIGIN]
veyl passkeys delete ID [--web-url ORIGIN]

veyl support submit "message"
veyl support report @alice [MESSAGE_ID] [--note TEXT] [--no-attachment]
```

Passkey links are one-time credentials; do not log or persist the returned URL. The list marks the credential currently authenticating the session and exposes the same shared deletion eligibility as web and iOS.

## Persistent runtime and events

Cold one-off commands must log in, unlock, and boot the Spark wallet. A foreground session pays that cost once and accepts commands over an owner-only local socket:

```bash
veyl --profile runner session start
veyl --profile runner --session default wallet balance
veyl --profile runner --session default chat send @alice "hello"
veyl --profile runner --session default chat enter @alice
# another shell, when the conversation is actually finished
veyl --profile runner --session default chat leave @alice
veyl --profile runner --session default session status
veyl --profile runner --session default session events
veyl --profile runner --session default session stop
```

The event stream subscribes to the shared live chat batches and transfer store; it is not a polling loop. Multiple subscribers lease the same underlying message sources.

Account deletion, credential revocation, and all-device logout automatically drain and stop an affected persistent runtime. Ordinary vault lock and single-session logout leave the foreground runtime available for an explicit login.

Event flags:

```text
--replay             include current rows at startup
--all                include self-authored messages; defaults to incoming only
--raw                include complete event payloads
--no-chats           omit message events
--no-transactions    omit transaction events
```

## Common selection and output flags

```text
--profile NAME
--network REGTEST|MAINNET
--session NAME
--count N
--limit N
--offset N
--raw
--web-url ORIGIN
--key VALUE
--no-save-key
--operation-id ID
--cid ID
```

## Environment

```text
VEYL_HOME            local profile directory
VEYL_PROFILE         default profile
VEYL_NETWORK         REGTEST or MAINNET
VEYL_ACCOUNT_KEY     account key used by login
VEYL_VAULT_KEY       vault key used by create/unlock
VEYL_WEB_URL         passkey browser origin
```
