@kaleidorg/mind 0.9.0 → 0.10.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.
Files changed (64) hide show
  1. package/dist/guards.d.ts.map +1 -1
  2. package/dist/guards.js +20 -0
  3. package/dist/guards.js.map +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/kaleidoswap/contract.d.ts +7 -0
  9. package/dist/kaleidoswap/contract.d.ts.map +1 -1
  10. package/dist/kaleidoswap/contract.js +71 -17
  11. package/dist/kaleidoswap/contract.js.map +1 -1
  12. package/dist/kaleidoswap/index.d.ts +1 -1
  13. package/dist/kaleidoswap/index.d.ts.map +1 -1
  14. package/dist/kaleidoswap/index.js +1 -1
  15. package/dist/kaleidoswap/index.js.map +1 -1
  16. package/dist/qvac/provider.d.ts.map +1 -1
  17. package/dist/qvac/provider.js +115 -96
  18. package/dist/qvac/provider.js.map +1 -1
  19. package/dist/recipe/asset-send.js +1 -1
  20. package/dist/recipe/asset-send.js.map +1 -1
  21. package/dist/testing/mock-wallet.d.ts.map +1 -1
  22. package/dist/testing/mock-wallet.js +6 -0
  23. package/dist/testing/mock-wallet.js.map +1 -1
  24. package/dist/wallet/contract.d.ts +5 -0
  25. package/dist/wallet/contract.d.ts.map +1 -1
  26. package/dist/wallet/contract.js +39 -6
  27. package/dist/wallet/contract.js.map +1 -1
  28. package/package.json +1 -1
  29. package/scripts/snapshot-mcp-tools.mjs +38 -0
  30. package/skills/README.md +98 -64
  31. package/skills/bitrefill/SKILL.md +30 -157
  32. package/skills/channel-manager/SKILL.md +31 -52
  33. package/skills/flashnet-swaps/SKILL.md +24 -150
  34. package/skills/kaleido-node/SKILL.md +25 -55
  35. package/skills/kaleido-trading/SKILL.md +28 -172
  36. package/skills/kaleido-trading/references/assets.md +4 -4
  37. package/skills/kaleido-trading/references/atomic.md +5 -7
  38. package/skills/merchant-finder/SKILL.md +25 -108
  39. package/skills/paid-data/SKILL.md +25 -58
  40. package/skills/portfolio-manager/SKILL.md +26 -60
  41. package/skills/rgb-lightning-node/SKILL.md +37 -255
  42. package/skills/rgb-lightning-node/references/channels.md +34 -0
  43. package/skills/spark-wallet/SKILL.md +26 -228
  44. package/skills/submarine-swaps/SKILL.md +19 -37
  45. package/skills/wallet-assistant/SKILL.md +26 -44
  46. package/src/funnel.mind.test.ts +6 -5
  47. package/src/guards.test.ts +12 -0
  48. package/src/guards.ts +20 -0
  49. package/src/index.ts +1 -0
  50. package/src/kaleidoswap/contract.test.ts +32 -3
  51. package/src/kaleidoswap/contract.ts +65 -17
  52. package/src/kaleidoswap/index.ts +1 -0
  53. package/src/qvac/provider.test.ts +17 -0
  54. package/src/qvac/provider.ts +23 -4
  55. package/src/recipe/asset-send.ts +1 -1
  56. package/src/recipe/recipe.test.ts +1 -1
  57. package/src/skills/catalog.test.ts +215 -0
  58. package/src/skills/mcp-tools.snapshot.json +1938 -0
  59. package/src/testing/mock-wallet.ts +6 -0
  60. package/src/wallet/contract.test.ts +20 -1
  61. package/src/wallet/contract.ts +36 -6
  62. package/skills/dca/SKILL.md +0 -48
  63. package/skills/kaleido-lsps/SKILL.md +0 -131
  64. package/skills/liquidity-optimizer/SKILL.md +0 -91
@@ -1,179 +1,35 @@
1
1
  ---
2
2
  name: kaleido-trading
3
- description: "Trade on KaleidoSwap — quote and execute swaps between BTC and RGB assets (USDT, XAUT). Get assets and pairs, pull an executable quote, or run/poll an atomic swap end-to-end. Triggers when the user wants a quote, to swap or trade assets, to rebalance between BTC and stablecoins, or to check the status of a swap / atomic swap."
4
- tools: kaleidoswap_get_assets, kaleidoswap_get_pairs, kaleidoswap_get_quote, kaleidoswap_atomic_init, kaleidoswap_atomic_execute, kaleidoswap_atomic_status, rln_get_node_info, rln_atomic_taker, rln_refresh_transfers, rln_get_asset_balance, rln_list_channels, rln_list_swaps, rln_get_swap
5
- triggers: quote, swap, trade, rebalance, slippage, pair, pairs, usdt, xaut, kaleidoswap, rfq, check status, order status, check the order, swap status, check my swap, atomic status
3
+ description: "Quote and run KaleidoSwap atomic swaps between BTC and RGB assets (USDT, XAUT): pairs, assets, quotes, swap execution and swap status."
4
+ tools: kaleidoswap_get_pairs, kaleidoswap_get_assets, kaleidoswap_get_quote, kaleidoswap_atomic_init, rln_atomic_taker, rln_get_node_info, kaleidoswap_atomic_execute, kaleidoswap_atomic_status, rln_refresh_transfers
5
+ requires-tools: kaleidoswap_get_quote
6
+ triggers: quote, swap, trade, pair, pairs, usdt, xaut, kaleidoswap, rfq, atomic, swap status
6
7
  metadata:
7
8
  author: kaleidoswap
8
- version: "0.5.0"
9
+ version: "0.6.0"
9
10
  ---
10
-
11
11
  # KaleidoSwap trading
12
12
 
13
- Quote and execute swaps on the KaleidoSwap maker. The model picks tools by
14
- name; the host binds them through whichever transport it runs over (WDK on
15
- mobile, HTTP/MCP/CLI on desktop).
16
-
17
- ## Critical rules — these override everything else
18
-
19
- You have **no knowledge** of any price, quote, fee, pair, or order. Every
20
- number, pair, or quote id in your reply MUST come from a tool result returned
21
- in the CURRENT turn:
22
-
23
- - "What pairs are listed?" → call `kaleidoswap_get_pairs` and list them.
24
- - "Quote 100k sats to USDT" → call `kaleidoswap_get_quote(BTC, USDT, 100000)`,
25
- then state the receive amount + fee from the result.
26
-
27
- **Calling the tool IS the answer.** Never write "the pairs are listed using
28
- kaleidoswap_get_pairs" or "the function returns the quote" — just call it.
29
-
30
- **Never reuse a number across turns.** If the user asks a new question, the
31
- previous turn's quote, price, or fee is irrelevant — fetch fresh.
32
-
33
- **Never invent a quote.** Without an `rfq_id` and a `to_asset.amount` returned
34
- this turn, you do not have a quote. Say so and re-quote.
35
-
36
- This skill is for tradeable pair quotes on the maker. It does NOT do generic
37
- "what is bitcoin worth in USD" spot prices — that's the wallet's job. If the
38
- user asks for a plain BTC price (not a swap), say you can quote a swap and ask
39
- which pair + amount.
40
-
41
- ## Asset codes (canonical)
42
-
43
- KaleidoSwap is the maker for **BTC ↔ RGB asset** atomic swaps. The asset
44
- family is **RGB**: USDT, XAUT, and any other RGB asset the maker prices.
45
- The RGB assets live on the user's **RLN** (RGB Lightning Node) — NOT on
46
- Spark, Arkade, or any other chain.
47
-
48
- Only these codes are accepted:
49
-
50
- - `BTC` (Bitcoin, amounts always in satoshis)
51
- - `USDT` (Tether, the RGB asset) — **not** `USD`, **not** `tether`
52
- - `XAUT` (Tether Gold, the RGB asset) — **not** `XAU`, **not** `gold`
53
-
54
- When the user types `USD` they almost always mean `USDT` — confirm before
55
- quoting. Same for `gold` → `XAUT`. Don't silently substitute.
56
-
57
- **Do NOT trade here:**
58
-
59
- - `USDB` and any other **Spark-native token** — those are on the Spark
60
- layer and trade on **Flashnet** (skill: `flashnet-swaps`), not on
61
- KaleidoSwap. Route the user there instead of inventing a maker pair.
62
- - Tokens from external chains (Ethereum USDT, Solana, etc.). They are
63
- not in the maker's catalog and the wallet does not custody them.
64
-
65
- ## Tools
66
-
67
- ### `kaleidoswap_get_pairs` — no args
68
- Use when the user asks "what can I trade", "list pairs", "what's available",
69
- or before quoting an unfamiliar pair.
70
-
71
- ### `kaleidoswap_get_quote` — REQUIRES `amount`
72
- Required args: `from_asset` AND `to_asset` AND `amount`. The maker rejects a
73
- quote that has no amount.
74
-
75
- **If the user didn't give an amount, ASK for it. Do NOT call the tool with
76
- from/to alone, and do NOT make up an amount.**
77
-
78
- `amount` is in the smallest unit of `from_asset`. Use the EXACT number the user
79
- typed (scaled if they used "k"/"m"/"M" shorthand: 100k → 100000, 2m → 2000000).
80
- **Never** copy an amount from a previous turn or from these instructions.
81
-
82
- Critical unit-and-leg anchor:
83
- - If the user says **sats** or **satoshis** anywhere, the BTC leg is implied
84
- (sats = the smallest unit of BTC). `BTC` is always `from_asset` OR `to_asset`
85
- depending on the verb.
86
- - "X sats TO Y" → `from_asset: "BTC"`, `to_asset: "Y"`, `amount: X-as-sats`.
87
- - "X Y TO BTC" (Y ∈ {USDT, XAUT}) → `from_asset: "Y"`, `to_asset: "BTC"`,
88
- `amount: X-in-Y-units`.
89
- - "buy Z of A with B" → spent = B → `from_asset: "B"`, received = A → `to_asset: "A"`,
90
- `amount: <amount of B the user wants to spend>`.
91
- - "rate of X to Y" with NO number → no amount → ASK: "How much do you want to
92
- swap?" → do NOT call the tool yet.
93
-
94
- ### Reading the quote response
95
-
96
- `kaleidoswap_get_quote` returns ready-to-read display fields — **use them
97
- verbatim. Do NOT do any arithmetic yourself.** The response looks like:
98
-
99
- ```
100
- {
101
- "rfq_id": "<id>",
102
- "from_amount_display": "100,000 BTC-sats", ← what the user spends
103
- "to_amount_display": "0.063176 USDT", ← what the user receives
104
- "fee_display": "0.000638 USDT", ← the fee
105
- "expires_at": <epoch>,
106
- ...raw numeric fields you should ignore...
107
- }
108
- ```
109
-
110
- To state the answer, copy the strings:
111
- - Receive amount → `to_amount_display`.
112
- - Fee → `fee_display`.
113
- - `rfq_id` is the quote handle (needed to start the atomic swap), short-lived (~60s) —
114
- mention it expires soon.
115
-
116
- **Read `to_amount_display` / `fee_display` exactly as given.** Do NOT compute
117
- `amount ÷ 10^precision`, do NOT restate the raw `price`/`amount` integers, and
118
- do NOT copy the numbers from this document — they are placeholders. The only
119
- correct numbers are the `*_display` strings in the CURRENT tool result.
120
-
121
- A good reply: *"100,000 sats → <to_amount_display> (fee <fee_display>). Quote
122
- <rfq_id> is valid ~60s — want me to place it?"*
123
-
124
- ### `kaleidoswap_atomic_init` 🔒 spend
125
- Only after `kaleidoswap_get_quote` returned an `rfq_id` THIS turn, and only when
126
- the user has explicitly approved the amount + direction. Starts the atomic
127
- swap from that quote; the rest of the chain (`rln_atomic_taker` →
128
- `kaleidoswap_atomic_execute` → `kaleidoswap_atomic_status`) is described
129
- below and in `references/atomic.md`.
130
-
131
- ### `kaleidoswap_atomic_status`
132
- Poll after executing an atomic swap until it reaches a terminal state
133
- (completed / failed / expired). Pass the exact ids returned by
134
- `kaleidoswap_atomic_init` (or surfaced in the most recent swap summary) — never
135
- invent them. Report the outcome plainly.
136
-
137
- ## Flow
138
-
139
- 1. **Pick a pair** — skip when obvious (`BTC/USDT`, `BTC/XAUT`).
140
- 2. **Quote** — `kaleidoswap_get_quote`. REQUIRES amount; ask if missing.
141
- 3. **Read + present** — compute the receive amount + fee from the response (see
142
- "Reading the quote response"). **Never hide cost.**
143
- 4. **Swap** — `kaleidoswap_atomic_init` → `rln_atomic_taker` →
144
- `kaleidoswap_atomic_execute`. Spend-gated by the engine; the host pauses for
145
- the user.
146
- 5. **Track** — poll `kaleidoswap_atomic_status` with the ids from
147
- `kaleidoswap_atomic_init` until it terminates.
148
-
149
- ## Don'ts
150
-
151
- - Don't invent prices, quotes, rfq_ids, swap ids, or access_tokens.
152
- - Don't reuse a number from a previous turn.
153
- - Don't describe how a tool works — call it.
154
- - Don't call `kaleidoswap_get_quote` with from/to only — ask for the amount.
155
- - Don't make up an amount the user didn't give.
156
- - Don't do unit math or restate raw integers — read the `*_display` strings.
157
- - Don't copy numbers from the skill docs — only the current tool result is real.
158
- - Don't accept `XAU` as `XAUT` or `USD` as `USDT` silently — confirm.
159
- - Don't retry the same failing tool call in a loop. If a call fails, read the
160
- error and either ask the user, fix the args, or stop.
161
- - Don't claim a swap completed without polling `kaleidoswap_atomic_status`
162
- and seeing a terminal state.
163
-
164
- For the full atomic-swap flow (init → whitelist on the RGB node → execute), a
165
- deterministic recipe drives the chain — the agentic loop is not safe to plan a
166
- multi-step, two-service swap on a small model. Status for atomics uses the
167
- `atomic_id` (or payment_hash) surfaced in the recipe summary.
168
-
169
- ## Over kaleido-mcp (desktop, Claude Code)
170
-
171
- kaleido-mcp 0.3.0+ is **atomic-only**. Its quote takes `from_asset_id` / `from_layer` /
172
- `from_amount` (display units) and returns `amount_raw` values that
173
- `kaleidoswap_atomic_init` takes unchanged. The full chain is quote →
174
- `kaleidoswap_atomic_init` → `rln_atomic_taker` + `rln_get_node_info` →
175
- `kaleidoswap_atomic_execute` → poll `kaleidoswap_atomic_status` →
176
- `rln_refresh_transfers`. Read `references/atomic.md` before the first swap,
177
- and `references/assets.md` for units and precision. Always follow the
178
- argument names in the tool schema you were given.
179
-
13
+ Amounts in `kaleidoswap_get_quote` are **display units**: `from_amount: 0.0005`
14
+ means 0.0005 BTC (50,000 sats; 1 BTC = 100,000,000 sats). Asset ids accept a
15
+ ticker (`BTC`, `USDT`, `XAUT`) or an `rgb:…` id.
16
+
17
+ ## Do
18
+ - Quote with exactly one amount: `from_amount` to sell a fixed input,
19
+ `to_amount` to buy a fixed output. No amount given → ask for one.
20
+ - Report `from_asset.amount_display`, `to_asset.amount_display` and
21
+ `expires_at` as given; `price` is in the maker's raw units, don't quote it.
22
+ The quote expires in about 60 s.
23
+ - Executing a swap moves funds: only after the user says yes to that quote.
24
+ Chain: `kaleidoswap_atomic_init` (rfq_id, both asset ids, both `amount_raw`
25
+ values unchanged) → `rln_atomic_taker` (swapstring) → `rln_get_node_info`
26
+ (pubkey) → `kaleidoswap_atomic_execute` → poll `kaleidoswap_atomic_status`.
27
+ Details and errors: `references/atomic.md`.
28
+ - `USD` is not `USDT` and `gold` is not `XAUT`: confirm before quoting.
29
+ Spark tokens such as USDB trade on Flashnet (`flashnet-swaps`), not here.
30
+
31
+ ## Examples
32
+ - "Quote 0.0005 BTC to USDT" → `kaleidoswap_get_quote {"from_asset_id":"BTC","to_asset_id":"USDT","from_amount":0.0005}`
33
+ - "Swap 100k sats into XAUT" → `kaleidoswap_get_quote {"from_asset_id":"BTC","to_asset_id":"XAUT","from_amount":0.001}`
34
+ - "I want to receive 10 USDT, how much BTC?" → `kaleidoswap_get_quote {"from_asset_id":"BTC","to_asset_id":"USDT","to_amount":10}`
35
+ - "Status of swap 9f2c…" → `kaleidoswap_atomic_status {"payment_hash":"9f2c…"}`
@@ -40,10 +40,10 @@ Read precision from the API; the table is illustrative.
40
40
 
41
41
  | Tool | Units |
42
42
  |---|---|
43
- | `kaleidoswap_get_quote` (kaleido-mcp) | display (`0.001` BTC, `65.0` USDT) |
44
- | `kaleidoswap_atomic_init` (kaleido-mcp) | raw: pass `quote.*.amount_raw` unchanged |
45
- | `kaleidoswap_get_quote` (in-app contract) | sats for BTC, asset units otherwise |
46
- | `rln_send_asset` / `rln_create_rgb_invoice` (kaleido-mcp) | display units |
43
+ | `kaleidoswap_get_quote` | display (`0.001` BTC, `65.0` USDT) |
44
+ | `kaleidoswap_atomic_init` | raw: pass `quote.*.amount_raw` unchanged |
45
+ | `rln_send_asset` / `rln_create_rgb_invoice` / `rln_issue_asset` | display units |
46
+ | `rln_list_assets` / `rln_get_asset_balance` balances | raw: divide by 10^precision |
47
47
 
48
48
  ## Mapping user words
49
49
 
@@ -1,13 +1,11 @@
1
- # Atomic swap over kaleido-mcp
1
+ # Atomic swap
2
2
 
3
3
  Every KaleidoSwap swap settles as an atomic HTLC swap between the maker and
4
- the user's RGB Lightning Node (RLN). There is no deposit or order flow on
5
- kaleido-mcp 0.3.0+. If either side fails, nothing settles. Typical end-to-end
4
+ the user's RGB Lightning Node (RLN). There is no deposit or order flow. If either side fails, nothing settles. Typical end-to-end
6
5
  time: 2–15 s.
7
6
 
8
- These are kaleido-mcp's argument names. In-app wallets that bind the
9
- `@kaleidorg/mind` KaleidoSwap contract use the simpler `from_asset` /
10
- `to_asset` / `amount` quote and run the chain through a recipe instead.
7
+ The argument names are the same in kaleido-mcp and in the `@kaleidorg/mind`
8
+ KaleidoSwap contract.
11
9
 
12
10
  ## Steps
13
11
 
@@ -58,7 +56,7 @@ and is not an order id.
58
56
 
59
57
  The swap needs outbound capacity on the asset you send and inbound capacity on
60
58
  the asset you receive. If either side is short, `atomic_execute` fails. Buy a
61
- channel first (skill: `kaleido-lsps`).
59
+ channel first (skill: `channel-manager`).
62
60
 
63
61
  ## Reading the result
64
62
 
@@ -1,117 +1,34 @@
1
1
  ---
2
2
  name: merchant-finder
3
- description: "Find Bitcoin-accepting merchants near the user using live BTC Map data and the device's real location. Triggers when the user asks where to spend Bitcoin, buy pizza/food with sats or bitcoin, eat at restaurants/cafes paying with sats, for a shop, store, restaurant, cafe, bar, or ATM that accepts Bitcoin, or for merchants nearby or in a city like turin."
3
+ description: "Find places that accept Bitcoin (shops, restaurants, cafes, bars, ATMs) near the user or in a named city, from live BTC Map data."
4
4
  tools: find_merchant_locations, search_knowledge
5
- triggers: merchant, merchants, shop, shops, store, stores, restaurant, restaurants, cafe, cafes, bar, bars, atm, atms, accept, accepts, accepting, nearby, near me, around me, where can i spend, pizza, pizz, food, coffee, eat, dinner, lunch, bitcoin map, btcmap
5
+ requires-tools: find_merchant_locations
6
+ triggers: merchant, merchants, shop, shops, store, restaurant, restaurants, cafe, cafes, coffee, bar, bars, atm, atms, near me, nearby, where can i spend, accept bitcoin, pizza, food, eat, btcmap, bitcoin map
6
7
  metadata:
7
8
  author: kaleidoswap
8
- version: "0.3.0"
9
+ version: "0.4.0"
9
10
  homepage: "https://btcmap.org"
10
11
  ---
11
-
12
12
  # Merchant finder
13
13
 
14
- Discover places that accept Bitcoin payments — cafés, restaurants, bars, shops,
15
- and ATMs. **Live BTC Map data only** — when the host has not injected a fetcher
16
- or cannot resolve a location, the tool returns `{success:false, error}`; relay
17
- that error to the user verbatim instead of inventing places.
18
-
19
- ## Critical rules (read first)
20
-
21
- 1. **Never answer from memory.** You have NO knowledge of any merchant. Every
22
- place, name, address and distance in your reply MUST come from a
23
- result returned by the merchant search tool in the CURRENT turn. Use the
24
- merchant search tool for every place question, even if a similar one
25
- was answered earlier — do NOT reuse a previous answer. Never invent a
26
- merchant. Do not mention the exact name of the tool in your text reply
27
- to the user.
28
- 2. **List, don't pick.** A "where can I…" / "find merchants" question is a
29
- LIST question. Show every merchant the tool returned (cap at the first ~5
30
- if there are many), ONE LINE EACH. Never collapse a list of 10 to one
31
- example. The host's "keep replies short" guidance applies to prose, not to
32
- a list the user explicitly asked for.
33
- 3. **Prefer minimal arguments; use understanding when mapping.** When the user
34
- speaks naturally, map their words to the available fields intelligently but
35
- conservatively. When in doubt, pass FEWER fields rather than guessing. The
36
- tool and the live data (plus any RAG hits you also fetch) are the source of
37
- truth — your job is to get the right starting call and then reason over
38
- what comes back.
39
-
40
- ## Using your understanding (the model is meant to help here)
41
-
42
- - Translate vague or natural language into the best minimal call:
43
- - "coffee near the station", "grab a bite", "something to eat" → `query: "coffee"` or `"food"` / `"pizza"` (or leave descriptive terms in `query`); consider `category: "cafe"` or `"restaurant"` only when it clearly fits one of the allowed values.
44
- - "near me for lunch" or "around here" → start with empty or just a broad `query`; let the device location do the work. You may infer a reasonable city from prior turns ("you mentioned Lugano earlier") and pass `near_address`.
45
- - "ATMs or shops that take lightning" → `query: "atm"` or separate calls, or put "atm shop lightning" in `query`.
46
- - "the cheaper ones", "with websites", "open late", "good for dinner" → use the tool first (possibly broad), then in the same or follow-up turn use the returned list + any other context/memory to filter, rank or describe. Do not fabricate entries.
47
- - **Critical for currency terms**: "where can I spend sats in turin", "bitcoin merchants in X", "places that accept crypto" are generic spend requests. **Do not** put "sats", "btc", "bitcoin", "spend" into `query` or invent a `category` (e.g. "shop"). Use only `near_address` (or empty). Putting currency words in query almost always returns zero results because the data source already only contains Bitcoin-accepting places.
48
-
49
- - Multi-turn and post-processing: After the merchant search tool returns a list you may (and should) reason over it: rank by distance or relevance to the user's phrasing, surface `phone`/`website`/`opening_hours` when present, note accepts_lightning, suggest next actions ("want directions or to check one?"), or combine with `search_knowledge` / memory results if merchants have been ingested for the area.
50
-
51
- - Hybrid live + RAG: If a `search_knowledge` tool is available and a merchant corpus is loaded, you can use both the live finder (for freshness + distance) and search for background on an area or previously-seen places. Present live results as the actionable list.
52
-
53
- - Context is fair game for *formulating the call or summarizing results* (e.g. previous city mentioned, user's preference for Lightning). It is never a substitute for calling the tool for the actual current list of places.
54
-
55
- ## How to call the tool
56
-
57
- 1. **Start with the merchant search tool.** Map the user's words to fields using the guidance above. The schema accepts:
58
-
59
- - `query` — free-text the user effectively named or implied (e.g. "coffee", "pizza", "food", "tapas", "atm"). Good place for terms that don't match a strict category. **Omit entirely** for generic "spend sats", "where can I spend", "merchants", "places to spend bitcoin", or "accept crypto". **Never** put "sats", "sat", "bitcoin", "btc", "crypto", "spend", or similar currency/verb terms here — the data source is already Bitcoin-only and this will usually return zero results.
60
-
61
- - `category` — **exactly one** of the allowed values when it fits cleanly: `restaurant`, `cafe`, `bar`, `shop`, `grocery`, `lodging`, `atm`. Leave empty otherwise. **For any generic "spend sats / where can I spend bitcoin / merchants in X" request, leave category empty.** Do not guess a category just because the user wants to spend. Generic nouns like "merchant", "place", "store" belong in `query` (or omitted), never as the category.
62
-
63
- - `near_address` — city / neighborhood / address when the user named a place instead of (or in addition to) "near me". The host will geocode it.
64
-
65
- - `radius_km` — only when the user gave a specific distance ("within 2 km"). Default (5 km) is already reasonable for a city; the backend applies a sensible bound.
66
-
67
- - `limit` — only when the user named a count (1–20).
68
-
69
- Positive examples (using understanding):
70
- - "where can I spend btc near me" → use the tool with `{}`
71
- - "where can I spend sats in turin" → use the tool with `{ near_address: "Turin" }` ← generic spend → minimal args, no query, no category
72
- - "where can I spend btc in Lugano" → use the tool with `{ near_address: "Lugano" }`
73
- - "cafes in Lisbon" → use the tool with `{ category: "cafe", near_address: "Lisbon" }`
74
- - "pizza places in Switzerland that take bitcoin" → use the tool with `{ query: "pizza", near_address: "Switzerland" }`
75
- - "lightning bars in NYC, within 2 km" → use the tool with `{ category: "bar", near_address: "New York", radius_km: 2 }`
76
- - "coffee near the station" or "grab a bite around here" → use the tool with `{ query: "coffee" }` or `{ query: "food" }` (let location come from device or prior context)
77
- - "ATMs or shops that take sats in the center" → first use the tool with `query: "atm shop"` + appropriate near_address; then reason over results.
78
-
79
- Things that are still wrong (schema or data reasons):
80
- - `category: "merchant"` or `"place"` (invalid per schema).
81
- - `query: "sats"`, `"btc"`, `"bitcoin"`, or any currency/spend verb (the dataset is already Bitcoin-only; these filters return nothing or almost nothing useful. "Spend sats" is a generic merchant request, not a filter term).
82
- - Guessing a tiny `radius_km` the user never mentioned (results will be empty).
83
- - Inventing a `category` (like "shop") for a completely generic "where can I spend sats" query — use no category and let the data speak.
84
- - Adding constraints the user did not name when a minimal call would have returned more relevant places.
85
-
86
- **Real bad example that causes zero results**:
87
- - "where can I spend sats in turin" → bad: use query "sats" + category "shop"
88
- ( "sats" in query + guessed category over-filters everything; correct is just the near_address or nothing).
89
-
90
- 2. **Present the results.** Each row carries:
91
- - `name`, `category`, `address`
92
- - `distance_m` when present — show in metres or km
93
- - `accepts_bitcoin` / `accepts_lightning` — relevant because Lightning is
94
- fastest for small payments
95
- - `phone`, `website`, `opening_hours` when present — surface if asked or relevant
96
-
97
- 3. **Handling failures.** If the tool returns `{success:false, error}`, relay
98
- the error as-is and stop. Common cases:
99
- - "Merchant search is unavailable…" → the host has no BTC Map adapter.
100
- - "Could not locate \"X\"…" → geocoding failed; ask the user for a nearby
101
- city or check the spelling.
102
- - "Could not determine your location…" → no `near_address` was passed and
103
- the device has no GPS / default location.
104
-
105
- Do NOT retry with invented data, and do NOT pretend you know merchants in
106
- the area. There is no offline fallback — a failure means no data.
107
-
108
- ## Reply style
109
-
110
- - **List, don't fabricate.** Show the merchants the tool actually returned (first ~5–8 is fine for long lists), one line each. You may add a short prose lead or helpful follow-up ("These are sorted by distance. The first two have websites.") but the names, categories, addresses and distances must come from the tool result in this turn.
111
- - One line per merchant (example):
112
- `Name — category, address (X m away, accepts: lightning, onchain)`.
113
- - If zero merchants: say so plainly. Suggest widening radius or trying a `near_address`. Do not invent alternatives.
114
- - When `precise_location` is false for a "near me" result, mention the fallback area that was used.
115
- - After showing the list you are free to reason, rank, or ask a clarifying follow-up using the data + conversation context.
116
-
117
- **Remember**: the live merchant search tool (plus any RAG merchant documents you also search) are the only sources of place information. Your value is excellent intent → arg mapping on the way in, and helpful reasoning / presentation on the way out. Do not name the tool in your user-facing reply.
14
+ Every place in a reply comes from `find_merchant_locations` in this turn. The
15
+ data is already Bitcoin-only.
16
+
17
+ ## Do
18
+ - Pass the fewest arguments that express the request:
19
+ - `near_address` when the user names a place; omit it for "near me".
20
+ - `category` only for a clear venue type: `restaurant`, `cafe`, `bar`,
21
+ `shop`, `grocery`, `lodging`, `atm`.
22
+ - `query` for a food or name ("pizza", "coffee"). Never "sats", "btc",
23
+ "bitcoin" or "spend".
24
+ - `radius_km` / `limit` only when the user gave a distance or count.
25
+ - List the results, one line each: name, category, address, distance, and
26
+ whether Lightning is accepted. Up to about 8.
27
+ - `{success:false, error}` → relay the error and stop.
28
+ - `search_knowledge` may add background from a loaded merchant corpus.
29
+
30
+ ## Examples
31
+ - "Where can I spend sats in Turin?" → `find_merchant_locations {"near_address":"Turin"}`
32
+ - "Cafes in Lisbon" → `find_merchant_locations {"category":"cafe","near_address":"Lisbon"}`
33
+ - "Pizza near me that takes bitcoin" → `find_merchant_locations {"query":"pizza"}`
34
+ - "Bitcoin ATMs within 2 km" → `find_merchant_locations {"category":"atm","radius_km":2}`
@@ -1,65 +1,32 @@
1
1
  ---
2
2
  name: paid-data
3
- description: Fetch premium or paywalled data behind an HTTP 402 Lightning payment (L402 or MPP, the Machine Payments Protocol) — paid feeds, pay-per-call APIs, unlockable resources — without signing up or holding an API key. Also finds paid APIs in the public 402index registry. Triggers when the user wants premium, paid, gated or unlockable data, or asks for a paid API.
4
- tools: fetch_paid_resource, search_paid_apis, mpp_request_challenge, mpp_parse_challenge_header, mpp_submit_credential, rln_mpp_pay, spark_mpp_pay, l402_request_challenge, l402_fetch_resource
5
- triggers: premium, paid, l402, mpp, 402, feed, subscription, unlock, paywall, pay per call, paid api, gated
3
+ description: "Fetch data behind an HTTP 402 Lightning paywall (L402 or MPP): paid feeds, pay-per-call APIs, unlockable resources, and finding paid APIs in the 402index registry."
4
+ tools: fetch_paid_resource, search_paid_apis, mpp_request_challenge, mpp_parse_challenge_header, rln_mpp_pay, spark_mpp_pay, mpp_submit_credential, l402_request_challenge, l402_fetch_resource
5
+ triggers: premium, paid, l402, mpp, 402, paywall, pay per call, paid api, gated, unlock
6
6
  metadata:
7
7
  author: kaleidoswap
8
- version: "0.2.0"
8
+ version: "0.3.0"
9
9
  ---
10
-
11
10
  # Paid data
12
11
 
13
- Servers gate a resource behind an HTTP 402 Lightning challenge; you pay the
14
- invoice and present the proof. L402 is the Lightning-only subset of MPP. Tell
15
- the user what was paid and what came back.
16
-
17
- Use whichever tools you have:
18
-
19
- ## In-app: one call
20
-
21
- `fetch_paid_resource({ url })` fetches, pays small invoices automatically
22
- (capped by the host) and returns the data. Anything above the cap is declined;
23
- report that instead of retrying.
24
-
25
- ## Over kaleido-mcp: three steps
26
-
27
- ```
28
- 1. mpp_request_challenge({ url })
29
- → { challenge_id, invoice, amount_sats, intent, expires_at, macaroon? }
30
-
31
- 2. rln_mpp_pay({ invoice, challenge_id, macaroon? }) ← pays from the RGB Lightning Node
32
- (or spark_mpp_pay with the same arguments, from the Spark wallet; better for
33
- tiny amounts where Lightning routing may fail)
34
- → { paid, payment_hash, preimage?, credential: "<JSON string>" }
35
-
36
- 3. mpp_submit_credential({ url, credential }) ← pass credential verbatim
37
- → { ok, status, data, receipt }
38
- ```
39
-
40
- Finish all three before `expires_at` (~60 s); a credential is single-use, so
41
- restart from step 1 if it expires. Keep the `receipt` as proof of payment.
42
-
43
- - **Discovery:** `search_paid_apis({ query, protocol?, health: "healthy" })`
44
- lists registered endpoints with their price; pick a healthy one, then run the
45
- flow on its `url`.
46
- - **Own fetch:** with a `WWW-Authenticate` header already in hand, use
47
- `mpp_parse_challenge_header({ url, www_authenticate })` instead of step 1.
48
- - **Legacy L402-only servers:** `l402_request_challenge` /
49
- `l402_fetch_resource`. Prefer the `mpp_*` tools; they handle both.
50
- - **Sessions:** `intent: "session"` challenges allow pay-once, then cheap
51
- repeat calls. Not every server offers them; fall back to `charge`.
52
-
53
- | Error | Meaning | Fix |
54
- |---|---|---|
55
- | `Expected HTTP 402` | URL is not payment-gated | Fetch it normally |
56
- | `payment failed` | Route or balance problem | Check balances; try `spark_mpp_pay` |
57
- | `401 after submit` | Bad or reused credential | Redo steps 1–3 |
58
- | `challenge expired` | Too slow between steps | Restart from step 1 |
59
-
60
- ## Rules
61
-
62
- 1. Show `amount_sats` before paying; ask for a yes above 1,000 sats.
63
- 2. Only pay challenges for URLs the user asked for.
64
- 3. Stop after two failures in a row and report; don't loop.
65
- 4. Dry run: report the price and what you would fetch; never pay.
12
+ A server answers 402 with a Lightning invoice; you pay it and present the proof.
13
+ Use whichever tools are available.
14
+
15
+ ## Do
16
+ - In-app: `fetch_paid_resource` with the `url` pays small invoices (capped by the host)
17
+ and returns the data. A declined payment is the answer; don't retry.
18
+ - kaleido-mcp, three steps before `expires_at` (~60 s):
19
+ 1. `mpp_request_challenge` (`url`) → `challenge_id`, `invoice`, `amount_sats`.
20
+ 2. `rln_mpp_pay` (`invoice`, `challenge_id`) (or `spark_mpp_pay`, same args) →
21
+ `credential`.
22
+ 3. `mpp_submit_credential` (`url`, `credential`) with the credential unchanged.
23
+ - Show `amount_sats` before paying; ask for a yes above 1,000 sats. Pay only
24
+ for URLs the user asked for. Stop after two failures.
25
+ - Find APIs: `search_paid_apis` (`query`, `health: "healthy"`), then run the flow on
26
+ the chosen `url`.
27
+
28
+ ## Examples
29
+ - "Get the premium feed at https://api.example.com/feed" → `mpp_request_challenge {"url":"https://api.example.com/feed"}`
30
+ - "Pay that challenge" → `rln_mpp_pay {"invoice":"<invoice>","challenge_id":"<challenge_id>"}`
31
+ - "Any paid weather APIs?" → `search_paid_apis {"query":"weather","health":"healthy"}`
32
+ - In-app → `fetch_paid_resource {"url":"https://api.example.com/feed"}`
@@ -1,67 +1,33 @@
1
1
  ---
2
2
  name: portfolio-manager
3
- description: "Keep a BTC / USDT / XAUT portfolio near its target allocation. Read live balances and prices, detect drift versus targets, and (when allowed) rebalance via an atomic swap on KaleidoSwap. Triggers when the user asks to rebalance, check allocation, review the portfolio, or optimize holdings — and is the skill the scheduled 'rebalance' loop runs."
4
- tools: rln_get_balances, rln_list_assets, kaleidoswap_get_pairs, kaleidoswap_get_quote, kaleidoswap_atomic_init, kaleidoswap_atomic_execute, kaleidoswap_atomic_status, get_price, get_market_data
5
- triggers: rebalance, allocation, portfolio, drift, optimize, target, weighting, holdings
3
+ description: "Portfolio across BTC, USDT and XAUT: holdings and allocation, drift versus targets, rebalancing and recurring DCA buys through KaleidoSwap atomic swaps. Runs the scheduled rebalance, DCA and daily summary tasks."
4
+ tools: rln_get_balances, rln_list_assets, get_price, get_market_data, kaleidoswap_get_pairs, kaleidoswap_get_quote, kaleidoswap_atomic_init, rln_atomic_taker, rln_get_node_info, kaleidoswap_atomic_execute, kaleidoswap_atomic_status
5
+ requires-tools: kaleidoswap_get_quote
6
+ triggers: portfolio, allocation, rebalance, drift, target, weighting, holdings, dca, dollar cost average, recurring buy, average in, accumulate, daily summary
6
7
  metadata:
7
8
  author: kaleidoswap
8
- version: "0.1.0"
9
+ version: "0.2.0"
9
10
  ---
10
-
11
11
  # Portfolio manager
12
12
 
13
- Keep the holdings near their target weights across **BTC**, **USDT**, and
14
- **XAUT**. You fetch everything live — never assume a balance, price, or target.
15
-
16
- ## Critical rules — these override everything else
17
-
18
- - **Read before you act.** Get balances (`rln_get_balances`) and prices
19
- (`get_price`) every run. Never reuse a number from a previous turn.
20
- - **Respect `dry_run`.** When `dry_run` is true you describe the rebalance you
21
- *would* make — you do NOT call `kaleidoswap_atomic_init`/`_execute`. This is
22
- non-negotiable.
23
- - **Respect fund safety.** Never propose a swap that breaches the BTC reserve or
24
- stop-loss floor passed in the task parameters. The host's risk gate is the
25
- final word, but don't even suggest a breach.
26
- - **Below-minimum drift = do nothing.** If every asset is within the drift
27
- threshold, say so and stop. Churn is a cost, not a feature.
28
-
29
- ## How to think about a rebalance
30
-
31
- 1. **Snapshot.** `rln_get_balances` → BTC sats + each RGB asset (raw units).
32
- 2. **Value it.** Convert each holding to a common denomination using
33
- `get_price`. Do NOT do arithmetic free-hand on raw RGB units — use the
34
- display fields the tools return; only convert sats↔USD with the live BTC
35
- price.
36
- 3. **Compare to targets.** Targets come in the task parameters (e.g.
37
- `BTC 70 / USDT 20 / XAUT 10`). Compute each asset's current weight and its
38
- drift = current − target.
39
- 4. **Decide.** If the largest drift exceeds the threshold, the over-weight asset
40
- sells into the most under-weight asset. One swap per run — smallest trade
41
- that brings the worst drift back inside the band.
42
- 5. **Quote.** `kaleidoswap_get_quote(from, to, amount)` for that single leg.
43
- 6. **Execute** (only when `dry_run` is false and the size is within limits): the
44
- atomic swap recipe drives `kaleidoswap_atomic_init` → `_execute`; then poll
45
- `kaleidoswap_atomic_status`.
46
-
47
- ## Asset codes (canonical)
48
-
49
- `BTC` (satoshis), `USDT` (not `USD`), `XAUT` (not `XAU`/gold).
50
-
51
- ## Scheduled (background) runs
52
-
53
- When run by the `rebalance` loop, after deciding, return STRICT JSON only:
54
-
55
- ```
56
- {"task":"rebalance","timestamp":"<ISO8601>","action":"rebalance|noop","dry_run":<bool>,"reason":"<why>","details":{"from":"<asset>","to":"<asset>","amount":"<n>","drift":{}}}
57
- ```
58
-
59
- `action` is `noop` when within band. Put the human explanation in `reason`.
60
-
61
- ## Don'ts
62
-
63
- - Don't invent prices, quotes, or balances — call the tool.
64
- - Don't rebalance on noise — honor the drift threshold.
65
- - Don't place more than one swap per run.
66
- - Don't breach the reserve / stop-loss, ever.
67
- - Don't execute anything when `dry_run` is true.
13
+ Holdings: BTC from `rln_get_balances`, RGB assets (with balances, raw units ÷
14
+ 10^precision) from `rln_list_assets`. Prices from `get_price`. Targets, budget,
15
+ reserve and `dry_run` come from the task parameters or the user.
16
+
17
+ ## Do
18
+ - Value each holding in one currency, compute weight and drift = weight −
19
+ target. Inside the threshold → no trade.
20
+ - Rebalance: one swap per run, the smallest that brings the worst drift back
21
+ inside the band, from the over-weight asset into the most under-weight one.
22
+ - DCA: buy the fixed slice every run; never catch up missed runs; skip when
23
+ BTC minus the slice would fall below the reserve.
24
+ - Quote with `kaleidoswap_get_quote` (display units). Execute only when
25
+ `dry_run` is false and within limits, via the atomic chain in the
26
+ `kaleido-trading` skill.
27
+ - Scheduled runs: `action` is `rebalance`, `buy`, `skip` or `noop`; put the
28
+ explanation in `reason`.
29
+
30
+ ## Examples
31
+ - "Show my allocation" → `rln_get_balances {}` then `rln_list_assets {}` then `get_price {"asset":"BTC"}`
32
+ - "DCA 0.0002 BTC into USDT" → `kaleidoswap_get_quote {"from_asset_id":"BTC","to_asset_id":"USDT","from_amount":0.0002}`
33
+ - "Sell 50 USDT back to BTC" → `kaleidoswap_get_quote {"from_asset_id":"USDT","to_asset_id":"BTC","from_amount":50}`