@kashdao/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/CONTRIBUTING.md +159 -0
- package/LICENSE +21 -0
- package/README.md +868 -0
- package/SECURITY.md +110 -0
- package/dist/account-AVFLEM5D.js +90 -0
- package/dist/account-AVFLEM5D.js.map +1 -0
- package/dist/auth-GUJCVKTD.js +239 -0
- package/dist/auth-GUJCVKTD.js.map +1 -0
- package/dist/chunk-BN2CUM42.js +9 -0
- package/dist/chunk-BN2CUM42.js.map +1 -0
- package/dist/chunk-BRK7KJ4O.js +154 -0
- package/dist/chunk-BRK7KJ4O.js.map +1 -0
- package/dist/chunk-KMBMQIZ7.js +393 -0
- package/dist/chunk-KMBMQIZ7.js.map +1 -0
- package/dist/chunk-LBIRQHX5.js +133 -0
- package/dist/chunk-LBIRQHX5.js.map +1 -0
- package/dist/chunk-MIXOZU2S.js +366 -0
- package/dist/chunk-MIXOZU2S.js.map +1 -0
- package/dist/chunk-QJMF73M5.js +129 -0
- package/dist/chunk-QJMF73M5.js.map +1 -0
- package/dist/chunk-UZNSYATZ.js +680 -0
- package/dist/chunk-UZNSYATZ.js.map +1 -0
- package/dist/chunk-VIADBYFY.js +94 -0
- package/dist/chunk-VIADBYFY.js.map +1 -0
- package/dist/chunk-YHCG2SUC.js +159 -0
- package/dist/chunk-YHCG2SUC.js.map +1 -0
- package/dist/chunk-YJX3JJ4M.js +174 -0
- package/dist/chunk-YJX3JJ4M.js.map +1 -0
- package/dist/client-IOM55ZCS.js +14 -0
- package/dist/client-IOM55ZCS.js.map +1 -0
- package/dist/completion-ZZGX5BQC.js +100 -0
- package/dist/completion-ZZGX5BQC.js.map +1 -0
- package/dist/config-XJL5TSYK.js +690 -0
- package/dist/config-XJL5TSYK.js.map +1 -0
- package/dist/config-store-3ZSYGXMQ.js +44 -0
- package/dist/config-store-3ZSYGXMQ.js.map +1 -0
- package/dist/docs-MDKKSJDC.js +102 -0
- package/dist/docs-MDKKSJDC.js.map +1 -0
- package/dist/eoa-IQ72EIHR.js +551 -0
- package/dist/eoa-IQ72EIHR.js.map +1 -0
- package/dist/errors-WMZIEGQI.js +18 -0
- package/dist/errors-WMZIEGQI.js.map +1 -0
- package/dist/explain-H4EH3KH3.js +165 -0
- package/dist/explain-H4EH3KH3.js.map +1 -0
- package/dist/global-options-XOLJUPTT.js +18 -0
- package/dist/global-options-XOLJUPTT.js.map +1 -0
- package/dist/health-VZEIII74.js +98 -0
- package/dist/health-VZEIII74.js.map +1 -0
- package/dist/help-footer-GTANVDNP.js +43 -0
- package/dist/help-footer-GTANVDNP.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +251 -0
- package/dist/index.js.map +1 -0
- package/dist/intro-PQQTYWR7.js +41 -0
- package/dist/intro-PQQTYWR7.js.map +1 -0
- package/dist/markets-C37JZDPE.js +295 -0
- package/dist/markets-C37JZDPE.js.map +1 -0
- package/dist/output-VCBZ3FM7.js +22 -0
- package/dist/output-VCBZ3FM7.js.map +1 -0
- package/dist/portfolio-2AEPIJIG.js +115 -0
- package/dist/portfolio-2AEPIJIG.js.map +1 -0
- package/dist/protocol-XEQXF2GW.js +1572 -0
- package/dist/protocol-XEQXF2GW.js.map +1 -0
- package/dist/quote-I4DVJ7ZB.js +144 -0
- package/dist/quote-I4DVJ7ZB.js.map +1 -0
- package/dist/schema-PIFQ65TS.js +410 -0
- package/dist/schema-PIFQ65TS.js.map +1 -0
- package/dist/setup-USZ6IODD.js +260 -0
- package/dist/setup-USZ6IODD.js.map +1 -0
- package/dist/stdin-YW2CEQXU.js +28 -0
- package/dist/stdin-YW2CEQXU.js.map +1 -0
- package/dist/trace-IZBYTUFO.js +103 -0
- package/dist/trace-IZBYTUFO.js.map +1 -0
- package/dist/trade-IIZSEXEI.js +586 -0
- package/dist/trade-IIZSEXEI.js.map +1 -0
- package/dist/version-JDK3PEP5.js +117 -0
- package/dist/version-JDK3PEP5.js.map +1 -0
- package/dist/version-check-TDCION37.js +138 -0
- package/dist/version-check-TDCION37.js.map +1 -0
- package/dist/webhooks-PTVRKICZ.js +680 -0
- package/dist/webhooks-PTVRKICZ.js.map +1 -0
- package/dist/with-retry-4FIZG3A7.js +223 -0
- package/dist/with-retry-4FIZG3A7.js.map +1 -0
- package/package.json +99 -0
package/README.md
ADDED
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
# `@kashdao/cli`
|
|
2
|
+
|
|
3
|
+
Official command-line interface for the [Kash](https://kash.bot) prediction-market protocol.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@kashdao/cli)
|
|
6
|
+
[](https://www.npmjs.com/package/@kashdao/cli)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
[](https://github.com/KashDAO/homebrew-tap)
|
|
10
|
+
|
|
11
|
+
Single binary, both modes — **both non-custodial**; user funds always
|
|
12
|
+
live in Privy-managed MPC smart accounts the user controls. The split
|
|
13
|
+
is about who orchestrates execution:
|
|
14
|
+
|
|
15
|
+
- **Kash-orchestrated** (default) — wraps [`@kashdao/sdk`](https://www.npmjs.com/package/@kashdao/sdk),
|
|
16
|
+
API-key auth, hits the public REST API. The API key is a scoped,
|
|
17
|
+
revocable delegation the user issues against their own Privy-managed
|
|
18
|
+
smart account; the user retains full custody at all times.
|
|
19
|
+
- **Self-orchestrated** (`kash protocol …`) — wraps
|
|
20
|
+
[`@kashdao/protocol-sdk`](https://www.npmjs.com/package/@kashdao/protocol-sdk),
|
|
21
|
+
signer + RPC + bundler, reads/writes on-chain. Zero Kash backend
|
|
22
|
+
dependency.
|
|
23
|
+
|
|
24
|
+
On both paths Kash never holds funds, never moves funds, never holds
|
|
25
|
+
keys, and never signs anything. See
|
|
26
|
+
[SECURITY.md § Non-custodial design](./SECURITY.md#non-custodial-design)
|
|
27
|
+
for the full statement.
|
|
28
|
+
|
|
29
|
+
The two SDKs are fully decoupled at the npm-package level (so API-only
|
|
30
|
+
consumers don't pay the viem cost), but the CLI integrates both behind
|
|
31
|
+
clearly-separated namespaces. The protocol-sdk loads lazily on the
|
|
32
|
+
first `kash protocol …` invocation — `kash --version` and the entire
|
|
33
|
+
Kash-orchestrated surface keep their fast cold start.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm install -g @kashdao/cli
|
|
37
|
+
kash auth set-key kash_live_…
|
|
38
|
+
kash markets list --status ACTIVE
|
|
39
|
+
kash trade buy <market-id> --outcome 0 --amount 10 --wait
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **Two audiences, equally first-class.** Humans get colored tables, spinners,
|
|
43
|
+
and tab completion; AI agents get `--json --quiet`, structured errors with
|
|
44
|
+
machine-readable recovery actions, and full command-tree introspection via
|
|
45
|
+
`kash docs --json`.
|
|
46
|
+
- **Stable JSON contracts.** Every shape an agent or script consumes is
|
|
47
|
+
pinned to a Zod schema and exposed via `kash schema --json`.
|
|
48
|
+
- **Multi-profile.** AWS-CLI-style profile system for juggling
|
|
49
|
+
test/staging/prod keys.
|
|
50
|
+
- **Zero-runtime config.** Drop in a `kash_*` API key and go — no OAuth,
|
|
51
|
+
no SSO, no browser flow.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Contents
|
|
56
|
+
|
|
57
|
+
- [Install](#install) · [Quickstart](#quickstart) · [Authentication](#authentication)
|
|
58
|
+
- [Commands](#commands) · [Multi-profile workflow](#multi-profile-workflow)
|
|
59
|
+
- [AI-agent / scripting mode](#ai-agent-scripting-mode) · [Webhook signing](#webhook-signing)
|
|
60
|
+
- [Configuration reference](#configuration-reference) · [Operational flags](#operational-flags)
|
|
61
|
+
- [Stability promise](#stability-promise) · [Troubleshooting](#troubleshooting)
|
|
62
|
+
- [Examples](#examples) · [Development](#development) · [License](#license)
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
> 🧪 **Staging release.** Production endpoints (`api.kash.bot`) are
|
|
67
|
+
> not yet live. Today only `kash_test_*` keys work — the CLI
|
|
68
|
+
> auto-routes them to staging (`api-staging.kash.bot`). To request a
|
|
69
|
+
> staging key, email [`engineering@kash.bot`](mailto:engineering@kash.bot)
|
|
70
|
+
> with your intended use case. Self-service key issuance, production
|
|
71
|
+
> endpoints, and the Homebrew tap all land with the production launch.
|
|
72
|
+
|
|
73
|
+
## Install
|
|
74
|
+
|
|
75
|
+
Pick whichever installer fits your environment:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# 1. One-line installer (POSIX shell — checks Node version,
|
|
79
|
+
# picks pnpm/yarn/npm automatically, idempotent on re-run).
|
|
80
|
+
curl -fsSL https://raw.githubusercontent.com/KashDAO/cli/main/scripts/install.sh | sh
|
|
81
|
+
|
|
82
|
+
# 2. npm / pnpm / yarn directly:
|
|
83
|
+
npm install -g @kashdao/cli
|
|
84
|
+
pnpm add -g @kashdao/cli
|
|
85
|
+
yarn global add @kashdao/cli
|
|
86
|
+
|
|
87
|
+
# 3. Zero-install (one-shot via npx — useful for CI smoke checks):
|
|
88
|
+
npx -y @kashdao/cli@latest --version
|
|
89
|
+
npx -y @kashdao/cli@latest markets list --json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A `kashdao/tap` Homebrew tap is planned for the production launch.
|
|
93
|
+
|
|
94
|
+
The package installs a `kash` binary. (The internal admin tooling that previously
|
|
95
|
+
shipped under the same name is now `kash-admin`.)
|
|
96
|
+
|
|
97
|
+
**Requirements:** Node.js 22 or newer. Works on macOS, Linux, and Windows
|
|
98
|
+
(WSL recommended). Chmod-based permission tightening is best-effort and skipped
|
|
99
|
+
on Windows.
|
|
100
|
+
|
|
101
|
+
The one-line installer accepts `--version <semver>`, `--pm <pnpm|yarn|npm>`,
|
|
102
|
+
and `--dry-run` if you want to inspect the resolved command before running it.
|
|
103
|
+
|
|
104
|
+
## Quickstart
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
# 1. Configure an API key (request a `kash_test_*` staging key by emailing engineering@kash.bot)
|
|
108
|
+
kash auth set-key kash_test_…
|
|
109
|
+
|
|
110
|
+
# 2. Browse markets
|
|
111
|
+
kash markets list --status ACTIVE
|
|
112
|
+
|
|
113
|
+
# 3. Place a trade and wait for settlement
|
|
114
|
+
kash trade buy <market-id> --outcome 0 --amount 10 --wait
|
|
115
|
+
|
|
116
|
+
# 4. Inspect your portfolio
|
|
117
|
+
kash portfolio show
|
|
118
|
+
kash portfolio positions
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Authentication
|
|
122
|
+
|
|
123
|
+
Request a `kash_test_*` staging key by emailing
|
|
124
|
+
[`engineering@kash.bot`](mailto:engineering@kash.bot) with your
|
|
125
|
+
intended use case, then store it locally with one of:
|
|
126
|
+
|
|
127
|
+
```sh
|
|
128
|
+
# Persisted in ~/.kash/config.json (mode 0600)
|
|
129
|
+
kash auth set-key kash_test_…
|
|
130
|
+
|
|
131
|
+
# Per-shell, no on-disk persistence
|
|
132
|
+
export KASH_API_KEY=kash_test_…
|
|
133
|
+
|
|
134
|
+
# Per-invocation, no persistence
|
|
135
|
+
KASH_API_KEY=kash_live_… kash markets list
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Inspect the resolved auth state with `kash auth status` (offline; does not call
|
|
139
|
+
the API). When you need a fresh shell or to log out:
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
kash auth logout # clears apiKey from the active profile
|
|
143
|
+
kash config reset --yes # nuclear: deletes ~/.kash/config.json entirely
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Every authenticated `kash` command requires an API key. The CLI fails
|
|
147
|
+
fast with a clear `AUTH_REQUIRED` message if no key is configured
|
|
148
|
+
(`kash config get apiKey` to check). Per-key rate limits and audit
|
|
149
|
+
attribution apply on every request.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Commands
|
|
154
|
+
|
|
155
|
+
| Group | Subcommands |
|
|
156
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
157
|
+
| `auth` | `set-key`, `status`, `logout` |
|
|
158
|
+
| `markets` | `list`, `get`, `predictions` |
|
|
159
|
+
| `quote` | `buy`, `sell` — AMM price quotes (`markets:quote` scope) |
|
|
160
|
+
| `trade` | `buy`, `sell`, `status`, `list`, `confirm` |
|
|
161
|
+
| `portfolio` | `show`, `positions` |
|
|
162
|
+
| `webhooks` | `list`, `rotate-secret`, `redeliver`, `verify`, `replay` |
|
|
163
|
+
| `protocol` | `balance`, `market`, `quote`, `position`, `allowance`, `smart-account`, `fees`, `token-id`, `decode-revert`, `trade`, `userop`, `watch` — direct mode (smart account, ERC-4337) |
|
|
164
|
+
| `eoa` | `balance`, `market`, `quote`, `position`, `allowance`, `fees`, `trade` — direct mode (vanilla EOA, EIP-1559) |
|
|
165
|
+
| `config` | `show`, `set`, `profiles`, `use`, `remove`, `reset`, `export`, `import` |
|
|
166
|
+
| `health` | (top-level; honors `--timeout-ms`, exits 1 when down) |
|
|
167
|
+
| `version` | (top-level; also accepts `--json`) |
|
|
168
|
+
| `explain` | `[codes...]` — error code lookup (multi-code allowed) |
|
|
169
|
+
| `schema` | `[name]` — JSON Schema for SDK + CLI envelopes |
|
|
170
|
+
| `setup` | first-run interactive wizard (auth + verify + completion) |
|
|
171
|
+
| `trace` | `<correlationId>` — curated event timeline for a trade |
|
|
172
|
+
| `with-retry` | `-- <command> [args...]` — retry on recoverable failures |
|
|
173
|
+
| `docs` | full command tree (use `--json` for the agent surface) |
|
|
174
|
+
| `completion` | `install`, `uninstall` |
|
|
175
|
+
|
|
176
|
+
Run `kash <command> --help` for full option reference. Every command's `--help`
|
|
177
|
+
includes worked examples for both human and `--json --quiet` invocations.
|
|
178
|
+
|
|
179
|
+
## Multi-profile workflow
|
|
180
|
+
|
|
181
|
+
The CLI supports AWS-CLI-style profiles for juggling multiple keys:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
# Issue keys against multiple environments
|
|
185
|
+
kash --profile prod auth set-key kash_live_…
|
|
186
|
+
kash --profile staging auth set-key kash_test_…
|
|
187
|
+
kash --profile ci auth set-key kash_live_…
|
|
188
|
+
|
|
189
|
+
# Switch the active profile (writes currentProfile to ~/.kash/config.json)
|
|
190
|
+
kash config use staging
|
|
191
|
+
# Or the shell-friendly alias `su`:
|
|
192
|
+
kash su staging
|
|
193
|
+
|
|
194
|
+
# List configured profiles
|
|
195
|
+
kash config profiles
|
|
196
|
+
# {
|
|
197
|
+
# "current": "staging",
|
|
198
|
+
# "profiles": ["ci", "prod", "staging"]
|
|
199
|
+
# }
|
|
200
|
+
|
|
201
|
+
# Override the active profile per-invocation
|
|
202
|
+
kash --profile prod markets list
|
|
203
|
+
|
|
204
|
+
# Override via environment for a sub-shell
|
|
205
|
+
KASH_PROFILE=ci kash trade list
|
|
206
|
+
|
|
207
|
+
# Remove a profile (refuses to remove the active one)
|
|
208
|
+
kash config remove staging
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The on-disk file at `~/.kash/config.json` looks like:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"version": 1,
|
|
216
|
+
"currentProfile": "staging",
|
|
217
|
+
"profiles": {
|
|
218
|
+
"prod": { "apiKey": "kash_live_…" },
|
|
219
|
+
"staging": { "apiKey": "kash_test_…", "baseUrl": "https://api-staging.kash.bot/v1" },
|
|
220
|
+
"ci": { "apiKey": "kash_live_…" }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Resolution order: explicit `--profile <name>` flag → `KASH_PROFILE` env →
|
|
226
|
+
`currentProfile` in the file → `default`.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## AI-agent / scripting mode
|
|
231
|
+
|
|
232
|
+
Every command supports `--json` and `--quiet` for machine consumption:
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
# JSON mode, suppress spinners/info — ideal for AI agents and CI.
|
|
236
|
+
kash markets list --status ACTIVE --json --quiet | jq '.data[0].id'
|
|
237
|
+
|
|
238
|
+
# Place a trade, block on settlement, parse the resulting tx hash.
|
|
239
|
+
kash trade buy <id> --outcome 0 --amount 5 --wait --json --quiet | jq -r .txHash
|
|
240
|
+
|
|
241
|
+
# Stream paginated reads as NDJSON (one record per line).
|
|
242
|
+
kash markets list --ndjson | while read -r line; do echo "$line" | jq -r .id; done
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Agent discovery surface
|
|
246
|
+
|
|
247
|
+
Three commands expose the CLI's shape in machine-readable form so an
|
|
248
|
+
AI agent can plan calls without scraping help text:
|
|
249
|
+
|
|
250
|
+
| Command | What it returns |
|
|
251
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
252
|
+
| `kash docs --json` | Full command tree (every command, argument, option, alias, default value). |
|
|
253
|
+
| `kash schema [<name>] --json` | JSON Schema for SDK request/response shapes + CLI-owned envelopes (`CreateTradeBody`, `TradeResource`, `MarketResource`, `CliErrorEnvelope`, …). |
|
|
254
|
+
| `kash explain [<code>] --json` | Error catalog with `recoverable`, `retryAfterMs`, `docsUrl`, and structured recovery `actions[]`. |
|
|
255
|
+
|
|
256
|
+
For first-time agent setup, dump everything into one document:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
kash version --json > kash-surface.json # cli/sdk/node/platform versions
|
|
260
|
+
kash docs --json >> kash-surface.json # full command tree
|
|
261
|
+
kash schema --json >> kash-surface.json # every JSON Schema
|
|
262
|
+
kash explain --json >> kash-surface.json # every error code + recovery actions
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
See [`examples/agent-discovery.py`](./examples/agent-discovery.py) for a runnable
|
|
266
|
+
recipe that loads this into an agent's startup context.
|
|
267
|
+
|
|
268
|
+
### Error envelope contract
|
|
269
|
+
|
|
270
|
+
Every command emits this shape on `--json` failures. The shape is
|
|
271
|
+
SemVer-stable; pin to it.
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"ok": false,
|
|
276
|
+
"error": {
|
|
277
|
+
"code": "RATE_LIMITED",
|
|
278
|
+
"message": "Rate limit exceeded",
|
|
279
|
+
"recoverable": true,
|
|
280
|
+
"retryAfterMs": 30000,
|
|
281
|
+
"docsUrl": "https://kash.bot/docs/api/rate-limits",
|
|
282
|
+
"requestId": "req_abc",
|
|
283
|
+
"suggestion": "Retry in 30s. Upgrade for higher limits: https://kash.bot/pricing",
|
|
284
|
+
"actions": [
|
|
285
|
+
{
|
|
286
|
+
"type": "wait_and_retry",
|
|
287
|
+
"delayMs": 30000,
|
|
288
|
+
"description": "Wait 30s then re-run the same command."
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"type": "open_url",
|
|
292
|
+
"url": "https://kash.bot/pricing",
|
|
293
|
+
"description": "Upgrade tier for higher rate limits."
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Required:** `code`, `message`, `recoverable`, `actions`. **Optional:**
|
|
301
|
+
`retryAfterMs`, `docsUrl`, `requestId`, `suggestion`. Action variants:
|
|
302
|
+
`run_command`, `set_env`, `wait_and_retry`, `open_url`, `check_input`.
|
|
303
|
+
|
|
304
|
+
Fetch the formal Zod-derived JSON Schema with:
|
|
305
|
+
|
|
306
|
+
```sh
|
|
307
|
+
kash schema CliErrorEnvelope --json
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Exit codes
|
|
311
|
+
|
|
312
|
+
- `0` — success
|
|
313
|
+
- `1` — generic error (validation, server, network, etc.)
|
|
314
|
+
- `2` — auth failure (missing or invalid API key, missing scope)
|
|
315
|
+
|
|
316
|
+
### Idempotent retries
|
|
317
|
+
|
|
318
|
+
For trade-creation calls (`kash trade buy/sell`), pass either an explicit
|
|
319
|
+
`--idempotency-key <uuid>` or `--auto-idempotency-key` to let the CLI generate
|
|
320
|
+
one. The resolved key is surfaced in the response, so a transient failure
|
|
321
|
+
mid-creation can be retried with the same key — the server guarantees the
|
|
322
|
+
trade is created at most once.
|
|
323
|
+
|
|
324
|
+
```sh
|
|
325
|
+
# Generate, capture, retry safely:
|
|
326
|
+
kash trade buy <id> --outcome 0 --amount 10 \
|
|
327
|
+
--auto-idempotency-key --wait --json --quiet
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Retry-loop wrapper
|
|
331
|
+
|
|
332
|
+
`kash with-retry [opts] -- <command> [args...]` re-runs any kash
|
|
333
|
+
command when the structured error envelope reports a recoverable
|
|
334
|
+
failure. The retry policy reads `code` (`RATE_LIMITED`, `NETWORK`,
|
|
335
|
+
`TIMEOUT`, `MAINTENANCE`, `SERVER_ERROR` are retryable;
|
|
336
|
+
`INVALID_INPUT`, `AUTH_REQUIRED`, `NOT_FOUND` etc. fail fast) and
|
|
337
|
+
honours the `retryAfterMs` field when present, falling back to
|
|
338
|
+
exponential backoff otherwise.
|
|
339
|
+
|
|
340
|
+
```sh
|
|
341
|
+
# Retry up to 5 times, with the wait dictated by the server.
|
|
342
|
+
kash with-retry --max-attempts 5 -- markets list --status ACTIVE --json --quiet
|
|
343
|
+
|
|
344
|
+
# Idempotent retry across attempts (the inner key persists).
|
|
345
|
+
kash with-retry -- trade buy <id> --outcome 0 --amount 10 \
|
|
346
|
+
--auto-idempotency-key --wait --json --quiet
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The wrapped command MUST come after `--`. Without `--json`, the
|
|
350
|
+
wrapper falls back to a fixed exponential schedule (1s, 2s, 4s, …
|
|
351
|
+
capped at `--max-delay-ms`).
|
|
352
|
+
|
|
353
|
+
### Tracing a trade end-to-end
|
|
354
|
+
|
|
355
|
+
`kash trace <correlationId>` returns the curated event timeline for a
|
|
356
|
+
single trade — every event the pipeline emits as the trade moves through
|
|
357
|
+
intent parsing → funding → bridge → execution → webhook delivery.
|
|
358
|
+
|
|
359
|
+
```sh
|
|
360
|
+
# Get the correlation id from any trade response and trace it.
|
|
361
|
+
CID=$(kash trade buy <market-id> --outcome 0 --amount 10 --json --quiet | jq -r .correlationId)
|
|
362
|
+
kash trace "$CID"
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
The server returns a sanitized timeline — raw event payloads are never
|
|
366
|
+
exposed; only an allowlisted subset of fields (`txHash`, `tokensOut`,
|
|
367
|
+
`errorCode`, etc.) appears. JSON output is pinned to `GetTraceResponse`
|
|
368
|
+
(fetch the schema with `kash schema TraceResource --json`).
|
|
369
|
+
|
|
370
|
+
### Dry-run preview
|
|
371
|
+
|
|
372
|
+
Pass `--dry-run` to `kash trade buy/sell` to preview the request without
|
|
373
|
+
sending it. The CLI validates inputs, resolves the idempotency key, and
|
|
374
|
+
emits the would-be body — no API call, no auth required. Useful for
|
|
375
|
+
agents planning trades and humans sanity-checking before committing.
|
|
376
|
+
|
|
377
|
+
```sh
|
|
378
|
+
$ kash trade buy <id> --outcome 0 --amount 10 --dry-run --json
|
|
379
|
+
{
|
|
380
|
+
"wouldSend": {
|
|
381
|
+
"marketId": "9f0b…",
|
|
382
|
+
"outcomeIndex": 0,
|
|
383
|
+
"amount": "10",
|
|
384
|
+
"side": "buy"
|
|
385
|
+
},
|
|
386
|
+
"idempotencyKey": null,
|
|
387
|
+
"endpoint": { "method": "POST", "path": "/v1/trades" }
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
The envelope is pinned to `TradeDryRunEnvelope` — fetch the full Zod
|
|
392
|
+
schema with `kash schema TradeDryRunEnvelope --json`.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Webhook signing
|
|
397
|
+
|
|
398
|
+
Kash webhooks are signed with HMAC-SHA256 in a Stripe-compatible format
|
|
399
|
+
(`X-Kash-Signature: t=<unix-ms>,v1=<hex>`). The SDK's `verifySignature`
|
|
400
|
+
helper handles parsing, replay-window enforcement, and constant-time
|
|
401
|
+
comparison.
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
import { KashClient } from '@kashdao/sdk';
|
|
405
|
+
const kash = new KashClient({}); // no apiKey needed for verifySignature
|
|
406
|
+
|
|
407
|
+
// In your HTTP handler — use the *raw* request body, not a re-serialised JSON.
|
|
408
|
+
const result = await kash.webhooks.verifySignature(rawBody, signatureHeader, secret);
|
|
409
|
+
if (!result.valid) {
|
|
410
|
+
return res.status(400).send(result.reason);
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Rotate the signing secret with `kash webhooks rotate-secret` (the new
|
|
415
|
+
plaintext is shown ONCE — capture it). See
|
|
416
|
+
[`examples/webhook-receiver.ts`](./examples/webhook-receiver.ts) for a
|
|
417
|
+
production-shaped Fastify receiver.
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Direct mode (`kash protocol …`)
|
|
422
|
+
|
|
423
|
+
Direct mode bypasses the Kash backend entirely and talks to the on-chain
|
|
424
|
+
contracts via [`@kashdao/protocol-sdk`](https://www.npmjs.com/package/@kashdao/protocol-sdk). It's for users
|
|
425
|
+
who want to read AMM state, quote trades, or submit UserOps from their
|
|
426
|
+
own signer without ever touching the public API.
|
|
427
|
+
|
|
428
|
+
The protocol-sdk loads lazily on first use, so Kash-orchestrated users
|
|
429
|
+
pay zero cold-start cost for it. `kash --version` and the entire
|
|
430
|
+
`kash <auth|markets|trade|…>` surface stay fast.
|
|
431
|
+
|
|
432
|
+
### What's wired today (read-only + offline helpers)
|
|
433
|
+
|
|
434
|
+
| Command | What it does |
|
|
435
|
+
| --------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
436
|
+
| `kash protocol balance [account]` | On-chain USDC + native gas balances. Defaults to the profile's smart account. |
|
|
437
|
+
| `kash protocol market <address>` | Full AMM state: status, reserve, outstanding tokens, weights, probabilities. |
|
|
438
|
+
| `kash protocol quote <address> --side …` | Buy/sell quote against on-chain reserves. |
|
|
439
|
+
| `kash protocol position <market> [account]` | On-chain ERC-1155 outcome-token holdings (per outcome). |
|
|
440
|
+
| `kash protocol allowance <spender> [account]` | USDC allowance from `account` → `spender`. Skips `approve` when sufficient. |
|
|
441
|
+
| `kash protocol smart-account compute --owner …` | Derive the deterministic SA address for an EOA owner (no deployment needed). |
|
|
442
|
+
| `kash protocol smart-account is-deployed [address]` | Check whether an SA has bytecode on-chain. |
|
|
443
|
+
| `kash protocol fees` | EIP-1559 fee estimate via `eth_feeHistory`. Tunable percentile / multiplier. |
|
|
444
|
+
| `kash protocol token-id --market-id … --outcome …` | Compute the ERC-1155 token id (offline; no RPC). |
|
|
445
|
+
| `kash protocol decode-revert <0x…>` | Decode raw revert data into `(name, args)` via Market + EntryPoint ABIs. |
|
|
446
|
+
|
|
447
|
+
### Trade execution (smart-account mode)
|
|
448
|
+
|
|
449
|
+
`kash protocol trade {buy,sell,close,approve}` runs the full one-shot
|
|
450
|
+
flow (prepare → simulate → sign → submit → wait). Default `--wait`,
|
|
451
|
+
default 0.5% slippage tolerance, default 5-minute deadline.
|
|
452
|
+
|
|
453
|
+
```sh
|
|
454
|
+
# Place a BUY using the configured signerKeyRef.
|
|
455
|
+
kash protocol trade buy 0xMarket... -o 0 -a 10
|
|
456
|
+
|
|
457
|
+
# Preview only — populated UserOp + hash, no signing.
|
|
458
|
+
kash protocol trade buy 0xMarket... -o 0 -a 10 --dry-run --json
|
|
459
|
+
|
|
460
|
+
# Fire-and-forget; print userOpHash and exit.
|
|
461
|
+
kash protocol trade buy 0xMarket... -o 0 -a 10 --no-wait --json --quiet
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Cold-storage flow (`kash protocol userop`)
|
|
465
|
+
|
|
466
|
+
For operators who sign on a different machine than the one preparing
|
|
467
|
+
or submitting:
|
|
468
|
+
|
|
469
|
+
```sh
|
|
470
|
+
# Machine A (no signer): prepare a fully-populated UserOp + hash.
|
|
471
|
+
kash protocol userop build buy 0xMarket... -o 0 -a 10 --out trade.json
|
|
472
|
+
|
|
473
|
+
# Machine B (signer-only): sign trade.json externally, write
|
|
474
|
+
# the resulting signature into the userOp.signature field.
|
|
475
|
+
|
|
476
|
+
# Machine C: submit and wait.
|
|
477
|
+
kash protocol userop submit signed.json --wait
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
`kash protocol userop {hash,simulate,receipt,wait}` are also exposed.
|
|
481
|
+
|
|
482
|
+
### Streaming (`kash protocol watch`)
|
|
483
|
+
|
|
484
|
+
Long-running NDJSON event stream for a market. Best-effort delivery —
|
|
485
|
+
on RPC reconnect missed events are NOT replayed; pair with
|
|
486
|
+
`kash markets predictions <id>` (indexer-backed) for gap-free coverage.
|
|
487
|
+
|
|
488
|
+
```sh
|
|
489
|
+
kash protocol watch 0xMarket... --json --quiet | jq -c
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Press Ctrl-C to terminate cleanly. `--max-events <n>` and
|
|
493
|
+
`--timeout-ms <n>` bound the run.
|
|
494
|
+
|
|
495
|
+
### EOA mode (`kash eoa …`)
|
|
496
|
+
|
|
497
|
+
Parallel namespace for operators who sign vanilla EIP-1559
|
|
498
|
+
transactions (no smart account, no bundler). Same surface as
|
|
499
|
+
`kash protocol` minus the UserOp lifecycle:
|
|
500
|
+
|
|
501
|
+
| Command | Notes |
|
|
502
|
+
| ----------------------------------------- | --------------------------------------- |
|
|
503
|
+
| `kash eoa balance [account]` | Defaults to the EOA address (signer's). |
|
|
504
|
+
| `kash eoa market <address>` | Same as `kash protocol market`. |
|
|
505
|
+
| `kash eoa quote <address>` | Same as `kash protocol quote`. |
|
|
506
|
+
| `kash eoa position <market>` | Same as `kash protocol position`. |
|
|
507
|
+
| `kash eoa allowance <spender>` | Same as `kash protocol allowance`. |
|
|
508
|
+
| `kash eoa fees` | Same as `kash protocol fees`. |
|
|
509
|
+
| `kash eoa trade {buy,sell,close,approve}` | Vanilla tx (no UserOp). |
|
|
510
|
+
|
|
511
|
+
Required config: `rpcUrl`, `defaultChainId`, `signerKeyRef`. EOA mode
|
|
512
|
+
ignores `smartAccount`, `bundlerUrl`, and `bundlerProvider`.
|
|
513
|
+
|
|
514
|
+
```sh
|
|
515
|
+
kash eoa balance
|
|
516
|
+
kash eoa trade buy 0xMarket... -o 0 -a 10 --json
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Configuration
|
|
520
|
+
|
|
521
|
+
Direct mode requires four pieces of config, all per-profile or via env:
|
|
522
|
+
|
|
523
|
+
| Field | Env | Notes |
|
|
524
|
+
| ----------------- | ----------------------- | ---------------------------------------------------- |
|
|
525
|
+
| `rpcUrl` | `KASH_RPC_URL` | EVM RPC URL (Alchemy, Infura, your own node, anvil). |
|
|
526
|
+
| `smartAccount` | `KASH_SMART_ACCOUNT` | The 0x-prefixed smart account address to read. |
|
|
527
|
+
| `bundlerUrl` | `KASH_BUNDLER_URL` | ERC-4337 bundler. Required only for write paths. |
|
|
528
|
+
| `bundlerProvider` | `KASH_BUNDLER_PROVIDER` | One of `flashbots`, `pimlico`, `alchemy`, `generic`. |
|
|
529
|
+
| `signerKeyRef` | `KASH_SIGNER_KEY_REF` | `file:<path>` or `env:<NAME>`. Required for writes. |
|
|
530
|
+
|
|
531
|
+
```sh
|
|
532
|
+
kash config set rpcUrl https://base-mainnet.g.alchemy.com/v2/<key>
|
|
533
|
+
kash config set smartAccount 0xabc…
|
|
534
|
+
kash protocol balance --json
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
The CLI never persists raw private keys — only references. `file:` reads
|
|
538
|
+
from a 0x-prefixed hex file at the path; `env:` reads from a process env
|
|
539
|
+
var at invocation time.
|
|
540
|
+
|
|
541
|
+
### Examples
|
|
542
|
+
|
|
543
|
+
```sh
|
|
544
|
+
# Read your own balances
|
|
545
|
+
kash protocol balance --json
|
|
546
|
+
# → { "account": "0x…", "chainId": 8453, "usdcAtomic": "1000000", "gasWei": "5000000000000000" }
|
|
547
|
+
|
|
548
|
+
# Inspect a market on-chain
|
|
549
|
+
kash protocol market 0xMarket… --json | jq '.outcomes[].probability'
|
|
550
|
+
|
|
551
|
+
# Quote a $10 buy on outcome 0
|
|
552
|
+
kash protocol quote 0xMarket… --side buy --outcome 0 --amount 10 --json
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Configuration reference
|
|
558
|
+
|
|
559
|
+
### Per-profile fields (in `~/.kash/config.json`)
|
|
560
|
+
|
|
561
|
+
| Field | Type | Default | Notes |
|
|
562
|
+
| ----------------- | --------- | ------------------------- | --------------------------------------------------- |
|
|
563
|
+
| `apiKey` | `string?` | unset | Must start with `kash_`. Stored at mode `0600`. |
|
|
564
|
+
| `baseUrl` | `string?` | `https://api.kash.bot/v1` | Validated as a URL. |
|
|
565
|
+
| `defaultChainId` | `number?` | `8453` (Base mainnet) | Used when chain id matters; positive integer. |
|
|
566
|
+
| `rpcUrl` | `string?` | unset | Direct-mode EVM RPC URL. |
|
|
567
|
+
| `smartAccount` | `string?` | unset | Direct-mode smart account address (`0x…`). |
|
|
568
|
+
| `bundlerUrl` | `string?` | unset | ERC-4337 bundler URL (write paths only). |
|
|
569
|
+
| `bundlerProvider` | `string?` | unset | `flashbots` \| `pimlico` \| `alchemy` \| `generic`. |
|
|
570
|
+
| `signerKeyRef` | `string?` | unset | `file:<path>` or `env:<NAME>` — never raw keys. |
|
|
571
|
+
|
|
572
|
+
### Environment variables (override file)
|
|
573
|
+
|
|
574
|
+
| Variable | Field | Notes |
|
|
575
|
+
| ----------------------- | ------------------- | --------------------------------------------------------- |
|
|
576
|
+
| `KASH_API_KEY` | `apiKey` | Highest precedence for the auth key. |
|
|
577
|
+
| `KASH_BASE_URL` | `baseUrl` | |
|
|
578
|
+
| `KASH_CHAIN_ID` | `defaultChainId` | Must parse as a positive integer. |
|
|
579
|
+
| `KASH_DEBUG` | (mirrors `--debug`) | Set to `1`/`true`/`yes`/`on` to enable lifecycle traces. |
|
|
580
|
+
| `KASH_RPC_URL` | `rpcUrl` | Direct-mode RPC URL. |
|
|
581
|
+
| `KASH_SMART_ACCOUNT` | `smartAccount` | Direct-mode smart account address. |
|
|
582
|
+
| `KASH_BUNDLER_URL` | `bundlerUrl` | Direct-mode ERC-4337 bundler URL. |
|
|
583
|
+
| `KASH_BUNDLER_PROVIDER` | `bundlerProvider` | Direct-mode bundler provider preset. |
|
|
584
|
+
| `KASH_SIGNER_KEY_REF` | `signerKeyRef` | `file:<path>` or `env:<NAME>` — never raw keys. |
|
|
585
|
+
| `KASH_PROFILE` | (active profile) | Equivalent to `--profile <name>` for the next invocation. |
|
|
586
|
+
| `KASH_CONFIG` | (config path) | Equivalent to `--config <path>`. |
|
|
587
|
+
| `NO_COLOR` | (color output) | Set to anything truthy to disable ANSI escapes. |
|
|
588
|
+
|
|
589
|
+
### Resolution order
|
|
590
|
+
|
|
591
|
+
For each field, highest precedence first:
|
|
592
|
+
|
|
593
|
+
1. Environment variable.
|
|
594
|
+
2. Active profile in `~/.kash/config.json`.
|
|
595
|
+
3. Built-in default.
|
|
596
|
+
|
|
597
|
+
For the active profile name itself:
|
|
598
|
+
|
|
599
|
+
1. Explicit `--profile <name>` flag.
|
|
600
|
+
2. `KASH_PROFILE` environment variable.
|
|
601
|
+
3. `currentProfile` field in the config file.
|
|
602
|
+
4. `default`.
|
|
603
|
+
|
|
604
|
+
For the config file path itself:
|
|
605
|
+
|
|
606
|
+
1. Explicit `--config <path>` flag.
|
|
607
|
+
2. `KASH_CONFIG` environment variable.
|
|
608
|
+
3. `~/.kash/config.json`.
|
|
609
|
+
|
|
610
|
+
### Operational flags
|
|
611
|
+
|
|
612
|
+
| Flag | Purpose |
|
|
613
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
614
|
+
| `--profile <name>` | Pick a stored credential profile. |
|
|
615
|
+
| `--config <path>` | Override `~/.kash/config.json` location. |
|
|
616
|
+
| `--debug` | Stream SDK request/response/retry/error traces to stderr. With `--json` becomes NDJSON. |
|
|
617
|
+
| `--base-url <url>` | Override API base URL (staging tests, CI matrix builds). |
|
|
618
|
+
| `--max-retries <n>` | Override SDK retry budget (0-10). |
|
|
619
|
+
| `--timeout-ms <n>` | Override SDK request timeout. |
|
|
620
|
+
| `--json` | Emit machine-readable JSON instead of human-formatted output. |
|
|
621
|
+
| `--fields <list>` | Project comma-separated dot-paths on `--json`/`--ndjson` output (e.g. `id,outcomes.label`). See [Field projection](#field-projection). |
|
|
622
|
+
| `--filter <expr>` | Boolean predicate on `--json`/`--ndjson` entries (e.g. `'status==ACTIVE && outcomeCount>2'`). See [Filter DSL](#filter-dsl). |
|
|
623
|
+
| `--quiet` | Suppress spinners, progress, and informational logs. |
|
|
624
|
+
| `--no-color` | Disable ANSI escapes (also honors `NO_COLOR`). |
|
|
625
|
+
|
|
626
|
+
### Field projection
|
|
627
|
+
|
|
628
|
+
Pass `--fields <list>` alongside `--json` or `--ndjson` to narrow output to
|
|
629
|
+
the dot-paths you care about. Reduces tokens for AI agents and noise for
|
|
630
|
+
shell pipelines, without spinning up `jq`.
|
|
631
|
+
|
|
632
|
+
```sh
|
|
633
|
+
# Top-level fields:
|
|
634
|
+
kash markets list --json --fields id,title,status
|
|
635
|
+
|
|
636
|
+
# Nested paths and array splay (entries inside arrays project per-element):
|
|
637
|
+
kash markets get <id> --json --fields title,outcomes.label,outcomes.tokenAddress
|
|
638
|
+
|
|
639
|
+
# Paginated envelopes preserve `pagination`/`meta` unchanged; only the
|
|
640
|
+
# `data` array entries are projected.
|
|
641
|
+
kash trade list --json --fields id,status,txHash --quiet | jq -c
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Filter DSL
|
|
645
|
+
|
|
646
|
+
Pass `--filter <expr>` alongside `--json` or `--ndjson` to keep only
|
|
647
|
+
entries matching a boolean predicate. Tiny DSL — `==`, `!=`, `<`,
|
|
648
|
+
`<=`, `>`, `>=`, `&&`, `||`, dotted field paths, numbers, booleans,
|
|
649
|
+
`null`, bare-word string values. Composes with `--fields`: filter
|
|
650
|
+
runs first, then projection narrows the survivors.
|
|
651
|
+
|
|
652
|
+
```sh
|
|
653
|
+
# Equality + comparison + boolean composition.
|
|
654
|
+
kash markets list --json --filter 'status==ACTIVE && outcomeCount>2'
|
|
655
|
+
|
|
656
|
+
# Filter on a dotted path.
|
|
657
|
+
kash trade list --json --filter 'webhookDelivery.status==delivered'
|
|
658
|
+
|
|
659
|
+
# Compose with --fields. The filter sees the FULL record; projection
|
|
660
|
+
# runs on what survives.
|
|
661
|
+
kash markets list --json --filter 'status==ACTIVE' --fields id
|
|
662
|
+
|
|
663
|
+
# NDJSON streams skip non-matching records entirely.
|
|
664
|
+
kash trade list --ndjson --filter 'side==buy && status==completed' | wc -l
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Type-coerced equality means `outcomeCount==2` matches both `2` and
|
|
668
|
+
`"2"`. Ordered comparisons (`<`, `>`, `<=`, `>=`) require both sides
|
|
669
|
+
to be finite numbers; otherwise the entry fails the predicate. The
|
|
670
|
+
DSL is intentionally narrow — for richer queries, pipe `--json` through
|
|
671
|
+
`jq`.
|
|
672
|
+
|
|
673
|
+
Path syntax: comma-separated, dot-segmented. Segments must match
|
|
674
|
+
`[A-Za-z_][A-Za-z0-9_]*`. Missing paths drop silently (jq semantics).
|
|
675
|
+
The flag is a no-op for human output and for non-JSON commands.
|
|
676
|
+
|
|
677
|
+
### `--debug` trace shape
|
|
678
|
+
|
|
679
|
+
With `--debug --json`, each SDK lifecycle event is emitted to **stderr** as a
|
|
680
|
+
single line of NDJSON. Pipe stderr separately if your tooling expects clean
|
|
681
|
+
NDJSON on a single stream.
|
|
682
|
+
|
|
683
|
+
```jsonc
|
|
684
|
+
// onRequest
|
|
685
|
+
{ "event": "request", "method": "GET", "url": "/v1/markets", "attempt": 1, "idempotencyKey": null }
|
|
686
|
+
// onResponse
|
|
687
|
+
{ "event": "response", "method": "GET", "url": "/v1/markets", "attempt": 1, "status": 200, "durationMs": 142, "requestId": "req_abc" }
|
|
688
|
+
// onRetry
|
|
689
|
+
{ "event": "retry", "method": "POST", "url": "/v1/trades", "attempt": 2, "reason": "rate_limit", "delayMs": 1000 }
|
|
690
|
+
// onError
|
|
691
|
+
{ "event": "error", "method": "POST", "url": "/v1/trades", "attempt": 3, "status": 429, "code": "RATE_LIMIT_EXCEEDED", "durationMs": 87 }
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
`reason` is one of `rate_limit`, `server_error`, `network`, `timeout`. Without
|
|
695
|
+
`--json`, the same events are rendered as compact human-readable lines on
|
|
696
|
+
stderr.
|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
## Stability promise
|
|
701
|
+
|
|
702
|
+
`@kashdao/cli` is currently `0.x` — under [Semantic Versioning](https://semver.org/)'s
|
|
703
|
+
own rules, `0.x` minor bumps may technically break anything. **We commit to
|
|
704
|
+
treating the contracts below as if SemVer-stable even before 1.0.** Additions
|
|
705
|
+
are minor bumps, behaviour changes or removals are major bumps. The 1.0
|
|
706
|
+
release will lock this in formally and remove the asterisk; until then, every
|
|
707
|
+
0.x release that ships will be reviewed against this list.
|
|
708
|
+
|
|
709
|
+
### Stable contracts
|
|
710
|
+
|
|
711
|
+
- **`--json` output shapes** for every command (validated by Zod schemas
|
|
712
|
+
available via `kash schema --json`).
|
|
713
|
+
- **The CLI error envelope** (`kash schema CliErrorEnvelope --json`).
|
|
714
|
+
- **The version manifest shape** (`kash version --json`).
|
|
715
|
+
- **The `--debug` NDJSON trace shape** (documented above).
|
|
716
|
+
- **Exit codes** (`0` ok, `1` generic error, `2` auth failure).
|
|
717
|
+
- **Error `code` strings** in the catalog (`kash explain --json`). New codes
|
|
718
|
+
appear in minor versions; existing codes never change meaning.
|
|
719
|
+
- **The `~/.kash/config.json` v1 file format**. Migrations to v2 will be
|
|
720
|
+
automatic and forward-compatible.
|
|
721
|
+
|
|
722
|
+
### Not stable
|
|
723
|
+
|
|
724
|
+
- Human-mode (non-`--json`) output formatting (tables, prose, color choices).
|
|
725
|
+
Scripts that rely on it should switch to `--json --quiet`.
|
|
726
|
+
- Internal module structure (`packages/cli/src/`); only the binary surface
|
|
727
|
+
is the public API.
|
|
728
|
+
- Help text wording.
|
|
729
|
+
|
|
730
|
+
### Deprecation policy
|
|
731
|
+
|
|
732
|
+
Behaviour changes that don't break the stable contracts are minor bumps
|
|
733
|
+
without warning. Anything that does will:
|
|
734
|
+
|
|
735
|
+
1. Be announced in the `CHANGELOG.md` of the deprecating release.
|
|
736
|
+
2. Continue to work for at least one minor version.
|
|
737
|
+
3. Emit a stderr warning when used (humans only; agents using `--json` see
|
|
738
|
+
no functional change until the major bump).
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
## Troubleshooting
|
|
743
|
+
|
|
744
|
+
### `[AUTH_REQUIRED] No API key configured.`
|
|
745
|
+
|
|
746
|
+
You haven't set an API key. Run `kash auth set-key kash_test_…`
|
|
747
|
+
(request a staging key by emailing `engineering@kash.bot`) or set
|
|
748
|
+
`KASH_API_KEY` in your environment. Every authenticated command needs
|
|
749
|
+
a key — only `kash --version`, `kash --help`, and `kash explain <code>`
|
|
750
|
+
work fully offline.
|
|
751
|
+
|
|
752
|
+
### `[INVALID_INPUT] --max-retries must be …`
|
|
753
|
+
|
|
754
|
+
CLI flag values are validated up front. The error envelope's `actions[0]`
|
|
755
|
+
of type `check_input` names the bad field. Look up the constraints in
|
|
756
|
+
the [Operational flags](#operational-flags) table or run
|
|
757
|
+
`kash <command> --help`.
|
|
758
|
+
|
|
759
|
+
### `[RATE_LIMITED]` with `retryAfterMs`
|
|
760
|
+
|
|
761
|
+
You're over your tier's rate limit. The error envelope tells you exactly
|
|
762
|
+
how long to wait. Either honor it programmatically (see
|
|
763
|
+
[`examples/trade-replay.sh`](./examples/trade-replay.sh)) or upgrade at
|
|
764
|
+
https://kash.bot/pricing.
|
|
765
|
+
|
|
766
|
+
### `[CONFLICT]` on `kash trade buy/sell`
|
|
767
|
+
|
|
768
|
+
A duplicate Idempotency-Key, the trade is awaiting high-value confirmation,
|
|
769
|
+
or the market closed between fetch and order. Inspect with
|
|
770
|
+
`kash trade status <id>` before retrying.
|
|
771
|
+
|
|
772
|
+
### `[NETWORK]` or `[TIMEOUT]`
|
|
773
|
+
|
|
774
|
+
Network path issues. The CLI already retries automatically; this means
|
|
775
|
+
retries were exhausted. Check connectivity to `api.kash.bot`. Retry with
|
|
776
|
+
`--timeout-ms 60000 --max-retries 5` if your environment has latency
|
|
777
|
+
spikes.
|
|
778
|
+
|
|
779
|
+
### `[CONFIGURATION] Config file at … is invalid`
|
|
780
|
+
|
|
781
|
+
The on-disk `~/.kash/config.json` is malformed. The error message names
|
|
782
|
+
the field. Run `kash config reset` to start fresh, or hand-edit the file
|
|
783
|
+
(it's valid JSON).
|
|
784
|
+
|
|
785
|
+
### `kash` collides with the admin CLI
|
|
786
|
+
|
|
787
|
+
The internal admin tooling used to ship a binary also called `kash`. It
|
|
788
|
+
has been renamed to `kash-admin`. If you have both installed, run
|
|
789
|
+
`which kash` to confirm you're invoking the public CLI.
|
|
790
|
+
|
|
791
|
+
### Diagnosing any other failure
|
|
792
|
+
|
|
793
|
+
Run with `--debug` to see SDK request/response/retry traces. With
|
|
794
|
+
`--debug --json` you get NDJSON on stderr — pipe it through `jq` to inspect
|
|
795
|
+
the request flow:
|
|
796
|
+
|
|
797
|
+
```sh
|
|
798
|
+
kash trade buy … --debug --json --quiet 2> >(jq .)
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
Capture `kash version --json` for issue triage:
|
|
802
|
+
|
|
803
|
+
```sh
|
|
804
|
+
kash version --json
|
|
805
|
+
# {
|
|
806
|
+
# "cli": "0.1.0",
|
|
807
|
+
# "sdk": "0.1.0",
|
|
808
|
+
# "node": "v22.4.1",
|
|
809
|
+
# "platform": "darwin",
|
|
810
|
+
# "release": "23.6.0",
|
|
811
|
+
# "arch": "arm64"
|
|
812
|
+
# }
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
Run `kash explain <code>` for any error code to get the catalog entry
|
|
816
|
+
including recommended recovery actions. File a bug at
|
|
817
|
+
https://github.com/KashDAO/cli/issues with the version manifest, the
|
|
818
|
+
`requestId` from the failing envelope, and the failing command.
|
|
819
|
+
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
## Examples
|
|
823
|
+
|
|
824
|
+
Worked recipes for both human scripts and AI agents in
|
|
825
|
+
[`examples/`](./examples/):
|
|
826
|
+
|
|
827
|
+
| File | Audience | Demonstrates |
|
|
828
|
+
| --------------------- | --------------------- | ------------------------------------------------------------------------------------------------- |
|
|
829
|
+
| `buy-and-follow.sh` | Bash scripts, CI | Place a trade, block on settlement with `--wait`, parse the tx hash from `--json --quiet` output. |
|
|
830
|
+
| `trade-replay.sh` | Reliability engineers | `--auto-idempotency-key` for safe retries; capture and reuse the generated key on failure. |
|
|
831
|
+
| `portfolio-export.sh` | Data ops, accountants | Stream all positions and trades as NDJSON; pipe through `jq` for filtering. |
|
|
832
|
+
| `webhook-receiver.ts` | Backend engineers | Production-shaped Fastify receiver verifying `X-Kash-Signature` with `verifySignature`. |
|
|
833
|
+
| `ai-agent.py` | LLM/agent engineers | Python loop calling `kash --json --quiet`, recovering from errors via `kash explain`. |
|
|
834
|
+
| `agent-discovery.py` | LLM/agent engineers | Use `kash docs --json` and `kash schema` to teach an agent the CLI surface at startup. |
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
## Development
|
|
839
|
+
|
|
840
|
+
```sh
|
|
841
|
+
pnpm --filter @kashdao/cli build
|
|
842
|
+
pnpm --filter @kashdao/cli test:unit
|
|
843
|
+
pnpm --filter @kashdao/cli typecheck
|
|
844
|
+
pnpm --filter @kashdao/cli lint
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
Run the bundled binary against a local API:
|
|
848
|
+
|
|
849
|
+
```sh
|
|
850
|
+
KASH_BASE_URL=http://localhost:3001/v1 \
|
|
851
|
+
KASH_API_KEY=kash_test_… \
|
|
852
|
+
node packages/cli/dist/index.js markets list
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
The CLI ships as a single ESM bundle (~85 KB) with an executable
|
|
856
|
+
shebang. Dependencies pinned in `package.json`: `commander`, `chalk`,
|
|
857
|
+
`cli-table3`, `omelette`, `ora`, `zod`, `zod-to-json-schema`, plus
|
|
858
|
+
`@kashdao/sdk` (workspace).
|
|
859
|
+
|
|
860
|
+
## Reporting issues / security
|
|
861
|
+
|
|
862
|
+
- General bugs: https://github.com/KashDAO/cli/issues
|
|
863
|
+
- Security disclosures: see [`SECURITY.md`](./SECURITY.md). Email
|
|
864
|
+
`security@kash.bot`; do not file a public issue.
|
|
865
|
+
|
|
866
|
+
## License
|
|
867
|
+
|
|
868
|
+
MIT — see [`LICENSE`](./LICENSE).
|