cairn-cli 0.1.6

Backpac Agent-Native CLI for autonomous settlement workflows
Documentation
# Cairn CLI Design Specification

This document provides a comprehensive specification for the Cairn CLI. It is language-agnostic and contains all necessary details to rebuild the CLI from scratch in any programming language (e.g., Go, Python, TypeScript).

## 1. Overview and Principles

**Cairn** (`cairn`) is an agent-native command-line tool for autonomous settlement workflows.

1. **API-First**: The CLI is a pure presentation layer over the Backpac REST APIs. It holds no complex state other than saved configuration and JWT authentication credentials.
2. **Machine-Readable**: All command outputs default to structured JSON. A `--output=text` flag is supported for flat shell piping.
3. **No Interactive Prompts**: The CLI must never block for interactive `stdin` prompts unless strictly necessary. It expects all inputs via arguments or flags.
4. **Deterministic Exits**: It strictly adheres to a predefined set of 16 exit codes for machine-readable error handling.

## 2. Configuration and State

The CLI manages local state in the user's home directory under `~/.backpac/`.

### `~/.backpac/config.json`
Stores user preferences and defaults.
```json
{
  "chain": "ethereum",
  "network": "mainnet",
  "tier": "standard",
  "default_confirmations": 24,
  "default_rebroadcast_max": 3,
  "default_valid_for": 600,
  "key_file": null,
  "credentials_path": null,
  "output": "json",
  "api_url": "https://api.backpac.xyz"
}
```

### `~/.backpac/credentials.json`
Stores the active authentication session.
```json
{
  "jwt": "eyJhbGci...",
  "agent_id": "agent_123...",
  "wallet": "0xABC...",
  "expires_at": "2026-12-31T23:59:59Z"
}
```

## 3. Global Flags Configuration

The following flags must be available on *all* commands globally:

| Flag | Env Var | Purpose | Default |
|:---|:---|:---|:---|
| `--output` | `CAIRN_OUTPUT` | Output formatting (`json` or `text`) | `json` |
| `--quiet`, `-q` | None | Suppress all `stdout`/`stderr` outputs, exit code only | `false` |
| `--api-url` | `BACKPAC_API_URL` | Override the default API base URL | none |
| `--jwt` | `BACKPAC_JWT` | Complete override of the saved JWT token | none |
| `--chain` | `CAIRN_CHAIN` | Chain identifier (e.g., `ethereum`) | from config |
| `--network` | `CAIRN_NETWORK` | Network within chain (e.g., `mainnet`) | from config |

## 4. HTTP Client and Auth Injection

1. **Base URL**: Resolve via `--api-url` -> `BACKPAC_API_URL` -> `config.json` -> fallback to `https://api.backpac.xyz`.
2. **JWT Injection**: Resolve via `--jwt` -> `BACKPAC_JWT` -> `~/.backpac/credentials.json`.
3. If a JWT is found, inject it as an HTTP header: `Authorization: Bearer <jwt>`.
4. All requests must send `Content-Type: application/json`.

## 5. Command Hierarchy and API Mapping

### `auth`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `auth challenge` | `--wallet`, `--chain`, `--did` | `POST /v1/agents/challenge` | Request an EIP-4361 signing challenge payload. |
| `auth connect` | `--wallet`, `--chain`, `--did`, `--nonce`, `--signature`, `[--key_file]` | `POST /v1/agents/connect` | Submit challenge signature. Saves JWT to `credentials.json`. Auto-signs if `--key_file` provided. |
| `auth refresh` | None | `POST /v1/agents/refresh` | Re-mints JWT using the currently valid JWT. Updates `credentials.json`. |
| `auth status` | None | `GET /v1/agents/status` | Checks token health, expiry, and scopes. |

### `identity`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `identity register` | `--did`, `--wallet`, `--public-key`, `[--display-name]` | `POST /v1/agents/identity` | Anchor a DID to the wallet. |
| `identity rotate` | `--did`, `--current-key`, `--new-key` | `PUT /v1/agents/identity/rotate` | Rotate the Ed25519 signing key for the DID. |
| `identity get` | `<did>` | `GET /v1/agents/identity/:did` | Look up state and current key for a registered DID. |

### `poi` (Proof of Intent)

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `poi create` | `[--chain]`, `[--network]`, `[--parent]`, `[--max-depth]`, `[--ttl]`, `[--metadata]` | `POST /v1/pois` | Create a new Proof of Intent tracking record. |
| `poi get` | `<poi_id>` | `GET /v1/pois/:poi_id` | Retrieve an existing PoI. |

### `intent`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `intent send` | `--method`, `--params`, `[--poi-id]`, `[--confidence]`, `[--id]` | `POST /` (RPC Route) | Submit JSON-RPC payload. Binds to PoI if `--poi-id` provided (via `X-Backpac-Poi-Id` header). |
| `intent status` | `<intent_id>` | `GET /v1/intents/:intent_id` | Check state of a specific execution intent. |
| `intent verify` | `<intent_id>`, `[--receiver-did]`, `[--min-confidence]` | `GET /v1/intents/:intent_id/verify` | Receiver-side verification endpoint for a settled PoI. |
| `intent wait` | `<intent_id>`, `[--interval]`, `[--timeout]` | Polling `GET /v1/intents/:intent_id` | Client-side poll until status is `FINALIZED`, `ABORTED`, or `EXPIRED`. |
| `intent list` | `[--status]`, `[--since]`, `[--limit]` | `GET /v1/intents` | List and filter authenticated agent's intents. |

### `watch`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `watch intent` | `<intent_id>` | `GET /v1/intents/:intent_id/stream` | Stream live SSE state transitions for a specific intent. |
| `watch agent` | None | `GET /v1/agents/stream` | Stream live SSE account-wide agent events and notifications. |

### `proof`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `proof get` | `<intent_id>`, `[--include-telemetry]`, `[--include-children]`, `[--verify-signature]`, `[--raw]` | `GET /v1/proofs/:intent_id` | Fetches the structured cryptographic PoT bundle. |
| `proof verify` | `<intent_id>` | `GET /v1/proofs/:intent_id` + `GET /.well-known/jwks.json` | Fetches bundle, fetches JWKS from issuer, performs local Ed25519 cryptographic signature verification against the payload hash. |

### `receive`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `receive` | `--poi-id`, `[--from]`, `[--recipient]`, `[--expect-value]`, `[--require-finalized]` | `GET /v1/pois/:poi_id` | Combined fetch and verify step for receiver agents. Validates sender, recipient, and value contexts. |

### `config`

| Command | Arguments | API Route | Description |
|:---|:---|:---|:---|
| `config set` | `<key>`, `<value>` | Local config.json | Edits values in `~/.backpac/config.json`. |
| `config get` | `[<key>]` | Local config.json | Fetches a specific value, or dumps the full configuration structure. |

## 6. Exit Codes

Errors must be strictly mapped from HTTP responses to integer exit codes to allow programmatic behavior.

| Condition / Meaning | Exit Code | HTTP Mapping |
|:---|:---:|:---|
| Success | `0` | `200`, `201`, `204` |
| General Error (Serialization, IO) | `1` | `500` or OS-level errors |
| Value Mismatch | `2` | PoI context validation failure |
| Not Finalized | `3` | `require-finalized` set but state is pending |
| Forbidden / Unauthorized | `4` | `401 Unauthorized` / `403 Forbidden` |
| Not Found | `5` | `404 Not Found` |
| Conflict | `6` | `409 Conflict` |
| Intent Expired | `7` | `410 Gone` (if message contains "expired") |
| Intent Aborted | `8` | `410 Gone` |
| Chain Depth Exceeded | `9` | Payload constraint check |
| Operation Timeout | `10` | `intent wait` duration exceeded |
| Signature Verification Error | `11` | Cryptographic match failure |
| PoT Not Ready | `12` | Proof missing signatures/payloads |
| Network Error | `13` | Unreachable endpoint, connection reset |
| Token Expired | `14` | `401 Unauthorized` (if message contains "expired") |
| Challenge Expired | `15` | Spec constraint |
| Insufficient Funds / x402 | `16` | `402 Payment Required` |

## 7. Cryptographic Requirements

To rebuild this CLI, your language must support the following cryptographic operations:
1. **EIP-4361 (Sign-In with Ethereum) Message Signing**: For authentication connecting a wallet. Standard `secp256k1` keccak256 signature recovery.
2. **Ed25519 Signing / Verification**: For DID usage (`did:key` base58 encoding) and local `proof verify` bundle verification using a remote JSON Web Key Set (JWKS).