moshcode 0.26.0 → 0.27.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.
@@ -18,6 +18,18 @@
18
18
  },
19
19
  "homepage": "https://github.com/moshcoder/moshcode#ticker",
20
20
  "keywords": ["stocks", "equity", "research", "markets", "advis0r"]
21
+ },
22
+ {
23
+ "name": "crypto",
24
+ "description": "Crypto market data slash commands backed by advis0r.com: live prices, technical scores, order books, OHLCV history and sparklines across Alpaca's US crypto venue.",
25
+ "source": "./plugins/crypto",
26
+ "category": "productivity",
27
+ "author": {
28
+ "name": "moshcoder",
29
+ "url": "https://moshcode.sh"
30
+ },
31
+ "homepage": "https://github.com/moshcoder/moshcode#crypto",
32
+ "keywords": ["crypto", "bitcoin", "markets", "prices", "advis0r"]
21
33
  }
22
34
  ]
23
35
  }
package/README.md CHANGED
@@ -47,6 +47,7 @@ or miss one that does. A test fails the build when it drifts.
47
47
  | `moshcode tools` | tools | list workflow tools and installation status |
48
48
  | `moshcode trade` | tools | look up markets and trade through Alpaca |
49
49
  | `moshcode ticker` <br>`advisor` | tools | equity research from advis0r.com |
50
+ | `moshcode crypto` <br>`coins` | tools | crypto market data from advis0r.com |
50
51
  | `moshcode plugin` <br>`plugins` | extend | install moshcode's slash commands into Claude Code |
51
52
  | `moshcode commands` | script | list built-in moshscript commands |
52
53
  | `moshcode completion` | extend | print a shell completion script |
@@ -238,6 +239,37 @@ delayed and which feed produced it. Scores labelled `offline` come from
238
239
  deterministic rules rather than a model. It is a research aid, not advice, and
239
240
  nothing under `ticker` can place an order.
240
241
 
242
+ ### Crypto market data (`moshcode crypto`)
243
+
244
+ `crypto` is `ticker`'s sibling on the same host: advis0r's read-only crypto
245
+ routes over Alpaca's US crypto venue, which trades 24/7 and needs no extra
246
+ subscription.
247
+
248
+ ```sh
249
+ moshcode crypto BTC # price, technicals, score, supply, order book
250
+ moshcode crypto lookup bitcoin # asset name → BTC/USD
251
+ moshcode crypto quote ETH-USD # latest trade + quote, spread in bps
252
+ moshcode crypto spark BTC ETH SOL # recent moves across pairs, as sparklines
253
+ moshcode crypto bars ETH-USD --timeframe 1Hour # historical OHLCV
254
+ moshcode crypto book BTC-USD --depth 5 # top of book, both sides
255
+ moshcode crypto assets # every supported pair
256
+ moshcode crypto open BTC # the shareable page
257
+ ```
258
+
259
+ Pairs are accepted as `BTC`, `BTC-USD`, `BTC/USD` or `BTCUSD` — a bare asset
260
+ resolves to that asset's USD pair. `--json` gives the raw response, `/crypto …`
261
+ is the same facade in the pit, and `MOSHCODE_ADVISOR_URL` points it elsewhere.
262
+
263
+ Unlike a `ticker` report, this is a **live venue read**, not a stored snapshot —
264
+ there are no transcripts, no filings and no signals behind a crypto pair, and
265
+ the failure mode runs the other way: the price is accurate to the second and
266
+ stale by the time you act on it. Every response stamps when it was fetched.
267
+
268
+ The technical score counts venue-local liquidity, so it is **not comparable** to
269
+ an equity's score, and each response ships the `caveats` that say so. Prices are
270
+ Alpaca's US venue alone and can differ materially from other exchanges. Research
271
+ aid, not advice — and like `ticker`, nothing under `crypto` can place an order.
272
+
241
273
  ### Social posting from the pit
242
274
 
243
275
  The pit can hand a prepared post to Bluesky or Nostr without storing either
@@ -340,19 +372,28 @@ inside your engine too:
340
372
  ```sh
341
373
  moshcode plugin list # what the marketplace ships, and who can take it
342
374
  moshcode plugin install # add the marketplace + install `ticker`
375
+ moshcode plugin install crypto # add the marketplace + install `crypto`
343
376
  moshcode plugin remove ticker # take it back off
344
377
  ```
345
378
 
346
379
  `ticker@moshcode` adds `/ticker`, `/signals`, `/research`, `/lookup`,
347
380
  `/reports`, and `/discover` — the same advis0r research surface described above,
348
- driven from inside a coding session. Restart the engine afterwards; a newly
349
- installed plugin is not live in a session that is already running.
381
+ driven from inside a coding session.
382
+
383
+ `crypto@moshcode` adds `/crypto`, `/quote`, `/book`, `/bars`, `/spark`,
384
+ `/pairs`, and `/coin`. It ships separately because it is a different surface,
385
+ not a mode of the first: live venue reads instead of stored snapshots, and a
386
+ score that must not be ranked against an equity's.
387
+
388
+ Restart the engine after installing either; a newly installed plugin is not live
389
+ in a session that is already running.
350
390
 
351
391
  The equivalent by hand:
352
392
 
353
393
  ```sh
354
394
  claude plugin marketplace add moshcoder/moshcode
355
395
  claude plugin install ticker@moshcode
396
+ claude plugin install crypto@moshcode
356
397
  ```
357
398
 
358
399
  Claude Code is currently the only engine with a plugin primitive. The others are
package/bin/moshcode.mjs CHANGED
@@ -21,6 +21,7 @@ import { selfUpdateCommand } from "../src/selfupdate.mjs";
21
21
  import { describeUninstall, uninstallPlan } from "../src/uninstall.mjs";
22
22
  import { mcpCommand, pluginCommand, skillCommand } from "../src/integrations.mjs";
23
23
  import { tickerCommand } from "../src/advisor.mjs";
24
+ import { cryptoCommand } from "../src/crypto.mjs";
24
25
  import { canOpenBrowser, openBrowser } from "../src/open-url.mjs";
25
26
  import { locate, tilde } from "../src/pwd.mjs";
26
27
  import { createPrd, listPrds, authoringPrompt } from "../src/prd.mjs";
@@ -353,6 +354,13 @@ async function main() {
353
354
  if (code) process.exitCode = code;
354
355
  return;
355
356
  }
357
+ if (cmd === "crypto" || cmd === "coins") {
358
+ const code = await cryptoCommand(rest, {
359
+ openUrl: (url) => canOpenBrowser() && openBrowser(url),
360
+ });
361
+ if (code) process.exitCode = code;
362
+ return;
363
+ }
356
364
  if (cmd === "plugin" || cmd === "plugins") {
357
365
  const code = await pluginCommand(rest);
358
366
  if (code) process.exitCode = code;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moshcode",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "type": "module",
5
5
  "description": "moshcode — a metal wrapper for coding engines and native UGig/CoinPay workflow CLIs, with OpenPRD and moshscript",
6
6
  "repository": {
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
+ "name": "crypto",
4
+ "description": "Crypto market data slash commands backed by advis0r.com: live prices, technical scores, order books, OHLCV history and sparklines across Alpaca's US crypto venue.",
5
+ "version": "0.1.0",
6
+ "author": {
7
+ "name": "moshcoder",
8
+ "url": "https://moshcode.sh"
9
+ },
10
+ "homepage": "https://github.com/moshcoder/moshcode#crypto",
11
+ "license": "MIT",
12
+ "keywords": ["crypto", "bitcoin", "markets", "prices", "advis0r"]
13
+ }
@@ -0,0 +1,66 @@
1
+ # crypto — market data in your engine 🤘
2
+
3
+ Slash commands backed by [advis0r.com](https://advis0r.com/api/crypto): live
4
+ prices, technical scores, order books, OHLCV history and multi-pair sparklines
5
+ across Alpaca's US crypto venue.
6
+
7
+ | command | what it does |
8
+ | --- | --- |
9
+ | `/crypto BTC` | price, technicals, score, supply, order book |
10
+ | `/quote ETH-USD` | latest trade and quote, with the spread in bps |
11
+ | `/book BTC-USD` | top of the order book, both sides |
12
+ | `/bars ETH-USD` | historical OHLCV at any supported timeframe |
13
+ | `/spark BTC ETH SOL` | recent moves across pairs, ranked |
14
+ | `/pairs` | every supported pair, grouped by quote asset |
15
+ | `/coin bitcoin` | asset name → `BTC/USD` |
16
+
17
+ Pairs are accepted as `BTC`, `BTC-USD`, `BTC/USD` or `BTCUSD`. A bare asset
18
+ resolves to that asset's USD pair.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ moshcode plugin install crypto
24
+ ```
25
+
26
+ Or straight from Claude Code:
27
+
28
+ ```bash
29
+ claude plugin marketplace add moshcoder/moshcode
30
+ claude plugin install crypto@moshcode
31
+ ```
32
+
33
+ Restart the engine afterwards — a newly installed plugin is not live in a
34
+ session that is already running.
35
+
36
+ ## How it works
37
+
38
+ Each command shells out to `moshcode crypto …`, which calls advis0r's public,
39
+ read-only API. No key, no login, no write routes. With `moshcode` absent, every
40
+ command falls back to `curl` against the same endpoints.
41
+
42
+ Point the commands at another instance with `MOSHCODE_ADVISOR_URL`.
43
+
44
+ ## Why this is separate from `ticker`
45
+
46
+ They answer different questions from different data, and share only a hostname.
47
+ A `/ticker` report is a **stored snapshot** built from transcripts, SEC
48
+ fundamentals and extracted signals — its risk is a stale price read as a live
49
+ one. A `/crypto` report is a **live venue read** with no transcripts, no
50
+ filings and no signals — its risk is the opposite: a price that is accurate to
51
+ the second and stale by the time you act on it.
52
+
53
+ The scores are not comparable either. The crypto technical score counts
54
+ venue-local liquidity, so ranking a coin against an equity by score is
55
+ meaningless. Both surfaces ship their own `caveats`, and both commands are
56
+ instructed to print them.
57
+
58
+ ## What this is not
59
+
60
+ A research aid, not advice. Prices are Alpaca's US crypto venue alone and can
61
+ differ materially from other exchanges. Crypto trades 24/7 with no circuit
62
+ breakers — there is no close, no premarket, and no halt.
63
+
64
+ Trading lives behind a different verb: `moshcode trade` wraps Alpaca, previews
65
+ orders by default, and requires an explicit `--submit`. Nothing in this plugin
66
+ can place an order.
@@ -0,0 +1,35 @@
1
+ ---
2
+ description: Historical crypto OHLCV for one pair, at any supported timeframe.
3
+ argument-hint: <PAIR> [timeframe]
4
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
5
+ ---
6
+
7
+ ## Task
8
+
9
+ Pull historical bars for `$ARGUMENTS`.
10
+
11
+ ```bash
12
+ moshcode crypto bars $ARGUMENTS --timeframe 1Day --limit 30 --json
13
+ ```
14
+
15
+ Timeframes: `1Min`, `5Min`, `15Min`, `1Hour`, `1Day`, `1Week`. Add
16
+ `--start`/`--end` (ISO dates) to pin a window.
17
+
18
+ Fallback: `curl -sS "https://advis0r.com/api/crypto/bars?symbol=<PAIR>&timeframe=1Day&limit=30"`
19
+
20
+ ## Reading the response
21
+
22
+ `bars` is keyed by canonical symbol (`"BTC/USD"`), each value an ascending array
23
+ of `{ timestamp, open, high, low, close, volume, vwap }`.
24
+
25
+ ## Rules
26
+
27
+ - **`limit` is upstream's page size, not a cap on what returns.** The response
28
+ can hold more bars than you asked for. If you show a subset, say which subset
29
+ — "the 5 most recent of 17", never a silent truncation.
30
+ - Bars are ascending by time. Confirm the direction before calling a move.
31
+ - `volume` is base-asset units on Alpaca's US venue alone, not aggregate market
32
+ volume. Do not compare it to a CoinGecko or exchange-aggregate figure.
33
+ - Crypto bars are calendar-based and continuous — no gaps, no sessions, no
34
+ weekends. A "20-day" window here is not 20 trading sessions.
35
+ - End with the response's own `disclaimer`.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Top of the crypto order book, both sides, with the spread.
3
+ argument-hint: <PAIR>
4
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
5
+ ---
6
+
7
+ ## Task
8
+
9
+ Show the order book for `$ARGUMENTS`.
10
+
11
+ ```bash
12
+ moshcode crypto book $ARGUMENTS --depth 10 --json
13
+ ```
14
+
15
+ Fallback: `curl -sS "https://advis0r.com/api/crypto/orderbook?symbol=$ARGUMENTS&depth=10"`
16
+
17
+ ## Reading the response
18
+
19
+ `orderbooks[]` each carry a `timestamp`, `bids[]` and `asks[]`, every level a
20
+ `{ price, size }`. Bids descend from the best bid; asks ascend from the best ask.
21
+
22
+ ## Rules
23
+
24
+ - Report the spread in basis points, not just in dollars — a $50 spread means
25
+ something different on BTC than on ETH.
26
+ - **Size is depth on one venue, not the market.** Do not describe the book as
27
+ "the market's" depth, and do not extrapolate what a large order would fill at.
28
+ - A book is a snapshot of an instant. Timestamp it.
29
+ - If one side is much thinner than the other, say so plainly rather than
30
+ reading it as a directional signal — it is a liquidity observation.
31
+ - End with the response's own `disclaimer`.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Find a crypto pair by asset name (bitcoin → BTC/USD).
3
+ argument-hint: <asset name>
4
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
5
+ ---
6
+
7
+ ## Task
8
+
9
+ Resolve `$ARGUMENTS` to a tradable pair.
10
+
11
+ ```bash
12
+ moshcode crypto lookup $ARGUMENTS --limit 10 --json
13
+ ```
14
+
15
+ Fallback: `curl -sS "https://advis0r.com/api/crypto/lookup?q=<url-encoded>&limit=10"`
16
+
17
+ ## Reading the response
18
+
19
+ `matches` is a list of `{ symbol, slug, base, quote, name }`.
20
+
21
+ ## Rules
22
+
23
+ - One coin usually returns several pairs — `BTC/USD`, `BTC/USDC`, `BTC/USDT`.
24
+ Show them all and say which quote asset each settles in; default to the USD
25
+ pair unless the user asked otherwise.
26
+ - Watch for name collisions: a query can match a different coin whose name
27
+ merely contains the words ("bitcoin" also returns Bitcoin Cash). Say which
28
+ match is the one they meant.
29
+ - No match: say this venue lists no such pair, and do not invent a symbol. The
30
+ coin may exist and simply not be listed here — those are different answers.
31
+ - Offer `/crypto <PAIR>` for the match you land on.
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: Research one crypto pair — price, technicals, score, supply and order book.
3
+ argument-hint: <PAIR>
4
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
5
+ ---
6
+
7
+ ## Task
8
+
9
+ Pull the full report for `$ARGUMENTS` and summarize it for the user.
10
+
11
+ Run:
12
+
13
+ ```bash
14
+ moshcode crypto $ARGUMENTS --json
15
+ ```
16
+
17
+ If `moshcode` is not installed, fall back to the API directly:
18
+
19
+ ```bash
20
+ curl -sS "https://advis0r.com/api/crypto/report?symbol=$ARGUMENTS"
21
+ ```
22
+
23
+ Pairs are accepted as `BTC`, `BTC-USD`, `BTC/USD` or `BTCUSD`. A bare asset
24
+ resolves to that asset's USD pair.
25
+
26
+ ## Reading the response
27
+
28
+ - `snapshot` is the live read: `latestTrade`, `latestQuote` (bid/ask),
29
+ `dailyBar`, `prevDailyBar`, and a `change` against yesterday's close.
30
+ - `technical` holds sma / ema / rsi14 / macd / bollinger / atr14 /
31
+ `relativeVolume` / `momentum` / `trend` / `volatilityRegime`.
32
+ - `technicalScore.score` is 0–100 with a `breakdown`. It is **technical only** —
33
+ there is no thesis, no transcript and no filing behind a crypto pair.
34
+ - `fundamentals` is CoinGecko supply data: market cap, rank, circulating and max
35
+ supply, 24h volume, all-time high. It is absent for many pairs.
36
+ - `caveats` are per-response and specific. Read them before quoting the score.
37
+
38
+ ## Rules
39
+
40
+ - **These prices are Alpaca's US crypto venue alone.** Say so. They can differ
41
+ materially from Coinbase, Binance, or an aggregate index.
42
+ - Crypto trades 24/7 with no circuit breakers and no market close. Never
43
+ describe a crypto price as "at the close" or "premarket".
44
+ - State `generatedAt` / `fetchedAt`. This is a live read, so it goes stale in
45
+ seconds, not days — the opposite failure mode from a stored `/ticker` report.
46
+ - The score's liquidity component counts venue-local volume only, so it is
47
+ **not comparable** to an equity's score from `/ticker`. Do not rank the two
48
+ against each other.
49
+ - End with the response's own `disclaimer`. This is research, not advice.
50
+ - Link the shareable page: `https://advis0r.com/crypto/<PAIR>`.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: Every crypto pair advis0r can price, and which are trading.
3
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
4
+ ---
5
+
6
+ ## Task
7
+
8
+ List the supported pairs.
9
+
10
+ ```bash
11
+ moshcode crypto assets --json
12
+ ```
13
+
14
+ Fallback: `curl -sS "https://advis0r.com/api/crypto/assets"`
15
+
16
+ ## Reading the response
17
+
18
+ `assets[]` are `{ symbol, slug, base, quote, name, status }`. `slug` is the
19
+ URL-safe spelling (`BTC-USD`) used in paths; `symbol` is canonical (`BTC/USD`).
20
+ `status` is `live` or `idle`.
21
+
22
+ ## Rules
23
+
24
+ - Group by `quote` asset. The same coin priced in USD, USDT and BTC are three
25
+ different markets with three different liquidity profiles.
26
+ - **`idle` means listed but not currently printing trades** — it is not the same
27
+ as unsupported. Show idle pairs, marked, rather than filtering them out.
28
+ - If the user was looking for a specific coin, use `/coin <name>` instead of
29
+ scanning this list for them.
30
+ - This is the coverage of one venue, not of crypto. A coin missing here is
31
+ missing *from Alpaca's US venue*.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: The latest crypto trade and quote, with the bid/ask spread.
3
+ argument-hint: <PAIR>
4
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
5
+ ---
6
+
7
+ ## Task
8
+
9
+ Get the current quote for `$ARGUMENTS`.
10
+
11
+ ```bash
12
+ moshcode crypto quote $ARGUMENTS --json
13
+ ```
14
+
15
+ Fallback: `curl -sS "https://advis0r.com/api/crypto/quote?symbol=$ARGUMENTS"`
16
+
17
+ ## Reading the response
18
+
19
+ `quotes[]` each carry `latestTrade` (price, size, timestamp), `latestQuote`
20
+ (bidPrice/bidSize/askPrice/askSize), `spread`, `spreadBps`, and `mid`.
21
+
22
+ ## Rules
23
+
24
+ - Give the price at the precision the pair trades at. SHIB near $0.000006
25
+ rounded to two decimals is "$0.00", which is wrong, not concise.
26
+ - **`spreadBps` is the cost of crossing.** A wide spread means thin liquidity on
27
+ this venue — report it alongside the price rather than burying it.
28
+ - `latestTrade.timestamp` and `latestQuote.timestamp` can differ. If the last
29
+ trade is old, the mid is a quote, not evidence of a trade at that level.
30
+ - Prices are Alpaca's US crypto venue and trade 24/7 — never "at the close".
31
+ - End with the response's own `disclaimer`.
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Compare recent moves across several crypto pairs at once.
3
+ argument-hint: <PAIR> [PAIR…]
4
+ allowed-tools: Bash(moshcode crypto:*), Bash(curl -sS https://advis0r.com/api/crypto/:*)
5
+ ---
6
+
7
+ ## Task
8
+
9
+ Compare recent price action across `$ARGUMENTS`.
10
+
11
+ ```bash
12
+ moshcode crypto spark $ARGUMENTS --period 24h --json
13
+ ```
14
+
15
+ `--period` is `24h` or `7d`. Up to 20 pairs per call. With no pairs given, ask
16
+ which ones — or offer the majors (BTC, ETH, SOL).
17
+
18
+ Fallback: `curl -sS "https://advis0r.com/api/crypto/sparklines?symbols=BTC-USD,ETH-USD&period=24h"`
19
+
20
+ ## Reading the response
21
+
22
+ `series` is keyed by canonical symbol, each with `points[]` (closes, ascending),
23
+ `first`, `last`, `changePercent`, and the `start`/`end` of the window.
24
+
25
+ ## Rules
26
+
27
+ - Lead with `changePercent` per pair and rank them — that is the question a
28
+ multi-pair call is asking.
29
+ - **Each series is scaled to itself.** A dramatic-looking shape on one pair and
30
+ a flat one on another can be the same percentage move; compare the numbers,
31
+ not the shapes.
32
+ - Name the window (`start` → `end`) and the period. "Up 5%" over 24h and over 7d
33
+ are different claims.
34
+ - Do not extrapolate a trend from 24 points, and do not call a direction
35
+ "momentum" without the technicals to back it — `/crypto <PAIR>` has those.
36
+ - End with the response's own `disclaimer`.
package/src/advisor.mjs CHANGED
@@ -279,8 +279,18 @@ function compact(v) {
279
279
  const n = Number(v);
280
280
  if (!Number.isFinite(n)) return null;
281
281
  const units = [[1e12, "T"], [1e9, "B"], [1e6, "M"], [1e3, "K"]];
282
- for (const [size, suffix] of units) {
283
- if (Math.abs(n) >= size) return `${(n / size).toFixed(2).replace(/\.?0+$/, "")}${suffix}`;
282
+ for (let i = 0; i < units.length; i++) {
283
+ const [size, suffix] = units[i];
284
+ if (Math.abs(n) < size) continue;
285
+ // Rounding to 2 decimals can push a value just under the next boundary up to
286
+ // a full thousand of this unit (999,999,999 → "1000M"); carry it to the next
287
+ // unit up (→ "1B") so the number never reads as an un-carried thousand.
288
+ const scaled = (n / size).toFixed(2);
289
+ if (Math.abs(Number(scaled)) >= 1000 && i > 0) {
290
+ const [upSize, upSuffix] = units[i - 1];
291
+ return `${(n / upSize).toFixed(2).replace(/\.?0+$/, "")}${upSuffix}`;
292
+ }
293
+ return `${scaled.replace(/\.?0+$/, "")}${suffix}`;
284
294
  }
285
295
  return String(n);
286
296
  }
@@ -316,6 +316,36 @@ export const CORE_CLI_COMMANDS = [
316
316
  note: "research aid, not advice — reports are stored snapshots and every one prints when it was generated. Set MOSHCODE_ADVISOR_URL to point at another instance.",
317
317
  },
318
318
  { name: "advisor", aliasOf: "ticker", description: "alias for ticker" },
319
+ {
320
+ name: "crypto",
321
+ group: "tools",
322
+ description: "crypto market data from advis0r.com",
323
+ synopsis: [
324
+ ["moshcode crypto <pair>", "the full report for one pair"],
325
+ ["moshcode crypto <verb> [args…]", ""],
326
+ ],
327
+ verbs: "CRYPTO_VERBS",
328
+ flags: [
329
+ ["--json", "print the raw API response", ""],
330
+ ["--timeframe <tf>", "bars: 1Min | 5Min | 15Min | 1Hour | 1Day | 1Week", "1Day"],
331
+ ["--start <iso>", "bars: window start", "the API's own default"],
332
+ ["--end <iso>", "bars: window end", "now"],
333
+ ["--limit <n>", "cap results (bars/lookup)", "the API's own default"],
334
+ ["--depth <n>", "book: levels per side", "10"],
335
+ ["--period <p>", "spark: 24h | 7d", "24h"],
336
+ ["--horizon <n>", "technicals: quarters the score looks ahead (1 or 2)", "2"],
337
+ ],
338
+ examples: [
339
+ ["moshcode crypto BTC", "price, technicals, score, supply, order book"],
340
+ ["moshcode crypto lookup bitcoin", "asset name → BTC/USD"],
341
+ ["moshcode crypto spark BTC ETH SOL", "24h closes as sparklines"],
342
+ ["moshcode crypto bars ETH --timeframe 1Hour", "historical OHLCV"],
343
+ ["moshcode crypto book BTC-USD --depth 5", "top of book, both sides"],
344
+ ],
345
+ seeAlso: ["ticker", "trade", "plugin"],
346
+ note: "research aid, not advice — prices are Alpaca's US crypto venue alone and can differ materially from other exchanges. Crypto trades 24/7 with no circuit breakers. Set MOSHCODE_ADVISOR_URL to point at another instance.",
347
+ },
348
+ { name: "coins", aliasOf: "crypto", description: "alias for crypto" },
319
349
  {
320
350
  name: "plugin",
321
351
  group: "extend",
@@ -541,6 +571,42 @@ export const TICKER_VERBS = [
541
571
  { name: "open", description: "open the shareable report page in a browser", synopsis: [["moshcode ticker open <symbol>", ""]] },
542
572
  ];
543
573
 
574
+ /**
575
+ * `crypto`'s verbs.
576
+ *
577
+ * `report` earns its place for the same reason ticker's does — a bare pair is
578
+ * the shortcut, so a pair that collides with a verb name needs a spelling that
579
+ * cannot be mistaken for one. src/crypto.mjs owns the parser and
580
+ * test/crypto.test.mjs fails when the two lists disagree.
581
+ */
582
+ export const CRYPTO_VERBS = [
583
+ { name: "report", description: "the full report for one pair", synopsis: [["moshcode crypto report <pair>", "same as `moshcode crypto <pair>`"]] },
584
+ { name: "quote", description: "latest trade and quote, with the bid/ask spread", synopsis: [["moshcode crypto quote <pair>", ""]] },
585
+ {
586
+ name: "snapshot", description: "trade, quote and daily bars for several pairs",
587
+ synopsis: [["moshcode crypto snapshot <pair…>", "up to 20 pairs"]],
588
+ },
589
+ {
590
+ name: "technicals", description: "indicators and the technical score",
591
+ synopsis: [["moshcode crypto technicals <pair> [--horizon 1|2]", ""]],
592
+ },
593
+ {
594
+ name: "bars", description: "historical OHLCV",
595
+ synopsis: [["moshcode crypto bars <pair> [--timeframe tf] [--start iso] [--end iso] [--limit n]", ""]],
596
+ },
597
+ { name: "book", description: "top of the order book, both sides", synopsis: [["moshcode crypto book <pair> [--depth n]", ""]] },
598
+ {
599
+ name: "spark", description: "recent closes, drawn as sparklines",
600
+ synopsis: [["moshcode crypto spark <pair…> [--period 24h|7d]", ""]],
601
+ },
602
+ { name: "assets", description: "every supported pair", synopsis: [["moshcode crypto assets", ""]] },
603
+ {
604
+ name: "lookup", description: "find a pair by asset name",
605
+ synopsis: [["moshcode crypto lookup <name…> [--limit n]", "bitcoin → BTC/USD"]],
606
+ },
607
+ { name: "open", description: "open the shareable page in a browser", synopsis: [["moshcode crypto open <pair>", ""]] },
608
+ ];
609
+
544
610
  export const PLUGIN_VERBS = [
545
611
  {
546
612
  name: "install", description: "add the marketplace and install a plugin",
@@ -561,6 +627,7 @@ export const VERB_TABLES = {
561
627
  DNS_VERBS,
562
628
  TRADE_VERBS,
563
629
  TICKER_VERBS,
630
+ CRYPTO_VERBS,
564
631
  PLUGIN_VERBS,
565
632
  };
566
633
 
@@ -590,6 +657,8 @@ export const PIT_COMMANDS = [
590
657
  description: "look up markets and preview/place Alpaca orders" },
591
658
  { name: "ticker", aliases: ["advisor"], args: "<symbol|verb> [args…]", cli: "ticker",
592
659
  description: "equity research from advis0r.com" },
660
+ { name: "crypto", aliases: ["coins"], args: "<pair|verb> [args…]", cli: "crypto",
661
+ description: "crypto market data from advis0r.com" },
593
662
  { name: "plugin", aliases: ["plugins"], args: "<verb> [name]", cli: "plugin",
594
663
  description: "install moshcode's slash commands into Claude Code" },
595
664
  { name: "socials", aliases: ["social"], pitOnly: true,