# CLI / TUI — `kryard`

The `kryard` CLI is a single static binary that speaks **both** of Kryard's auth
tiers: [X-Stamp API-key][xstamp] access to the **`/public/v1/*`** surface (the same
surface [`@kryard/sdk`][sdk] exposes), and **human device login** access to the
**`/dashboard/v1/*`** surface (organizations, wallet reads, the operator console).
It also ships an interactive **TUI** + scriptable `--json` subcommands, with secrets
kept in the OS keychain (never argv, never a file).

The CLI is a sister surface to the SDK: each X-Stamp flow the SDK does,
`kryard --json` does too — and additionally surfaces the dashboard tier, which the
SDK does not. The two are byte-identical on the crypto paths; the `xstamp` header is
RFC-6979 P-256, byte-identical to `@kryard/sdk`/`viem`, and the EVM signing path is
byte-identical to the deployed `KryardDelegate` and `viem`.

::: info Proven live on Sepolia
`relay submit` has broadcast a real managed-relay transaction on Sepolia
(`0x2a056e76…`), and the EIP-7702 authorization produced by the CLI has been
accepted on-chain. The `sponsor` (4337) command is built and tested against the
4337 paymaster shape.
:::

## Install

::: code-group

```bash [curl | sh]
curl -fsSL https://kryard.com/install.sh | sh
```

```bash [pin a version]
KRYARD_VERSION=0.1.0 curl -fsSL https://kryard.com/install.sh | sh
```

```bash [from source]
cd cli && go build -o kryard ./cmd/kryard
```

:::

The installer downloads a static binary from `https://kryard.com/dl`, verifies its
SHA-256 against `checksums.txt`, and installs to `/usr/local/bin` (falling back to
`$HOME/.local/bin` when that path is not writable). macOS/Linux × amd64/arm64;
*no Homebrew tap* is wired yet.

| Variable | Default | Purpose |
|---|---|---|
| `KRYARD_VERSION` | contents of `/dl/latest` | pin a specific release, e.g. `0.1.0` |
| `KRYARD_INSTALL_DIR` | `/usr/local/bin` (else `$HOME/.local/bin`) | where to install |
| `KRYARD_BASE` | `https://kryard.com/dl` | download base URL |

Confirm the install:

```bash
kryard version
# 0.1.0
```

## Two tiers, two logins

| Tier | Surface | How you log in | What you can do |
|---|---|---|---|
| **API key (X-Stamp)** | `/public/v1/*` | `kryard login --api-key` | everything the SDK does — query orgs/wallets/activities, sign, [relay submit][relay], sponsor, read balances |
| **Device login (human)** | `/dashboard/v1/*` | `kryard login` (no `--api-key`) | everything above PLUS multi-org `org ls`, session-authed dashboard reads, logout (`/session`) |

Because the API-key tier is identical to what the SDK exposes, the X-Stamp flow is
the same one documented in [`/relay/quickstart`][quickstart] and [`/signing/`][signing]:
you (or someone) registers an API key in the console and the CLI signs each request
with its private half — the only difference is the CLI pulls the private key from
the OS keychain rather than `process.env`.

The **device-login** tier is unique to the CLI: open the printed URL, sign in with
email/passkey in the browser, approve, paste the phrase the page prints. The CLI
stores the refresh token in the keychain, caches the short-lived access JWT, and
rotates on expiry. Logout revokes.

## Quickstart (API-key tier)

```bash
kryard login --api-key --generate      # mint a P-256 key; prints the PUBLIC half
# → register that public key in the Kryard console (API Keys), then:
kryard org use <organization-id>
kryard whoami
kryard wallets ls
kryard activities ls
kryard relay balance
kryard tui                            # interactive dashboard
```

Import an existing API key instead of generating (the private key is read from
**stdin**, never argv — secrets never show up in `ps` or shell history):

```bash
kryard login --api-key                 # paste the private key hex when prompted
```

CI / non-interactive (no keychain): set `KRYARD_API_PUBLIC_KEY` +
`KRYARD_API_PRIVATE_KEY` and use `--json` for every command — the config + keychain
seam is bypassed entirely.

## Quickstart (device tier)

```bash
kryard login                          # browser-based phrase flow
kryard org ls                         # multi-org users only see this here
kryard org use <id>
kryard logout                         # revoke the session
```

`org ls` (your organizations across the operator account) lives on the device tier,
not the API-key tier, because API keys are scoped to *one* org — a single API key
cannot list the orgs a human user belongs to.

## Relay & sponsorship write lanes

The CLI signs your **own EOA** for the managed-relay + 4337 lanes; the relayer key
itself stays Kryard-custodied. Import your EOA key once (read from **stdin**,
never argv; only the address is ever printed):

```bash
kryard eoa import                     # paste the EOA private key hex → prints the address
kryard eoa address                    # show the stored EOA address
```

Sponsor an EIP-7702 transaction through the [managed relay][relay] — for the
`sponsorExecute` shape, attach the 7702 authorization:

```bash
kryard relay submit --key <relayer-addr-or-id> --chain 11155111 --to 0x… \
    [--value <wei>] [--data 0x…]
# 7702 sponsored execution (signs the authorization with the stored EOA key):
kryard relay submit --key <relayer> --chain 11155111 --to 0x… \
    --authorize <delegate-contract> --auth-nonce <eoa-account-nonce>
kryard relay status <transaction-id>
```

Request ERC-4337 gas sponsorship for a v0.7 UserOperation (the UserOp is read from
a file or stdin as JSON):

```bash
kryard sponsor --chain 11155111 --user-op ./userop.json \
    [--valid-after <unix-sec>] [--valid-until <unix-sec>]
```

::: warning Values the CLI cannot source offline
The 7702 authorization nonce is the EOA's own account nonce (`--auth-nonce`) — the
CLI does not fetch account state to avoid a stale-nonce race; pass it explicitly. Gas
limit is the one other override (`--gas-limit`); the relay pipeline sources
everything else (relayer nonce, fees, gas estimation) server-side.
:::

## Scripting — `--json`

Every command accepts `--json` and prints machine-readable output (skipping the
human formatting). This is what the X-Stamp tier emits anyway — the activity
envelope is JSON — so the scriptable mode is the same shape the SDK returns.

```bash
kryard --json wallets ls | jq '.[] | {id, address, organizationId}'
```

::: tip Global flags
`--json`, `--org <id>` (override the saved default), and `--profile <name>` (select
a named config profile) apply to every command. The defaults are stored in
`~/.config/kryard/config.toml`.
:::

## Security model

- **Secrets in the OS keychain**, never argv, never a config file. `login` and
  `eoa import` read the private key from stdin so it never appears in `ps` or
  shell history. Only the *address* of a stored EOA key is printed at any point.
- **Crypto is byte-pinned** to the canonical SDK/viem — the X-Stamp header, the
  KryardDelegate EIP-712 digest, and the EIP-7702 authorization hash all match
  `@kryard/sdk` / `viem` byte-for-byte. Drift is a failing test, not a production
  incident.
- **No wallet keys leave the client.** The CLI signs the user's own EOA for the
  7702 authorization + 4337 sponsor lanes; Kryard's signer only holds the *relayer*
  key. This is the same division as the SDK — see [`/relay/quickstart`][quickstart].

## Next steps

- [CLI command reference][reference] — every subcommand, every flag.
- [Relay quickstart][quickstart] — the same flow via the SDK, side-by-side.
- [Signing API][signing] — the `/public/v1/*` surface the CLI speaks.

[xstamp]: /signing/#authentication-x-stamp
[sdk]: https://www.npmjs.com/package/@kryard/sdk
[quickstart]: /relay/quickstart
[signing]: /signing/
[relay]: /relay/
[reference]: /cli/reference
