Official command-line interface for the Kash prediction-market protocol.
Single binary, both modes — both non-custodial; user funds always live in Privy-managed MPC smart accounts the user controls. The split is about who orchestrates execution:
- Kash-orchestrated (default) — wraps
@kashdao/sdk, API-key auth, hits the public REST API. The API key is a scoped, revocable delegation the user issues against their own Privy-managed smart account; the user retains full custody at all times. - Self-orchestrated (
kash protocol …) — wraps@kashdao/protocol-sdk, signer + RPC + bundler, reads/writes on-chain. Zero Kash backend dependency.
On both paths Kash never holds funds, never moves funds, never holds keys, and never signs anything. See SECURITY.md § Non-custodial design for the full statement.
The two SDKs are fully decoupled at the npm-package level (so API-only
consumers don't pay the viem cost), but the CLI integrates both behind
clearly-separated namespaces. The protocol-sdk loads lazily on the
first kash protocol … invocation — kash --version and the entire
Kash-orchestrated surface keep their fast cold start.
npm install -g @kashdao/cli
kash auth set-key kash_live_…
kash markets list --status ACTIVE
kash trade buy <market-id> --outcome 0 --amount 10 --wait- Two audiences, equally first-class. Humans get colored tables, spinners,
and tab completion; AI agents get
--json --quiet, structured errors with machine-readable recovery actions, and full command-tree introspection viakash docs --json. - Stable JSON contracts. Every shape an agent or script consumes is
pinned to a Zod schema and exposed via
kash schema --json. - Multi-profile. AWS-CLI-style profile system for juggling test/staging/prod keys.
- Zero-runtime config. Drop in a
kash_*API key and go — no OAuth, no SSO, no browser flow.
- Install · Quickstart · Authentication
- Commands · Multi-profile workflow
- AI-agent / scripting mode · Webhook signing
- Configuration reference · Operational flags
- Stability promise · Troubleshooting
- Examples · Development · License
🧪 Staging release. Production endpoints (
api.kash.bot) are not yet live. Today onlykash_test_*keys work — the CLI auto-routes them to staging (api-staging.kash.bot). To request a staging key, emailengineering@kash.botwith your intended use case. Self-service key issuance, production endpoints, and the Homebrew tap all land with the production launch.
Pick whichever installer fits your environment:
# 1. One-line installer (POSIX shell — checks Node version,
# picks pnpm/yarn/npm automatically, idempotent on re-run).
curl -fsSL https://raw.githubusercontent.com/KashDAO/cli/main/scripts/install.sh | sh
# 2. npm / pnpm / yarn directly:
npm install -g @kashdao/cli
pnpm add -g @kashdao/cli
yarn global add @kashdao/cli
# 3. Zero-install (one-shot via npx — useful for CI smoke checks):
npx -y @kashdao/cli@latest --version
npx -y @kashdao/cli@latest markets list --jsonA kashdao/tap Homebrew tap is planned for the production launch.
The package installs a kash binary. (The internal admin tooling that previously
shipped under the same name is now kash-admin.)
Requirements: Node.js 22 or newer. Works on macOS, Linux, and Windows (WSL recommended). Chmod-based permission tightening is best-effort and skipped on Windows.
The one-line installer accepts --version <semver>, --pm <pnpm|yarn|npm>,
and --dry-run if you want to inspect the resolved command before running it.
# 1. Configure an API key (request a `kash_test_*` staging key by emailing engineering@kash.bot)
kash auth set-key kash_test_…
# 2. Browse markets
kash markets list --status ACTIVE
# 3. Place a trade and wait for settlement
kash trade buy <market-id> --outcome 0 --amount 10 --wait
# 4. Inspect your portfolio
kash portfolio show
kash portfolio positionsRequest a kash_test_* staging key by emailing
engineering@kash.bot with your
intended use case, then store it locally with one of:
# Persisted in ~/.kash/config.json (mode 0600)
kash auth set-key kash_test_…
# Per-shell, no on-disk persistence
export KASH_API_KEY=kash_test_…
# Per-invocation, no persistence
KASH_API_KEY=kash_live_… kash markets listInspect the resolved auth state with kash auth status (offline; does not call
the API). When you need a fresh shell or to log out:
kash auth logout # clears apiKey from the active profile
kash config reset --yes # nuclear: deletes ~/.kash/config.json entirelyEvery authenticated kash command requires an API key. The CLI fails
fast with a clear AUTH_REQUIRED message if no key is configured
(kash config get apiKey to check). Per-key rate limits and audit
attribution apply on every request.
| Group | Subcommands |
|---|---|
auth |
set-key, status, logout |
markets |
list, get, predictions |
quote |
buy, sell — AMM price quotes (markets:quote scope) |
trade |
buy, sell, status, list, confirm |
portfolio |
show, positions |
webhooks |
list, rotate-secret, redeliver, verify, replay |
protocol |
balance, market, quote, position, allowance, smart-account, fees, token-id, decode-revert, trade, userop, watch — direct mode (smart account, ERC-4337) |
eoa |
balance, market, quote, position, allowance, fees, trade — direct mode (vanilla EOA, EIP-1559) |
config |
show, set, profiles, use, remove, reset, export, import |
health |
(top-level; honors --timeout-ms, exits 1 when down) |
version |
(top-level; also accepts --json) |
explain |
[codes...] — error code lookup (multi-code allowed) |
schema |
[name] — JSON Schema for SDK + CLI envelopes |
setup |
first-run interactive wizard (auth + verify + completion) |
trace |
<correlationId> — curated event timeline for a trade |
with-retry |
-- <command> [args...] — retry on recoverable failures |
docs |
full command tree (use --json for the agent surface) |
completion |
install, uninstall |
Run kash <command> --help for full option reference. Every command's --help
includes worked examples for both human and --json --quiet invocations.
The CLI supports AWS-CLI-style profiles for juggling multiple keys:
# Issue keys against multiple environments
kash --profile prod auth set-key kash_live_…
kash --profile staging auth set-key kash_test_…
kash --profile ci auth set-key kash_live_…
# Switch the active profile (writes currentProfile to ~/.kash/config.json)
kash config use staging
# Or the shell-friendly alias `su`:
kash su staging
# List configured profiles
kash config profiles
# {
# "current": "staging",
# "profiles": ["ci", "prod", "staging"]
# }
# Override the active profile per-invocation
kash --profile prod markets list
# Override via environment for a sub-shell
KASH_PROFILE=ci kash trade list
# Remove a profile (refuses to remove the active one)
kash config remove stagingThe on-disk file at ~/.kash/config.json looks like:
{
"version": 1,
"currentProfile": "staging",
"profiles": {
"prod": { "apiKey": "kash_live_…" },
"staging": { "apiKey": "kash_test_…", "baseUrl": "https://api-staging.kash.bot/v1" },
"ci": { "apiKey": "kash_live_…" }
}
}Resolution order: explicit --profile <name> flag → KASH_PROFILE env →
currentProfile in the file → default.
Every command supports --json and --quiet for machine consumption:
# JSON mode, suppress spinners/info — ideal for AI agents and CI.
kash markets list --status ACTIVE --json --quiet | jq '.data[0].id'
# Place a trade, block on settlement, parse the resulting tx hash.
kash trade buy <id> --outcome 0 --amount 5 --wait --json --quiet | jq -r .txHash
# Stream paginated reads as NDJSON (one record per line).
kash markets list --ndjson | while read -r line; do echo "$line" | jq -r .id; doneThree commands expose the CLI's shape in machine-readable form so an AI agent can plan calls without scraping help text:
| Command | What it returns |
|---|---|
kash docs --json |
Full command tree (every command, argument, option, alias, default value). |
kash schema [<name>] --json |
JSON Schema for SDK request/response shapes + CLI-owned envelopes (CreateTradeBody, TradeResource, MarketResource, CliErrorEnvelope, …). |
kash explain [<code>] --json |
Error catalog with recoverable, retryAfterMs, docsUrl, and structured recovery actions[]. |
For first-time agent setup, dump everything into one document:
kash version --json > kash-surface.json # cli/sdk/node/platform versions
kash docs --json >> kash-surface.json # full command tree
kash schema --json >> kash-surface.json # every JSON Schema
kash explain --json >> kash-surface.json # every error code + recovery actionsSee examples/agent-discovery.py for a runnable
recipe that loads this into an agent's startup context.
Every command emits this shape on --json failures. The shape is
SemVer-stable; pin to it.
{
"ok": false,
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded",
"recoverable": true,
"retryAfterMs": 30000,
"docsUrl": "https://kash.bot/docs/api/rate-limits",
"requestId": "req_abc",
"suggestion": "Retry in 30s. Upgrade for higher limits: https://kash.bot/pricing",
"actions": [
{
"type": "wait_and_retry",
"delayMs": 30000,
"description": "Wait 30s then re-run the same command."
},
{
"type": "open_url",
"url": "https://kash.bot/pricing",
"description": "Upgrade tier for higher rate limits."
}
]
}
}Required: code, message, recoverable, actions. Optional:
retryAfterMs, docsUrl, requestId, suggestion. Action variants:
run_command, set_env, wait_and_retry, open_url, check_input.
Fetch the formal Zod-derived JSON Schema with:
kash schema CliErrorEnvelope --json0— success1— generic error (validation, server, network, etc.)2— auth failure (missing or invalid API key, missing scope)
For trade-creation calls (kash trade buy/sell), pass either an explicit
--idempotency-key <uuid> or --auto-idempotency-key to let the CLI generate
one. The resolved key is surfaced in the response, so a transient failure
mid-creation can be retried with the same key — the server guarantees the
trade is created at most once.
# Generate, capture, retry safely:
kash trade buy <id> --outcome 0 --amount 10 \
--auto-idempotency-key --wait --json --quietkash with-retry [opts] -- <command> [args...] re-runs any kash
command when the structured error envelope reports a recoverable
failure. The retry policy reads code (RATE_LIMITED, NETWORK,
TIMEOUT, MAINTENANCE, SERVER_ERROR are retryable;
INVALID_INPUT, AUTH_REQUIRED, NOT_FOUND etc. fail fast) and
honours the retryAfterMs field when present, falling back to
exponential backoff otherwise.
# Retry up to 5 times, with the wait dictated by the server.
kash with-retry --max-attempts 5 -- markets list --status ACTIVE --json --quiet
# Idempotent retry across attempts (the inner key persists).
kash with-retry -- trade buy <id> --outcome 0 --amount 10 \
--auto-idempotency-key --wait --json --quietThe wrapped command MUST come after --. Without --json, the
wrapper falls back to a fixed exponential schedule (1s, 2s, 4s, …
capped at --max-delay-ms).
kash trace <correlationId> returns the curated event timeline for a
single trade — every event the pipeline emits as the trade moves through
intent parsing → funding → bridge → execution → webhook delivery.
# Get the correlation id from any trade response and trace it.
CID=$(kash trade buy <market-id> --outcome 0 --amount 10 --json --quiet | jq -r .correlationId)
kash trace "$CID"The server returns a sanitized timeline — raw event payloads are never
exposed; only an allowlisted subset of fields (txHash, tokensOut,
errorCode, etc.) appears. JSON output is pinned to GetTraceResponse
(fetch the schema with kash schema TraceResource --json).
Pass --dry-run to kash trade buy/sell to preview the request without
sending it. The CLI validates inputs, resolves the idempotency key, and
emits the would-be body — no API call, no auth required. Useful for
agents planning trades and humans sanity-checking before committing.
$ kash trade buy <id> --outcome 0 --amount 10 --dry-run --json
{
"wouldSend": {
"marketId": "9f0b…",
"outcomeIndex": 0,
"amount": "10",
"side": "buy"
},
"idempotencyKey": null,
"endpoint": { "method": "POST", "path": "/v1/trades" }
}The envelope is pinned to TradeDryRunEnvelope — fetch the full Zod
schema with kash schema TradeDryRunEnvelope --json.
Kash webhooks are signed with HMAC-SHA256 in a Stripe-compatible format
(X-Kash-Signature: t=<unix-ms>,v1=<hex>). The SDK's verifySignature
helper handles parsing, replay-window enforcement, and constant-time
comparison.
import { KashClient } from '@kashdao/sdk';
const kash = new KashClient({}); // no apiKey needed for verifySignature
// In your HTTP handler — use the *raw* request body, not a re-serialised JSON.
const result = await kash.webhooks.verifySignature(rawBody, signatureHeader, secret);
if (!result.valid) {
return res.status(400).send(result.reason);
}Rotate the signing secret with kash webhooks rotate-secret (the new
plaintext is shown ONCE — capture it). See
examples/webhook-receiver.ts for a
production-shaped Fastify receiver.
Direct mode bypasses the Kash backend entirely and talks to the on-chain
contracts via @kashdao/protocol-sdk. It's for users
who want to read AMM state, quote trades, or submit UserOps from their
own signer without ever touching the public API.
The protocol-sdk loads lazily on first use, so Kash-orchestrated users
pay zero cold-start cost for it. kash --version and the entire
kash <auth|markets|trade|…> surface stay fast.
| Command | What it does |
|---|---|
kash protocol balance [account] |
On-chain USDC + native gas balances. Defaults to the profile's smart account. |
kash protocol market <address> |
Full AMM state: status, reserve, outstanding tokens, weights, probabilities. |
kash protocol quote <address> --side … |
Buy/sell quote against on-chain reserves. |
kash protocol position <market> [account] |
On-chain ERC-1155 outcome-token holdings (per outcome). |
kash protocol allowance <spender> [account] |
USDC allowance from account → spender. Skips approve when sufficient. |
kash protocol smart-account compute --owner … |
Derive the deterministic SA address for an EOA owner (no deployment needed). |
kash protocol smart-account is-deployed [address] |
Check whether an SA has bytecode on-chain. |
kash protocol fees |
EIP-1559 fee estimate via eth_feeHistory. Tunable percentile / multiplier. |
kash protocol token-id --market-id … --outcome … |
Compute the ERC-1155 token id (offline; no RPC). |
kash protocol decode-revert <0x…> |
Decode raw revert data into (name, args) via Market + EntryPoint ABIs. |
kash protocol trade {buy,sell,close,approve} runs the full one-shot
flow (prepare → simulate → sign → submit → wait). Default --wait,
default 0.5% slippage tolerance, default 5-minute deadline.
# Place a BUY using the configured signerKeyRef.
kash protocol trade buy 0xMarket... -o 0 -a 10
# Preview only — populated UserOp + hash, no signing.
kash protocol trade buy 0xMarket... -o 0 -a 10 --dry-run --json
# Fire-and-forget; print userOpHash and exit.
kash protocol trade buy 0xMarket... -o 0 -a 10 --no-wait --json --quietFor operators who sign on a different machine than the one preparing or submitting:
# Machine A (no signer): prepare a fully-populated UserOp + hash.
kash protocol userop build buy 0xMarket... -o 0 -a 10 --out trade.json
# Machine B (signer-only): sign trade.json externally, write
# the resulting signature into the userOp.signature field.
# Machine C: submit and wait.
kash protocol userop submit signed.json --waitkash protocol userop {hash,simulate,receipt,wait} are also exposed.
Long-running NDJSON event stream for a market. Best-effort delivery —
on RPC reconnect missed events are NOT replayed; pair with
kash markets predictions <id> (indexer-backed) for gap-free coverage.
kash protocol watch 0xMarket... --json --quiet | jq -cPress Ctrl-C to terminate cleanly. --max-events <n> and
--timeout-ms <n> bound the run.
Parallel namespace for operators who sign vanilla EIP-1559
transactions (no smart account, no bundler). Same surface as
kash protocol minus the UserOp lifecycle:
| Command | Notes |
|---|---|
kash eoa balance [account] |
Defaults to the EOA address (signer's). |
kash eoa market <address> |
Same as kash protocol market. |
kash eoa quote <address> |
Same as kash protocol quote. |
kash eoa position <market> |
Same as kash protocol position. |
kash eoa allowance <spender> |
Same as kash protocol allowance. |
kash eoa fees |
Same as kash protocol fees. |
kash eoa trade {buy,sell,close,approve} |
Vanilla tx (no UserOp). |
Required config: rpcUrl, defaultChainId, signerKeyRef. EOA mode
ignores smartAccount, bundlerUrl, and bundlerProvider.
kash eoa balance
kash eoa trade buy 0xMarket... -o 0 -a 10 --jsonDirect mode requires four pieces of config, all per-profile or via env:
| Field | Env | Notes |
|---|---|---|
rpcUrl |
KASH_RPC_URL |
EVM RPC URL (Alchemy, Infura, your own node, anvil). |
smartAccount |
KASH_SMART_ACCOUNT |
The 0x-prefixed smart account address to read. |
bundlerUrl |
KASH_BUNDLER_URL |
ERC-4337 bundler. Required only for write paths. |
bundlerProvider |
KASH_BUNDLER_PROVIDER |
One of flashbots, pimlico, alchemy, generic. |
signerKeyRef |
KASH_SIGNER_KEY_REF |
file:<path> or env:<NAME>. Required for writes. |
kash config set rpcUrl https://base-mainnet.g.alchemy.com/v2/<key>
kash config set smartAccount 0xabc…
kash protocol balance --jsonThe CLI never persists raw private keys — only references. file: reads
from a 0x-prefixed hex file at the path; env: reads from a process env
var at invocation time.
# Read your own balances
kash protocol balance --json
# → { "account": "0x…", "chainId": 8453, "usdcAtomic": "1000000", "gasWei": "5000000000000000" }
# Inspect a market on-chain
kash protocol market 0xMarket… --json | jq '.outcomes[].probability'
# Quote a $10 buy on outcome 0
kash protocol quote 0xMarket… --side buy --outcome 0 --amount 10 --json| Field | Type | Default | Notes |
|---|---|---|---|
apiKey |
string? |
unset | Must start with kash_. Stored at mode 0600. |
baseUrl |
string? |
https://api.kash.bot/v1 |
Validated as a URL. |
defaultChainId |
number? |
8453 (Base mainnet) |
Used when chain id matters; positive integer. |
rpcUrl |
string? |
unset | Direct-mode EVM RPC URL. |
smartAccount |
string? |
unset | Direct-mode smart account address (0x…). |
bundlerUrl |
string? |
unset | ERC-4337 bundler URL (write paths only). |
bundlerProvider |
string? |
unset | flashbots | pimlico | alchemy | generic. |
signerKeyRef |
string? |
unset | file:<path> or env:<NAME> — never raw keys. |
| Variable | Field | Notes |
|---|---|---|
KASH_API_KEY |
apiKey |
Highest precedence for the auth key. |
KASH_BASE_URL |
baseUrl |
|
KASH_CHAIN_ID |
defaultChainId |
Must parse as a positive integer. |
KASH_DEBUG |
(mirrors --debug) |
Set to 1/true/yes/on to enable lifecycle traces. |
KASH_RPC_URL |
rpcUrl |
Direct-mode RPC URL. |
KASH_SMART_ACCOUNT |
smartAccount |
Direct-mode smart account address. |
KASH_BUNDLER_URL |
bundlerUrl |
Direct-mode ERC-4337 bundler URL. |
KASH_BUNDLER_PROVIDER |
bundlerProvider |
Direct-mode bundler provider preset. |
KASH_SIGNER_KEY_REF |
signerKeyRef |
file:<path> or env:<NAME> — never raw keys. |
KASH_PROFILE |
(active profile) | Equivalent to --profile <name> for the next invocation. |
KASH_CONFIG |
(config path) | Equivalent to --config <path>. |
NO_COLOR |
(color output) | Set to anything truthy to disable ANSI escapes. |
For each field, highest precedence first:
- Environment variable.
- Active profile in
~/.kash/config.json. - Built-in default.
For the active profile name itself:
- Explicit
--profile <name>flag. KASH_PROFILEenvironment variable.currentProfilefield in the config file.default.
For the config file path itself:
- Explicit
--config <path>flag. KASH_CONFIGenvironment variable.~/.kash/config.json.
| Flag | Purpose |
|---|---|
--profile <name> |
Pick a stored credential profile. |
--config <path> |
Override ~/.kash/config.json location. |
--debug |
Stream SDK request/response/retry/error traces to stderr. With --json becomes NDJSON. |
--base-url <url> |
Override API base URL (staging tests, CI matrix builds). |
--max-retries <n> |
Override SDK retry budget (0-10). |
--timeout-ms <n> |
Override SDK request timeout. |
--json |
Emit machine-readable JSON instead of human-formatted output. |
--fields <list> |
Project comma-separated dot-paths on --json/--ndjson output (e.g. id,outcomes.label). See Field projection. |
--filter <expr> |
Boolean predicate on --json/--ndjson entries (e.g. 'status==ACTIVE && outcomeCount>2'). See Filter DSL. |
--quiet |
Suppress spinners, progress, and informational logs. |
--no-color |
Disable ANSI escapes (also honors NO_COLOR). |
Pass --fields <list> alongside --json or --ndjson to narrow output to
the dot-paths you care about. Reduces tokens for AI agents and noise for
shell pipelines, without spinning up jq.
# Top-level fields:
kash markets list --json --fields id,title,status
# Nested paths and array splay (entries inside arrays project per-element):
kash markets get <id> --json --fields title,outcomes.label,outcomes.tokenAddress
# Paginated envelopes preserve `pagination`/`meta` unchanged; only the
# `data` array entries are projected.
kash trade list --json --fields id,status,txHash --quiet | jq -cPass --filter <expr> alongside --json or --ndjson to keep only
entries matching a boolean predicate. Tiny DSL — ==, !=, <,
<=, >, >=, &&, ||, dotted field paths, numbers, booleans,
null, bare-word string values. Composes with --fields: filter
runs first, then projection narrows the survivors.
# Equality + comparison + boolean composition.
kash markets list --json --filter 'status==ACTIVE && outcomeCount>2'
# Filter on a dotted path.
kash trade list --json --filter 'webhookDelivery.status==delivered'
# Compose with --fields. The filter sees the FULL record; projection
# runs on what survives.
kash markets list --json --filter 'status==ACTIVE' --fields id
# NDJSON streams skip non-matching records entirely.
kash trade list --ndjson --filter 'side==buy && status==completed' | wc -lType-coerced equality means outcomeCount==2 matches both 2 and
"2". Ordered comparisons (<, >, <=, >=) require both sides
to be finite numbers; otherwise the entry fails the predicate. The
DSL is intentionally narrow — for richer queries, pipe --json through
jq.
Path syntax: comma-separated, dot-segmented. Segments must match
[A-Za-z_][A-Za-z0-9_]*. Missing paths drop silently (jq semantics).
The flag is a no-op for human output and for non-JSON commands.
With --debug --json, each SDK lifecycle event is emitted to stderr as a
single line of NDJSON. Pipe stderr separately if your tooling expects clean
NDJSON on a single stream.
reason is one of rate_limit, server_error, network, timeout. Without
--json, the same events are rendered as compact human-readable lines on
stderr.
@kashdao/cli is currently 0.x — under Semantic Versioning's
own rules, 0.x minor bumps may technically break anything. We commit to
treating the contracts below as if SemVer-stable even before 1.0. Additions
are minor bumps, behaviour changes or removals are major bumps. The 1.0
release will lock this in formally and remove the asterisk; until then, every
0.x release that ships will be reviewed against this list.
--jsonoutput shapes for every command (validated by Zod schemas available viakash schema --json).- The CLI error envelope (
kash schema CliErrorEnvelope --json). - The version manifest shape (
kash version --json). - The
--debugNDJSON trace shape (documented above). - Exit codes (
0ok,1generic error,2auth failure). - Error
codestrings in the catalog (kash explain --json). New codes appear in minor versions; existing codes never change meaning. - The
~/.kash/config.jsonv1 file format. Migrations to v2 will be automatic and forward-compatible.
- Human-mode (non-
--json) output formatting (tables, prose, color choices). Scripts that rely on it should switch to--json --quiet. - Internal module structure (
packages/cli/src/); only the binary surface is the public API. - Help text wording.
Behaviour changes that don't break the stable contracts are minor bumps without warning. Anything that does will:
- Be announced in the
CHANGELOG.mdof the deprecating release. - Continue to work for at least one minor version.
- Emit a stderr warning when used (humans only; agents using
--jsonsee no functional change until the major bump).
You haven't set an API key. Run kash auth set-key kash_test_…
(request a staging key by emailing engineering@kash.bot) or set
KASH_API_KEY in your environment. Every authenticated command needs
a key — only kash --version, kash --help, and kash explain <code>
work fully offline.
CLI flag values are validated up front. The error envelope's actions[0]
of type check_input names the bad field. Look up the constraints in
the Operational flags table or run
kash <command> --help.
You're over your tier's rate limit. The error envelope tells you exactly
how long to wait. Either honor it programmatically (see
examples/trade-replay.sh) or upgrade at
https://kash.bot/pricing.
A duplicate Idempotency-Key, the trade is awaiting high-value confirmation,
or the market closed between fetch and order. Inspect with
kash trade status <id> before retrying.
Network path issues. The CLI already retries automatically; this means
retries were exhausted. Check connectivity to api.kash.bot. Retry with
--timeout-ms 60000 --max-retries 5 if your environment has latency
spikes.
The on-disk ~/.kash/config.json is malformed. The error message names
the field. Run kash config reset to start fresh, or hand-edit the file
(it's valid JSON).
The internal admin tooling used to ship a binary also called kash. It
has been renamed to kash-admin. If you have both installed, run
which kash to confirm you're invoking the public CLI.
Run with --debug to see SDK request/response/retry traces. With
--debug --json you get NDJSON on stderr — pipe it through jq to inspect
the request flow:
kash trade buy … --debug --json --quiet 2> >(jq .)Capture kash version --json for issue triage:
kash version --json
# {
# "cli": "0.1.0",
# "sdk": "0.1.0",
# "node": "v22.4.1",
# "platform": "darwin",
# "release": "23.6.0",
# "arch": "arm64"
# }Run kash explain <code> for any error code to get the catalog entry
including recommended recovery actions. File a bug at
https://github.com/KashDAO/cli/issues with the version manifest, the
requestId from the failing envelope, and the failing command.
Worked recipes for both human scripts and AI agents in
examples/:
| File | Audience | Demonstrates |
|---|---|---|
buy-and-follow.sh |
Bash scripts, CI | Place a trade, block on settlement with --wait, parse the tx hash from --json --quiet output. |
trade-replay.sh |
Reliability engineers | --auto-idempotency-key for safe retries; capture and reuse the generated key on failure. |
portfolio-export.sh |
Data ops, accountants | Stream all positions and trades as NDJSON; pipe through jq for filtering. |
webhook-receiver.ts |
Backend engineers | Production-shaped Fastify receiver verifying X-Kash-Signature with verifySignature. |
ai-agent.py |
LLM/agent engineers | Python loop calling kash --json --quiet, recovering from errors via kash explain. |
agent-discovery.py |
LLM/agent engineers | Use kash docs --json and kash schema to teach an agent the CLI surface at startup. |
pnpm --filter @kashdao/cli build
pnpm --filter @kashdao/cli test:unit
pnpm --filter @kashdao/cli typecheck
pnpm --filter @kashdao/cli lintRun the bundled binary against a local API:
KASH_BASE_URL=http://localhost:3001/v1 \
KASH_API_KEY=kash_test_… \
node packages/cli/dist/index.js markets listThe CLI ships as a single ESM bundle (~85 KB) with an executable
shebang. Dependencies pinned in package.json: commander, chalk,
cli-table3, omelette, ora, zod, zod-to-json-schema, plus
@kashdao/sdk (workspace).
- General bugs: https://github.com/KashDAO/cli/issues
- Security disclosures: see
SECURITY.md. Emailsecurity@kash.bot; do not file a public issue.
MIT — see LICENSE.