Public CLI for the Bron API — a non-custodial treasury management platform for digital assets. Single static binary, regenerated from the OpenAPI spec on every API release. Designed to be a first-class surface for both humans and LLM agents.
Use it to script everything you do in the Bron UI: list accounts and balances, create and approve withdrawals, manage address books, query transaction history, set up automation. If you don't have a Bron account yet, start here.
- An active Bron workspace (sign up at bron.org).
- A workspace member with API key permissions in that workspace.
- Access to the Bron UI to register the public half of an API key (Settings → API keys).
If you only need a UI client, you don't need the CLI. It targets API consumers — automations, treasury scripts, on-call dashboards, and agent integrations.
brew install bronlabs/apps/bronPicks the right artifact for your OS/arch automatically. Available builds: darwin-arm64, darwin-amd64, linux-arm64, linux-amd64, windows-amd64.exe.
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -L "https://github.com/bronlabs/bron-cli/releases/latest/download/bron-${OS}-${ARCH}" -o /usr/local/bin/bron
chmod +x /usr/local/bin/bronWindows: download bron-windows-amd64.exe from the releases page and put it on %PATH%.
go install github.com/bronlabs/bron-cli/cmd/bron@latestThe CLI talks to the Bron API with a per-key JWT signature. You generate a P-256 keypair locally, register the public half with Bron (UI → API keys), and keep the private half on disk in a 0600 file (the CLI refuses to load anything more permissive).
# 1. generate a keypair (private goes to a file, public is printed to stdout)
bron auth keygen --file ~/.config/bron/keys/me.jwk
# 2. paste the printed public JWK into the Bron UI to authorize this key (Bron returns nothing — the binding is by `kid`)
open https://app.bron.org/settings/api-keys # Settings -> API keys
# 3. wire it into a profile
bron config init --name default --workspace <workspaceId> --key-file ~/.config/bron/keys/me.jwk
# 4. sanity-check
bron config
bron workspace infoYou can have multiple profiles (--name staging etc.) and switch with bron config use-profile <name>. Per-call overrides via --profile, --workspace, --key-file, --proxy or env vars (BRON_PROFILE, BRON_WORKSPACE_ID, BRON_API_KEY / BRON_API_KEY_FILE, BRON_PROXY). BRON_API_KEY carries the raw JWK bytes, intended for secret-store wrappers (op run, vault, …) that pipe the value at startup so it never lives on disk.
If you sit behind an HTTP/HTTPS proxy: persist it once with bron config set proxy=http://user:pass@host:8080, or set HTTPS_PROXY / HTTP_PROXY in the environment — both are honored automatically.
Compact list of every command — placeholders in <angle brackets>, real-looking values where they matter (enums, asset/network ids).
Bron CLI — public API client.
Resources follow the URL: bron <resource> <verb>. The <workspaceId> is implicit (from the active profile config).
Examples:
bron help
bron help <resource> <verb> [--output yaml]
bron help <topic> # signing | profiles | output | body | errors | idempotency | agents
bron help --schema # full CLI schema (every command + types) as one JSON
bron auth keygen --file ~/.config/bron/keys/me.jwk
bron config
bron config init --workspace <workspaceId> --key-file ~/.config/bron/keys/me.jwk
bron config use-profile production
bron config set workspace=<workspaceId> key_file=~/.config/bron/keys/me.jwk
bron accounts list --accountTypes vault --limit 50
bron accounts get <accountId>
bron balances list --accountId <accountId> --assetId 5000 --networkId ETH --nonEmpty true
bron tx list --transactionStatuses waiting-approval,signing --limit 50
bron tx list --transactionTypes withdrawal,allowance --createdAtFrom 2026-04-01
bron tx get <transactionId>
bron tx events <transactionId>
bron tx withdrawal \
--accountId <accountId> \
--externalId <idempotencyKey> \
--description "Q2 vendor payout" \
--params.amount=100 \
--params.assetId=5000 \
--params.networkId=ETH \
--params.toAddress=<address> \
--params.memo="invoice-42" \
--params.feeLevel=medium \
--params.includeFee=true
bron tx allowance # see "bron tx allowance --help" for params
bron tx bridge
bron tx deposit
bron tx defi
bron tx defi-message
bron tx intents
bron tx stake-delegation
bron tx stake-undelegation
bron tx stake-claim
bron tx stake-withdrawal
bron tx address-creation
bron tx address-activation
bron tx fiat-in
bron tx fiat-out
bron tx withdrawal --file ./tx.json
cat tx.json | bron tx withdrawal --file -
bron tx withdrawal --json '{"accountId":"<accountId>","params":{"amount":100,"assetId":"5000"}}'
bron tx withdrawal --file ./tx.json --params.amount=250 --externalId <idempotencyKey>
bron tx approve <transactionId>
bron tx decline <transactionId>
bron tx cancel <transactionId>
bron tx create-signing-request <transactionId>
bron tx accept-deposit-offer <transactionId>
bron tx reject-outgoing-offer <transactionId>
bron tx withdrawal --accountId <accId> --externalId <idem> \
--params.amount=100 --params.assetId=5000 --params.networkId=ETH \
--params.toAddressBookRecordId=<recordId>
# --params.toAddress=<rawAddress> on-chain address (raw)
# --params.toAddressBookRecordId=<recordId> pre-saved address-book entry (validated by Bron)
# --params.toAccountId=<accountId> internal transfer (instant, no fee path)
# --params.toWorkspaceTag=<tag> route to another Bron workspace
# Lower-level — when no "tx <type>" shortcut fits or you want full control:
bron tx create \
--transactionType withdrawal \
--accountId <accountId> \
--externalId <idempotencyKey> \
--params.amount=100 \
--params.assetId=5000 \
--params.networkId=ETH \
--params.toAddress=<address>
bron tx dry-run --file ./tx.json
bron tx bulk-create --file ./batch.json
bron tx list --output yaml --includeEvents true
bron tx list --output table --columns transactionId,status,transactionType,createdAt
bron tx list --output table --query '.transactions[*]'
bron tx get <transactionId> --query '.status'
bron deposit-addresses list --accountId <accountId> --networkId ETH
bron activities list --accountIds <accountId> --activityTypes login,transaction-completed --limit 50
bron members list --includePermissionGroups true --includeUsersProfiles true
bron stakes list --accountId <accountId> --assetId 5000
bron transaction-limits list --statuses active
bron transaction-limits get <limitId>
bron workspace info --includeSettings true
bron assets list --search btc --assetType blockchain --networkIds ETH --limit 50
bron assets get <assetId>
bron assets prices
bron networks list --networkIds ETH,TRX
bron networks get <networkId>
bron symbols list --assetIds 5000,5001
bron symbols prices --baseAssetIds 5000
bron intents create --json '{"params":{...}}'
bron intents get <intentId>
bron address-book list --networkIds ETH,TRX
bron address-book create --name "Alice" --address <address> --networkId ETH
bron address-book delete <recordId>
bron completion install # auto-detects $SHELL (zsh|bash|fish)
Flags:
--cell-max int max chars per table cell; 0 disables truncation (default 28)
--columns string comma-separated keys to keep, e.g. transactionId,status,createdAt (works for json/yaml/jsonl/table)
--embed string comma list of related entities to embed in the response (e.g. prices,assets,events,permission-groups)
-h, --help help for bron
--key-file string path to JWK private key (overrides profile)
--output string output format: table|json|yaml|jsonl (default json)
--profile string config profile name
--proxy string HTTP/HTTPS proxy URL (overrides profile)
--query string JSONPath subset filter, e.g. .transactions[*].transactionId
--schema print JSON schema (request + response) for the command instead of running it
-v, --version version for bron
--workspace string workspace id (overrides profile)
Use "bron <resource> <verb> --help" for any command's flags.
BRON_PROFILE=staging bron tx list
BRON_WORKSPACE_ID=<workspaceId> bron tx list
BRON_API_KEY_FILE=~/.config/bron/keys/other.jwk bron tx list
BRON_API_KEY="$(op read 'op://Personal/Bron/jwk')" bron tx list # raw JWK bytes; never lands on disk
BRON_PROXY=http://user:pass@proxy:8080 bron tx list
HTTPS_PROXY=http://proxy:8080 bron tx list # standard env vars are honored too
BRON_CONFIG=/tmp/cli.yaml bron config show
BRON_API_KEY (raw JWK bytes) wins over BRON_API_KEY_FILE and key_file: when both are set — pair it with a secret store (1Password, Vault, sops) so the private JWK never lives on disk. The CLI strips the var from its environment after reading, so child processes don't inherit it.
Every endpoint in the OpenAPI spec becomes a command:
bron <resource> <verb> [<positional-id>...] [--<field>...] [--file <path> | --json '{...}']
<resource>— first URL segment, lowercased and shortened where useful (txfortransactions,address-bookforaddress-book-records, …)<verb>— remaining path segments verbatim (list,get,create,accept-deposit-offer, …){workspaceId}is implicit (from profile or--workspace); other path params are positional in URL order- query parameters become
--<name>flags; body fields become--<field>/--<a>.<b>flags
Special case — bron tx <type> (e.g. bron tx withdrawal, bron tx allowance, bron tx stake-delegation): shortcut for bron tx create --transactionType <type>, with the type-specific body fields exposed as --params.<field>. List the available types and verbs with bron tx --help.
bron doubles as a Model Context Protocol stdio server when invoked with the mcp subcommand — same pattern as gh mcp / stripe mcp. Every public-API endpoint the CLI knows about is exposed as a typed MCP tool (bron_tx_list, bron_balances_list, bron_tx_withdrawal, bron_tx_approve, …), plus a long-poll bron_tx_wait_for_state for waiting on a transaction's terminal state without polling.
Auth follows the same precedence as the rest of the CLI: active profile, then env (BRON_PROFILE, BRON_API_KEY / BRON_API_KEY_FILE, BRON_WORKSPACE_ID, BRON_BASE_URL, BRON_PROXY).
# Claude Code
claude mcp add bron -- bron mcp
# Claude Code, with the JWK fetched on-demand from 1Password (never lands on disk)
claude mcp add bron --env BRON_API_KEY='op://Personal/Bron/private-jwk' -- op run -- bron mcp
# Cursor / Claude Desktop / VS Code — drop into your mcp.json:
{
"mcpServers": {
"bron": { "command": "bron", "args": ["mcp"] }
}
}Pass --read-only to register only GET endpoints + tx dry-run. Use this for agents that should observe a workspace without being able to move funds (audit pipelines, untrusted prompt sources, CI runs):
claude mcp add bron-readonly -- bron mcp --read-onlyBron Desktop has its own built-in MCP server when installed — use that for operator-at-their-desk workflows. Use bron mcp for headless / CI / API-key automations where Desktop isn't running.
bron tx subscribe is "GET extended" — same filters as bron tx list, but the connection stays open. The server replays the historical match as the first batch, then streams live updates as they happen. Output is JSONL only (--output is ignored for this command); pipe to jq for any reshaping.
# Live-only, no history (recommended for long-running watchers).
bron tx subscribe --no-history
# Filter the same way you would on `bron tx list`.
bron tx subscribe --no-history --transactionStatuses signing-required,waiting-approval
bron tx subscribe --accountId <accountId> --transactionTypes withdrawal,bridge
# Pipe to jq for any extra filtering / reshaping.
bron tx subscribe --no-history | jq 'select(.status == "completed")'Without --no-history the server replays everything matching the filters before going live — that can be a lot on a busy workspace. Pair with explicit filters or pass --no-history if you only care about new events.
bron tx list --output json # default — pretty-printed JSON, colored on TTY
bron tx list --output yaml
bron tx list --output jsonl
bron tx list --output table # nested objects collapse to {…}/[…N], *At fields render as ISO UTC
# JSONPath subset filter (no jq, no select — just navigation)
bron tx list --query '.transactions[*].transactionId'
bron tx get <id> --query '.status'
bron accounts list --output table --query '.accounts[*]'
# --columns picks fields (works for json / yaml / jsonl / table) in the listed order.
# Supports dot-paths: table shows flat headers, json/yaml emit nested objects.
bron tx list --output table --columns transactionId,transactionType,params.amount,params.assetId,createdAt
bron tx list --output json --columns transactionId,status,params.amount
bron tx get <id> --columns transactionId,status,paramsJSON output is colored when stdout is a TTY. Disable with NO_COLOR=1, force on with FORCE_COLOR=1.
Table cells are truncated at 28 characters by default (long IDs/addresses get …). Override with --cell-max <N>; pass --cell-max 0 to disable truncation entirely (useful when piping to scripts that need full values).
bron <resource> <verb> --schema (or bron help <resource> <verb> --schema) prints the JSON schema (path/query params, body, every response status) — handy for AI agents or quick API exploration.
The --schema output is OpenAPI 3.1; the wire shape is stable across the 0.x line. Major format migrations (e.g. OpenAPI 4) ship with a CLI major-version bump.
For heavier transformations, pipe to jq:
bron tx list --output json | jq '.transactions[] | select(.status=="signed")'Date-shaped query parameters and body fields (anything the OpenAPI spec marks as format: "date-time-millis") accept both ISO-8601 (2026-04-01T00:00:00Z, 2026-04-01) and millisecond-epoch integers — the CLI normalizes to millis before sending. The set of recognized names is auto-derived from the embedded spec at startup, so any new @EpochMillis field added on the backend picks up coercion as soon as make spec regenerates the SDK — no hardcoded suffix list to drift.
Two baseline sources (mutually exclusive), then field-flag overlay:
--file <path>— read body from a file (-= stdin), or--json '{...}'— inline JSON string.--<field>/--<a>.<b>— structured field flags. Override matching paths in the baseline.
# baseline from file
bron tx withdrawal --file ./tx.json
# baseline from stdin
cat tx.json | bron tx withdrawal --file -
# baseline as inline JSON
bron tx withdrawal --json '{"accountId":"acc_xxx","params":{"amount":100,"assetId":20145}}'
# baseline + per-field overrides
bron tx withdrawal --file ./tx.json \
--externalId <idempotencyKey> \
--params.amount=250 \
--params.feeLevel=HIGHMapped from HTTP status:
| Status | Exit | |
|---|---|---|
401 / 403 |
3 |
not authorized |
404 |
4 |
not found |
400 |
5 |
bad request |
409 |
6 |
conflict |
429 |
7 |
rate limited |
5xx |
8 |
server error |
| other / non-API | 1 |
bron help # navigation page (topics + entry points)
bron --help # full root help (flags + examples)
bron help <topic> # topic blurb (signing | profiles | output | body | errors | idempotency | agents | mcp)
bron help <resource> # list verbs for the resource
bron help <resource> <verb> # human help (same as `bron <r> <v> --help`)
bron help <resource> <verb> --schema # per-command JSON schema (machine-readable)
bron help --schema # full CLI schema as one OpenAPI 3.1 document
bron --output yaml help <r> <v> --schema # same per-command dump in YAML
--schema is the entry point for any tooling that wants to introspect the CLI without parsing freeform --help text. Output is a strict OpenAPI 3.1 fragment; pipe to jq / swagger-cli / any spec consumer.
make build # incremental: regen if spec/cligen changed, then go build
make generate # force-run cligen against the OpenAPI spec
make dist # cross-compile darwin/linux × amd64/arm64 into bin/
make testVERSION=<tag> make build stamps the binary with bron --version.
Generated files (generated/commands.go, helpdoc.go, spec.go, spec.json) are committed alongside the spec so go install github.com/bronlabs/bron-cli/cmd/bron@latest works on a fresh clone. make build regenerates them via cligen; CI verifies they stay in sync with the spec. bin/ is gitignored.
bron-sdk-go provides JWT signing, the HTTP client (retries, APIError), and shared types. The CLI adds dynamic command dispatch, profile config, output formatting.
While on 0.x, breaking changes may land in any minor bump. We treat the
exit-code contract, flag/verb names, and the --schema output shape as the
stable surface — best-effort across 0.x, fully versioned across 1.x+. Any
intentional breaking change is called out in the release notes for the
relevant tag on the releases page.
MIT License - see LICENSE file for details.