> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joyride.exchange/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI Guide

> Install, configure, and use the Joyride CLI for quoting, trading, and streaming 0DTE options.

## What the CLI does

The CLI is the fastest way to:

* create and manage Solana wallets for trading
* inspect active instruments and options chains
* get quotes and order book snapshots
* place and cancel paper-trading orders
* review balances, positions, and trade history
* stream live market data in the terminal

Both human-readable table output and machine-readable JSON output are supported on every command.

**Current mode:** Paper trading only. No real money at risk.

## Installation

### Prerequisites

* **Node.js** >= 20.0.0

### Install

```bash theme={null}
npm install -g joyride-cli
```

This installs the `joyride` CLI and the bundled MCP server. Verify it's working:

```bash theme={null}
joyride --help
```

### Uninstall

```bash theme={null}
npm uninstall -g joyride-cli
```

## Setup and authentication

### First-run setup

The first time you run any command, an interactive setup wizard launches:

```
$ joyride chain SOL

┌  Joyride CLI Setup
│
◇  Joyride origin
│  https://joyride.exchange
│
◇  How would you like to set up your wallet?
│  Create new wallet / Import existing wallet
│
◇  Enter passphrase to encrypt wallet:
│  ********
│
◇  Wallet created: GmQo...9wC8
│
◇  Default asset
│  SOL
│
└  Configuration saved!
```

Or run the wizard explicitly:

```bash theme={null}
joyride setup
```

### Authentication model

The CLI authenticates to Joyride using a Solana wallet via SIWS (Sign-In with Solana). The SIWS handshake runs over the core trading WebSocket, and the resulting session token (a JWT) is stored locally and reused as a Bearer credential for reads. Your wallet's private key is encrypted with a passphrase and stored locally as a keystore file.

The CLI is **login-only**. Account creation happens in the web app at [joyride.exchange](https://joyride.exchange) (referral code + terms attestation). Signing in with a wallet that has no Joyride account fails with a clear "sign up at joyride.exchange" message — invite/referral codes are redeemed in the web app, not the CLI.

**Session lifetime.** `joyride login` mints a session whose lifetime the **server** sets (from the JWT's `exp` claim) — it is not a fixed client-side default. Run `joyride auth status` at any time to see the wallet and the session's exact expiry date. On a shared or untrusted machine, run `joyride logout` when you are done — this deletes the stored token.

The CLI resolves wallet credentials in this order:

1. **`JOYRIDE_PRIVATE_KEY` env var** — Base58-encoded private key (bypasses keystore entirely)
2. **Keystore + `JOYRIDE_KEYSTORE_PASSWORD` env var** — decrypts the keystore automatically
3. **Keystore + interactive passphrase prompt** — prompts in TTY mode

For scripting and automation, set the env var to avoid interactive prompts:

```bash theme={null}
export JOYRIDE_KEYSTORE_PASSWORD="your-passphrase"
```

### Config file

Config is saved to `~/.joyride/config.toml`:

```toml theme={null}
[auth]
wallet_address = "GmQozSzrtMjXt5F1Bed8Vrt55zCbiga8vDZr47RX9wC8"

[defaults]
asset = "SOL"
mode = "paper"
output = "table"

[connection]
http_url = "https://joyride.exchange"
```

The `[connection]` section uses **config schema v2**. Every service URL derives from a single public origin, so the only value you normally set is `http_url` (a bare origin — no path). The CLI derives the core trading WebSocket, market-data WebSocket, oracle WebSocket, public API, and query API URLs from it. To override the derived WebSocket endpoints explicitly, add:

```toml theme={null}
[connection]
http_url       = "https://joyride.exchange"
trading_ws_url = "wss://joyride.exchange/api/client"   # core trading WS (optional)
md_ws_url      = "wss://joyride.exchange/api/md"       # core market-data WS (optional)
```

Legacy v1 keys (`ws_url`, `gateway_ws_url`, `gateway_http_url`, or an `http_url` carrying a gateway path) are no longer valid: on load they are reset to the v2 defaults with a one-time notice. You can edit this file directly instead of re-running `joyride setup`.

### Configuration priority

Settings resolve in this order (highest priority first):

1. **CLI flags** (`--gateway` → trading WS, `--http` → origin, `--asset`, `--output`)
2. **Environment variables** (`JOYRIDE_TRADING_WS_URL`, `JOYRIDE_MD_WS_URL`, `JOYRIDE_HTTP_URL`, `JOYRIDE_PRIVATE_KEY`, `JOYRIDE_KEYSTORE_PASSWORD`)
3. **Config file** (`~/.joyride/config.toml`)
4. **Defaults** (origin `https://joyride.exchange`)

The old env names `JOYRIDE_WS_URL` / `JOYRIDE_GATEWAY_URL` are accepted for one release with a deprecation warning; use `JOYRIDE_TRADING_WS_URL` and `JOYRIDE_MD_WS_URL` instead.

## Instrument ID format

All instrument IDs follow this pattern:

```
{ASSET}_USDC-{DMMMYY}-{STRIKE}-{C|P}
```

| Component | Description                     | Examples              |
| --------- | ------------------------------- | --------------------- |
| `ASSET`   | Underlying asset                | `SOL`, `BTC`, `ETH`   |
| `DMMMYY`  | Expiry date (1- or 2-digit day) | `3MAR26`, `27FEB26`   |
| `STRIKE`  | Strike price (integer USD)      | `75`, `100`, `200`    |
| `C\|P`    | Option type                     | `C` (call), `P` (put) |

Examples:

* `SOL_USDC-3MAR26-75-C` — SOL \$75 call expiring Mar 3, 2026
* `SOL_USDC-27FEB26-100-P` — SOL \$100 put expiring Feb 27, 2026

Use `joyride chain SOL` to see all available instruments and their valid IDs.

Joyride currently offers same-day (0DTE) options. Instruments expire at end of day and refresh daily.

## Command reference

### Wallet management

#### `joyride wallet create`

Generate a new Solana wallet, encrypt it with a passphrase, and save it locally.

```bash theme={null}
$ joyride wallet create
◇  Enter passphrase to encrypt wallet: ********
◇  Confirm passphrase: ********

⚠  BACKUP YOUR PRIVATE KEY — write it down or save it in a password manager.
   Do not share it. Do not send it over email or chat.
   If you lose your passphrase and keystore, this is your only recovery path.

◇  5Kd8F...base58-private-key

ℹ  To recover this wallet later: joyride wallet import --private-key <key>

  Address   GmQozSzrtMjXt5F1Bed8Vrt55zCbiga8vDZr47RX9wC8
  Keystore  /Users/you/.joyride/wallets/GmQo...9wC8.json
  Active    Yes (auto-selected as first wallet)
```

The first wallet you create is automatically set as the active wallet.

#### `joyride wallet import`

Import a wallet from a Base58-encoded private key.

```bash theme={null}
# Interactive
$ joyride wallet import

# Non-interactive
$ joyride wallet import --private-key 5Kd8F...
```

| Flag                  | Required | Description                                      |
| --------------------- | -------- | ------------------------------------------------ |
| `--private-key <key>` | No       | Base58-encoded private key. Prompted if omitted. |

#### `joyride wallet list`

List all wallets in the keystore directory.

```bash theme={null}
$ joyride wallet list
┌──────────────────────────────────────────────┬────────┐
│ Address                                      │ Active │
├──────────────────────────────────────────────┼────────┤
│ GmQozSzrtMjXt5F1Bed8Vrt55zCbiga8vDZr47RX9wC8 │ ✓      │
│ 7nYB...second-wallet                         │        │
└──────────────────────────────────────────────┴────────┘
```

#### `joyride wallet show`

Show the active wallet address and keystore path.

```bash theme={null}
$ joyride wallet show
  Wallet           GmQozSzrtMjXt5F1Bed8Vrt55zCbiga8vDZr47RX9wC8
  Keystore         /Users/you/.joyride/wallets/GmQo...9wC8.json
  Keystore exists  Yes
```

#### `joyride wallet use <address>`

Switch the active wallet.

```bash theme={null}
$ joyride wallet use 7nYB...second-wallet
✔ Active wallet set to 7nYB...second-wallet
```

### Market data

#### `joyride chain <asset>`

List all options contracts for an asset. **Start here** to see available instruments.

```bash theme={null}
$ joyride chain SOL
✔ 72 instruments found
┌────────────────────────┬────────┬─────────┬──────┬───────────┬──────────┐
│ Instrument             │ Strike │ Expiry  │ Type │ Tick Size │ Min Size │
├────────────────────────┼────────┼─────────┼──────┼───────────┼──────────┤
│ SOL_USDC-3MAR26-75-C   │    $75 │ 3MAR26  │ CALL │     $0.01 │      0.1 │
│ SOL_USDC-3MAR26-75-P   │    $75 │ 3MAR26  │ PUT  │     $0.01 │      0.1 │
│ ...                    │        │         │      │           │          │
└────────────────────────┴────────┴─────────┴──────┴───────────┴──────────┘
```

**Transport:** HTTP (public API)

#### `joyride quote <instrument>`

Get the current best bid, ask, and mid price.

```bash theme={null}
$ joyride quote SOL_USDC-3MAR26-75-C
✔ Quote fetched
┌──────────────────────┬───────┬───────┬───────┐
│ Instrument           │ Bid   │ Ask   │ Mid   │
├──────────────────────┼───────┼───────┼───────┤
│ SOL_USDC-3MAR26-75-C │ $3.50 │ $5.00 │ $4.25 │
└──────────────────────┴───────┴───────┴───────┘
```

If the book is empty, bid/ask/mid show `-`.

**Transport:** WebSocket

#### `joyride book <instrument>`

Show bid and ask price levels with sizes.

```bash theme={null}
$ joyride book SOL_USDC-3MAR26-75-C
✔ Order book fetched
Order Book: SOL_USDC-3MAR26-75-C

   Bids                    Asks
   $3.50  ×  2.0           $5.00  ×  1.0
   $3.00  ×  5.0           $5.50  ×  3.0
```

| Flag               | Description                                     |
| ------------------ | ----------------------------------------------- |
| `--depth <levels>` | Number of price levels (default: 10)            |
| `--live`           | Stream real-time updates (press Ctrl+C to exit) |

**Transport:** WebSocket

#### `joyride ticker <instrument>`

Reduced ticker: best bid, ask, and last trade, synthesized from the market-data book mirror. Mark, IV, and 24h stats are not available in alpha.

**Transport:** WebSocket (MD)

#### `joyride tickers`

Reduced ticker summary across instruments (best bid/ask/last).

**Transport:** WebSocket (MD)

#### `joyride price <asset>`

Current spot price for the underlying asset, from the oracle feed.

```bash theme={null}
$ joyride price SOL
```

**Transport:** WebSocket (oracle)

#### `joyride market-config`

Exchange-level settings (tick sizes, contract sizes). Reduced against core: returns decimals and version only.

<Note>
  **Removed at core cutover.** `joyride history` (OHLCV candles) and `joyride greeks` (mark, IV, and option Greeks) are no longer available — the core exchange exposes no public candle or Greeks surface. For one release these commands still print a "removed at core cutover" notice and exit non-zero, then are dropped.
</Note>

### Trading

#### `joyride order place`

Place a limit or market order.

```bash theme={null}
# Limit order: sell 1 contract at $5.00
$ joyride order place --instrument SOL_USDC-3MAR26-75-C --side sell --size 1 --price 5
✔ Order placed
┌────────────┬──────────────────────┐
│ Order ID   │ 1994754              │
├────────────┼──────────────────────┤
│ Instrument │ SOL_USDC-3MAR26-75-C │
├────────────┼──────────────────────┤
│ Side       │ Sell                 │
├────────────┼──────────────────────┤
│ Type       │ limit                │
├────────────┼──────────────────────┤
│ Price      │ $5.00                │
├────────────┼──────────────────────┤
│ Size       │ 1                    │
├────────────┼──────────────────────┤
│ Status     │ open                 │
└────────────┴──────────────────────┘

# Market order (no --price)
$ joyride order place --instrument SOL_USDC-3MAR26-75-C --side sell --size 1
```

| Flag                 | Required | Description                                        |
| -------------------- | -------- | -------------------------------------------------- |
| `--instrument <id>`  | Yes      | Instrument ID                                      |
| `--side <buy\|sell>` | Yes      | Order side                                         |
| `--size <contracts>` | Yes      | Number of contracts (decimals allowed, e.g. `0.5`) |
| `--price <usd>`      | No       | Limit price in USD. Omit for market order.         |

Market orders execute immediately at the best available price. If no counterparty exists, the order is cancelled.

**Transport:** WebSocket

#### `joyride order list`

List open orders.

Query-api currently has no cursor. Table output warns when a non-empty response may have additional rows; JSON returns `{ orders, complete }`, with `complete: false` for every non-empty response.

```bash theme={null}
$ joyride order list
✔ 2 open order(s)
┌──────────┬──────────────────────┬──────┬───────┬──────┬────────┐
│ Order ID │ Instrument           │ Side │ Price │ Size │ Status │
├──────────┼──────────────────────┼──────┼───────┼──────┼────────┤
│ 1994754  │ SOL_USDC-3MAR26-75-C │ Sell │ $5.00 │    1 │ open   │
│ 1995088  │ SOL_USDC-3MAR26-75-P │ Buy  │ $2.00 │    1 │ open   │
└──────────┴──────────────────────┴──────┴───────┴──────┴────────┘
```

**Transport:** HTTP (query API, Bearer)

#### `joyride order status <orderId>`

Check order status with query-api's exact, account-scoped `order_id` filter. Terminal-state order history is not available in alpha, so an order id that is not currently open prints a deterministic notice — it may have filled, been cancelled, or expired (check `joyride trades`) rather than a bare "not found".

**Transport:** HTTP (query API, Bearer)

#### `joyride order cancel <orderId>`

Cancel a specific order.

```bash theme={null}
$ joyride order cancel 1994754 --instrument SOL_USDC-3MAR26-75-C
```

| Flag                | Required | Description                |
| ------------------- | -------- | -------------------------- |
| `--instrument <id>` | Yes      | Instrument ID of the order |

**Transport:** WebSocket

#### `joyride order cancel-all`

Cancel all open orders.

```bash theme={null}
$ joyride order cancel-all
$ joyride order cancel-all --instrument SOL_USDC-3MAR26-75-C
```

The command drains server-filtered batches concurrently and reports success only after an empty read proves that no matching open orders remain. Projection lag or a missing core symbol-filter deployment returns an incomplete failure instead of a false success.

**Transport:** HTTP (query API, Bearer) + WebSocket

### Account

#### `joyride balance`

Available account collateral. Core does not expose locked or total balance fields.

```bash theme={null}
$ joyride balance
✔ Balance fetched
┌───────────┬────────────┐
│ Account   │ 7          │
├───────────┼────────────┤
│ Available │ $10,000.00 │
└───────────┴────────────┘
```

**Transport:** HTTP (query API, Bearer)

#### `joyride account`

Combined balance and positions overview.

**Transport:** HTTP (query API, Bearer)

#### `joyride positions`

Open positions (raw quantity and average price).

```bash theme={null}
$ joyride positions
```

Mark, PnL, breakeven, and current-value enrichment is not available in alpha — the core query API returns raw positions only, and the `--metrics` flag has been removed.

**Transport:** HTTP (query API, Bearer)

#### `joyride trades`

Trade history. Add `--live <instrument>` for a real-time feed.

```bash theme={null}
$ joyride trades
$ joyride trades --live SOL_USDC-3MAR26-75-C
```

**Transport:** HTTP (snapshot), WebSocket (live)

### MCP server management

#### `joyride mcp install`

Configure the Joyride MCP server in an AI client. This is the easiest way to connect Joyride to Claude Code, Cursor, or Codex.

```bash theme={null}
$ joyride mcp install --client claude    # Claude Code
$ joyride mcp install --client cursor    # Cursor
$ joyride mcp install --client codex     # Codex
```

| Flag                | Required | Description                                     |
| ------------------- | -------- | ----------------------------------------------- |
| `--client <client>` | Yes      | Target client: `claude`, `codex`, or `cursor`   |
| `--force`           | No       | Overwrite existing config if already configured |

Requires an active session (`joyride login`). See the [MCP Server Guide](./mcp-server) for full details.

#### `joyride mcp uninstall`

Remove the Joyride MCP server from an AI client.

```bash theme={null}
$ joyride mcp uninstall --client claude
```

Safe to run even if joyride is not currently configured.

#### `joyride mcp serve`

Start the MCP server directly (stdio transport). This is called automatically by AI clients — you typically don't need to run it yourself.

```bash theme={null}
$ joyride mcp serve
```

### Live streaming

Two commands support live-updating terminal UIs powered by [Ink](https://github.com/vadimdemedes/ink). Press `Ctrl+C` to exit.

```bash theme={null}
# Live order book with colored bids/asks and spread
joyride book SOL_USDC-3MAR26-75-C --live

# Scrolling trade feed
joyride trades --live SOL_USDC-3MAR26-75-C
```

#### `joyride watch <channel> [argument]`

Subscribe to a WebSocket channel and stream events as JSON lines (one event per line) to stdout. Designed for piping into `jq`, log files, or downstream agents. Reconnects automatically on transient disconnects. Press `Ctrl+C` to exit.

```bash theme={null}
# Public channels (no auth required)
joyride watch book SOL_USDC-3MAR26-75-C
joyride watch book SOL_USDC-3MAR26-75-C --depth 5
joyride watch trades SOL_USDC-3MAR26-75-C

# Private channels (require an active session via joyride login)
joyride watch fills
joyride watch settlements

# Pipe into jq for live filtering
joyride watch trades SOL_USDC-3MAR26-75-C | jq 'select(.size > 1)'
```

| Channel       | Argument       | Auth | Description                                                 |
| ------------- | -------------- | ---- | ----------------------------------------------------------- |
| `book`        | `<instrument>` | No   | Order book updates (snapshots and deltas), from the MD WS   |
| `trades`      | `<instrument>` | No   | Public trade feed, from the MD WS                           |
| `fills`       | —              | Yes  | Your fill reports, from the trading WS private stream       |
| `settlements` | —              | Yes  | Your settlement entries, from the trading WS private stream |

The gateway-era `spot`, `tickers`, and `orders` channels have been removed. Spot now has its own command (`joyride price <asset>`), and order events surface through `fills`.

| Flag               | Description                                                                             |
| ------------------ | --------------------------------------------------------------------------------------- |
| `--depth <levels>` | Number of price levels for the `book` channel (default: 10). Ignored on other channels. |
| `--interval <ms>`  | Poll interval for public channels.                                                      |

If a private channel is used without an active session, the command exits immediately with a clear error. Run `joyride login` first.

**Transport:** WebSocket

## Output modes

Every command supports two output formats:

### Table (default)

Human-readable tables with formatting and colors.

```bash theme={null}
$ joyride balance
```

### JSON

Machine-readable JSON for scripts, pipes, and AI agents.

```bash theme={null}
$ joyride balance --output json
$ joyride balance -o json

# Pipe to jq
$ joyride order list --output json | jq '.orders[].symbol'
```

#### Session expiry metadata

When `--output json` is used and an active session is loaded, object-typed JSON responses are enriched with a `_session` field containing the absolute session expiry timestamp. Long-running agents can read this to refresh proactively before the session expires (and the next request returns `401`).

```json theme={null}
{
  "account_id": 7,
  "available": "10000.00",
  "updated_at": "2026-05-01T12:00:00Z",
  "_session": {
    "expiresAt": "2026-05-26T00:00:00.000Z"
  }
}
```

| Field                | Type              | Description                                                                                                                            |
| -------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `_session.expiresAt` | string (ISO 8601) | Absolute UTC timestamp when the current session expires. Compare against the current time to decide whether to re-run `joyride login`. |

Notes:

* Enrichment only applies when output mode is `json`. Table output is unaffected.
* Only object-typed JSON payloads are enriched. Array-typed responses (`positions`, `chain`, etc.) are left as-is. `order list` now returns an object so it can include the pagination-safety `complete` flag and session metadata.
* If no session is loaded (e.g. before `joyride login` has run), the `_session` field is omitted. Treat its absence as a non-error.
* The previously-considered `_session.expiresIn` field is intentionally not emitted — use `expiresAt` and compute the remaining time at read-time to avoid drift between command execution and output consumption.

## Global flags

These flags work on every command:

| Flag                | Short | Description                                  |
| ------------------- | ----- | -------------------------------------------- |
| `--output <format>` | `-o`  | `table` (default) or `json`                  |
| `--verbose`         | `-v`  | Enable verbose logging                       |
| `--gateway <url>`   |       | Override the core trading WebSocket URL      |
| `--http <url>`      |       | Override the origin (`http_url`)             |
| `--asset <asset>`   |       | Override default asset (`SOL`, `BTC`, `ETH`) |
| `--version`         | `-V`  | Show CLI version                             |
| `--help`            | `-h`  | Show help                                    |

## Transport reference

The CLI talks to the core exchange over WebSocket (trading + market data) and HTTP (query/public API), all derived from the single origin in `http_url`.

### WebSocket commands (real-time)

| Command              | Description                                            |
| -------------------- | ------------------------------------------------------ |
| `chain`              | List available instruments                             |
| `quote`              | Best bid/ask/mid (synthesized from the MD book mirror) |
| `book`               | Order book snapshot or live stream                     |
| `order place`        | Place limit or market order                            |
| `order cancel`       | Cancel an order                                        |
| `order cancel-all`   | Cancel all orders (iterates open orders)               |
| `order list`         | List open orders                                       |
| `order status`       | Check status against open orders                       |
| `balance`            | Account balance                                        |
| `ticker` / `tickers` | Reduced best bid/ask/last (from the MD book mirror)    |
| `price`              | Underlying spot price (oracle WS)                      |
| `trades --live`      | Live trade feed                                        |
| `watch`              | Stream a channel as JSON lines                         |

### HTTP commands (snapshots)

| Command         | Description                               |
| --------------- | ----------------------------------------- |
| `market-config` | Exchange configuration (decimals/version) |
| `account`       | Account summary                           |
| `positions`     | Open positions (raw)                      |
| `trades`        | Trade history                             |

Production endpoint:

* Origin: `https://joyride.exchange` (trading WS `/api/client`, MD WS `/api/md`, oracle WS `/api/oracle`, query/public API under `/api`)

## Troubleshooting

### `zsh: command not found: joyride`

The CLI is not installed or not on your PATH. Run `npm install -g joyride-cli` and restart your shell.

### Setup wizard hangs or won't accept input

The wizard requires an interactive terminal (TTY). It won't work when piped or in CI. Run `joyride setup` directly in your terminal.

### `iter.next is not a function`

Your installed CLI version is out of date. Upgrade to the latest Joyride CLI package or binary provided for the alpha.

### Passphrase prompted on every command

Each CLI invocation is a separate process. To avoid repeated prompts, export the passphrase:

```bash theme={null}
export JOYRIDE_KEYSTORE_PASSWORD="your-passphrase"
```

Or use `JOYRIDE_PRIVATE_KEY` to bypass the keystore entirely.

### Quote shows all dashes

The order book is empty — no bids or asks are resting. This is normal on a thin paper trading market. Try `joyride chain SOL` to find instruments with activity.

### HTTP commands fail

Check your config:

```bash theme={null}
cat ~/.joyride/config.toml
```

Verify `http_url` is correct and the endpoint is running. WebSocket commands will still work without HTTP.

### Orders disappear immediately

0DTE options expire at end of day. If instruments have expired, orders may be automatically cancelled. Use `joyride chain SOL` to check current expiry dates.

### Debug mode

```bash theme={null}
JOYRIDE_DEBUG=1 joyride quote SOL_USDC-3MAR26-75-C 2>debug.log
cat debug.log
```

Logs all incoming WebSocket message types and payloads to stderr.
