# Voltage Sandbox CLI

This CLI is the first concrete CAP package example. It is designed for an agent-assisted human to create a fresh Voltage-hosted LND sandbox node and get it ready to send and receive MutinyNet payments.

In the broader CAP product, `voltage-sandbox` is a `cli-tool` package: a CLI artifact with structured output, embedded operating guidance, explicit secret boundaries, and safe commands that agents can call through `cap run`. The repo now includes the first thin Codex plugin/MCP wrapper plus a skill so Codex can see typed tools and durable instructions instead of treating the raw CLI as the only interface.

The UX goal is to keep current operational knowledge and safe secret handling in the tool. Codex, Claude Code, and similar agents should be able to run `voltage-sandbox report --json`, `voltage-sandbox brief`, or `voltage-sandbox doctor` and know the required inputs, API endpoints, caveats, local state files, and next commands without doing a fresh web search.

Agents should treat this CLI as the trusted boundary:

- Prefer host-mediated invocation such as `cap run lightningnode/voltage-sandbox -- report --json` when installed through CAP.
- Do not browse the web for this workflow unless the CLI or docs explicitly say the embedded knowledge is insufficient.
- Do not read credential files directly.
- Do not parse unrelated repo env files for macaroons or node URLs.
- Do not call Voltage with ad hoc `curl`.
- Do not decrypt Voltage backups outside this CLI.
- If the CLI output is missing something important, improve the CLI or ask the user for the missing input.
- On macOS, use `voltage-sandbox credentials --gui` when the user needs to enter secrets outside a terminal or chat UI.

## CAP Capability Card

The package should advertise itself to the resolver roughly as:

```json
{
  "name": "lightningnode/voltage-sandbox",
  "kind": "cli-tool",
  "bestFor": [
    "create a mutinynet voltage lnd node",
    "inspect voltage sandbox node readiness",
    "prepare a lightning sandbox for tests"
  ],
  "safeTrials": [
    "voltage-sandbox brief --json",
    "voltage-sandbox doctor --json",
    "voltage-sandbox credentials --check"
  ],
  "permissions": {
    "filesystem": ["cap-state:read", "cap-state:write"],
    "network": ["api.voltage.cloud", "mutinynet faucet services"],
    "secrets": ["voltage-api-key", "voltage-node-password"]
  },
  "agentInterface": {
    "mcpTools": [
      "voltage_sandbox_brief",
      "voltage_sandbox_report",
      "voltage_sandbox_doctor",
      "voltage_sandbox_credentials_check",
      "voltage_sandbox_setup_dry_run"
    ],
    "skill": "plugins/voltage-sandbox/skills/voltage-sandbox/SKILL.md",
    "rawCliOnly": false,
    "preferred": "mcp-wrapper",
    "current": "codex-plugin-mcp",
    "structuredOutput": true
  }
}
```

`brief --json` and `doctor --json` are good resolver trial commands because they do not require secret disclosure. `credentials --gui`, `setup`, `fund`, and `test` cross stronger policy boundaries and should require explicit human or standing policy approval.

## End-To-End Use Case

The first full CAP workflow is Codex or Claude Code helping a user set up a new Lightning testnet-style node. The detailed journey is documented in [use-case-codex-claude-code-new-lightning-testnet-node.md](use-case-codex-claude-code-new-lightning-testnet-node.md).

## Agent Journey

When a user asks for information about a Voltage sandbox Lightning node, do not stop after reporting missing local state or credentials. Treat that as the beginning of a guided flow.

First ask:

```text
Do you already have a Voltage node to connect to, or should I help create a new MutinyNet sandbox node?
```

Phone tree:

1. Status requested: run `voltage-sandbox report --json`. If local state exists, or if exactly one clear running MutinyNet node is visible, report platform/LND status and payment readiness. If state is missing and no clear node can be selected, continue to the existing-node or new-node branch.
2. Existing node: run `voltage-sandbox credentials --gui` on macOS, or `voltage-sandbox credentials` in an interactive terminal, if the API key or org ID is missing. Then run `voltage-sandbox report --node-id <id> --save-state --json` or `voltage-sandbox report --node-name <name> --save-state --json`. The CLI first tries local state and Voltage encrypted macaroon backups for LND details. Ask for `--macaroon-file`, `--macaroon-hex`, `LND_MACAROON_PATH`, or `LND_MACAROON_HEX` only if the CLI reports that no macaroon is available.
3. New node: run `voltage-sandbox credentials --gui` on macOS, or `voltage-sandbox credentials` in an interactive terminal, then `voltage-sandbox doctor --live`, then `voltage-sandbox setup --fund --test`. MutinyNet nodes must be created with Voltage node type `ephemeral`; the CLI defaults MutinyNet setup to `ephemeral`, so `--type ephemeral` is optional. If `mutinynet-cli` is unavailable, create the node first and explain the dashboard or `mutinynet-cli` funding path.

## Install

From this repo:

```bash
npm link
voltage-sandbox doctor
```

Or run directly:

```bash
node src/cli.js doctor
```

## Required Human Inputs

- A Voltage account and team.
- A Voltage team API key, created in the dashboard and copied immediately because it is only shown once.
- A Voltage organization ID. The CLI tries to discover this from `GET /organizations` after the API key is entered.
- A fresh LND node wallet password. The human can choose one or let the CLI generate one.
- An existing 24-word LND aezeed seed phrase if restoring a wallet, or approval to leave the seed prompt blank so LND can generate a fresh seed.

On macOS, the CLI stores credentials in Keychain by default, and `setup` stores the generated or entered seed phrase in Keychain by default. On other platforms, credentials are stored in a private env file and the seed phrase is stored in the state directory with `0600` file permissions:

```text
~/.cap/secrets/voltage-sandbox/credentials.env
```

The parent directory is written with `0700` permissions and the credentials file with `0600` permissions. `setup`, `report`, `status`, and `doctor` load the selected credential store automatically. Override the file path with `--credentials-file <path>` or `VOLTAGE_CREDENTIALS_FILE`; either one also selects file storage.

Credential storage examples:

```bash
voltage-sandbox credentials --credential-store keychain
voltage-sandbox credentials --credential-store keychain --check
voltage-sandbox setup --credential-store keychain
voltage-sandbox setup --seed-store keychain
voltage-sandbox credentials --credential-store file
voltage-sandbox setup --seed-store file
```

The equivalent environment selectors are `VOLTAGE_CREDENTIAL_STORE=keychain|file` and `VOLTAGE_SEED_STORE=keychain|file`. File credential storage prints a warning before saving because it writes the Voltage API key and node wallet password to disk.

Optional, but recommended for automatic payment readiness:

```bash
cargo install mutinynet-cli
mutinynet-cli login
```

`mutinynet-cli` uses the MutinyNet faucet to open channels and pay test invoices.

## Agent-Friendly Commands

```bash
cap run lightningnode/voltage-sandbox -- brief --json
cap run lightningnode/voltage-sandbox -- report --json
cap run lightningnode/voltage-sandbox -- doctor --json
voltage-sandbox brief
voltage-sandbox brief --json
voltage-sandbox report
voltage-sandbox report --json
voltage-sandbox doctor
voltage-sandbox doctor --json
voltage-sandbox credentials
voltage-sandbox credentials --gui
voltage-sandbox credentials --check
```

`report --json` is the preferred first command for user-facing node information. It loads credentials only through the configured credential store, lists visible Voltage nodes, auto-selects one clear running MutinyNet node when possible, saves selected state when requested, decrypts Voltage encrypted macaroon backups in memory when the saved node password is available, runs read-only LND checks, and returns a redacted JSON report.

`brief` embeds the current Voltage/LND setup runbook, known caveats, source URLs, and expected state files.

`credentials` guides the user through signing in to Voltage, creating a team API key, discovering or entering the organization ID, choosing or generating the node wallet password, and saving credentials to the selected store.

On macOS, `credentials --gui` opens native dialogs for the API key, organization selection or entry, and node wallet password. This avoids terminal prompt limitations in agent UIs while still saving through the configured credential store. Secrets are not printed in chat or terminal output.

`doctor` checks local prerequisites, saved credentials, and optional tooling. It does not require web search to explain what is missing.

The current Codex plugin MCP wrapper maps directly to these narrow operations:

- `voltage_sandbox_brief`
- `voltage_sandbox_report`
- `voltage_sandbox_doctor`
- `voltage_sandbox_credentials_check`
- `voltage_sandbox_setup_dry_run`

Approval-sensitive tools such as credential GUI entry, live doctor checks, state-saving reports, live setup, funding, and payment tests are intentionally not exposed in the first plugin slice. They should become separate tools only with explicit descriptions and policy requirements.

## Credential Setup

```bash
voltage-sandbox credentials
voltage-sandbox credentials --gui
```

What `credentials` does:

1. Tells the human to sign in to `https://app.voltage.cloud/` and select or create a team.
2. Points them to the dashboard API key page: current Voltage docs describe Settings -> API Keys -> Manage -> Create a New Key; some dashboard views label this API -> Keys.
3. Prompts for the API key using hidden input.
4. Calls the Voltage platform API to discover organizations visible to that key, or asks for the organization ID if discovery is unavailable.
5. Prompts for a node wallet password using hidden input, or generates one if the prompt is left blank.
6. Saves `VOLTAGE_API_KEY`, `VOLTAGE_ORG_ID`, and `VOLTAGE_NODE_PASSWORD` to macOS Keychain by default on macOS, or to `~/.cap/secrets/voltage-sandbox/credentials.env` on other platforms.

Use the GUI flow on macOS when an agent cannot safely hand control to a terminal prompt:

```bash
voltage-sandbox credentials --gui
```

The GUI flow uses native macOS dialogs with hidden input for the API key and node wallet password, then saves through the same credential store. If multiple organizations are visible, it shows a native organization chooser. If discovery is unavailable, it opens a dialog for the organization ID.

Check without printing secrets:

```bash
voltage-sandbox credentials --check
voltage-sandbox doctor --live
```

## Dry Run

```bash
voltage-sandbox setup --dry-run --node-name codex-sandbox
```

This loads the saved credentials and prints the Voltage create-node request body without creating anything.

For MutinyNet, the create request uses `type: "ephemeral"`. Voltage rejects `standard` MutinyNet nodes, so the CLI fails fast if `--network mutinynet --type standard` is requested.

## Full Setup

```bash
voltage-sandbox credentials
voltage-sandbox setup --fund --test
```

What `setup` does:

1. Creates a Voltage node using the platform API. MutinyNet setup uses node type `ephemeral`; keep the same `--node-name` if retrying after a rejected `standard` create request.
2. Polls until the node is waiting for LND wallet initialization.
3. Prompts for an existing 24-word LND aezeed seed phrase when running interactively or with `--gui`; if the prompt is blank, calls LND `genseed`.
4. Calls LND `initwallet` with `stateless_init=true`.
5. Saves the seed phrase through secure seed storage: macOS Keychain by default on macOS, or `seed-phrase.txt` with `0600` file permissions on other platforms.
6. Uploads CryptoJS-compatible encrypted seed and admin macaroon backups to Voltage.
7. Verifies LND `getinfo`.
8. If `--fund` is passed, uses `mutinynet-cli channel` to request a split-liquidity faucet channel.
9. If `--test` is passed, tests receiving from the faucet and sending to a faucet invoice.

## Important Files

Default credential store:

```text
~/.cap/secrets/voltage-sandbox/credentials.env
```

This file contains the Voltage API key, organization ID, and node wallet password. It is secret and should not be committed.
On macOS, `--credential-store keychain` stores those values in Keychain instead.

Seed phrase store:

```text
macOS default: macos-keychain:cap.voltage-sandbox:LND_SEED_PHRASE:<node_id>
other platforms: ~/.cap/state/voltage-sandbox/current/seed-phrase.txt
```

Use `--seed-store keychain` or `VOLTAGE_SEED_STORE=keychain` to force Keychain storage on macOS. Use `--seed-store file` for the file fallback. To initialize from an existing seed phrase without pasting it into chat, run setup interactively or with `--gui`, or pass `--seed-phrase-file <path>` from a secure local file.

Default state directory:

```text
~/.cap/state/voltage-sandbox/current/
```

Project-local `.voltage-sandbox/current` state is not used by default. Pass `--dir .voltage-sandbox/current` explicitly if you intentionally want a workspace-local state directory.

Files:

- `state.json`: non-secret setup metadata.
- `connection.json`: LND REST/gRPC connection details.
- `admin.macaroon`: binary admin macaroon for `lncli`. Secret.
- `admin.macaroon.hex`: admin macaroon for LND REST/gRPC. Secret.
- `admin.macaroon.base64`: same macaroon in base64. Secret.
- `seed-phrase.txt`: LND aezeed seed phrase. Secret. This file is only written when seed phrase storage is `file`; on macOS the default is Keychain.

## Status And LND Environment

```bash
voltage-sandbox status
voltage-sandbox status --json
voltage-sandbox report --json
voltage-sandbox status --node-id <existing_node_id>
voltage-sandbox status --node-name <existing-node-name>
voltage-sandbox report --node-id <existing_node_id> --save-state --json
voltage-sandbox status --api-endpoint <host> --macaroon-file <admin.macaroon>
voltage-sandbox lnd-env
```

`status` first uses `~/.cap/state/voltage-sandbox/current/state.json` when it exists. If there is no local state file, it falls back to saved or environment-provided Voltage credentials, lists visible existing nodes, and inspects the selected node. Use `--node-id` or `--node-name` when more than one existing node is visible. Add `--save-state` to cache discovered existing-node metadata in `state.json`.

`report` uses the same state and selection logic, but is optimized for agent UX. It auto-selects exactly one clear running MutinyNet node, saves that selection by default, returns richer LND details, and checks Voltage encrypted macaroon backups before asking for manual macaroon input.

LND `getinfo` and channel balances are checked when an admin macaroon is available from local state, `--macaroon-hex`, `--macaroon-file`, `LND_MACAROON_HEX`, `LND_MACAROON_PATH`, or a Voltage encrypted backup that can be decrypted with the saved node password. Without a macaroon, `status` and `report` still report Voltage platform status for existing nodes.

`fund` and `test` use the same macaroon resolution path as `report`, so an existing Voltage node discovered from the platform can be funded and tested after the CLI decrypts its Voltage encrypted admin macaroon backup. When LND `getinfo` is available, `fund` refreshes the public node pubkey and advertised peer host into state before calling `mutinynet-cli channel`. The CLI does not hardcode faucet peer addresses. If a peer connection is explicitly needed, pass a user-provided `--connect-peer <pubkey@host>` value or set `VOLTAGE_SANDBOX_CONNECT_PEER`.

`lnd-env` prints shell exports and an `lncli getinfo` example.

## Known Caveats

- Voltage’s current docs describe MutinyNet as the sandbox path, while some API reference fields still mention `testnet`/`mainnet`. The CLI defaults to `mutinynet`; pass `--network` if your Voltage account expects a different value.
- Voltage requires MutinyNet nodes to use type `ephemeral`. The CLI defaults MutinyNet setup to `ephemeral` and rejects non-ephemeral MutinyNet create requests before calling Voltage.
- A created and initialized node is not payment-ready until it has channel liquidity.
- Automatic liquidity depends on `mutinynet-cli` and faucet reachability to the Voltage node’s advertised peer address.
- If automatic channel opening fails, use the Voltage dashboard MutinyNet controls: get MutinyNet coins, then open a channel.
- Voltage cannot recover a lost node password or seed phrase.
