@t2000/cli 3.1.1 → 3.2.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/README.md +12 -7
- package/dist/{chunk-R7KXQRHQ.js → chunk-ZH6PX6WS.js} +91 -82
- package/dist/{chunk-R7KXQRHQ.js.map → chunk-ZH6PX6WS.js.map} +1 -1
- package/dist/{dist-2LJUAYXZ.js → dist-NH7XYB4F.js} +105 -50
- package/dist/{dist-2LJUAYXZ.js.map → dist-NH7XYB4F.js.map} +1 -1
- package/dist/{dist-A7D5R6SM.js → dist-UOJPIH47.js} +4 -2
- package/dist/index.js +52 -37
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- /package/dist/{dist-A7D5R6SM.js.map → dist-UOJPIH47.js.map} +0 -0
|
@@ -134371,6 +134371,63 @@ var init_cetus_swap = __esm2({
|
|
|
134371
134371
|
clientCache = /* @__PURE__ */ new Map();
|
|
134372
134372
|
}
|
|
134373
134373
|
});
|
|
134374
|
+
var swap_quote_exports = {};
|
|
134375
|
+
__export2(swap_quote_exports, {
|
|
134376
|
+
getSwapQuote: () => getSwapQuote
|
|
134377
|
+
});
|
|
134378
|
+
async function getSwapQuote(params) {
|
|
134379
|
+
const { findSwapRoute: findSwapRoute2, resolveTokenType: resolveTokenType2 } = await Promise.resolve().then(() => (init_cetus_swap(), cetus_swap_exports));
|
|
134380
|
+
const fromType = resolveTokenType2(params.from);
|
|
134381
|
+
const toType = resolveTokenType2(params.to);
|
|
134382
|
+
if (!fromType) {
|
|
134383
|
+
throw new T2000Error(
|
|
134384
|
+
"ASSET_NOT_SUPPORTED",
|
|
134385
|
+
`Unknown token: ${params.from}. Provide the symbol (USDC, SUI, ...) or full coin type.`
|
|
134386
|
+
);
|
|
134387
|
+
}
|
|
134388
|
+
if (!toType) {
|
|
134389
|
+
throw new T2000Error(
|
|
134390
|
+
"ASSET_NOT_SUPPORTED",
|
|
134391
|
+
`Unknown token: ${params.to}. Provide the symbol (USDC, SUI, ...) or full coin type.`
|
|
134392
|
+
);
|
|
134393
|
+
}
|
|
134394
|
+
const byAmountIn = params.byAmountIn ?? true;
|
|
134395
|
+
const fromDecimals = getDecimalsForCoinType(fromType);
|
|
134396
|
+
const rawAmount = BigInt(Math.floor(params.amount * 10 ** fromDecimals));
|
|
134397
|
+
const route = await findSwapRoute2({
|
|
134398
|
+
walletAddress: params.walletAddress,
|
|
134399
|
+
from: fromType,
|
|
134400
|
+
to: toType,
|
|
134401
|
+
amount: rawAmount,
|
|
134402
|
+
byAmountIn,
|
|
134403
|
+
providers: params.providers
|
|
134404
|
+
});
|
|
134405
|
+
if (!route) throw new T2000Error("SWAP_FAILED", `No swap route found for ${params.from} -> ${params.to}.`);
|
|
134406
|
+
if (route.insufficientLiquidity) {
|
|
134407
|
+
throw new T2000Error("SWAP_FAILED", `Insufficient liquidity for ${params.from} -> ${params.to}.`);
|
|
134408
|
+
}
|
|
134409
|
+
const toDecimals = getDecimalsForCoinType(toType);
|
|
134410
|
+
const fromAmount = Number(route.amountIn) / 10 ** fromDecimals;
|
|
134411
|
+
const toAmount = Number(route.amountOut) / 10 ** toDecimals;
|
|
134412
|
+
const routeDesc = route.routerData.paths?.map((p) => p.provider).filter(Boolean).slice(0, 3).join(" + ") ?? "Cetus Aggregator";
|
|
134413
|
+
const { serializeCetusRoute: serializeCetusRoute2 } = await Promise.resolve().then(() => (init_cetus_swap(), cetus_swap_exports));
|
|
134414
|
+
const serializedRoute = serializeCetusRoute2(route, { fromCoinType: fromType, toCoinType: toType });
|
|
134415
|
+
return {
|
|
134416
|
+
fromToken: params.from,
|
|
134417
|
+
toToken: params.to,
|
|
134418
|
+
fromAmount,
|
|
134419
|
+
toAmount,
|
|
134420
|
+
priceImpact: route.priceImpact,
|
|
134421
|
+
route: routeDesc,
|
|
134422
|
+
serializedRoute
|
|
134423
|
+
};
|
|
134424
|
+
}
|
|
134425
|
+
var init_swap_quote = __esm2({
|
|
134426
|
+
"src/swap-quote.ts"() {
|
|
134427
|
+
init_errors9();
|
|
134428
|
+
init_token_registry();
|
|
134429
|
+
}
|
|
134430
|
+
});
|
|
134374
134431
|
init_errors9();
|
|
134375
134432
|
var MIST_PER_SUI2 = 1000000000n;
|
|
134376
134433
|
var SUPPORTED_ASSETS = {
|
|
@@ -134429,7 +134486,8 @@ var SUPPORTED_ASSETS = {
|
|
|
134429
134486
|
displayName: "XAUM"
|
|
134430
134487
|
}
|
|
134431
134488
|
};
|
|
134432
|
-
var STABLE_ASSETS = ["USDC"];
|
|
134489
|
+
var STABLE_ASSETS = ["USDC", "USDsui"];
|
|
134490
|
+
var SAVEABLE_ASSETS = ["USDC", "USDsui"];
|
|
134433
134491
|
var ALL_NAVI_ASSETS = Object.keys(SUPPORTED_ASSETS);
|
|
134434
134492
|
var OPERATION_ASSETS = {
|
|
134435
134493
|
save: ["USDC", "USDsui"],
|
|
@@ -139054,7 +139112,7 @@ var ProtocolRegistry = class {
|
|
|
139054
139112
|
}
|
|
139055
139113
|
async bestSaveRateAcrossAssets() {
|
|
139056
139114
|
const candidates = [];
|
|
139057
|
-
for (const asset of
|
|
139115
|
+
for (const asset of SAVEABLE_ASSETS) {
|
|
139058
139116
|
for (const adapter2 of this.lending.values()) {
|
|
139059
139117
|
if (!adapter2.supportedAssets.includes(asset)) continue;
|
|
139060
139118
|
if (!adapter2.capabilities.includes("save")) continue;
|
|
@@ -139074,7 +139132,7 @@ var ProtocolRegistry = class {
|
|
|
139074
139132
|
async allRatesAcrossAssets() {
|
|
139075
139133
|
const results = [];
|
|
139076
139134
|
const seen = /* @__PURE__ */ new Set();
|
|
139077
|
-
for (const asset of
|
|
139135
|
+
for (const asset of SAVEABLE_ASSETS) {
|
|
139078
139136
|
if (seen.has(asset)) continue;
|
|
139079
139137
|
seen.add(asset);
|
|
139080
139138
|
for (const adapter2 of this.lending.values()) {
|
|
@@ -139782,36 +139840,24 @@ var T2000 = class _T2000 extends import_index2.default {
|
|
|
139782
139840
|
gasCost: gasResult.gasCostSui
|
|
139783
139841
|
};
|
|
139784
139842
|
}
|
|
139843
|
+
/**
|
|
139844
|
+
* [SPEC_AGENTIC_STACK P1 / SDK F2 — 2026-05-25]
|
|
139845
|
+
* Thin wrapper around the standalone `getSwapQuote()`. Pre-Phase 1 this method
|
|
139846
|
+
* was ~50 LoC duplicating `swap-quote.ts` — missing `serializedRoute` (SPEC 20.2
|
|
139847
|
+
* fast-path) and the `providers` allow-list (Bug A fix / Pyth-dependent
|
|
139848
|
+
* provider filter for sponsored callers). Routing both API surfaces through
|
|
139849
|
+
* one implementation ensures fixes land for both.
|
|
139850
|
+
*/
|
|
139785
139851
|
async swapQuote(params) {
|
|
139786
|
-
const {
|
|
139787
|
-
|
|
139788
|
-
const toType = resolveTokenType2(params.to);
|
|
139789
|
-
if (!fromType) throw new T2000Error("ASSET_NOT_SUPPORTED", `Unknown token: ${params.from}. Provide the full coin type.`);
|
|
139790
|
-
if (!toType) throw new T2000Error("ASSET_NOT_SUPPORTED", `Unknown token: ${params.to}. Provide the full coin type.`);
|
|
139791
|
-
const byAmountIn = params.byAmountIn ?? true;
|
|
139792
|
-
const fromDecimals = getDecimalsForCoinType(fromType);
|
|
139793
|
-
const rawAmount = BigInt(Math.floor(params.amount * 10 ** fromDecimals));
|
|
139794
|
-
const route = await findSwapRoute2({
|
|
139852
|
+
const { getSwapQuote: getSwapQuote2 } = await Promise.resolve().then(() => (init_swap_quote(), swap_quote_exports));
|
|
139853
|
+
return getSwapQuote2({
|
|
139795
139854
|
walletAddress: this._address,
|
|
139796
|
-
from:
|
|
139797
|
-
to:
|
|
139798
|
-
amount:
|
|
139799
|
-
byAmountIn
|
|
139855
|
+
from: params.from,
|
|
139856
|
+
to: params.to,
|
|
139857
|
+
amount: params.amount,
|
|
139858
|
+
byAmountIn: params.byAmountIn,
|
|
139859
|
+
providers: params.providers
|
|
139800
139860
|
});
|
|
139801
|
-
if (!route) throw new T2000Error("SWAP_NO_ROUTE", `No swap route found for ${params.from} -> ${params.to}.`);
|
|
139802
|
-
if (route.insufficientLiquidity) throw new T2000Error("SWAP_NO_ROUTE", `Insufficient liquidity for ${params.from} -> ${params.to}.`);
|
|
139803
|
-
const toDecimals = getDecimalsForCoinType(toType);
|
|
139804
|
-
const fromAmount = Number(route.amountIn) / 10 ** fromDecimals;
|
|
139805
|
-
const toAmount = Number(route.amountOut) / 10 ** toDecimals;
|
|
139806
|
-
const routeDesc = route.routerData.paths?.map((p) => p.provider).filter(Boolean).slice(0, 3).join(" + ") ?? "Cetus Aggregator";
|
|
139807
|
-
return {
|
|
139808
|
-
fromToken: params.from,
|
|
139809
|
-
toToken: params.to,
|
|
139810
|
-
fromAmount,
|
|
139811
|
-
toAmount,
|
|
139812
|
-
priceImpact: route.priceImpact,
|
|
139813
|
-
route: routeDesc
|
|
139814
|
-
};
|
|
139815
139861
|
}
|
|
139816
139862
|
// -- Wallet --
|
|
139817
139863
|
address() {
|
|
@@ -139942,6 +139988,16 @@ var T2000 = class _T2000 extends import_index2.default {
|
|
|
139942
139988
|
].join("\n")
|
|
139943
139989
|
};
|
|
139944
139990
|
}
|
|
139991
|
+
/**
|
|
139992
|
+
* [SPEC_AGENTIC_STACK P1 / SDK F2 (CLI rename support) — 2026-05-25]
|
|
139993
|
+
* Preferred alias of `deposit()`. The CLI surface is `t2000 fund` post-Phase 1
|
|
139994
|
+
* (more intuitive than "deposit" which sounds like a NAVI lending action).
|
|
139995
|
+
* `deposit()` stays as the canonical method name for back-compat; it is NOT
|
|
139996
|
+
* deprecated. This wrapper exists so SDK consumers can mirror CLI naming.
|
|
139997
|
+
*/
|
|
139998
|
+
async fund() {
|
|
139999
|
+
return this.deposit();
|
|
140000
|
+
}
|
|
139945
140001
|
receive(params) {
|
|
139946
140002
|
const amount2 = params?.amount ?? null;
|
|
139947
140003
|
const currency2 = params?.currency ?? "USDC";
|
|
@@ -140656,7 +140712,7 @@ var T2000 = class _T2000 extends import_index2.default {
|
|
|
140656
140712
|
this.emit("yield", {
|
|
140657
140713
|
earned: result.dailyEarning,
|
|
140658
140714
|
total: result.totalYieldEarned,
|
|
140659
|
-
apy: result.currentApy
|
|
140715
|
+
apy: result.currentApy,
|
|
140660
140716
|
timestamp: Date.now()
|
|
140661
140717
|
});
|
|
140662
140718
|
}
|
|
@@ -140724,8 +140780,7 @@ init_token_registry();
|
|
|
140724
140780
|
init_errors9();
|
|
140725
140781
|
init_errors9();
|
|
140726
140782
|
init_errors9();
|
|
140727
|
-
|
|
140728
|
-
init_token_registry();
|
|
140783
|
+
init_swap_quote();
|
|
140729
140784
|
init_cetus_swap();
|
|
140730
140785
|
init_token_registry();
|
|
140731
140786
|
init_volo();
|
|
@@ -141465,7 +141520,7 @@ init_zod();
|
|
|
141465
141520
|
var cachedSkills = null;
|
|
141466
141521
|
function getBakedSkills() {
|
|
141467
141522
|
if (cachedSkills) return cachedSkills;
|
|
141468
|
-
const raw = '[{"name":"t2000-account-report","description":"Render a complete account snapshot \u2014 wallet, savings, debt, recent activity, yield, and portfolio allocation, plus a short headline. Use when asked for a full report, account summary, \\"everything about my account\\", or \\"show me the full picture\\". Multi-tool orchestration \u2014 no single CLI command covers all six dimensions.","body":"# t2000: Account Report\\n\\n## Purpose\\nRender a complete account snapshot across six dimensions \u2014 wallet, savings,\\ndebt, recent activity, yield, portfolio allocation \u2014 followed by a 2\u20133\\nsentence headline. This is a **multi-tool orchestration**, not a single CLI\\ncommand. The right call sequence depends on the consumer:\\n\\n| Consumer | Call pattern |\\n|---|---|\\n| **MCP / Cursor / Claude Desktop** | `t2000_overview` covers wallet + savings + debt + health + earnings + rewards in one call. Add `t2000_history` (limit: 20) and `t2000_positions` if you also want activity and per-position APYs. |\\n| **CLI** | `t2000 balance --show-limits` + `t2000 positions` + `t2000 history --limit 20` |\\n| **Engine (audric/web)** | 6 parallel read tools \u2014 one per rendered card (see below). Calling fewer tools = missing cards. |\\n\\n## Engine orchestration (audric/web)\\n\\nWhen called inside the Audric chat agent, each read tool renders a\\ncanvas card. **Skipping a tool = missing card.** Always emit all six\\ntool_use blocks in parallel in the same assistant turn:\\n\\n| Tool | Card | Purpose |\\n|---|---|---|\\n| `balance_check` | BALANCE CHECK | Wallet, savings, debt, total |\\n| `savings_info` | SAVINGS INFO | Per-position breakdown, supply/borrow APY, daily earnings |\\n| `health_check` | HEALTH CHECK | Health factor, supplied, borrowed, max borrow, liquidation threshold |\\n| `activity_summary` | ACTIVITY SUMMARY | Monthly tx breakdown by category |\\n| `yield_summary` | YIELD SUMMARY | Today / week / month / all-time earnings, projected yearly |\\n| `portfolio_analysis` | PORTFOLIO ANALYSIS | Allocation %, week change, insights |\\n\\nAfter all six cards render, write a **2\u20133 sentence headline** that:\\n- Leads with net worth and weekly change.\\n- Mentions health factor in one phrase.\\n- Ends with the single most actionable insight (idle USDC, debt repayment, rate gap, etc).\\n- Does **NOT** narrate the cards\' contents \u2014 they render themselves.\\n- Does **NOT** list asset percentages, APYs, or savings positions in prose.\\n\\nMax 3 sentences total.\\n\\n## CLI quick command (no canvas)\\n\\nFor terminal users who just want the numbers in their shell:\\n\\n```bash\\nt2000 balance --show-limits\\nt2000 positions\\nt2000 history --limit 20\\n```\\n\\nThese three commands cover wallet + per-position APYs + recent activity.\\nFor a one-shot machine-parseable version, add `--json` to each.\\n\\n## Notes\\n\\n- This skill orchestrates **read-only** tools \u2014 no signatures, no on-chain writes.\\n- For a workflow-shaped advisor brief on top of this snapshot (recommendations, USDC APY gap, rebalance suggestion), use the `financial-report` MCP prompt \u2014 it composes this skill plus advisor framing.\\n- If the user holds non-USDC tokens, the portfolio card surfaces them but does not flag them as \\"saveable\\" \u2014 see `t2000-save` for the USDC/USDsui save-eligibility rule."},{"name":"t2000-borrow","description":"Borrow USDC or USDsui against savings collateral. Use when asked to borrow, take a loan, get credit, leverage savings, or access funds without withdrawing from savings. A 0.05% protocol fee applies. Only accepts USDC or USDsui. Always validates projected health factor before signing \u2014 refuses if HF would drop below 1.5.","body":"# t2000: Borrow USDC or USDsui\\n\\n## Purpose\\nTake a collateralized loan using savings deposits as collateral.\\nBorrowed funds go to the available balance. A 0.05% protocol fee applies.\\nUSDsui is permitted as a strategic exception (v0.51.0+) alongside USDC \u2014\\nboth have NAVI lending pools.\\n\\n## Command\\n```bash\\nt2000 borrow <amount> [--asset USDC|USDsui]\\n\\n# Examples:\\nt2000 borrow 40 # 40 USDC (default)\\nt2000 borrow 100 --asset USDsui # 100 USDsui\\n```\\n\\n`--asset` defaults to USDC when omitted.\\n\\n## Pre-borrow safety check (always runs)\\n\\nBefore broadcasting the borrow transaction, t2000 evaluates the projected\\nhealth factor and routes the user through one of three paths:\\n\\n| Projected HF after borrow | What happens |\\n|---|---|\\n| **< 1.5** | **Refuse** \u2014 borrow blocked with `HEALTH_FACTOR_TOO_LOW`. Error includes `maxBorrow` (the largest amount that keeps HF \u2265 1.5). Suggest: repay existing debt OR add more collateral. |\\n| **1.5 \u2013 2.0** | **Warn** \u2014 surface the projected HF and require explicit user confirmation. Always state: borrow amount, projected HF, current borrow APY. Do NOT silently proceed. |\\n| **> 2.0** | **Proceed** \u2014 borrow is well-collateralized, no extra confirmation needed beyond the standard signing flow. |\\n\\nAlways state to the user: **borrow amount**, **interest rate**, and\\n**projected health factor** before signing.\\n\\n## Engine orchestration (audric/web)\\n\\nWhen called inside the Audric chat agent:\\n\\n1. Call `health_check` first to get current HF and `maxBorrow`.\\n2. Compute projected HF: `(supplied \xD7 liquidationThreshold) / (borrowed + amountUsd)`.\\n3. Apply the table above \u2014 refuse / warn / proceed.\\n4. On user confirmation, emit `borrow({ amount, asset })` as the write tool_use.\\n\\nBorrows are always **single-write** \u2014 never bundle with another write in a\\nPayment Intent. The user must consciously accept the debt.\\n\\n## Fees\\n\\n- Protocol fee: 0.05% of the borrow amount\\n\\n## Output\\n\\n```\\n\u2713 Borrowed $XX.XX <asset>\\n Health Factor: X.XX\\n Borrow APY: X.XX%\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Error handling\\n\\n- `NO_COLLATERAL` \u2014 no savings deposited to borrow against. Use `t2000 save` first.\\n- `HEALTH_FACTOR_TOO_LOW` \u2014 borrow would drop HF below 1.5. Error data includes `maxBorrow`. Suggest: repay debt or add collateral.\\n- `UNSUPPORTED_ASSET` \u2014 asset is not USDC or USDsui. Other tokens cannot be borrowed (NAVI doesn\'t have pools for them).\\n\\n## Repayment symmetry (important)\\n\\n**A USDsui borrow MUST be repaid with USDsui.** A USDC borrow MUST be repaid\\nwith USDC. The SDK fetches the matching coin type per borrow asset. If the\\nuser holds only the wrong stable, tell them to swap manually first \u2014 never\\nauto-chain swap + repay. See `t2000-repay` for the repay flow.\\n\\n## What\'s NOT permitted\\n\\n- Borrowing in any asset other than USDC or USDsui (no SUI, GOLD, USDT, ETH borrows \u2014 NAVI doesn\'t have lending pools for those).\\n- Borrowing without a savings position (collateral first).\\n- Borrowing that drops HF below 1.5 (always refused; safety-critical)."},{"name":"t2000-check-balance","description":"Check the t2000 agent wallet balance on Sui. Use when asked about wallet balance, how much USDC is available, savings balance, gas reserve, or total funds. Also use before any send or borrow operation to confirm sufficient funds exist.","body":"# t2000: Check Balance\\n\\n## Purpose\\nFetch the current balance across all accounts: available USDC,\\nsavings (NAVI), gas reserve (SUI), and total value.\\n\\n## Commands\\n```bash\\nt2000 balance # human-readable summary\\nt2000 balance --show-limits # includes maxWithdraw, maxBorrow, healthFactor\\nt2000 balance --json # machine-parseable JSON (works on all commands)\\n```\\n\\n## Output (default)\\n```\\nAvailable: $150.00 (checking \u2014 spendable)\\nSavings: $2,000.00 (earning 5.10% APY)\\nGas: 0.50 SUI (~$0.50)\\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\nTotal: $2,150.50\\nEarning ~$0.27/day\\n```\\n\\n## Output (--show-limits)\\nAppends to the above:\\n```\\nLimits:\\n Max withdraw: $XX.XX\\n Max borrow: $XX.XX\\n Health factor: X.XX (\u221E if no active loan)\\n```\\n\\n## Notes\\n- `gasReserve.usdEquiv` is an estimate at current SUI price; it fluctuates\\n- If balance shows $0.00 available and wallet was just created, fund it first\\n via Coinbase Onramp or a direct USDC transfer to the wallet address\\n- `--json` is a global flag that works on all t2000 commands, not just balance"},{"name":"t2000-contacts","description":"Manage contacts \u2014 save a name-to-address mapping so the user can send money by name instead of pasting raw Sui addresses. Use when asked to add, remove, or list contacts, or to look up a saved address.","body":"# t2000: Contacts\\n\\n## Purpose\\nLet users send money by name instead of raw addresses. Contacts are stored\\nlocally in `~/.t2000/contacts.json` \u2014 no blockchain lookups, no network calls.\\n\\n## Commands\\n\\n```bash\\n# List all contacts\\nt2000 contacts\\n\\n# Add or update a contact\\nt2000 contacts add <name> <address>\\n\\n# Remove a contact\\nt2000 contacts remove <name>\\n```\\n\\n## Examples\\n\\n```bash\\nt2000 contacts add Tom 0x8b3e4f2a...\\n# \u2713 Added Tom (0x8b3e...f4a2)\\n\\nt2000 contacts add Tom 0xNEWADDRESS...\\n# \u2713 Updated Tom (0xNEWA...RESS)\\n\\nt2000 contacts remove Tom\\n# \u2713 Removed Tom\\n\\nt2000 contacts\\n# Contacts\\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n# Tom 0x8b3e...f4a2\\n# Alice 0x40cd...3e62\\n```\\n\\n## Sending by name\\n\\nOnce a contact is saved, use the name directly in `t2000 send`:\\n\\n```bash\\nt2000 send 50 USDC to Tom\\n# \u2713 Sent $50.00 USDC \u2192 Tom (0x8b3e...f4a2)\\n```\\n\\n## Name rules\\n- Letters, numbers, underscores only\\n- Case-insensitive (Tom = tom = TOM)\\n- Max 32 characters\\n- Reserved names: `to`, `all`, `address`\\n- Cannot start with `0x`\\n\\n## No PIN required\\nContact commands are local file operations \u2014 no wallet access, no PIN prompt.\\n\\n## JSON mode\\nAll subcommands support `--json` for structured output:\\n\\n```bash\\nt2000 contacts --json\\nt2000 contacts add Tom 0x... --json\\nt2000 contacts remove Tom --json\\n```\\n\\n## Error handling\\n- `INVALID_CONTACT_NAME`: name violates naming rules\\n- `CONTACT_NOT_FOUND`: name not in contacts when sending\\n- `INVALID_ADDRESS`: address provided to `add` is not a valid Sui address"},{"name":"t2000-engine","description":"Use the @t2000/engine package to build conversational AI agents with financial capabilities. Use when asked to set up AISDKEngine, build custom tools, configure LLM providers, handle streaming events, or integrate with MCP servers. Powers the Audric consumer product.","body":"# t2000: Agent Engine\\n\\n## Purpose\\nBuild conversational AI agents with financial capabilities on Sui.\\n`@t2000/engine` provides `AISDKEngine`, 37 financial tools (25 read + 12 write),\\nLLM orchestration via Vercel AI SDK v6, MCP client/server integration,\\nstreaming, sessions, and cost tracking.\\n\\n> The legacy `QueryEngine` + `AnthropicProvider` were deleted in engine v2.0.0 (2026-05-17).\\n> The `LLMProvider` abstraction + `AISDKAnthropicProvider` class were retired in v3.1.0\\n> (2026-05-25). `AISDKEngine` is the only engine; it wraps Vercel AI SDK v6\'s `streamText`\\n> and accepts `anthropicApiKey` (or `modelInstance` for custom providers / gateway routing).\\n\\n## Quick Start\\n```typescript\\nimport { AISDKEngine, getDefaultTools } from \'@t2000/engine\';\\nimport { T2000 } from \'@t2000/sdk\';\\n\\nconst agent = await T2000.create({ pin: process.env.T2000_PIN });\\n\\nconst engine = new AISDKEngine({\\n anthropicApiKey: process.env.ANTHROPIC_API_KEY,\\n agent,\\n tools: getDefaultTools(),\\n});\\n\\nfor await (const event of engine.submitMessage(\'What is my balance?\')) {\\n if (event.type === \'text_delta\') process.stdout.write(event.text);\\n}\\n```\\n\\n## Building Custom Tools\\n```typescript\\nimport { z } from \'zod\';\\nimport { defineTool } from \'@t2000/engine\';\\n\\nconst myTool = defineTool({\\n name: \'my_tool\',\\n description: \'Tool description for the LLM\',\\n inputSchema: z.object({ query: z.string() }),\\n isReadOnly: true,\\n isConcurrencySafe: true,\\n permissionLevel: \'auto\',\\n async call(input, context) {\\n return { data: { result: input.query }, displayText: `Result: ${input.query}` };\\n },\\n});\\n```\\n\\n> `defineTool` is the v2 factory. The pre-v2 `buildTool` was deleted in engine\\n> `1.38.0`. Signature is the same (Zod schema, isReadOnly, permissionLevel, `call`).\\n\\n## Permission Levels\\n| Level | Behavior | Use for |\\n|-------|----------|---------|\\n| `auto` | Executes immediately | Read-only queries |\\n| `confirm` | Yields `pending_action`, client executes and resumes | Financial writes |\\n| `explicit` | Never auto-dispatched by LLM | Dangerous operations |\\n\\nUSD-aware resolution: write tools with `permissionLevel: \'confirm\'` are\\ndynamically downgraded to `auto` if `amountUsd < rule.autoBelow` and the user\'s\\n`permissionConfig` is plumbed through `ToolContext`. See\\n`packages/engine/src/permission-rules.ts` for the three presets\\n(`conservative` / `balanced` / `aggressive`) and `borrow`-always-confirms rule.\\n\\n## Event Types\\n```typescript\\nfor await (const event of engine.submitMessage(prompt)) {\\n switch (event.type) {\\n case \'stream_started\': // first event \u2014 carries engine-generated streamId (v2.2.0+, when streamCheckpointStore is wired)\\n case \'text_delta\': // LLM text chunk (markers like <proactive> and <eval_summary> pass through verbatim; host strips at render)\\n case \'thinking_delta\': // Extended-thinking chunk (always-on)\\n case \'thinking_done\': // Thinking block closed\\n case \'tool_start\': // Tool execution beginning\\n case \'tool_result\': // Tool execution complete\\n case \'pending_action\': // Write tool needs approval \u2192 client executes, then resumes. action.attemptId is a UUID v4; persist on TurnMetrics + key resume `updateMany` on it\\n case \'canvas\': // Inline HTML/React canvas artifact\\n case \'turn_complete\': // Conversation turn finished\\n case \'usage\': // Token usage report (input / output / cache reads + writes)\\n case \'error\': // Unrecoverable error\\n }\\n}\\n```\\n\\n## MCP Client (consume external MCPs)\\n```typescript\\nimport { McpClientManager, NAVI_MCP_CONFIG } from \'@t2000/engine\';\\n\\nconst mcpManager = new McpClientManager();\\nawait mcpManager.connect(NAVI_MCP_CONFIG);\\n\\n// Read tools auto-use MCP when available, SDK as fallback\\nconst engine = new AISDKEngine({\\n provider,\\n agent,\\n mcpManager,\\n walletAddress: \'0x...\',\\n tools: getDefaultTools(),\\n});\\n```\\n\\n> Internally backed by `@ai-sdk/mcp`\'s `createMCPClient` since engine `v2.1.0`\\n> (SPEC 37 v0.7a Phase 4); `McpClientManager` class name + public method\\n> signatures preserved verbatim. `McpPromptAdapter` for MCP prompts is new in `v2.1.0`.\\n\\n## MCP Server (expose tools to AI clients)\\n```typescript\\nimport { registerEngineTools, getDefaultTools } from \'@t2000/engine\';\\nimport { McpServer } from \'@modelcontextprotocol/sdk/server/mcp.js\';\\n\\nconst server = new McpServer({ name: \'audric\', version: \'0.1.0\' });\\nregisterEngineTools(server, getDefaultTools());\\n// Tools exposed as audric_balance_check, audric_save_deposit, etc.\\n```\\n\\n## SSE Streaming (web apps)\\n```typescript\\n// [v2.2.0 / SPEC 37 v0.7a Phase 5 Slice A] `engineToSSE` was deleted \u2014\\n// iterate EngineEvent raw and call serializeSSE per event. Audric chat +\\n// resume routes have used this pattern since v1.4.2 (Spec G3). Hosts that\\n// want the SPEC 21.1 routing/quoting/etc \u2192 stream_state choreography wrap\\n// with `withStreamState` directly.\\nimport { serializeSSE, withStreamState } from \'@t2000/engine\';\\n\\nfor await (const event of withStreamState(engine.submitMessage(prompt))) {\\n const wireBytes = event.type === \'error\'\\n ? serializeSSE({ type: \'error\', message: event.error.message })\\n : serializeSSE(event);\\n // Send wireBytes to client via SSE\\n}\\n// Write tools yield pending_action \u2192 client executes on-chain \u2192 POST /api/engine/resume\\n```\\n\\n## Stream Checkpoint Resume (v2.2.0+)\\n```typescript\\n// Wire a checkpoint store to enable page-reload / cold-start resume of the\\n// LIVE stream. Engine emits `stream_started` first (carries the streamId),\\n// appends every event fire-and-forget, and replays the checkpoint when the\\n// host passes the id back as `EngineConfig.resumeStreamId`.\\nimport { InMemoryStreamCheckpointStore } from \'@t2000/engine\';\\n\\nconst engine = new AISDKEngine({\\n // ...\\n streamCheckpointStore: new InMemoryStreamCheckpointStore(),\\n});\\n// In-flight tool on resume = Path B (error + re-prompt). CLI / MCP / tests\\n// use the in-memory default; multi-instance hosts (audric on Vercel) inject Upstash.\\n```\\n\\n## Built-in Tools (26 \u2014 was 31 pre-S.277)\\n\\n### Read (18, parallel, auto-approved)\\n`render_canvas`, `balance_check`, `savings_info`, `health_check`, `rates_info`,\\n`transaction_history`, `swap_quote`, `explain_tx`, `portfolio_analysis`,\\n`token_prices`, `create_payment_link`, `list_payment_links`,\\n`cancel_payment_link`, `spending_analytics`, `yield_summary`,\\n`activity_summary`, `resolve_suins`, `pending_rewards`\\n\\n### Write (8, structurally serial, confirmation required)\\n`save_deposit` (USDC + USDsui), `withdraw`, `send_transfer`,\\n`borrow` (USDC + USDsui), `repay_debt` (USDC + USDsui \u2014 same asset as borrow),\\n`claim_rewards`, `harvest_rewards`, `swap_execute`\\n\\n> **S.245 (2026-05-22):** `pay_api` (write) + `mpp_services` (read) deleted\\n> per V07E_D_QUESTION_AUDITS D-2 reframe. The legacy MPP gateway\\n> capability returns as a Commerce primitive in the upcoming Audric Store\\n> SPEC \u2014 clean-slate redesign, not a port of the legacy 3-leg apps/web flow.\\n>\\n> **S.269 (2026-05-23):** `save_contact` deleted (engine-side dead \u2014 host\\n> owns Prisma persistence). V07E_INVOICE_DEPRECATION (item 7 of S.269)\\n> deleted 3 invoice tools \u2014 `create_invoice`, `list_invoices`,\\n> `cancel_invoice` \u2014 and the `InvoiceSchema` Zod definition. Payment\\n> links absorb the invoicing use case (label/memo encode invoice\\n> context). 35 \u2192 31 tools.\\n>\\n> **S.277 (2026-05-23):** \\"Earns Its Keep\\" audit cut 5 tools + 2 dead\\n> guards (engine 2.18.0). Volo trio (`volo_stats`, `volo_stake`,\\n> `volo_unstake`) \u2014 no Audric chip / product slot for liquid staking;\\n> `harvest_rewards` routes vSUI via Cetus, not Volo. `web_search`\\n> (Brave-backed) \u2014 gateway path uses Vercel AI Gateway\'s\\n> `perplexity_search` instead. `protocol_deep_dive` (DefiLlama) \u2014\\n> `rates_info` covers the in-product safety lens; engine no longer\\n> talks to `api.llama.fi`. 2 dead guards removed (`guardCostWarning`,\\n> `guardArtifactPreview`) \u2014 both unreachable post-S.245. `explain_tx`\\n> kept but description tightened to \\"arbitrary external digest only\\".\\n> SDK + CLI + MCP retain Volo for non-Audric consumers. 31 \u2192 26 tools\\n> (18 read + 8 write), 14 \u2192 12 guards.\\n>\\n> **S.269 item 6 (2026-05-23):** `save_contact` (write) deleted as part of\\n> the template-divergence cleanup slice. Engine-side dead tool \u2014 host-side\\n> Prisma persistence with no engine-owned effect; the user surface is the\\n> audric send screen, not the LLM.\\n>\\n> **S.277 (2026-05-23):** \\"Earns Its Keep\\" audit cut 5 tools from the\\n> engine surface \u2014 `volo_stats` / `volo_stake` / `volo_unstake` (no\\n> Audric chip / product slot; SDK + CLI + MCP retain Volo for non-Audric\\n> consumers), `web_search` (Brave-backed; gateway path uses Vercel AI\\n> Gateway\'s `perplexity_search`), `protocol_deep_dive` (DefiLlama-backed;\\n> rates_info is the in-product proxy). Also dropped: 2 dead guards\\n> (`costWarning`, `artifactPreview`) + the `costAware` flag. `explain_tx`\\n> kept but description tightened to \\"arbitrary external digest only\\". Net\\n> 31 \u2192 26 engine tools. See `spec/archive/v07e/AUDIT_V07E_EARNS_ITS_KEEP_2026-05-23.md`.\\n\\n> Write serialization is structural in v2 \u2014 no in-process mutex. Confirm-tier\\n> writes yield a `pending_action` event, the host round-trips through user\\n> confirm, and the next step runs the next write. Auto-execute writes\\n> (USD-aware permission resolver, sub-threshold) inherit one-write-per-step\\n> from the LLM\'s planning + the conservative-default preset.\\n\\n## Configuration\\n```typescript\\nnew AISDKEngine({\\n anthropicApiKey: process.env.ANTHROPIC_API_KEY, // Required (or pass `modelInstance` for custom providers)\\n agent, // T2000 SDK instance\\n mcpManager, // McpClientManager for MCP-first reads\\n walletAddress, // Sui address for MCP reads\\n tools: getDefaultTools(),\\n systemPrompt, // Override default Audric prompt\\n model: \'claude-sonnet-4-5\',\\n maxTurns: 10,\\n maxTokens: 4096,\\n costTracker: { budgetLimitUsd: 1.0 },\\n streamCheckpointStore, // optional, v2.2.0+ for live-stream resume\\n resumeStreamId, // optional, replays a checkpointed stream on cold start\\n});\\n```\\n\\n## Key Imports\\n```typescript\\n// Core\\nimport { AISDKEngine, getDefaultTools } from \'@t2000/engine\';\\n// Tools (defineTool is the v2 factory; READ_TOOL_SET / WRITE_TOOL_SET / READ_TOOL_NAMES are the tool registries since v3.0.0)\\nimport { defineTool, READ_TOOL_SET, WRITE_TOOL_SET, READ_TOOL_NAMES } from \'@t2000/engine\';\\n// Streaming (`engineToSSE` was deleted in v2.2.0 \u2014 see \\"SSE Streaming\\" above)\\nimport { serializeSSE, parseSSE, withStreamState } from \'@t2000/engine\';\\n// Stream checkpoint resume (v2.2.0+)\\nimport { InMemoryStreamCheckpointStore } from \'@t2000/engine\';\\n// Sessions\\nimport { MemorySessionStore } from \'@t2000/engine\';\\n// Cost\\nimport { CostTracker } from \'@t2000/engine\';\\n// Microcompact + context budgeting\\nimport { microcompact, compactMessages, estimateTokens } from \'@t2000/engine\';\\n// Granular permissions (USD-aware resolver)\\nimport {\\n resolvePermissionTier, resolveUsdValue, toolNameToOperation,\\n DEFAULT_PERMISSION_CONFIG, PERMISSION_PRESETS,\\n} from \'@t2000/engine\';\\n// MCP\\nimport {\\n McpClientManager, McpPromptAdapter,\\n NAVI_MCP_CONFIG, buildMcpTools, registerEngineTools,\\n} from \'@t2000/engine\';\\n```"},{"name":"t2000-mcp","description":"Connect a t2000 agent bank account to Claude Desktop, Cursor, Cline, Continue, or any MCP-compatible client. Use when asked to set up MCP, paste an MCP server config, install @t2000/mcp, or troubleshoot why the MCP server \\"doesn\'t do anything\\" when run from a terminal. Provides 29 tools and 14 prompts over stdio.","body":"# t2000: MCP Server\\n\\n## Purpose\\nExpose a t2000 agent bank account (Sui wallet + DeFi positions) to any\\nMCP-compatible AI client over stdio. **29 tools, 14 prompts**, safeguard\\nenforced. No global install required \u2014 the recommended path uses `npx`\\nso the AI client always pulls the latest published version.\\n\\n## \u26A0\uFE0F The most common confusion\\n\\n**`npx @t2000/mcp` is NOT a command you run from a terminal to \\"use\\" the\\nMCP server.** It is a JSON-RPC server that listens silently on `stdin`.\\nIf you run it manually it will appear to hang \u2014 that\'s correct behavior.\\nIt is meant to be launched as a subprocess by an AI client (Claude\\nDesktop, Cursor, etc.) which speaks JSON-RPC to it over `stdin`/`stdout`.\\n\\nThe JSON snippets below go into your **AI client\'s MCP settings file**,\\nnot into a shell.\\n\\n## Setup\\n\\n### 1. Create a wallet + safeguards (one-time, in a terminal)\\n\\n```bash\\n# Install CLI long enough to bootstrap a wallet and set safety limits\\nnpx @t2000/cli init\\nnpx @t2000/cli config set maxPerTx 100\\nnpx @t2000/cli config set maxDailySend 500\\n\\n# Create a session so MCP can reuse the saved PIN\\nnpx @t2000/cli balance\\n```\\n\\nThe MCP server **refuses to start** until `maxPerTx` and `maxDailySend`\\nare configured. This is intentional.\\n\\n### 2. Add the MCP server to your AI client\\n\\nRecommended config (auto-updates on every launch, no global install):\\n\\n```json\\n{\\n \\"mcpServers\\": {\\n \\"t2000\\": {\\n \\"command\\": \\"npx\\",\\n \\"args\\": [\\"-y\\", \\"@t2000/mcp@latest\\"]\\n }\\n }\\n}\\n```\\n\\nAlternative (if `@t2000/cli` is already installed globally):\\n\\n```json\\n{\\n \\"mcpServers\\": {\\n \\"t2000\\": {\\n \\"command\\": \\"t2000\\",\\n \\"args\\": [\\"mcp\\"]\\n }\\n }\\n}\\n```\\n\\n### 3. Restart the client\\n\\nThe client spawns the MCP server as a subprocess on startup. You should\\nsee `t2000_*` tools appear in the tool list.\\n\\n## Per-client config file paths\\n\\n| Client | Config file |\\n|--------|-------------|\\n| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |\\n| Claude Desktop (Windows) | `%APPDATA%\\\\Claude\\\\claude_desktop_config.json` |\\n| Cursor | Settings \u2192 MCP \u2192 Add new MCP server (or `~/.cursor/mcp.json`) |\\n| Cline | VSCode settings \u2192 `cline.mcpServers` |\\n| Continue | `~/.continue/config.json` under `mcpServers` |\\n\\n## Verification (optional, before wiring into a client)\\n\\nConfirm the server responds to a real MCP `initialize` request:\\n\\n```bash\\nprintf \'%s\\\\n\' \\\\\\n \'{\\"jsonrpc\\":\\"2.0\\",\\"id\\":1,\\"method\\":\\"initialize\\",\\"params\\":{\\"protocolVersion\\":\\"2024-11-05\\",\\"capabilities\\":{},\\"clientInfo\\":{\\"name\\":\\"test\\",\\"version\\":\\"1.0\\"}}}\' \\\\\\n | npx -y @t2000/mcp@latest\\n```\\n\\nYou should see a JSON response containing `\\"serverInfo\\":{\\"name\\":\\"t2000\\"...}`\\nand exit. If you see that, the server is healthy and ready to be launched\\nby a client.\\n\\n## Available Tools (29)\\n\\n### Read-only (15)\\n| Tool | Description |\\n|------|-------------|\\n| `t2000_overview` | Complete account snapshot in one call |\\n| `t2000_balance` | Current balance |\\n| `t2000_address` | Wallet address |\\n| `t2000_positions` | Lending positions |\\n| `t2000_rates` | Best interest rates per asset |\\n| `t2000_all_rates` | Per-protocol rate comparison |\\n| `t2000_health` | Health factor |\\n| `t2000_history` | Transaction history |\\n| `t2000_earnings` | Yield earnings |\\n| `t2000_fund_status` | Savings fund status |\\n| `t2000_pending_rewards` | Pending protocol rewards |\\n| `t2000_deposit_info` | Deposit instructions |\\n| `t2000_receive` | Generate payment request with address, nonce, and Payment Kit URI (`sui:pay?\u2026`) |\\n| `t2000_services` | List all MPP services and endpoints |\\n| `t2000_contacts` | List saved contacts |\\n\\n### State-changing (12)\\nAll support `dryRun: true` for previews without signing.\\n\\n| Tool | Description |\\n|------|-------------|\\n| `t2000_send` | Send USDC |\\n| `t2000_save` | Deposit to savings |\\n| `t2000_withdraw` | Withdraw from savings |\\n| `t2000_borrow` | Borrow against collateral |\\n| `t2000_repay` | Repay debt |\\n| `t2000_claim_rewards` | Claim pending protocol rewards |\\n| `t2000_pay` | Pay for and call any MPP API service with USDC |\\n| `t2000_swap` | Execute a token swap via Cetus Aggregator |\\n| `t2000_stake` | Stake SUI for vSUI via VOLO liquid staking |\\n| `t2000_unstake` | Unstake vSUI and redeem SUI |\\n| `t2000_contact_add` | Save a contact name \u2192 address |\\n| `t2000_contact_remove` | Remove a saved contact |\\n\\n### Safety (2)\\n| Tool | Description |\\n|------|-------------|\\n| `t2000_config` | View/set limits |\\n| `t2000_lock` | Emergency freeze |\\n\\n## Prompts (14)\\n| Prompt | Description |\\n|--------|-------------|\\n| `financial-report` | Full financial summary |\\n| `optimize-yield` | Yield optimization analysis |\\n| `send-money` | Guided send with preview |\\n| `budget-check` | Can I afford $X? |\\n| `savings-strategy` | Recommend how much to save and where |\\n| `what-if` | Scenario planning \u2014 model impact before acting |\\n| `sweep` | Route idle funds to optimal earning positions |\\n| `risk-check` | Health factor, concentration, liquidation risk |\\n| `weekly-recap` | Week in review \u2014 activity, yield |\\n| `claim-rewards` | Check and claim pending protocol rewards |\\n| `safeguards` | Review safety settings \u2014 limits, lock, PIN-protected operations |\\n| `onboarding` | New user setup \u2014 deposit, first save, explore features |\\n| `emergency` | Lock account, assess damage, recovery guidance |\\n| `optimize-all` | One-shot full optimization \u2014 sweep, compare APYs, claim rewards |\\n\\n## Troubleshooting\\n\\n| Symptom | Cause | Fix |\\n|---------|-------|-----|\\n| `npx @t2000/mcp` \\"hangs\\" with no output | Working as designed \u2014 server is waiting for JSON-RPC on stdin | Don\'t run it manually; let the AI client launch it |\\n| Server exits with `Safeguards not configured` | `maxPerTx` / `maxDailySend` not set | Run `npx @t2000/cli config set maxPerTx 100 && ... maxDailySend 500` |\\n| Client shows no `t2000_*` tools after restart | Wrong config path, or stale npx cache | Verify with the `printf | npx ...` test above; clear cache with `rm -rf ~/.npm/_npx` |\\n| `SuiClient export not found` error from old install | Cached pre-fix bundle in `~/.npm/_npx` | `rm -rf ~/.npm/_npx` then restart the client |\\n\\n## Engine MCP Adapter (Audric)\\n\\n`@t2000/engine` can also expose its financial tools as MCP tools, enabling\\nAudric to serve as an MCP server alongside `@t2000/mcp`:\\n\\n```typescript\\nimport { registerEngineTools, getDefaultTools } from \'@t2000/engine\';\\nimport { McpServer } from \'@modelcontextprotocol/sdk/server/mcp.js\';\\n\\nconst server = new McpServer({ name: \'audric\', version: \'0.1.0\' });\\nregisterEngineTools(server, getDefaultTools());\\n// Exposes: audric_balance_check, audric_save_deposit, etc.\\n```\\n\\nEngine tools use `audric_` prefix to avoid collisions with `t2000_` prefixed\\ntools from `@t2000/mcp`. The engine adapter includes permission-level metadata\\nand supports the full confirmation flow.\\n\\n## Security\\n- Safeguard gate: server refuses to start without configured limits\\n- `unlock` is CLI-only \u2014 AI cannot circumvent a locked agent\\n- `dryRun: true` previews operations before signing\\n- Local-only stdio transport \u2014 key never leaves the machine"},{"name":"t2000-pay","description":"Pay for an MPP-protected API service using the t2000 wallet. Use when asked to call an AI model, search the web, generate images, send email, buy gift cards, send physical mail, check weather, execute code, or any task that requires a paid API. Handles the full MPP 402 challenge automatically. Use t2000_services to discover all available services first.","body":"# t2000: Pay for MPP API Service\\n\\n## Status\\nActive \u2014 requires `t2000` CLI with `@suimpp/mpp` installed.\\n\\n## Purpose\\nMake a paid HTTP request to any MPP-protected endpoint. Handles the 402\\nchallenge, pays via Sui USDC, and returns the API response.\\n\\n## Service Discovery\\nBefore calling `t2000 pay`, discover available services:\\n```bash\\n# CLI\\nt2000 pay https://mpp.t2000.ai/api/services\\n\\n# MCP\\nt2000_services\\n```\\n\\nAll services are hosted at `https://mpp.t2000.ai/`.\\n\\n## Command\\n```bash\\nt2000 pay <url> [options]\\n```\\n\\n## Options\\n| Option | Description | Default |\\n|--------|-------------|---------|\\n| `--method <method>` | HTTP method (GET, POST, PUT) | POST |\\n| `--data <json>` | Request body for POST/PUT | \u2014 |\\n| `--max-price <amount>` | Max USDC per request | $1.00 |\\n| `--header <key=value>` | Additional HTTP header (repeatable) | \u2014 |\\n| `--timeout <seconds>` | Request timeout in seconds | 30 |\\n| `--dry-run` | Show what would be paid without paying | \u2014 |\\n\\n## Available Services (40 services, 88 endpoints)\\n\\n> For the live, canonical list use `t2000_services` (MCP) or GET `https://mpp.t2000.ai/api/services`.\\n> The table below is a quick reference.\\n\\n### AI Models\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| OpenAI Chat | `/openai/v1/chat/completions` | $0.01 |\\n| OpenAI Embeddings | `/openai/v1/embeddings` | $0.005 |\\n| OpenAI Audio Transcription | `/openai/v1/audio/transcriptions` | $0.01 |\\n| OpenAI Text-to-Speech | `/openai/v1/audio/speech` | $0.02 |\\n| Anthropic | `/anthropic/v1/messages` | $0.01 |\\n| Google Gemini Flash | `/gemini/v1beta/models/gemini-2.5-flash` | $0.005 |\\n| Google Gemini Pro | `/gemini/v1beta/models/gemini-2.5-pro` | $0.01 |\\n| Google Gemini Embeddings | `/gemini/v1beta/models/embedding-001` | $0.005 |\\n| DeepSeek | `/deepseek/v1/chat/completions` | $0.005 |\\n| Groq Chat | `/groq/v1/chat/completions` | $0.005 |\\n| Groq Audio Transcription | `/groq/v1/audio/transcriptions` | $0.005 |\\n| Together AI Chat | `/together/v1/chat/completions` | $0.005 |\\n| Together AI Embeddings | `/together/v1/embeddings` | $0.005 |\\n| Perplexity | `/perplexity/v1/chat/completions` | $0.01 |\\n| Mistral Chat | `/mistral/v1/chat/completions` | $0.005 |\\n| Mistral Embeddings | `/mistral/v1/embeddings` | $0.005 |\\n| Cohere Chat | `/cohere/v1/chat` | $0.005 |\\n| Cohere Embed | `/cohere/v1/embed` | $0.005 |\\n| Cohere Rerank | `/cohere/v1/rerank` | $0.005 |\\n\\n### Media & Generation\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| OpenAI DALL-E | `/openai/v1/images/generations` | $0.05 |\\n| Fal.ai Flux Dev | `/fal/fal-ai/flux/dev` | $0.03 |\\n| Fal.ai Flux Pro | `/fal/fal-ai/flux-pro` | $0.05 |\\n| Fal.ai Flux Realism | `/fal/fal-ai/flux-realism` | $0.05 |\\n| Fal.ai Recraft 20B | `/fal/fal-ai/recraft-20b` | $0.05 |\\n| Fal.ai Whisper | `/fal/fal-ai/whisper` | $0.01 |\\n| Together AI Images | `/together/v1/images/generations` | $0.03 |\\n| ElevenLabs TTS | `/elevenlabs/v1/text-to-speech/:voiceId` | $0.05 |\\n| ElevenLabs SFX | `/elevenlabs/v1/sound-generation` | $0.05 |\\n| Replicate (any model) | `/replicate/v1/predictions` | $0.02 |\\n| Replicate (check status) | `/replicate/v1/predictions/status` | $0.005 |\\n| Stability AI (generate) | `/stability/v1/generate` | $0.03 |\\n| Stability AI (edit) | `/stability/v1/edit` | $0.03 |\\n| AssemblyAI (transcribe) | `/assemblyai/v1/transcribe` | $0.02 |\\n| AssemblyAI (get result) | `/assemblyai/v1/result` | $0.005 |\\n\\n### Search\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Brave Web Search | `/brave/v1/web/search` | $0.005 |\\n| Brave Image Search | `/brave/v1/images/search` | $0.005 |\\n| Brave News Search | `/brave/v1/news/search` | $0.005 |\\n| Brave Video Search | `/brave/v1/videos/search` | $0.005 |\\n| Brave Summarizer | `/brave/v1/summarizer/search` | $0.01 |\\n| Exa (semantic search) | `/exa/v1/search` | $0.01 |\\n| Exa (content extract) | `/exa/v1/contents` | $0.01 |\\n| Serper (Google search) | `/serper/v1/search` | $0.005 |\\n| Serper (image search) | `/serper/v1/images` | $0.005 |\\n| SerpAPI (Google search) | `/serpapi/v1/search` | $0.01 |\\n| SerpAPI (Google Flights) | `/serpapi/v1/flights` | $0.01 |\\n| SerpAPI (locations) | `/serpapi/v1/locations` | $0.005 |\\n| NewsAPI (headlines) | `/newsapi/v1/headlines` | $0.005 |\\n| NewsAPI (article search) | `/newsapi/v1/search` | $0.005 |\\n\\n### Data\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| OpenWeather Current | `/openweather/v1/weather` | $0.005 |\\n| OpenWeather Forecast | `/openweather/v1/forecast` | $0.005 |\\n| Google Maps Geocode | `/googlemaps/v1/geocode` | $0.01 |\\n| Google Maps Places | `/googlemaps/v1/places` | $0.01 |\\n| Google Maps Directions | `/googlemaps/v1/directions` | $0.01 |\\n| CoinGecko (price) | `/coingecko/v1/price` | $0.005 |\\n| CoinGecko (markets) | `/coingecko/v1/markets` | $0.005 |\\n| CoinGecko (trending) | `/coingecko/v1/trending` | $0.005 |\\n| Alpha Vantage (quote) | `/alphavantage/v1/quote` | $0.005 |\\n| Alpha Vantage (daily) | `/alphavantage/v1/daily` | $0.005 |\\n| Alpha Vantage (search) | `/alphavantage/v1/search` | $0.005 |\\n\\n### Web & Documents\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Firecrawl Scrape | `/firecrawl/v1/scrape` | $0.01 |\\n| Firecrawl Crawl | `/firecrawl/v1/crawl` | $0.02 |\\n| Firecrawl Map | `/firecrawl/v1/map` | $0.01 |\\n| Firecrawl Extract | `/firecrawl/v1/extract` | $0.02 |\\n| Jina Reader | `/jina/v1/read` | $0.005 |\\n| ScreenshotOne | `/screenshot/v1/capture` | $0.01 |\\n| PDFShift (HTML to PDF) | `/pdfshift/v1/convert` | $0.01 |\\n| QR Code | `/qrcode/v1/generate` | $0.005 |\\n\\n### Translation\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| DeepL (translate) | `/deepl/v1/translate` | $0.005 |\\n| Google Translate | `/translate/v1/translate` | $0.005 |\\n| Google Detect Language | `/translate/v1/detect` | $0.005 |\\n\\n### Intelligence\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Hunter.io (domain search) | `/hunter/v1/search` | $0.02 |\\n| Hunter.io (verify email) | `/hunter/v1/verify` | $0.02 |\\n| IPinfo (IP lookup) | `/ipinfo/v1/lookup` | $0.005 |\\n\\n### Tools & Compute\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Judge0 Code Exec | `/judge0/v1/submissions` | $0.005 |\\n| Judge0 Languages | `/judge0/v1/languages` | $0.005 |\\n| Resend Email | `/resend/v1/emails` | $0.005 |\\n| Resend Batch Email | `/resend/v1/emails/batch` | $0.01 |\\n\\n### Commerce\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Lob Postcards | `/lob/v1/postcards` | $1.00 |\\n| Lob Letters | `/lob/v1/letters` | $1.50 |\\n| Lob Address Verify | `/lob/v1/verify` | $0.01 |\\n| Printful (browse) | `/printful/v1/products` | $0.005 |\\n| Printful (estimate) | `/printful/v1/estimate` | $0.005 |\\n| Printful (order) | `/printful/v1/order` | dynamic |\\n\\n### Messaging\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Pushover | `/pushover/v1/push` | $0.005 |\\n\\n### Security\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| VirusTotal (URL/file scan) | `/virustotal/v1/scan` | $0.01 |\\n\\n### Finance\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| ExchangeRate (rates) | `/exchangerate/v1/rates` | $0.005 |\\n| ExchangeRate (convert) | `/exchangerate/v1/convert` | $0.005 |\\n\\n### Utility\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Short.io (URL shortener) | `/shortio/v1/shorten` | $0.005 |\\n\\n## Example Commands\\n\\n### Ask an AI model\\n```bash\\nt2000 pay https://mpp.t2000.ai/openai/v1/chat/completions \\\\\\n --data \'{\\"model\\":\\"gpt-4o\\",\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\"Explain quantum computing in 3 sentences\\"}]}\'\\n```\\n\\n### Search the web\\n```bash\\nt2000 pay https://mpp.t2000.ai/brave/v1/web/search \\\\\\n --data \'{\\"q\\":\\"latest Sui blockchain news\\"}\'\\n```\\n\\n### Generate an image\\n```bash\\nt2000 pay https://mpp.t2000.ai/fal/fal-ai/flux/dev \\\\\\n --data \'{\\"prompt\\":\\"a futuristic city at sunset, cyberpunk style\\"}\'\\n```\\n\\n### Check weather\\n```bash\\nt2000 pay https://mpp.t2000.ai/openweather/v1/weather \\\\\\n --data \'{\\"q\\":\\"Tokyo\\"}\'\\n```\\n\\n### Send an email\\n```bash\\nt2000 pay https://mpp.t2000.ai/resend/v1/emails \\\\\\n --data \'{\\"from\\":\\"agent@t2000.ai\\",\\"to\\":\\"user@example.com\\",\\"subject\\":\\"Hello\\",\\"text\\":\\"Sent by an AI agent\\"}\'\\n```\\n\\n### Execute code\\n```bash\\nt2000 pay https://mpp.t2000.ai/judge0/v1/submissions \\\\\\n --data \'{\\"source_code\\":\\"print(42)\\",\\"language_id\\":71}\'\\n```\\n\\n### Send physical mail\\n```bash\\n# Send a postcard\\nt2000 pay https://mpp.t2000.ai/lob/v1/postcards \\\\\\n --max-price 2 \\\\\\n --data \'{\\n \\"to\\":{\\"name\\":\\"Jane Doe\\",\\"address_line1\\":\\"123 Main St\\",\\"address_city\\":\\"San Francisco\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94105\\"},\\n \\"from\\":{\\"name\\":\\"AI Agent\\",\\"address_line1\\":\\"456 Oak Ave\\",\\"address_city\\":\\"Palo Alto\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94301\\"},\\n \\"front\\":\\"https://example.com/front.png\\",\\n \\"back\\":\\"https://example.com/back.png\\",\\n \\"use_type\\":\\"operational\\"\\n }\'\\n\\n# Send a letter\\nt2000 pay https://mpp.t2000.ai/lob/v1/letters \\\\\\n --max-price 2 \\\\\\n --data \'{\\n \\"to\\":{\\"name\\":\\"Jane Doe\\",\\"address_line1\\":\\"123 Main St\\",\\"address_city\\":\\"San Francisco\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94105\\"},\\n \\"from\\":{\\"name\\":\\"AI Agent\\",\\"address_line1\\":\\"456 Oak Ave\\",\\"address_city\\":\\"Palo Alto\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94301\\"},\\n \\"file\\":\\"https://example.com/letter.pdf\\",\\n \\"use_type\\":\\"operational\\",\\n \\"color\\":false\\n }\'\\n\\n# Verify a US address\\nt2000 pay https://mpp.t2000.ai/lob/v1/verify \\\\\\n --data \'{\\"primary_line\\":\\"123 Main St\\",\\"city\\":\\"San Francisco\\",\\"state\\":\\"CA\\",\\"zip_code\\":\\"94105\\"}\'\\n```\\n\\n### Get directions\\n```bash\\nt2000 pay https://mpp.t2000.ai/googlemaps/v1/directions \\\\\\n --data \'{\\"origin\\":\\"San Francisco, CA\\",\\"destination\\":\\"Palo Alto, CA\\"}\'\\n```\\n\\n### Get crypto prices\\n```bash\\nt2000 pay https://mpp.t2000.ai/coingecko/v1/price \\\\\\n --data \'{\\"ids\\":\\"sui,bitcoin,ethereum\\",\\"vs_currencies\\":\\"usd\\"}\'\\n```\\n\\n### Get a stock quote\\n```bash\\nt2000 pay https://mpp.t2000.ai/alphavantage/v1/quote \\\\\\n --data \'{\\"symbol\\":\\"AAPL\\"}\'\\n```\\n\\n### Get breaking news\\n```bash\\nt2000 pay https://mpp.t2000.ai/newsapi/v1/headlines \\\\\\n --data \'{\\"country\\":\\"us\\",\\"category\\":\\"technology\\"}\'\\n```\\n\\n### Translate text\\n```bash\\nt2000 pay https://mpp.t2000.ai/deepl/v1/translate \\\\\\n --data \'{\\"text\\":[\\"Hello, how are you?\\"],\\"target_lang\\":\\"ES\\"}\'\\n```\\n\\n### Semantic search\\n```bash\\nt2000 pay https://mpp.t2000.ai/exa/v1/search \\\\\\n --data \'{\\"query\\":\\"best practices for AI agent payments\\",\\"numResults\\":5}\'\\n```\\n\\n### Read a URL as markdown\\n```bash\\nt2000 pay https://mpp.t2000.ai/jina/v1/read \\\\\\n --data \'{\\"url\\":\\"https://docs.sui.io/concepts/tokenomics\\"}\'\\n```\\n\\n### Google search (structured)\\n```bash\\nt2000 pay https://mpp.t2000.ai/serper/v1/search \\\\\\n --data \'{\\"q\\":\\"Sui blockchain TVL 2026\\"}\'\\n```\\n\\n### Screenshot a webpage\\n```bash\\nt2000 pay https://mpp.t2000.ai/screenshot/v1/capture \\\\\\n --data \'{\\"url\\":\\"https://example.com\\",\\"format\\":\\"png\\",\\"viewport_width\\":\\"1280\\"}\'\\n```\\n\\n### Generate a QR code\\n```bash\\nt2000 pay https://mpp.t2000.ai/qrcode/v1/generate \\\\\\n --data \'{\\"data\\":\\"https://t2000.ai\\",\\"size\\":\\"400x400\\"}\'\\n```\\n\\n### Convert HTML to PDF\\n```bash\\nt2000 pay https://mpp.t2000.ai/pdfshift/v1/convert \\\\\\n --data \'{\\"source\\":\\"https://t2000.ai/docs\\"}\'\\n```\\n\\n### Run a Replicate model\\n```bash\\nt2000 pay https://mpp.t2000.ai/replicate/v1/predictions \\\\\\n --data \'{\\"model\\":\\"meta/llama-3-70b-instruct\\",\\"input\\":{\\"prompt\\":\\"Explain DeFi in 3 sentences\\"}}\'\\n```\\n\\n### Find emails for a domain\\n```bash\\nt2000 pay https://mpp.t2000.ai/hunter/v1/search \\\\\\n --data \'{\\"domain\\":\\"mystenlabs.com\\"}\'\\n```\\n\\n### Look up an IP address\\n```bash\\nt2000 pay https://mpp.t2000.ai/ipinfo/v1/lookup \\\\\\n --data \'{\\"ip\\":\\"8.8.8.8\\"}\'\\n```\\n\\n### Order print-on-demand merchandise\\n```bash\\nt2000 pay https://mpp.t2000.ai/printful/v1/order \\\\\\n --max-price 30 \\\\\\n --data \'{\\"recipient\\":{\\"name\\":\\"Jane Doe\\",\\"address1\\":\\"123 Main St\\",\\"city\\":\\"SF\\",\\"state_code\\":\\"CA\\",\\"country_code\\":\\"US\\",\\"zip\\":\\"94105\\"},\\"items\\":[{\\"variant_id\\":4012,\\"quantity\\":1,\\"files\\":[{\\"url\\":\\"https://example.com/design.png\\"}]}]}\'\\n```\\n\\n### Search for flights\\n```bash\\nt2000 pay https://mpp.t2000.ai/serpapi/v1/flights \\\\\\n --data \'{\\"departure_id\\":\\"LAX\\",\\"arrival_id\\":\\"NRT\\",\\"outbound_date\\":\\"2026-05-01\\",\\"type\\":\\"2\\"}\'\\n```\\n\\n### Convert currency\\n```bash\\nt2000 pay https://mpp.t2000.ai/exchangerate/v1/convert \\\\\\n --data \'{\\"from\\":\\"USD\\",\\"to\\":\\"EUR\\",\\"amount\\":100}\'\\n```\\n\\n### Scan a URL for malware\\n```bash\\nt2000 pay https://mpp.t2000.ai/virustotal/v1/scan \\\\\\n --data \'{\\"url\\":\\"https://suspicious-site.com\\"}\'\\n```\\n\\n### Shorten a URL\\n```bash\\nt2000 pay https://mpp.t2000.ai/shortio/v1/shorten \\\\\\n --data \'{\\"url\\":\\"https://example.com/very/long/url/path\\"}\'\\n```\\n\\n### Send a push notification\\n```bash\\nt2000 pay https://mpp.t2000.ai/pushover/v1/push \\\\\\n --data \'{\\"user\\":\\"USER_KEY\\",\\"message\\":\\"Your agent has a message!\\"}\'\\n```\\n\\n## Flow (automatic)\\n1. Makes initial HTTP request to the URL\\n2. If 402: reads MPP challenge for amount and terms\\n3. If price <= --max-price: pays via Sui USDC\\n4. Retries with credential header\\n5. Returns the API response body\\n\\n## Safety\\n- If requested price exceeds --max-price, payment is refused (no funds spent)\\n- Default max-price: $1.00 USDC per request\\n- For commerce (mail, merch), set --max-price higher\\n- Payment only broadcast after 402 terms are validated\\n\\n## Errors\\n- `PRICE_EXCEEDS_LIMIT`: API asking more than --max-price\\n- `INSUFFICIENT_BALANCE`: not enough available USDC\\n- `UNSUPPORTED_NETWORK`: MPP requires a network other than Sui\\n- `PAYMENT_EXPIRED`: payment challenge has expired\\n- `DUPLICATE_PAYMENT`: nonce already used on-chain\\n\\n## MCP\\nVia MCP: use `t2000_services` to discover services, then `t2000_pay` to call them."},{"name":"t2000-rebalance","description":"Rebalance the wallet to a target allocation by executing multiple swaps in one atomic Payment Intent. Use when asked to rebalance, adjust allocation, \\"shuffle my positions\\", or move from one set of holdings to another. Every leg prices against the same on-chain snapshot \u2014 no cross-leg slippage drift; user signs once.","body":"# t2000: Rebalance Portfolio\\n\\n## Purpose\\nMove from a current allocation to a target allocation by emitting all\\nthe required `swap_execute` calls **in the same assistant turn** so the\\nengine compiles them into one Payment Intent. Result: every leg of the\\nrebalance prices against the same Sui state, slippage is bounded once,\\nand the user signs once.\\n\\n## When to use\\n\\n- \\"Rebalance my portfolio to 60% USDC / 30% SUI / 10% GOLD\\"\\n- \\"Move everything to USDC\\"\\n- \\"Adjust my allocation \u2014 I want less SUI exposure\\"\\n- \\"I\'m 80% SUI, get me to 50/50 with USDC\\"\\n\\n## Flow\\n\\n### Step 1 \u2014 Current allocation\\nCall `balance_check` (engine) or `t2000_balance --json` (CLI) to get the\\ncurrent breakdown. Compute the percentage held in each asset by USD value.\\n\\n### Step 2 \u2014 Plan trades\\nFor each asset, compute the delta vs the target:\\n- Asset over-allocated \u2192 swap **out** to USDC (or another reduce-target asset)\\n- Asset under-allocated \u2192 swap **in** from USDC (or another excess-source asset)\\n\\nPresent the plan to the user **before** executing:\\n\\n```\\n\u{1F4CA} REBALANCE PLAN\\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n Current Target \u0394\\n USDC $400 $600 +$200\\n SUI $400 $300 \u2212$100\\n GOLD $200 $100 \u2212$100\\n\\nTrades (1 atomic Payment Intent):\\n 1. swap 0.5 SUI \u2192 ~$100 USDC\\n 2. swap 0.05 GOLD \u2192 ~$100 USDC\\n\\nEstimated slippage: 0.3% on each leg\\nProceed?\\n```\\n\\n### Step 3 \u2014 Execute (bundled)\\n\\n**Critical:** emit ALL the `swap_execute` calls as parallel `tool_use` blocks\\n**in the same assistant turn**. The engine\'s permission gate compiles them\\ninto ONE Payment Intent. The user signs once; every leg either succeeds or\\nthe whole rebalance reverts.\\n\\n**Do NOT** call them sequentially across turns \u2014 that defeats the atomicity\\nand exposes the user to price drift between legs.\\n\\n```\\n[ASSISTANT TURN \u2014 emit in parallel]\\n tool_use: swap_execute({ from: \\"SUI\\", to: \\"USDC\\", amount: 0.5 })\\n tool_use: swap_execute({ from: \\"GOLD\\", to: \\"USDC\\", amount: 0.05 })\\n```\\n\\n### Step 4 \u2014 Summary\\nAfter the Payment Intent settles, call `balance_check` again and show the\\nfinal allocation vs target. Highlight any drift > 1% (caused by slippage\\nor rounding) and ask if the user wants a follow-up swap to close it.\\n\\n## Error handling\\n\\n| Error | Cause | What to do |\\n|---|---|---|\\n| Intent failed \u2014 `INSUFFICIENT_BALANCE` | One of the swap legs would consume more than the wallet holds | Abort the entire intent (no swaps execute). Reduce the amount on the offending leg. |\\n| Intent failed \u2014 `SLIPPAGE_EXCEEDED` | A leg exceeded the configured slippage tolerance | Abort. Re-run with looser slippage OR smaller leg sizes. |\\n| Intent failed \u2014 any reason | Atomic Payment Intent reverts the WHOLE bundle | No funds moved. Tell the user the on-chain state is unchanged. |\\n\\n## CLI fallback (no bundling)\\n\\nThe CLI does not support Payment Intent bundling today. To rebalance from\\nthe CLI, execute swaps one at a time:\\n\\n```bash\\nt2000 swap 0.5 SUI to USDC\\nt2000 swap 0.05 GOLD to USDC\\n```\\n\\nEach swap prices against the on-chain state **at the moment of execution**,\\nwhich means small drift between legs. For larger rebalances ($1k+) prefer\\nthe agent path (which bundles into one Payment Intent).\\n\\n## Fees\\n\\nPer swap leg:\\n- Cetus protocol fee: ~0.1% of swap amount (varies by pool)\\n- Audric overlay fee: 10 bps (~0.1%)\\n\\nBundled rebalances pay the same per-leg fees \u2014 bundling reduces slippage\\nrisk, not fee cost.\\n\\n## Notes\\n\\n- This skill is **engine-first** \u2014 the bundling guarantee only exists in\\n the audric/web chat agent (or any engine consumer with Payment Intent\\n compile support).\\n- For \\"optimize my yield\\" intent (sweep idle USDC into best-APY savings,\\n claim rewards, compare USDC pools), use the `optimize-all` MCP prompt\\n instead \u2014 that\'s a different shape of workflow.\\n- Health-factor check **does not run** for swap-only rebalances (no\\n collateral position changes). For rebalances that involve withdrawing\\n from savings, see `t2000-withdraw` (the safety check runs there)."},{"name":"t2000-receive","description":"Generate a payment request to receive funds into the t2000 agent wallet. Use when asked to receive money, create a payment link, share a wallet address, or generate a QR code for receiving payment. Produces a payment request with address, Sui Payment Kit URI (sui:pay?\u2026), nonce, and optional amount/memo.","body":"# t2000: Receive Payment\\n\\n## Purpose\\nGenerate a payment request containing the agent\'s wallet address, a unique\\nnonce, and a Sui Payment Kit URI (`sui:pay?\u2026`). The sender can scan the QR or\\ncopy the address to send funds. No on-chain transaction is created \u2014 this is a\\nlocal, read-only operation.\\n\\n## Command\\n```bash\\nt2000 receive [options]\\n\\n# Examples:\\nt2000 receive # Address only\\nt2000 receive --amount 25 # Request $25 USDC\\nt2000 receive --amount 100 --memo \\"Invoice #42\\" # With memo\\nt2000 receive --amount 50 --label \\"Freelance work\\" # With label\\nt2000 receive --currency SUI --amount 10 # Request SUI\\n```\\n\\n## Options\\n| Option | Description |\\n|--------|-------------|\\n| `--amount <n>` | Amount to request (omit for open amount) |\\n| `--currency <sym>` | Currency symbol (default: USDC) |\\n| `--memo <text>` | Payment note shown to sender |\\n| `--label <text>` | Description for the payment request |\\n\\n## Output\\n```\\n\u2713 Payment Request\\n\\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n Address 0x8b3e...d412\\n Network Sui Mainnet\\n Nonce a1b2c3d4-e5f6-7890-abcd-ef1234567890\\n Amount $25.00 USDC\\n Memo Invoice #42\\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n\\n Payment URI sui:pay?receiver=0x8b3e...&amount=25000000&...\\n\\n Share this URI or scan the QR to pay via any Sui wallet.\\n```\\n\\n## SDK Usage\\n```typescript\\nconst request = agent.receive({ amount: 25, memo: \'Invoice #42\' });\\n// Returns: { address, network, amount, currency, memo, label, nonce, qrUri, displayText }\\n```\\n\\n## MCP Tool\\nTool name: `t2000_receive` (read-only, auto-approved).\\n\\n## Notes\\n- This is a **local operation** \u2014 no transaction is created, no gas is used\\n- Uses **Sui Payment Kit** \u2014 generates `sui:pay?` URIs with nonce binding\\n- The nonce is a UUID that uniquely identifies each payment request\\n- Wallets that support Payment Kit register payment in an on-chain registry, preventing double-spend\\n- Without `--amount`, the request is open-ended (any amount accepted)\\n- Default currency is USDC; specify `--currency SUI` for native SUI"},{"name":"t2000-repay","description":"Repay outstanding debt. Use when asked to repay a loan, pay back debt, reduce outstanding balance, or clear borrows. Supports partial and full repayment. User pays with USDC.","body":"# t2000: Repay Borrow\\n\\n## Purpose\\nRepay outstanding debt in USDC. Supports specific amounts or `repay all` to clear the full\\nbalance including accrued interest.\\n\\n## Command\\n```bash\\nt2000 repay <amount>\\nt2000 repay all\\n\\n# Examples:\\nt2000 repay 20\\nt2000 repay all\\n```\\n\\n## Fees\\n- No protocol fee on repayment\\n\\n## Output\\n```\\n\u2713 Repaid $XX.XX USDC\\n Remaining Debt: $XX.XX\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Notes\\n- `repay all` calculates full outstanding principal + accrued interest\\n- Available USDC balance must cover the repayment amount"},{"name":"t2000-safeguards","description":"Configure spending limits and safety controls for t2000 agent wallets. Use when asked to set transaction limits, daily send limits, lock or unlock the agent, view safeguard settings, or protect the wallet from unauthorized spending. Required before enabling MCP server access.","body":"# t2000: Agent Safeguards\\n\\n## Purpose\\nConfigure spending limits and safety guardrails for autonomous agent\\noperation. Three controls: agent lock (kill switch), per-transaction\\nlimit, and daily send limit.\\n\\n> Safeguards are enforced on CLI and MCP. All state-changing actions\\n> require explicit confirmation before execution.\\n\\n## Commands\\n```bash\\nt2000 config show # view all safeguard settings\\nt2000 config set maxPerTx 500 # max $500 per outbound transaction\\nt2000 config set maxDailySend 1000 # max $1000 outbound per day\\nt2000 lock # freeze ALL operations immediately\\nt2000 unlock # resume operations (requires PIN)\\n```\\n\\n## Controls\\n\\n| Control | Description | Default |\\n|---------|-------------|---------|\\n| `maxPerTx` | Max USDC per single outbound op (send/pay) | 0 (unlimited) |\\n| `maxDailySend` | Max total USDC outbound per calendar day | 0 (unlimited) |\\n| `locked` | Kill switch \u2014 freezes ALL operations | false |\\n\\n## What counts as outbound\\n- `t2000 send` \u2014 transfers to other addresses\\n- `t2000 pay` \u2014 MPP API payments\\n\\n## What is NOT limited\\nInternal operations (save, withdraw, borrow, repay)\\nmove funds within the agent\'s own wallet and protocol positions. They\\nare not subject to send limits.\\n\\n## Output (config show)\\n```\\n Agent Safeguards\\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n Locked: No\\n Per-transaction: $500.00\\n Daily send limit: $1,000.00 ($350.00 used today)\\n```\\n\\n## Blocked output\\n```\\n \u2717 Blocked: amount $1,000.00 exceeds per-transaction limit ($500.00)\\n \u2717 Blocked: daily send limit reached ($1,000.00/$1,000.00 used today)\\n \u2717 Agent is locked. All operations frozen.\\n```\\n\\n## JSON mode\\n```bash\\nt2000 config show --json\\n```\\n```json\\n{ \\"locked\\": false, \\"maxPerTx\\": 500, \\"maxDailySend\\": 1000, \\"dailyUsed\\": 350 }\\n```\\n\\n## SDK\\n```typescript\\nconst agent = await T2000.create({ pin });\\n\\n// Check config\\nagent.enforcer.getConfig(); // { locked, maxPerTx, maxDailySend, dailyUsed, ... }\\nagent.enforcer.isConfigured(); // true if any limit is non-zero\\n\\n// Set limits\\nagent.enforcer.set(\'maxPerTx\', 500);\\nagent.enforcer.set(\'maxDailySend\', 1000);\\n\\n// Lock/unlock\\nagent.enforcer.lock();\\nagent.enforcer.unlock();\\n```\\n\\n## Important\\n- Safeguards are opt-in \u2014 defaults are permissive (0 = unlimited)\\n- MCP server requires non-zero limits before starting\\n- Lock freezes ALL operations (including internal) as a safety measure\\n- Daily counter resets at midnight UTC"},{"name":"t2000-save","description":"Deposit USDC or USDsui into savings to earn yield on Sui via NAVI Protocol. Use when asked to save money, earn interest, deposit to savings, \\"swap and save\\" a non-USDC token, or put funds to work. Not for sending to other addresses \u2014 use t2000-send for that.","body":"# t2000: Save (Deposit to Savings)\\n\\n## Purpose\\nDeposit **USDC or USDsui** into savings to earn yield on NAVI Protocol. Funds remain non-custodial and\\nwithdrawable at any time. USDsui is permitted as a strategic exception (v0.51.0+) because it has\\nits own NAVI pool, often at a different APY than USDC. Every other token (GOLD, SUI, USDT, USDe,\\nETH, NAVX, WAL) is **not saveable** \u2014 swap to USDC or USDsui first.\\n\\n## Command\\n```bash\\nt2000 save <amount> [--asset USDC|USDsui]\\nt2000 save all [--asset USDC|USDsui]\\n\\n# Examples:\\nt2000 save 80 # 80 USDC (default)\\nt2000 save 80 --asset USDsui # 80 USDsui\\nt2000 save all # full USDC balance (minus $1 gas reserve)\\nt2000 save all --asset USDsui # full USDsui balance (minus 1.0 reserve)\\n```\\n\\n- `save all`: deposits full available balance of the chosen asset minus 1.0 of that asset for safety\\n- `--asset` defaults to USDC when omitted\\n\\n## Fees\\n- Protocol fee: 0.1% on deposit (collected atomically on-chain)\\n\\n## Output\\n```\\n\u2713 Gas manager: $1.00 USDC \u2192 SUI [only shown if auto-topup triggered]\\n\u2713 Saved $XX.XX <asset> to best rate\\n\u2713 Current APY: X.XX%\\n\u2713 Savings balance: $XX.XX <asset>\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Notes\\n- APY is variable based on protocol utilization (USDC and USDsui pools quote independently)\\n- If available balance of the chosen asset is too low, returns INSUFFICIENT_BALANCE\\n- `t2000 supply` is an alias for `t2000 save`\\n- **Repay symmetry (v0.51.1+):** if you borrow USDsui, you must repay with USDsui (and USDC borrows must repay with USDC) \u2014 the SDK fetches the matching coin type per borrow asset.\\n\\n## Saving a non-USDC token (\\"swap and save\\")\\n\\nIf the user wants to save a token that\'s **not** USDC or USDsui \u2014 GOLD,\\nSUI, USDT, USDe, ETH, NAVX, WAL \u2014 the agent must swap first, then save.\\nThe right flow depends on the consumer:\\n\\n### Engine (audric/web) \u2014 bundled atomic swap + save\\n\\nEmit BOTH tool_use blocks in the SAME assistant turn. The engine\'s\\npermission gate compiles them into ONE Payment Intent: the swap\'s\\n`received` coin handles off as the save\'s input via coin-ref inside the\\nsame PTB. Atomic \u2014 both succeed or both revert. User signs once.\\n\\n```\\n[ASSISTANT TURN \u2014 emit in parallel]\\n tool_use: swap_execute({ from: \\"SUI\\", to: \\"USDC\\", amount: 1.0 })\\n tool_use: save_deposit({ amount: <swap_received>, asset: \\"USDC\\" })\\n```\\n\\nBefore emitting, **always preview** to the user:\\n- The source token + amount being swapped\\n- Estimated USDC received (from `swap_quote`)\\n- The save APY they\'ll earn\\n- Total fees (Cetus + Audric overlay + NAVI save fee)\\n\\n**Do NOT** call swap then save in separate turns \u2014 that loses atomicity\\nand exposes the user to price drift between the legs.\\n\\n**Do NOT** auto-decide for the user. If they say \\"save 10 SUI\\", confirm\\nthe intent: \\"That requires swapping ~10 SUI to ~$XX USDC first, then\\ndepositing. Proceed?\\" Some users want to hold SUI.\\n\\n### CLI \u2014 sequential (no bundling)\\n\\nThe CLI doesn\'t support Payment Intent bundling. Run two commands:\\n\\n```bash\\nt2000 swap 1.0 SUI to USDC\\nt2000 save all\\n```\\n\\nEach command prices against on-chain state at the moment of execution,\\nso there\'s small price drift between them. For large amounts ($1k+),\\nprefer the agent path which bundles into one Payment Intent.\\n\\n### What\'s NOT saveable\\n\\nGOLD, SUI, USDT, USDe, ETH, NAVX, WAL \u2014 none of these have NAVI lending\\npools today, so they can\'t be saved directly. Must swap to USDC or\\nUSDsui first. This is enforced by the SDK\'s `assertAllowedAsset(\'save\',\\nasset)` allow-list \u2014 calling `save_deposit({ asset: \'SUI\' })` returns\\n`UNSUPPORTED_ASSET`."},{"name":"t2000-send","description":"Send USDC from the t2000 agent wallet to another address on Sui. Use when asked to pay someone, transfer funds, send money, tip a creator, or make a payment to a specific Sui address or saved contact. Do NOT use for API payments \u2014 use t2000-pay for MPP-protected services.","body":"# t2000: Send USDC\\n\\n## Purpose\\nTransfer USDC from the agent\'s available balance to any Sui address. Gas is\\nself-funded from the agent\'s SUI reserve (auto-topped up if needed).\\n\\n## Command\\n```bash\\nt2000 send <amount> <asset> to <address_or_contact>\\nt2000 send <amount> <asset> <address_or_contact>\\n\\n# Examples:\\nt2000 send 10 USDC to 0x8b3e...d412\\nt2000 send 50 USDC to Tom\\nt2000 send 50 USDC 0xabcd...1234\\n```\\n\\nThe `to` keyword is optional. The recipient can be a Sui address (0x...) or a\\nsaved contact name (e.g. \\"Tom\\"). Use `t2000 contacts` to list saved contacts.\\n\\n## Pre-flight checks (automatic)\\n1. Sufficient available USDC balance\\n2. SUI gas reserve present; if not, auto-topup triggers transparently\\n\\n## Output\\n```\\n\u2713 Sent $XX.XX USDC \u2192 0x8b3e...d412\\n Gas: X.XXXX SUI (self-funded)\\n Balance: $XX.XX USDC\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Error handling\\n- `INSUFFICIENT_BALANCE`: available balance is less than the requested amount\\n- `INVALID_ADDRESS`: destination is not a valid Sui address\\n- `CONTACT_NOT_FOUND`: name is not a saved contact or valid address\\n- `SIMULATION_FAILED`: transaction would fail on-chain; details in error message\\n\\n## Recipient resolution flow\\n\\nWhen the user provides a recipient, resolve it before broadcasting:\\n\\n1. **Name given** \u2192 look up in saved contacts. If found, use the mapped\\n address. If not found and not a valid `0x...` address, ask the user\\n to clarify (suggest `t2000 contacts add <name> <address>` first).\\n2. **Address given (`0x...`)** \u2192 validate with `isValidSuiAddress()`. If\\n invalid, refuse with `INVALID_ADDRESS`.\\n3. **Ambiguous** (looks like a name AND a valid prefix) \u2192 ask the user\\n which they meant.\\n\\nAfter a successful send to a **previously-unknown raw address** (not a\\nsaved contact), offer to save it:\\n\\n> \\"Want to save 0x8b3e\u2026d412 as a contact? Say `yes <name>` to save.\\"\\n\\nIf the user provides a name, call `t2000 contacts add <name> <address>`\\n(CLI). This makes future sends to the same person work by name\\n(`t2000 send 10 USDC to <name>`). The engine no longer ships a\\n`save_contact` tool \u2014 contacts are CLI-only state today; audric users\\nmanage contacts via the send screen.\\n\\n**Do not auto-save** without asking \u2014 the user might not want every\\none-off recipient cluttering their contacts list.\\n\\n## Engine orchestration (audric/web)\\n\\nWhen called inside the Audric chat agent:\\n\\n1. Resolve recipient (contacts lookup or address validation) \u2014 no tool call needed for contacts; resolution happens in prose.\\n2. Call `balance_check` to confirm sufficient funds.\\n3. Emit `send_transfer({ to, amount, asset })` as the write tool_use.\\n4. After the send settles, if the recipient was a raw address not already\\n in contacts, surface the \\"save as contact?\\" prompt to the user (see\\n above). The user confirms in the next turn; the host (CLI / audric)\\n handles persistence \u2014 the engine has no contact-write tool.\\n\\nSends are **single-write** \u2014 never bundle with another write in a\\nPayment Intent. Each transfer is its own intent."},{"name":"t2000-withdraw","description":"Withdraw from savings and receive USDC or USDsui. Use when asked to withdraw from savings, access deposited funds, pull money out of savings, reduce yield position, \\"close my position\\", or emergency withdraw. For sending to another address, use t2000-send.","body":"# t2000: Withdraw from Savings\\n\\n## Purpose\\nWithdraw USDC or USDsui from savings back to your checking balance.\\n\\n## Command\\n```bash\\nt2000 withdraw <amount> [--asset USDC|USDsui]\\nt2000 withdraw all [--asset USDC|USDsui]\\n\\n# Examples:\\nt2000 withdraw 25 # 25 USDC (default)\\nt2000 withdraw 25 --asset USDsui # 25 USDsui\\nt2000 withdraw all # full USDC savings position\\nt2000 withdraw all --asset USDsui # full USDsui savings position\\n```\\n\\n`--asset` defaults to USDC when omitted.\\n\\n## Fees\\n- No protocol fee on withdrawals\\n\\n## Output\\n```\\n\u2713 Withdrew $XX.XX <asset>\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Safety check (active when debt exists)\\n\\nIf the wallet has outstanding debt, t2000 evaluates whether the withdrawal\\nwould push the health factor below 1.5:\\n\\n| Scenario | Behavior |\\n|---|---|\\n| No debt | Withdrawal proceeds \u2014 no HF check. |\\n| Withdrawal keeps HF \u2265 1.5 | Withdrawal proceeds \u2014 note the new HF in the output. |\\n| Withdrawal would drop HF < 1.5 | **Refused** with `WITHDRAW_WOULD_LIQUIDATE`. Error data includes `safeWithdrawAmount` (the largest amount that keeps HF \u2265 1.5). |\\n\\n## Emergency / \\"close my position\\" flow\\n\\nWhen the user asks to \\"withdraw everything\\", \\"close my position\\", or\\n\\"emergency withdraw\\":\\n\\n### Step 1 \u2014 Read state\\nCall `health_check` (engine) or `t2000 balance --show-limits` (CLI) to\\nsee savings, debt, and current HF.\\n\\n### Step 2 \u2014 Decide path\\n\\n| Wallet state | Path |\\n|---|---|\\n| **No debt** | Single-write `withdraw all` for each asset held in savings. |\\n| **Has debt, savings \u2265 debt** | **Bundled repay + withdraw** \u2014 emit `repay_debt(all)` and `withdraw(remaining)` as parallel `tool_use` blocks in the SAME assistant turn. Engine compiles into one Payment Intent: atomic repay-then-withdraw, one signature. |\\n| **Has debt, savings < debt** | **Refuse** \u2014 user can\'t fully close position without first acquiring more of the borrowed asset. Tell them how much more they\'d need; do not auto-swap. |\\n\\n### Step 3 \u2014 Bundled emit (engine path)\\n\\nFor the \\"bundled repay + withdraw\\" case, emit BOTH tool_use blocks in the\\nsame assistant turn:\\n\\n```\\n[ASSISTANT TURN \u2014 emit in parallel]\\n tool_use: repay_debt({ amount: <debt>, asset: <borrowed_asset> })\\n tool_use: withdraw({ amount: <remaining>, asset: <savings_asset> })\\n```\\n\\nThe engine\'s permission gate compiles these into ONE Payment Intent. Both\\nlegs succeed or both revert \u2014 no partial close. The user signs once.\\n\\n**Do NOT** call them sequentially across turns \u2014 that loses atomicity and\\nexposes the user to a window where debt is repaid but the withdraw fails,\\nleaving the wallet in an awkward state.\\n\\n**Critical:** `repay_debt` MUST use the SAME asset as the original borrow\\n(USDsui debt \u2192 USDsui repay, USDC debt \u2192 USDC repay \u2014 see `t2000-repay`).\\nIf the user doesn\'t hold enough of the matching asset, abort with a clear\\nmessage; do not auto-swap.\\n\\n## Error handling\\n- `WITHDRAW_WOULD_LIQUIDATE` \u2014 withdrawal would push HF < 1.5. Use `safeWithdrawAmount` from error data, or repay debt first.\\n- `NO_COLLATERAL` \u2014 no savings position in the requested asset.\\n- `INSUFFICIENT_BALANCE` \u2014 requested amount exceeds savings balance.\\n- Intent failed (bundled flow) \u2014 atomic revert. No funds moved."}]';
|
|
141523
|
+
const raw = '[{"name":"t2000-account-report","description":"Render a complete account snapshot \u2014 wallet, savings, debt, recent activity, yield, and portfolio allocation, plus a short headline. Use when asked for a full report, account summary, \\"everything about my account\\", or \\"show me the full picture\\". Multi-tool orchestration \u2014 no single CLI command covers all six dimensions.","body":"# t2000: Account Report\\n\\n## Purpose\\nRender a complete account snapshot across six dimensions \u2014 wallet, savings,\\ndebt, recent activity, yield, portfolio allocation \u2014 followed by a 2\u20133\\nsentence headline. This is a **multi-tool orchestration**, not a single CLI\\ncommand. The right call sequence depends on the consumer:\\n\\n| Consumer | Call pattern |\\n|---|---|\\n| **MCP / Cursor / Claude Desktop** | `t2000_overview` covers wallet + savings + debt + health + earnings + rewards in one call. Add `t2000_history` (limit: 20) and `t2000_positions` if you also want activity and per-position APYs. |\\n| **CLI** | `t2000 balance --show-limits` + `t2000 positions` + `t2000 history --limit 20` |\\n| **Engine (audric/web)** | 6 parallel read tools \u2014 one per rendered card (see below). Calling fewer tools = missing cards. |\\n\\n## Engine orchestration (audric/web)\\n\\nWhen called inside the Audric chat agent, each read tool renders a\\ncanvas card. **Skipping a tool = missing card.** Always emit all six\\ntool_use blocks in parallel in the same assistant turn:\\n\\n| Tool | Card | Purpose |\\n|---|---|---|\\n| `balance_check` | BALANCE CHECK | Wallet, savings, debt, total |\\n| `savings_info` | SAVINGS INFO | Per-position breakdown, supply/borrow APY, daily earnings |\\n| `health_check` | HEALTH CHECK | Health factor, supplied, borrowed, max borrow, liquidation threshold |\\n| `activity_summary` | ACTIVITY SUMMARY | Monthly tx breakdown by category |\\n| `yield_summary` | YIELD SUMMARY | Today / week / month / all-time earnings, projected yearly |\\n| `portfolio_analysis` | PORTFOLIO ANALYSIS | Allocation %, week change, insights |\\n\\nAfter all six cards render, write a **2\u20133 sentence headline** that:\\n- Leads with net worth and weekly change.\\n- Mentions health factor in one phrase.\\n- Ends with the single most actionable insight (idle USDC, debt repayment, rate gap, etc).\\n- Does **NOT** narrate the cards\' contents \u2014 they render themselves.\\n- Does **NOT** list asset percentages, APYs, or savings positions in prose.\\n\\nMax 3 sentences total.\\n\\n## CLI quick command (no canvas)\\n\\nFor terminal users who just want the numbers in their shell:\\n\\n```bash\\nt2000 balance --show-limits\\nt2000 positions\\nt2000 history --limit 20\\n```\\n\\nThese three commands cover wallet + per-position APYs + recent activity.\\nFor a one-shot machine-parseable version, add `--json` to each.\\n\\n## Notes\\n\\n- This skill orchestrates **read-only** tools \u2014 no signatures, no on-chain writes.\\n- For a workflow-shaped advisor brief on top of this snapshot (recommendations, USDC APY gap, rebalance suggestion), use the `financial-report` MCP prompt \u2014 it composes this skill plus advisor framing.\\n- If the user holds non-USDC tokens, the portfolio card surfaces them but does not flag them as \\"saveable\\" \u2014 see `t2000-save` for the USDC/USDsui save-eligibility rule."},{"name":"t2000-borrow","description":"Borrow USDC or USDsui against savings collateral. Use when asked to borrow, take a loan, get credit, leverage savings, or access funds without withdrawing from savings. A 0.05% protocol fee applies. Only accepts USDC or USDsui. Always validates projected health factor before signing \u2014 refuses if HF would drop below 1.5.","body":"# t2000: Borrow USDC or USDsui\\n\\n## Purpose\\nTake a collateralized loan using savings deposits as collateral.\\nBorrowed funds go to the available balance. A 0.05% protocol fee applies.\\nUSDsui is permitted as a strategic exception (v0.51.0+) alongside USDC \u2014\\nboth have NAVI lending pools.\\n\\n## Command\\n```bash\\nt2000 borrow <amount> [--asset USDC|USDsui]\\n\\n# Examples:\\nt2000 borrow 40 # 40 USDC (default)\\nt2000 borrow 100 --asset USDsui # 100 USDsui\\n```\\n\\n`--asset` defaults to USDC when omitted.\\n\\n## Pre-borrow safety check (always runs)\\n\\nBefore broadcasting the borrow transaction, t2000 evaluates the projected\\nhealth factor and routes the user through one of three paths:\\n\\n| Projected HF after borrow | What happens |\\n|---|---|\\n| **< 1.5** | **Refuse** \u2014 borrow blocked with `HEALTH_FACTOR_TOO_LOW`. Error includes `maxBorrow` (the largest amount that keeps HF \u2265 1.5). Suggest: repay existing debt OR add more collateral. |\\n| **1.5 \u2013 2.0** | **Warn** \u2014 surface the projected HF and require explicit user confirmation. Always state: borrow amount, projected HF, current borrow APY. Do NOT silently proceed. |\\n| **> 2.0** | **Proceed** \u2014 borrow is well-collateralized, no extra confirmation needed beyond the standard signing flow. |\\n\\nAlways state to the user: **borrow amount**, **interest rate**, and\\n**projected health factor** before signing.\\n\\n## Engine orchestration (audric/web)\\n\\nWhen called inside the Audric chat agent:\\n\\n1. Call `health_check` first to get current HF and `maxBorrow`.\\n2. Compute projected HF: `(supplied \xD7 liquidationThreshold) / (borrowed + amountUsd)`.\\n3. Apply the table above \u2014 refuse / warn / proceed.\\n4. On user confirmation, emit `borrow({ amount, asset })` as the write tool_use.\\n\\nBorrows are always **single-write** \u2014 never bundle with another write in a\\nPayment Intent. The user must consciously accept the debt.\\n\\n## Fees\\n\\n- Protocol fee: 0.05% of the borrow amount\\n\\n## Output\\n\\n```\\n\u2713 Borrowed $XX.XX <asset>\\n Health Factor: X.XX\\n Borrow APY: X.XX%\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Error handling\\n\\n- `NO_COLLATERAL` \u2014 no savings deposited to borrow against. Use `t2000 save` first.\\n- `HEALTH_FACTOR_TOO_LOW` \u2014 borrow would drop HF below 1.5. Error data includes `maxBorrow`. Suggest: repay debt or add collateral.\\n- `UNSUPPORTED_ASSET` \u2014 asset is not USDC or USDsui. Other tokens cannot be borrowed (NAVI doesn\'t have pools for them).\\n\\n## Repayment symmetry (important)\\n\\n**A USDsui borrow MUST be repaid with USDsui.** A USDC borrow MUST be repaid\\nwith USDC. The SDK fetches the matching coin type per borrow asset. If the\\nuser holds only the wrong stable, tell them to swap manually first \u2014 never\\nauto-chain swap + repay. See `t2000-repay` for the repay flow.\\n\\n## What\'s NOT permitted\\n\\n- Borrowing in any asset other than USDC or USDsui (no SUI, GOLD, USDT, ETH borrows \u2014 NAVI doesn\'t have lending pools for those).\\n- Borrowing without a savings position (collateral first).\\n- Borrowing that drops HF below 1.5 (always refused; safety-critical)."},{"name":"t2000-check-balance","description":"Check the t2000 agent wallet balance on Sui. Use when asked about wallet balance, how much USDC is available, savings balance, gas reserve, or total funds. Also use before any send or borrow operation to confirm sufficient funds exist.","body":"# t2000: Check Balance\\n\\n## Purpose\\nFetch the current balance across all accounts: available USDC,\\nsavings (NAVI), gas reserve (SUI), and total value.\\n\\n## Commands\\n```bash\\nt2000 balance # human-readable summary\\nt2000 balance --show-limits # includes maxWithdraw, maxBorrow, healthFactor\\nt2000 balance --json # machine-parseable JSON (works on all commands)\\n```\\n\\n## Output (default)\\n```\\nAvailable: $150.00 (checking \u2014 spendable)\\nSavings: $2,000.00 (earning 5.10% APY)\\nGas: 0.50 SUI (~$0.50)\\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\nTotal: $2,150.50\\nEarning ~$0.27/day\\n```\\n\\n## Output (--show-limits)\\nAppends to the above:\\n```\\nLimits:\\n Max withdraw: $XX.XX\\n Max borrow: $XX.XX\\n Health factor: X.XX (\u221E if no active loan)\\n```\\n\\n## Notes\\n- `gasReserve.usdEquiv` is an estimate at current SUI price; it fluctuates\\n- If balance shows $0.00 available and wallet was just created, fund it first\\n via Coinbase Onramp or a direct USDC transfer to the wallet address\\n- `--json` is a global flag that works on all t2000 commands, not just balance"},{"name":"t2000-contacts","description":"Manage contacts \u2014 save a name-to-address mapping so the user can send money by name instead of pasting raw Sui addresses. Use when asked to add, remove, or list contacts, or to look up a saved address.","body":"# t2000: Contacts\\n\\n## Purpose\\nLet users send money by name instead of raw addresses. Contacts are stored\\nlocally in `~/.t2000/contacts.json` \u2014 no blockchain lookups, no network calls.\\n\\n## Commands\\n\\n```bash\\n# List all contacts\\nt2000 contacts\\n\\n# Add or update a contact\\nt2000 contacts add <name> <address>\\n\\n# Remove a contact\\nt2000 contacts remove <name>\\n```\\n\\n## Examples\\n\\n```bash\\nt2000 contacts add Tom 0x8b3e4f2a...\\n# \u2713 Added Tom (0x8b3e...f4a2)\\n\\nt2000 contacts add Tom 0xNEWADDRESS...\\n# \u2713 Updated Tom (0xNEWA...RESS)\\n\\nt2000 contacts remove Tom\\n# \u2713 Removed Tom\\n\\nt2000 contacts\\n# Contacts\\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n# Tom 0x8b3e...f4a2\\n# Alice 0x40cd...3e62\\n```\\n\\n## Sending by name\\n\\nOnce a contact is saved, use the name directly in `t2000 send`:\\n\\n```bash\\nt2000 send 50 USDC to Tom\\n# \u2713 Sent $50.00 USDC \u2192 Tom (0x8b3e...f4a2)\\n```\\n\\n## Name rules\\n- Letters, numbers, underscores only\\n- Case-insensitive (Tom = tom = TOM)\\n- Max 32 characters\\n- Reserved names: `to`, `all`, `address`\\n- Cannot start with `0x`\\n\\n## No PIN required\\nContact commands are local file operations \u2014 no wallet access, no PIN prompt.\\n\\n## JSON mode\\nAll subcommands support `--json` for structured output:\\n\\n```bash\\nt2000 contacts --json\\nt2000 contacts add Tom 0x... --json\\nt2000 contacts remove Tom --json\\n```\\n\\n## Error handling\\n- `INVALID_CONTACT_NAME`: name violates naming rules\\n- `CONTACT_NOT_FOUND`: name not in contacts when sending\\n- `INVALID_ADDRESS`: address provided to `add` is not a valid Sui address"},{"name":"t2000-engine","description":"Use the @t2000/engine package to build conversational AI agents with financial capabilities. Use when asked to set up AISDKEngine, build custom tools, configure LLM providers, handle streaming events, or integrate with MCP servers. Powers the Audric consumer product.","body":"# t2000: Agent Engine\\n\\n## Purpose\\nBuild conversational AI agents with financial capabilities on Sui.\\n`@t2000/engine` provides `AISDKEngine`, 37 financial tools (25 read + 12 write),\\nLLM orchestration via Vercel AI SDK v6, MCP client/server integration,\\nstreaming, sessions, and cost tracking.\\n\\n> The legacy `QueryEngine` + `AnthropicProvider` were deleted in engine v2.0.0 (2026-05-17).\\n> The `LLMProvider` abstraction + `AISDKAnthropicProvider` class were retired in v3.1.0\\n> (2026-05-25). `AISDKEngine` is the only engine; it wraps Vercel AI SDK v6\'s `streamText`\\n> and accepts `anthropicApiKey` (or `modelInstance` for custom providers / gateway routing).\\n\\n## Quick Start\\n```typescript\\nimport { AISDKEngine, getDefaultTools } from \'@t2000/engine\';\\nimport { T2000 } from \'@t2000/sdk\';\\n\\nconst agent = await T2000.create({ pin: process.env.T2000_PIN });\\n\\nconst engine = new AISDKEngine({\\n anthropicApiKey: process.env.ANTHROPIC_API_KEY,\\n agent,\\n tools: getDefaultTools(),\\n});\\n\\nfor await (const event of engine.submitMessage(\'What is my balance?\')) {\\n if (event.type === \'text_delta\') process.stdout.write(event.text);\\n}\\n```\\n\\n## Building Custom Tools\\n```typescript\\nimport { z } from \'zod\';\\nimport { defineTool } from \'@t2000/engine\';\\n\\nconst myTool = defineTool({\\n name: \'my_tool\',\\n description: \'Tool description for the LLM\',\\n inputSchema: z.object({ query: z.string() }),\\n isReadOnly: true,\\n isConcurrencySafe: true,\\n permissionLevel: \'auto\',\\n async call(input, context) {\\n return { data: { result: input.query }, displayText: `Result: ${input.query}` };\\n },\\n});\\n```\\n\\n> `defineTool` is the v2 factory. The pre-v2 `buildTool` was deleted in engine\\n> `1.38.0`. Signature is the same (Zod schema, isReadOnly, permissionLevel, `call`).\\n\\n## Permission Levels\\n| Level | Behavior | Use for |\\n|-------|----------|---------|\\n| `auto` | Executes immediately | Read-only queries |\\n| `confirm` | Yields `pending_action`, client executes and resumes | Financial writes |\\n| `explicit` | Never auto-dispatched by LLM | Dangerous operations |\\n\\nUSD-aware resolution: write tools with `permissionLevel: \'confirm\'` are\\ndynamically downgraded to `auto` if `amountUsd < rule.autoBelow` and the user\'s\\n`permissionConfig` is plumbed through `ToolContext`. See\\n`packages/engine/src/permission-rules.ts` for the three presets\\n(`conservative` / `balanced` / `aggressive`) and `borrow`-always-confirms rule.\\n\\n## Event Types\\n```typescript\\nfor await (const event of engine.submitMessage(prompt)) {\\n switch (event.type) {\\n case \'stream_started\': // first event \u2014 carries engine-generated streamId (v2.2.0+, when streamCheckpointStore is wired)\\n case \'text_delta\': // LLM text chunk (markers like <proactive> and <eval_summary> pass through verbatim; host strips at render)\\n case \'thinking_delta\': // Extended-thinking chunk (always-on)\\n case \'thinking_done\': // Thinking block closed\\n case \'tool_start\': // Tool execution beginning\\n case \'tool_result\': // Tool execution complete\\n case \'pending_action\': // Write tool needs approval \u2192 client executes, then resumes. action.attemptId is a UUID v4; persist on TurnMetrics + key resume `updateMany` on it\\n case \'canvas\': // Inline HTML/React canvas artifact\\n case \'turn_complete\': // Conversation turn finished\\n case \'usage\': // Token usage report (input / output / cache reads + writes)\\n case \'error\': // Unrecoverable error\\n }\\n}\\n```\\n\\n## MCP Client (consume external MCPs)\\n```typescript\\nimport { McpClientManager, NAVI_MCP_CONFIG } from \'@t2000/engine\';\\n\\nconst mcpManager = new McpClientManager();\\nawait mcpManager.connect(NAVI_MCP_CONFIG);\\n\\n// Read tools auto-use MCP when available, SDK as fallback\\nconst engine = new AISDKEngine({\\n provider,\\n agent,\\n mcpManager,\\n walletAddress: \'0x...\',\\n tools: getDefaultTools(),\\n});\\n```\\n\\n> Internally backed by `@ai-sdk/mcp`\'s `createMCPClient` since engine `v2.1.0`\\n> (SPEC 37 v0.7a Phase 4); `McpClientManager` class name + public method\\n> signatures preserved verbatim. `McpPromptAdapter` for MCP prompts is new in `v2.1.0`.\\n\\n## MCP Server (expose tools to AI clients)\\n```typescript\\nimport { registerEngineTools, getDefaultTools } from \'@t2000/engine\';\\nimport { McpServer } from \'@modelcontextprotocol/sdk/server/mcp.js\';\\n\\nconst server = new McpServer({ name: \'audric\', version: \'0.1.0\' });\\nregisterEngineTools(server, getDefaultTools());\\n// Tools exposed as audric_balance_check, audric_save_deposit, etc.\\n```\\n\\n## SSE Streaming (web apps)\\n```typescript\\n// [v2.2.0 / SPEC 37 v0.7a Phase 5 Slice A] `engineToSSE` was deleted \u2014\\n// iterate EngineEvent raw and call serializeSSE per event. Audric chat +\\n// resume routes have used this pattern since v1.4.2 (Spec G3). Hosts that\\n// want the SPEC 21.1 routing/quoting/etc \u2192 stream_state choreography wrap\\n// with `withStreamState` directly.\\nimport { serializeSSE, withStreamState } from \'@t2000/engine\';\\n\\nfor await (const event of withStreamState(engine.submitMessage(prompt))) {\\n const wireBytes = event.type === \'error\'\\n ? serializeSSE({ type: \'error\', message: event.error.message })\\n : serializeSSE(event);\\n // Send wireBytes to client via SSE\\n}\\n// Write tools yield pending_action \u2192 client executes on-chain \u2192 POST /api/engine/resume\\n```\\n\\n## Stream Checkpoint Resume (v2.2.0+)\\n```typescript\\n// Wire a checkpoint store to enable page-reload / cold-start resume of the\\n// LIVE stream. Engine emits `stream_started` first (carries the streamId),\\n// appends every event fire-and-forget, and replays the checkpoint when the\\n// host passes the id back as `EngineConfig.resumeStreamId`.\\nimport { InMemoryStreamCheckpointStore } from \'@t2000/engine\';\\n\\nconst engine = new AISDKEngine({\\n // ...\\n streamCheckpointStore: new InMemoryStreamCheckpointStore(),\\n});\\n// In-flight tool on resume = Path B (error + re-prompt). CLI / MCP / tests\\n// use the in-memory default; multi-instance hosts (audric on Vercel) inject Upstash.\\n```\\n\\n## Built-in Tools (26 \u2014 was 31 pre-S.277)\\n\\n### Read (18, parallel, auto-approved)\\n`render_canvas`, `balance_check`, `savings_info`, `health_check`, `rates_info`,\\n`transaction_history`, `swap_quote`, `explain_tx`, `portfolio_analysis`,\\n`token_prices`, `create_payment_link`, `list_payment_links`,\\n`cancel_payment_link`, `spending_analytics`, `yield_summary`,\\n`activity_summary`, `resolve_suins`, `pending_rewards`\\n\\n### Write (8, structurally serial, confirmation required)\\n`save_deposit` (USDC + USDsui), `withdraw`, `send_transfer`,\\n`borrow` (USDC + USDsui), `repay_debt` (USDC + USDsui \u2014 same asset as borrow),\\n`claim_rewards`, `harvest_rewards`, `swap_execute`\\n\\n> **S.245 (2026-05-22):** `pay_api` (write) + `mpp_services` (read) deleted\\n> per V07E_D_QUESTION_AUDITS D-2 reframe. The legacy MPP gateway\\n> capability returns as a Commerce primitive in the upcoming Audric Store\\n> SPEC \u2014 clean-slate redesign, not a port of the legacy 3-leg apps/web flow.\\n>\\n> **S.269 (2026-05-23):** `save_contact` deleted (engine-side dead \u2014 host\\n> owns Prisma persistence). V07E_INVOICE_DEPRECATION (item 7 of S.269)\\n> deleted 3 invoice tools \u2014 `create_invoice`, `list_invoices`,\\n> `cancel_invoice` \u2014 and the `InvoiceSchema` Zod definition. Payment\\n> links absorb the invoicing use case (label/memo encode invoice\\n> context). 35 \u2192 31 tools.\\n>\\n> **S.277 (2026-05-23):** \\"Earns Its Keep\\" audit cut 5 tools + 2 dead\\n> guards (engine 2.18.0). Volo trio (`volo_stats`, `volo_stake`,\\n> `volo_unstake`) \u2014 no Audric chip / product slot for liquid staking;\\n> `harvest_rewards` routes vSUI via Cetus, not Volo. `web_search`\\n> (Brave-backed) \u2014 gateway path uses Vercel AI Gateway\'s\\n> `perplexity_search` instead. `protocol_deep_dive` (DefiLlama) \u2014\\n> `rates_info` covers the in-product safety lens; engine no longer\\n> talks to `api.llama.fi`. 2 dead guards removed (`guardCostWarning`,\\n> `guardArtifactPreview`) \u2014 both unreachable post-S.245. `explain_tx`\\n> kept but description tightened to \\"arbitrary external digest only\\".\\n> SDK + CLI + MCP retain Volo for non-Audric consumers. 31 \u2192 26 tools\\n> (18 read + 8 write), 14 \u2192 12 guards.\\n>\\n> **S.269 item 6 (2026-05-23):** `save_contact` (write) deleted as part of\\n> the template-divergence cleanup slice. Engine-side dead tool \u2014 host-side\\n> Prisma persistence with no engine-owned effect; the user surface is the\\n> audric send screen, not the LLM.\\n>\\n> **S.277 (2026-05-23):** \\"Earns Its Keep\\" audit cut 5 tools from the\\n> engine surface \u2014 `volo_stats` / `volo_stake` / `volo_unstake` (no\\n> Audric chip / product slot; SDK + CLI + MCP retain Volo for non-Audric\\n> consumers), `web_search` (Brave-backed; gateway path uses Vercel AI\\n> Gateway\'s `perplexity_search`), `protocol_deep_dive` (DefiLlama-backed;\\n> rates_info is the in-product proxy). Also dropped: 2 dead guards\\n> (`costWarning`, `artifactPreview`) + the `costAware` flag. `explain_tx`\\n> kept but description tightened to \\"arbitrary external digest only\\". Net\\n> 31 \u2192 26 engine tools. See `spec/archive/v07e/AUDIT_V07E_EARNS_ITS_KEEP_2026-05-23.md`.\\n\\n> Write serialization is structural in v2 \u2014 no in-process mutex. Confirm-tier\\n> writes yield a `pending_action` event, the host round-trips through user\\n> confirm, and the next step runs the next write. Auto-execute writes\\n> (USD-aware permission resolver, sub-threshold) inherit one-write-per-step\\n> from the LLM\'s planning + the conservative-default preset.\\n\\n## Configuration\\n```typescript\\nnew AISDKEngine({\\n anthropicApiKey: process.env.ANTHROPIC_API_KEY, // Required (or pass `modelInstance` for custom providers)\\n agent, // T2000 SDK instance\\n mcpManager, // McpClientManager for MCP-first reads\\n walletAddress, // Sui address for MCP reads\\n tools: getDefaultTools(),\\n systemPrompt, // Override default Audric prompt\\n model: \'claude-sonnet-4-5\',\\n maxTurns: 10,\\n maxTokens: 4096,\\n costTracker: { budgetLimitUsd: 1.0 },\\n streamCheckpointStore, // optional, v2.2.0+ for live-stream resume\\n resumeStreamId, // optional, replays a checkpointed stream on cold start\\n});\\n```\\n\\n## Key Imports\\n```typescript\\n// Core\\nimport { AISDKEngine, getDefaultTools } from \'@t2000/engine\';\\n// Tools (defineTool is the v2 factory; READ_TOOL_SET / WRITE_TOOL_SET / READ_TOOL_NAMES are the tool registries since v3.0.0)\\nimport { defineTool, READ_TOOL_SET, WRITE_TOOL_SET, READ_TOOL_NAMES } from \'@t2000/engine\';\\n// Streaming (`engineToSSE` was deleted in v2.2.0 \u2014 see \\"SSE Streaming\\" above)\\nimport { serializeSSE, parseSSE, withStreamState } from \'@t2000/engine\';\\n// Stream checkpoint resume (v2.2.0+)\\nimport { InMemoryStreamCheckpointStore } from \'@t2000/engine\';\\n// Sessions\\nimport { MemorySessionStore } from \'@t2000/engine\';\\n// Cost\\nimport { CostTracker } from \'@t2000/engine\';\\n// Microcompact + context budgeting\\nimport { microcompact, compactMessages, estimateTokens } from \'@t2000/engine\';\\n// Granular permissions (USD-aware resolver)\\nimport {\\n resolvePermissionTier, resolveUsdValue, toolNameToOperation,\\n DEFAULT_PERMISSION_CONFIG, PERMISSION_PRESETS,\\n} from \'@t2000/engine\';\\n// MCP\\nimport {\\n McpClientManager, McpPromptAdapter,\\n NAVI_MCP_CONFIG, buildMcpTools, registerEngineTools,\\n} from \'@t2000/engine\';\\n```"},{"name":"t2000-mcp","description":"Connect a t2000 Agentic Wallet to Claude Desktop, Cursor, Cline, Continue, or any MCP-compatible client. Use when asked to set up MCP, paste an MCP server config, install @t2000/mcp, or troubleshoot why the MCP server \\"doesn\'t do anything\\" when run from a terminal. Provides 29 tools and 14 prompts over stdio.","body":"# t2000: MCP Server\\n\\n## Purpose\\nExpose a t2000 Agentic Wallet (Sui wallet + DeFi positions) to any\\nMCP-compatible AI client over stdio. **29 tools, 14 prompts**, safeguard\\nenforced. No global install required \u2014 the recommended path uses `npx`\\nso the AI client always pulls the latest published version.\\n\\n## \u26A0\uFE0F The most common confusion\\n\\n**`npx @t2000/mcp` is NOT a command you run from a terminal to \\"use\\" the\\nMCP server.** It is a JSON-RPC server that listens silently on `stdin`.\\nIf you run it manually it will appear to hang \u2014 that\'s correct behavior.\\nIt is meant to be launched as a subprocess by an AI client (Claude\\nDesktop, Cursor, etc.) which speaks JSON-RPC to it over `stdin`/`stdout`.\\n\\nThe JSON snippets below go into your **AI client\'s MCP settings file**,\\nnot into a shell.\\n\\n## Setup\\n\\n### 1. Create a wallet + safeguards (one-time, in a terminal)\\n\\n```bash\\n# Install CLI long enough to bootstrap a wallet and set safety limits\\nnpx @t2000/cli init\\nnpx @t2000/cli config set maxPerTx 100\\nnpx @t2000/cli config set maxDailySend 500\\n\\n# Create a session so MCP can reuse the saved PIN\\nnpx @t2000/cli balance\\n```\\n\\nThe MCP server **refuses to start** until `maxPerTx` and `maxDailySend`\\nare configured. This is intentional.\\n\\n### 2. Add the MCP server to your AI client\\n\\nRecommended config (auto-updates on every launch, no global install):\\n\\n```json\\n{\\n \\"mcpServers\\": {\\n \\"t2000\\": {\\n \\"command\\": \\"npx\\",\\n \\"args\\": [\\"-y\\", \\"@t2000/mcp@latest\\"]\\n }\\n }\\n}\\n```\\n\\nAlternative (if `@t2000/cli` is already installed globally):\\n\\n```json\\n{\\n \\"mcpServers\\": {\\n \\"t2000\\": {\\n \\"command\\": \\"t2000\\",\\n \\"args\\": [\\"mcp\\"]\\n }\\n }\\n}\\n```\\n\\n### 3. Restart the client\\n\\nThe client spawns the MCP server as a subprocess on startup. You should\\nsee `t2000_*` tools appear in the tool list.\\n\\n## Per-client config file paths\\n\\n| Client | Config file |\\n|--------|-------------|\\n| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |\\n| Claude Desktop (Windows) | `%APPDATA%\\\\Claude\\\\claude_desktop_config.json` |\\n| Cursor | Settings \u2192 MCP \u2192 Add new MCP server (or `~/.cursor/mcp.json`) |\\n| Cline | VSCode settings \u2192 `cline.mcpServers` |\\n| Continue | `~/.continue/config.json` under `mcpServers` |\\n\\n## Verification (optional, before wiring into a client)\\n\\nConfirm the server responds to a real MCP `initialize` request:\\n\\n```bash\\nprintf \'%s\\\\n\' \\\\\\n \'{\\"jsonrpc\\":\\"2.0\\",\\"id\\":1,\\"method\\":\\"initialize\\",\\"params\\":{\\"protocolVersion\\":\\"2024-11-05\\",\\"capabilities\\":{},\\"clientInfo\\":{\\"name\\":\\"test\\",\\"version\\":\\"1.0\\"}}}\' \\\\\\n | npx -y @t2000/mcp@latest\\n```\\n\\nYou should see a JSON response containing `\\"serverInfo\\":{\\"name\\":\\"t2000\\"...}`\\nand exit. If you see that, the server is healthy and ready to be launched\\nby a client.\\n\\n## Available Tools (29)\\n\\n### Read-only (15)\\n| Tool | Description |\\n|------|-------------|\\n| `t2000_overview` | Complete account snapshot in one call |\\n| `t2000_balance` | Current balance |\\n| `t2000_address` | Wallet address |\\n| `t2000_positions` | Lending positions |\\n| `t2000_rates` | Best interest rates per asset |\\n| `t2000_all_rates` | Per-protocol rate comparison |\\n| `t2000_health` | Health factor |\\n| `t2000_history` | Transaction history |\\n| `t2000_earnings` | Yield earnings |\\n| `t2000_fund_status` | Savings fund status |\\n| `t2000_pending_rewards` | Pending protocol rewards |\\n| `t2000_deposit_info` | Deposit instructions |\\n| `t2000_receive` | Generate payment request with address, nonce, and Payment Kit URI (`sui:pay?\u2026`) |\\n| `t2000_services` | List all MPP services and endpoints |\\n| `t2000_contacts` | List saved contacts |\\n\\n### State-changing (12)\\nAll support `dryRun: true` for previews without signing.\\n\\n| Tool | Description |\\n|------|-------------|\\n| `t2000_send` | Send USDC |\\n| `t2000_save` | Deposit to savings |\\n| `t2000_withdraw` | Withdraw from savings |\\n| `t2000_borrow` | Borrow against collateral |\\n| `t2000_repay` | Repay debt |\\n| `t2000_claim_rewards` | Claim pending protocol rewards |\\n| `t2000_pay` | Pay for and call any MPP API service with USDC |\\n| `t2000_swap` | Execute a token swap via Cetus Aggregator |\\n| `t2000_stake` | Stake SUI for vSUI via VOLO liquid staking |\\n| `t2000_unstake` | Unstake vSUI and redeem SUI |\\n| `t2000_contact_add` | Save a contact name \u2192 address |\\n| `t2000_contact_remove` | Remove a saved contact |\\n\\n### Safety (2)\\n| Tool | Description |\\n|------|-------------|\\n| `t2000_config` | View/set limits |\\n| `t2000_lock` | Emergency freeze |\\n\\n## Prompts (14)\\n| Prompt | Description |\\n|--------|-------------|\\n| `financial-report` | Full financial summary |\\n| `optimize-yield` | Yield optimization analysis |\\n| `send-money` | Guided send with preview |\\n| `budget-check` | Can I afford $X? |\\n| `savings-strategy` | Recommend how much to save and where |\\n| `what-if` | Scenario planning \u2014 model impact before acting |\\n| `sweep` | Route idle funds to optimal earning positions |\\n| `risk-check` | Health factor, concentration, liquidation risk |\\n| `weekly-recap` | Week in review \u2014 activity, yield |\\n| `claim-rewards` | Check and claim pending protocol rewards |\\n| `safeguards` | Review safety settings \u2014 limits, lock, PIN-protected operations |\\n| `onboarding` | New user setup \u2014 deposit, first save, explore features |\\n| `emergency` | Lock account, assess damage, recovery guidance |\\n| `optimize-all` | One-shot full optimization \u2014 sweep, compare APYs, claim rewards |\\n\\n## Troubleshooting\\n\\n| Symptom | Cause | Fix |\\n|---------|-------|-----|\\n| `npx @t2000/mcp` \\"hangs\\" with no output | Working as designed \u2014 server is waiting for JSON-RPC on stdin | Don\'t run it manually; let the AI client launch it |\\n| Server exits with `Safeguards not configured` | `maxPerTx` / `maxDailySend` not set | Run `npx @t2000/cli config set maxPerTx 100 && ... maxDailySend 500` |\\n| Client shows no `t2000_*` tools after restart | Wrong config path, or stale npx cache | Verify with the `printf | npx ...` test above; clear cache with `rm -rf ~/.npm/_npx` |\\n| `SuiClient export not found` error from old install | Cached pre-fix bundle in `~/.npm/_npx` | `rm -rf ~/.npm/_npx` then restart the client |\\n\\n## Engine MCP Adapter (Audric)\\n\\n`@t2000/engine` can also expose its financial tools as MCP tools, enabling\\nAudric to serve as an MCP server alongside `@t2000/mcp`:\\n\\n```typescript\\nimport { registerEngineTools, getDefaultTools } from \'@t2000/engine\';\\nimport { McpServer } from \'@modelcontextprotocol/sdk/server/mcp.js\';\\n\\nconst server = new McpServer({ name: \'audric\', version: \'0.1.0\' });\\nregisterEngineTools(server, getDefaultTools());\\n// Exposes: audric_balance_check, audric_save_deposit, etc.\\n```\\n\\nEngine tools use `audric_` prefix to avoid collisions with `t2000_` prefixed\\ntools from `@t2000/mcp`. The engine adapter includes permission-level metadata\\nand supports the full confirmation flow.\\n\\n## Security\\n- Safeguard gate: server refuses to start without configured limits\\n- `unlock` is CLI-only \u2014 AI cannot circumvent a locked agent\\n- `dryRun: true` previews operations before signing\\n- Local-only stdio transport \u2014 key never leaves the machine"},{"name":"t2000-pay","description":"Pay for an MPP-protected API service using the t2000 wallet. Use when asked to call an AI model, search the web, generate images, send email, buy gift cards, send physical mail, check weather, execute code, or any task that requires a paid API. Handles the full MPP 402 challenge automatically. Use t2000_services to discover all available services first.","body":"# t2000: Pay for MPP API Service\\n\\n## Status\\nActive \u2014 requires `t2000` CLI with `@suimpp/mpp` installed.\\n\\n## Purpose\\nMake a paid HTTP request to any MPP-protected endpoint. Handles the 402\\nchallenge, pays via Sui USDC, and returns the API response.\\n\\n## Service Discovery\\nBefore calling `t2000 pay`, discover available services:\\n```bash\\n# CLI\\nt2000 pay https://mpp.t2000.ai/api/services\\n\\n# MCP\\nt2000_services\\n```\\n\\nAll services are hosted at `https://mpp.t2000.ai/`.\\n\\n## Command\\n```bash\\nt2000 pay <url> [options]\\n```\\n\\n## Options\\n| Option | Description | Default |\\n|--------|-------------|---------|\\n| `--method <method>` | HTTP method (GET, POST, PUT) | POST |\\n| `--data <json>` | Request body for POST/PUT | \u2014 |\\n| `--max-price <amount>` | Max USDC per request | $1.00 |\\n| `--header <key=value>` | Additional HTTP header (repeatable) | \u2014 |\\n| `--timeout <seconds>` | Request timeout in seconds | 30 |\\n| `--dry-run` | Show what would be paid without paying | \u2014 |\\n\\n## Available Services (40 services, 88 endpoints)\\n\\n> For the live, canonical list use `t2000_services` (MCP) or GET `https://mpp.t2000.ai/api/services`.\\n> The table below is a quick reference.\\n\\n### AI Models\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| OpenAI Chat | `/openai/v1/chat/completions` | $0.01 |\\n| OpenAI Embeddings | `/openai/v1/embeddings` | $0.005 |\\n| OpenAI Audio Transcription | `/openai/v1/audio/transcriptions` | $0.01 |\\n| OpenAI Text-to-Speech | `/openai/v1/audio/speech` | $0.02 |\\n| Anthropic | `/anthropic/v1/messages` | $0.01 |\\n| Google Gemini Flash | `/gemini/v1beta/models/gemini-2.5-flash` | $0.005 |\\n| Google Gemini Pro | `/gemini/v1beta/models/gemini-2.5-pro` | $0.01 |\\n| Google Gemini Embeddings | `/gemini/v1beta/models/embedding-001` | $0.005 |\\n| DeepSeek | `/deepseek/v1/chat/completions` | $0.005 |\\n| Groq Chat | `/groq/v1/chat/completions` | $0.005 |\\n| Groq Audio Transcription | `/groq/v1/audio/transcriptions` | $0.005 |\\n| Together AI Chat | `/together/v1/chat/completions` | $0.005 |\\n| Together AI Embeddings | `/together/v1/embeddings` | $0.005 |\\n| Perplexity | `/perplexity/v1/chat/completions` | $0.01 |\\n| Mistral Chat | `/mistral/v1/chat/completions` | $0.005 |\\n| Mistral Embeddings | `/mistral/v1/embeddings` | $0.005 |\\n| Cohere Chat | `/cohere/v1/chat` | $0.005 |\\n| Cohere Embed | `/cohere/v1/embed` | $0.005 |\\n| Cohere Rerank | `/cohere/v1/rerank` | $0.005 |\\n\\n### Media & Generation\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| OpenAI DALL-E | `/openai/v1/images/generations` | $0.05 |\\n| Fal.ai Flux Dev | `/fal/fal-ai/flux/dev` | $0.03 |\\n| Fal.ai Flux Pro | `/fal/fal-ai/flux-pro` | $0.05 |\\n| Fal.ai Flux Realism | `/fal/fal-ai/flux-realism` | $0.05 |\\n| Fal.ai Recraft 20B | `/fal/fal-ai/recraft-20b` | $0.05 |\\n| Fal.ai Whisper | `/fal/fal-ai/whisper` | $0.01 |\\n| Together AI Images | `/together/v1/images/generations` | $0.03 |\\n| ElevenLabs TTS | `/elevenlabs/v1/text-to-speech/:voiceId` | $0.05 |\\n| ElevenLabs SFX | `/elevenlabs/v1/sound-generation` | $0.05 |\\n| Replicate (any model) | `/replicate/v1/predictions` | $0.02 |\\n| Replicate (check status) | `/replicate/v1/predictions/status` | $0.005 |\\n| Stability AI (generate) | `/stability/v1/generate` | $0.03 |\\n| Stability AI (edit) | `/stability/v1/edit` | $0.03 |\\n| AssemblyAI (transcribe) | `/assemblyai/v1/transcribe` | $0.02 |\\n| AssemblyAI (get result) | `/assemblyai/v1/result` | $0.005 |\\n\\n### Search\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Brave Web Search | `/brave/v1/web/search` | $0.005 |\\n| Brave Image Search | `/brave/v1/images/search` | $0.005 |\\n| Brave News Search | `/brave/v1/news/search` | $0.005 |\\n| Brave Video Search | `/brave/v1/videos/search` | $0.005 |\\n| Brave Summarizer | `/brave/v1/summarizer/search` | $0.01 |\\n| Exa (semantic search) | `/exa/v1/search` | $0.01 |\\n| Exa (content extract) | `/exa/v1/contents` | $0.01 |\\n| Serper (Google search) | `/serper/v1/search` | $0.005 |\\n| Serper (image search) | `/serper/v1/images` | $0.005 |\\n| SerpAPI (Google search) | `/serpapi/v1/search` | $0.01 |\\n| SerpAPI (Google Flights) | `/serpapi/v1/flights` | $0.01 |\\n| SerpAPI (locations) | `/serpapi/v1/locations` | $0.005 |\\n| NewsAPI (headlines) | `/newsapi/v1/headlines` | $0.005 |\\n| NewsAPI (article search) | `/newsapi/v1/search` | $0.005 |\\n\\n### Data\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| OpenWeather Current | `/openweather/v1/weather` | $0.005 |\\n| OpenWeather Forecast | `/openweather/v1/forecast` | $0.005 |\\n| Google Maps Geocode | `/googlemaps/v1/geocode` | $0.01 |\\n| Google Maps Places | `/googlemaps/v1/places` | $0.01 |\\n| Google Maps Directions | `/googlemaps/v1/directions` | $0.01 |\\n| CoinGecko (price) | `/coingecko/v1/price` | $0.005 |\\n| CoinGecko (markets) | `/coingecko/v1/markets` | $0.005 |\\n| CoinGecko (trending) | `/coingecko/v1/trending` | $0.005 |\\n| Alpha Vantage (quote) | `/alphavantage/v1/quote` | $0.005 |\\n| Alpha Vantage (daily) | `/alphavantage/v1/daily` | $0.005 |\\n| Alpha Vantage (search) | `/alphavantage/v1/search` | $0.005 |\\n\\n### Web & Documents\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Firecrawl Scrape | `/firecrawl/v1/scrape` | $0.01 |\\n| Firecrawl Crawl | `/firecrawl/v1/crawl` | $0.02 |\\n| Firecrawl Map | `/firecrawl/v1/map` | $0.01 |\\n| Firecrawl Extract | `/firecrawl/v1/extract` | $0.02 |\\n| Jina Reader | `/jina/v1/read` | $0.005 |\\n| ScreenshotOne | `/screenshot/v1/capture` | $0.01 |\\n| PDFShift (HTML to PDF) | `/pdfshift/v1/convert` | $0.01 |\\n| QR Code | `/qrcode/v1/generate` | $0.005 |\\n\\n### Translation\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| DeepL (translate) | `/deepl/v1/translate` | $0.005 |\\n| Google Translate | `/translate/v1/translate` | $0.005 |\\n| Google Detect Language | `/translate/v1/detect` | $0.005 |\\n\\n### Intelligence\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Hunter.io (domain search) | `/hunter/v1/search` | $0.02 |\\n| Hunter.io (verify email) | `/hunter/v1/verify` | $0.02 |\\n| IPinfo (IP lookup) | `/ipinfo/v1/lookup` | $0.005 |\\n\\n### Tools & Compute\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Judge0 Code Exec | `/judge0/v1/submissions` | $0.005 |\\n| Judge0 Languages | `/judge0/v1/languages` | $0.005 |\\n| Resend Email | `/resend/v1/emails` | $0.005 |\\n| Resend Batch Email | `/resend/v1/emails/batch` | $0.01 |\\n\\n### Commerce\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Lob Postcards | `/lob/v1/postcards` | $1.00 |\\n| Lob Letters | `/lob/v1/letters` | $1.50 |\\n| Lob Address Verify | `/lob/v1/verify` | $0.01 |\\n| Printful (browse) | `/printful/v1/products` | $0.005 |\\n| Printful (estimate) | `/printful/v1/estimate` | $0.005 |\\n| Printful (order) | `/printful/v1/order` | dynamic |\\n\\n### Messaging\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Pushover | `/pushover/v1/push` | $0.005 |\\n\\n### Security\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| VirusTotal (URL/file scan) | `/virustotal/v1/scan` | $0.01 |\\n\\n### Finance\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| ExchangeRate (rates) | `/exchangerate/v1/rates` | $0.005 |\\n| ExchangeRate (convert) | `/exchangerate/v1/convert` | $0.005 |\\n\\n### Utility\\n| Service | Endpoint | Price |\\n|---------|----------|-------|\\n| Short.io (URL shortener) | `/shortio/v1/shorten` | $0.005 |\\n\\n## Example Commands\\n\\n### Ask an AI model\\n```bash\\nt2000 pay https://mpp.t2000.ai/openai/v1/chat/completions \\\\\\n --data \'{\\"model\\":\\"gpt-4o\\",\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\"Explain quantum computing in 3 sentences\\"}]}\'\\n```\\n\\n### Search the web\\n```bash\\nt2000 pay https://mpp.t2000.ai/brave/v1/web/search \\\\\\n --data \'{\\"q\\":\\"latest Sui blockchain news\\"}\'\\n```\\n\\n### Generate an image\\n```bash\\nt2000 pay https://mpp.t2000.ai/fal/fal-ai/flux/dev \\\\\\n --data \'{\\"prompt\\":\\"a futuristic city at sunset, cyberpunk style\\"}\'\\n```\\n\\n### Check weather\\n```bash\\nt2000 pay https://mpp.t2000.ai/openweather/v1/weather \\\\\\n --data \'{\\"q\\":\\"Tokyo\\"}\'\\n```\\n\\n### Send an email\\n```bash\\nt2000 pay https://mpp.t2000.ai/resend/v1/emails \\\\\\n --data \'{\\"from\\":\\"agent@t2000.ai\\",\\"to\\":\\"user@example.com\\",\\"subject\\":\\"Hello\\",\\"text\\":\\"Sent by an AI agent\\"}\'\\n```\\n\\n### Execute code\\n```bash\\nt2000 pay https://mpp.t2000.ai/judge0/v1/submissions \\\\\\n --data \'{\\"source_code\\":\\"print(42)\\",\\"language_id\\":71}\'\\n```\\n\\n### Send physical mail\\n```bash\\n# Send a postcard\\nt2000 pay https://mpp.t2000.ai/lob/v1/postcards \\\\\\n --max-price 2 \\\\\\n --data \'{\\n \\"to\\":{\\"name\\":\\"Jane Doe\\",\\"address_line1\\":\\"123 Main St\\",\\"address_city\\":\\"San Francisco\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94105\\"},\\n \\"from\\":{\\"name\\":\\"AI Agent\\",\\"address_line1\\":\\"456 Oak Ave\\",\\"address_city\\":\\"Palo Alto\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94301\\"},\\n \\"front\\":\\"https://example.com/front.png\\",\\n \\"back\\":\\"https://example.com/back.png\\",\\n \\"use_type\\":\\"operational\\"\\n }\'\\n\\n# Send a letter\\nt2000 pay https://mpp.t2000.ai/lob/v1/letters \\\\\\n --max-price 2 \\\\\\n --data \'{\\n \\"to\\":{\\"name\\":\\"Jane Doe\\",\\"address_line1\\":\\"123 Main St\\",\\"address_city\\":\\"San Francisco\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94105\\"},\\n \\"from\\":{\\"name\\":\\"AI Agent\\",\\"address_line1\\":\\"456 Oak Ave\\",\\"address_city\\":\\"Palo Alto\\",\\"address_state\\":\\"CA\\",\\"address_zip\\":\\"94301\\"},\\n \\"file\\":\\"https://example.com/letter.pdf\\",\\n \\"use_type\\":\\"operational\\",\\n \\"color\\":false\\n }\'\\n\\n# Verify a US address\\nt2000 pay https://mpp.t2000.ai/lob/v1/verify \\\\\\n --data \'{\\"primary_line\\":\\"123 Main St\\",\\"city\\":\\"San Francisco\\",\\"state\\":\\"CA\\",\\"zip_code\\":\\"94105\\"}\'\\n```\\n\\n### Get directions\\n```bash\\nt2000 pay https://mpp.t2000.ai/googlemaps/v1/directions \\\\\\n --data \'{\\"origin\\":\\"San Francisco, CA\\",\\"destination\\":\\"Palo Alto, CA\\"}\'\\n```\\n\\n### Get crypto prices\\n```bash\\nt2000 pay https://mpp.t2000.ai/coingecko/v1/price \\\\\\n --data \'{\\"ids\\":\\"sui,bitcoin,ethereum\\",\\"vs_currencies\\":\\"usd\\"}\'\\n```\\n\\n### Get a stock quote\\n```bash\\nt2000 pay https://mpp.t2000.ai/alphavantage/v1/quote \\\\\\n --data \'{\\"symbol\\":\\"AAPL\\"}\'\\n```\\n\\n### Get breaking news\\n```bash\\nt2000 pay https://mpp.t2000.ai/newsapi/v1/headlines \\\\\\n --data \'{\\"country\\":\\"us\\",\\"category\\":\\"technology\\"}\'\\n```\\n\\n### Translate text\\n```bash\\nt2000 pay https://mpp.t2000.ai/deepl/v1/translate \\\\\\n --data \'{\\"text\\":[\\"Hello, how are you?\\"],\\"target_lang\\":\\"ES\\"}\'\\n```\\n\\n### Semantic search\\n```bash\\nt2000 pay https://mpp.t2000.ai/exa/v1/search \\\\\\n --data \'{\\"query\\":\\"best practices for AI agent payments\\",\\"numResults\\":5}\'\\n```\\n\\n### Read a URL as markdown\\n```bash\\nt2000 pay https://mpp.t2000.ai/jina/v1/read \\\\\\n --data \'{\\"url\\":\\"https://docs.sui.io/concepts/tokenomics\\"}\'\\n```\\n\\n### Google search (structured)\\n```bash\\nt2000 pay https://mpp.t2000.ai/serper/v1/search \\\\\\n --data \'{\\"q\\":\\"Sui blockchain TVL 2026\\"}\'\\n```\\n\\n### Screenshot a webpage\\n```bash\\nt2000 pay https://mpp.t2000.ai/screenshot/v1/capture \\\\\\n --data \'{\\"url\\":\\"https://example.com\\",\\"format\\":\\"png\\",\\"viewport_width\\":\\"1280\\"}\'\\n```\\n\\n### Generate a QR code\\n```bash\\nt2000 pay https://mpp.t2000.ai/qrcode/v1/generate \\\\\\n --data \'{\\"data\\":\\"https://t2000.ai\\",\\"size\\":\\"400x400\\"}\'\\n```\\n\\n### Convert HTML to PDF\\n```bash\\nt2000 pay https://mpp.t2000.ai/pdfshift/v1/convert \\\\\\n --data \'{\\"source\\":\\"https://t2000.ai/docs\\"}\'\\n```\\n\\n### Run a Replicate model\\n```bash\\nt2000 pay https://mpp.t2000.ai/replicate/v1/predictions \\\\\\n --data \'{\\"model\\":\\"meta/llama-3-70b-instruct\\",\\"input\\":{\\"prompt\\":\\"Explain DeFi in 3 sentences\\"}}\'\\n```\\n\\n### Find emails for a domain\\n```bash\\nt2000 pay https://mpp.t2000.ai/hunter/v1/search \\\\\\n --data \'{\\"domain\\":\\"mystenlabs.com\\"}\'\\n```\\n\\n### Look up an IP address\\n```bash\\nt2000 pay https://mpp.t2000.ai/ipinfo/v1/lookup \\\\\\n --data \'{\\"ip\\":\\"8.8.8.8\\"}\'\\n```\\n\\n### Order print-on-demand merchandise\\n```bash\\nt2000 pay https://mpp.t2000.ai/printful/v1/order \\\\\\n --max-price 30 \\\\\\n --data \'{\\"recipient\\":{\\"name\\":\\"Jane Doe\\",\\"address1\\":\\"123 Main St\\",\\"city\\":\\"SF\\",\\"state_code\\":\\"CA\\",\\"country_code\\":\\"US\\",\\"zip\\":\\"94105\\"},\\"items\\":[{\\"variant_id\\":4012,\\"quantity\\":1,\\"files\\":[{\\"url\\":\\"https://example.com/design.png\\"}]}]}\'\\n```\\n\\n### Search for flights\\n```bash\\nt2000 pay https://mpp.t2000.ai/serpapi/v1/flights \\\\\\n --data \'{\\"departure_id\\":\\"LAX\\",\\"arrival_id\\":\\"NRT\\",\\"outbound_date\\":\\"2026-05-01\\",\\"type\\":\\"2\\"}\'\\n```\\n\\n### Convert currency\\n```bash\\nt2000 pay https://mpp.t2000.ai/exchangerate/v1/convert \\\\\\n --data \'{\\"from\\":\\"USD\\",\\"to\\":\\"EUR\\",\\"amount\\":100}\'\\n```\\n\\n### Scan a URL for malware\\n```bash\\nt2000 pay https://mpp.t2000.ai/virustotal/v1/scan \\\\\\n --data \'{\\"url\\":\\"https://suspicious-site.com\\"}\'\\n```\\n\\n### Shorten a URL\\n```bash\\nt2000 pay https://mpp.t2000.ai/shortio/v1/shorten \\\\\\n --data \'{\\"url\\":\\"https://example.com/very/long/url/path\\"}\'\\n```\\n\\n### Send a push notification\\n```bash\\nt2000 pay https://mpp.t2000.ai/pushover/v1/push \\\\\\n --data \'{\\"user\\":\\"USER_KEY\\",\\"message\\":\\"Your agent has a message!\\"}\'\\n```\\n\\n## Flow (automatic)\\n1. Makes initial HTTP request to the URL\\n2. If 402: reads MPP challenge for amount and terms\\n3. If price <= --max-price: pays via Sui USDC\\n4. Retries with credential header\\n5. Returns the API response body\\n\\n## Safety\\n- If requested price exceeds --max-price, payment is refused (no funds spent)\\n- Default max-price: $1.00 USDC per request\\n- For commerce (mail, merch), set --max-price higher\\n- Payment only broadcast after 402 terms are validated\\n\\n## Errors\\n- `PRICE_EXCEEDS_LIMIT`: API asking more than --max-price\\n- `INSUFFICIENT_BALANCE`: not enough available USDC\\n- `UNSUPPORTED_NETWORK`: MPP requires a network other than Sui\\n- `PAYMENT_EXPIRED`: payment challenge has expired\\n- `DUPLICATE_PAYMENT`: nonce already used on-chain\\n\\n## MCP\\nVia MCP: use `t2000_services` to discover services, then `t2000_pay` to call them."},{"name":"t2000-rebalance","description":"Rebalance the wallet to a target allocation by executing multiple swaps in one atomic Payment Intent. Use when asked to rebalance, adjust allocation, \\"shuffle my positions\\", or move from one set of holdings to another. Every leg prices against the same on-chain snapshot \u2014 no cross-leg slippage drift; user signs once.","body":"# t2000: Rebalance Portfolio\\n\\n## Purpose\\nMove from a current allocation to a target allocation by emitting all\\nthe required `swap_execute` calls **in the same assistant turn** so the\\nengine compiles them into one Payment Intent. Result: every leg of the\\nrebalance prices against the same Sui state, slippage is bounded once,\\nand the user signs once.\\n\\n## When to use\\n\\n- \\"Rebalance my portfolio to 60% USDC / 30% SUI / 10% GOLD\\"\\n- \\"Move everything to USDC\\"\\n- \\"Adjust my allocation \u2014 I want less SUI exposure\\"\\n- \\"I\'m 80% SUI, get me to 50/50 with USDC\\"\\n\\n## Flow\\n\\n### Step 1 \u2014 Current allocation\\nCall `balance_check` (engine) or `t2000_balance --json` (CLI) to get the\\ncurrent breakdown. Compute the percentage held in each asset by USD value.\\n\\n### Step 2 \u2014 Plan trades\\nFor each asset, compute the delta vs the target:\\n- Asset over-allocated \u2192 swap **out** to USDC (or another reduce-target asset)\\n- Asset under-allocated \u2192 swap **in** from USDC (or another excess-source asset)\\n\\nPresent the plan to the user **before** executing:\\n\\n```\\n\u{1F4CA} REBALANCE PLAN\\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n Current Target \u0394\\n USDC $400 $600 +$200\\n SUI $400 $300 \u2212$100\\n GOLD $200 $100 \u2212$100\\n\\nTrades (1 atomic Payment Intent):\\n 1. swap 0.5 SUI \u2192 ~$100 USDC\\n 2. swap 0.05 GOLD \u2192 ~$100 USDC\\n\\nEstimated slippage: 0.3% on each leg\\nProceed?\\n```\\n\\n### Step 3 \u2014 Execute (bundled)\\n\\n**Critical:** emit ALL the `swap_execute` calls as parallel `tool_use` blocks\\n**in the same assistant turn**. The engine\'s permission gate compiles them\\ninto ONE Payment Intent. The user signs once; every leg either succeeds or\\nthe whole rebalance reverts.\\n\\n**Do NOT** call them sequentially across turns \u2014 that defeats the atomicity\\nand exposes the user to price drift between legs.\\n\\n```\\n[ASSISTANT TURN \u2014 emit in parallel]\\n tool_use: swap_execute({ from: \\"SUI\\", to: \\"USDC\\", amount: 0.5 })\\n tool_use: swap_execute({ from: \\"GOLD\\", to: \\"USDC\\", amount: 0.05 })\\n```\\n\\n### Step 4 \u2014 Summary\\nAfter the Payment Intent settles, call `balance_check` again and show the\\nfinal allocation vs target. Highlight any drift > 1% (caused by slippage\\nor rounding) and ask if the user wants a follow-up swap to close it.\\n\\n## Error handling\\n\\n| Error | Cause | What to do |\\n|---|---|---|\\n| Intent failed \u2014 `INSUFFICIENT_BALANCE` | One of the swap legs would consume more than the wallet holds | Abort the entire intent (no swaps execute). Reduce the amount on the offending leg. |\\n| Intent failed \u2014 `SLIPPAGE_EXCEEDED` | A leg exceeded the configured slippage tolerance | Abort. Re-run with looser slippage OR smaller leg sizes. |\\n| Intent failed \u2014 any reason | Atomic Payment Intent reverts the WHOLE bundle | No funds moved. Tell the user the on-chain state is unchanged. |\\n\\n## CLI fallback (no bundling)\\n\\nThe CLI does not support Payment Intent bundling today. To rebalance from\\nthe CLI, execute swaps one at a time:\\n\\n```bash\\nt2000 swap 0.5 SUI to USDC\\nt2000 swap 0.05 GOLD to USDC\\n```\\n\\nEach swap prices against the on-chain state **at the moment of execution**,\\nwhich means small drift between legs. For larger rebalances ($1k+) prefer\\nthe agent path (which bundles into one Payment Intent).\\n\\n## Fees\\n\\nPer swap leg:\\n- Cetus protocol fee: ~0.1% of swap amount (varies by pool)\\n- Audric overlay fee: 10 bps (~0.1%)\\n\\nBundled rebalances pay the same per-leg fees \u2014 bundling reduces slippage\\nrisk, not fee cost.\\n\\n## Notes\\n\\n- This skill is **engine-first** \u2014 the bundling guarantee only exists in\\n the audric/web chat agent (or any engine consumer with Payment Intent\\n compile support).\\n- For \\"optimize my yield\\" intent (sweep idle USDC into best-APY savings,\\n claim rewards, compare USDC pools), use the `optimize-all` MCP prompt\\n instead \u2014 that\'s a different shape of workflow.\\n- Health-factor check **does not run** for swap-only rebalances (no\\n collateral position changes). For rebalances that involve withdrawing\\n from savings, see `t2000-withdraw` (the safety check runs there)."},{"name":"t2000-receive","description":"Generate a payment request to receive funds into the t2000 agent wallet. Use when asked to receive money, create a payment link, share a wallet address, or generate a QR code for receiving payment. Produces a payment request with address, Sui Payment Kit URI (sui:pay?\u2026), nonce, and optional amount/memo.","body":"# t2000: Receive Payment\\n\\n## Purpose\\nGenerate a payment request containing the agent\'s wallet address, a unique\\nnonce, and a Sui Payment Kit URI (`sui:pay?\u2026`). The sender can scan the QR or\\ncopy the address to send funds. No on-chain transaction is created \u2014 this is a\\nlocal, read-only operation.\\n\\n## Command\\n```bash\\nt2000 receive [options]\\n\\n# Examples:\\nt2000 receive # Address only\\nt2000 receive --amount 25 # Request $25 USDC\\nt2000 receive --amount 100 --memo \\"Invoice #42\\" # With memo\\nt2000 receive --amount 50 --label \\"Freelance work\\" # With label\\nt2000 receive --currency SUI --amount 10 # Request SUI\\n```\\n\\n## Options\\n| Option | Description |\\n|--------|-------------|\\n| `--amount <n>` | Amount to request (omit for open amount) |\\n| `--currency <sym>` | Currency symbol (default: USDC) |\\n| `--memo <text>` | Payment note shown to sender |\\n| `--label <text>` | Description for the payment request |\\n\\n## Output\\n```\\n\u2713 Payment Request\\n\\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n Address 0x8b3e...d412\\n Network Sui Mainnet\\n Nonce a1b2c3d4-e5f6-7890-abcd-ef1234567890\\n Amount $25.00 USDC\\n Memo Invoice #42\\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n\\n Payment URI sui:pay?receiver=0x8b3e...&amount=25000000&...\\n\\n Share this URI or scan the QR to pay via any Sui wallet.\\n```\\n\\n## SDK Usage\\n```typescript\\nconst request = agent.receive({ amount: 25, memo: \'Invoice #42\' });\\n// Returns: { address, network, amount, currency, memo, label, nonce, qrUri, displayText }\\n```\\n\\n## MCP Tool\\nTool name: `t2000_receive` (read-only, auto-approved).\\n\\n## Notes\\n- This is a **local operation** \u2014 no transaction is created, no gas is used\\n- Uses **Sui Payment Kit** \u2014 generates `sui:pay?` URIs with nonce binding\\n- The nonce is a UUID that uniquely identifies each payment request\\n- Wallets that support Payment Kit register payment in an on-chain registry, preventing double-spend\\n- Without `--amount`, the request is open-ended (any amount accepted)\\n- Default currency is USDC; specify `--currency SUI` for native SUI"},{"name":"t2000-repay","description":"Repay outstanding debt. Use when asked to repay a loan, pay back debt, reduce outstanding balance, or clear borrows. Supports partial and full repayment. User pays with USDC.","body":"# t2000: Repay Borrow\\n\\n## Purpose\\nRepay outstanding debt in USDC. Supports specific amounts or `repay all` to clear the full\\nbalance including accrued interest.\\n\\n## Command\\n```bash\\nt2000 repay <amount>\\nt2000 repay all\\n\\n# Examples:\\nt2000 repay 20\\nt2000 repay all\\n```\\n\\n## Fees\\n- No protocol fee on repayment\\n\\n## Output\\n```\\n\u2713 Repaid $XX.XX USDC\\n Remaining Debt: $XX.XX\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Notes\\n- `repay all` calculates full outstanding principal + accrued interest\\n- Available USDC balance must cover the repayment amount"},{"name":"t2000-safeguards","description":"Configure spending limits and safety controls for t2000 agent wallets. Use when asked to set transaction limits, daily send limits, lock or unlock the agent, view safeguard settings, or protect the wallet from unauthorized spending. Required before enabling MCP server access.","body":"# t2000: Agent Safeguards\\n\\n## Purpose\\nConfigure spending limits and safety guardrails for autonomous agent\\noperation. Three controls: agent lock (kill switch), per-transaction\\nlimit, and daily send limit.\\n\\n> Safeguards are enforced on CLI and MCP. All state-changing actions\\n> require explicit confirmation before execution.\\n\\n## Commands\\n```bash\\nt2000 config show # view all safeguard settings\\nt2000 config set maxPerTx 500 # max $500 per outbound transaction\\nt2000 config set maxDailySend 1000 # max $1000 outbound per day\\nt2000 lock # freeze ALL operations immediately\\nt2000 unlock # resume operations (requires PIN)\\n```\\n\\n## Controls\\n\\n| Control | Description | Default |\\n|---------|-------------|---------|\\n| `maxPerTx` | Max USDC per single outbound op (send/pay) | 0 (unlimited) |\\n| `maxDailySend` | Max total USDC outbound per calendar day | 0 (unlimited) |\\n| `locked` | Kill switch \u2014 freezes ALL operations | false |\\n\\n## What counts as outbound\\n- `t2000 send` \u2014 transfers to other addresses\\n- `t2000 pay` \u2014 MPP API payments\\n\\n## What is NOT limited\\nInternal operations (save, withdraw, borrow, repay)\\nmove funds within the agent\'s own wallet and protocol positions. They\\nare not subject to send limits.\\n\\n## Output (config show)\\n```\\n Agent Safeguards\\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n Locked: No\\n Per-transaction: $500.00\\n Daily send limit: $1,000.00 ($350.00 used today)\\n```\\n\\n## Blocked output\\n```\\n \u2717 Blocked: amount $1,000.00 exceeds per-transaction limit ($500.00)\\n \u2717 Blocked: daily send limit reached ($1,000.00/$1,000.00 used today)\\n \u2717 Agent is locked. All operations frozen.\\n```\\n\\n## JSON mode\\n```bash\\nt2000 config show --json\\n```\\n```json\\n{ \\"locked\\": false, \\"maxPerTx\\": 500, \\"maxDailySend\\": 1000, \\"dailyUsed\\": 350 }\\n```\\n\\n## SDK\\n```typescript\\nconst agent = await T2000.create({ pin });\\n\\n// Check config\\nagent.enforcer.getConfig(); // { locked, maxPerTx, maxDailySend, dailyUsed, ... }\\nagent.enforcer.isConfigured(); // true if any limit is non-zero\\n\\n// Set limits\\nagent.enforcer.set(\'maxPerTx\', 500);\\nagent.enforcer.set(\'maxDailySend\', 1000);\\n\\n// Lock/unlock\\nagent.enforcer.lock();\\nagent.enforcer.unlock();\\n```\\n\\n## Important\\n- Safeguards are opt-in \u2014 defaults are permissive (0 = unlimited)\\n- MCP server requires non-zero limits before starting\\n- Lock freezes ALL operations (including internal) as a safety measure\\n- Daily counter resets at midnight UTC"},{"name":"t2000-save","description":"Deposit USDC or USDsui into savings to earn yield on Sui via NAVI Protocol. Use when asked to save money, earn interest, deposit to savings, \\"swap and save\\" a non-USDC token, or put funds to work. Not for sending to other addresses \u2014 use t2000-send for that.","body":"# t2000: Save (Deposit to Savings)\\n\\n## Purpose\\nDeposit **USDC or USDsui** into savings to earn yield on NAVI Protocol. Funds remain non-custodial and\\nwithdrawable at any time. USDsui is permitted as a strategic exception (v0.51.0+) because it has\\nits own NAVI pool, often at a different APY than USDC. Every other token (GOLD, SUI, USDT, USDe,\\nETH, NAVX, WAL) is **not saveable** \u2014 swap to USDC or USDsui first.\\n\\n## Command\\n```bash\\nt2000 save <amount> [--asset USDC|USDsui]\\nt2000 save all [--asset USDC|USDsui]\\n\\n# Examples:\\nt2000 save 80 # 80 USDC (default)\\nt2000 save 80 --asset USDsui # 80 USDsui\\nt2000 save all # full USDC balance (minus $1 gas reserve)\\nt2000 save all --asset USDsui # full USDsui balance (minus 1.0 reserve)\\n```\\n\\n- `save all`: deposits full available balance of the chosen asset minus 1.0 of that asset for safety\\n- `--asset` defaults to USDC when omitted\\n\\n## Fees\\n- Protocol fee: 0.1% on deposit (collected atomically on-chain)\\n\\n## Output\\n```\\n\u2713 Gas manager: $1.00 USDC \u2192 SUI [only shown if auto-topup triggered]\\n\u2713 Saved $XX.XX <asset> to best rate\\n\u2713 Current APY: X.XX%\\n\u2713 Savings balance: $XX.XX <asset>\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Notes\\n- APY is variable based on protocol utilization (USDC and USDsui pools quote independently)\\n- If available balance of the chosen asset is too low, returns INSUFFICIENT_BALANCE\\n- `t2000 supply` is an alias for `t2000 save`\\n- **Repay symmetry (v0.51.1+):** if you borrow USDsui, you must repay with USDsui (and USDC borrows must repay with USDC) \u2014 the SDK fetches the matching coin type per borrow asset.\\n\\n## Saving a non-USDC token (\\"swap and save\\")\\n\\nIf the user wants to save a token that\'s **not** USDC or USDsui \u2014 GOLD,\\nSUI, USDT, USDe, ETH, NAVX, WAL \u2014 the agent must swap first, then save.\\nThe right flow depends on the consumer:\\n\\n### Engine (audric/web) \u2014 bundled atomic swap + save\\n\\nEmit BOTH tool_use blocks in the SAME assistant turn. The engine\'s\\npermission gate compiles them into ONE Payment Intent: the swap\'s\\n`received` coin handles off as the save\'s input via coin-ref inside the\\nsame PTB. Atomic \u2014 both succeed or both revert. User signs once.\\n\\n```\\n[ASSISTANT TURN \u2014 emit in parallel]\\n tool_use: swap_execute({ from: \\"SUI\\", to: \\"USDC\\", amount: 1.0 })\\n tool_use: save_deposit({ amount: <swap_received>, asset: \\"USDC\\" })\\n```\\n\\nBefore emitting, **always preview** to the user:\\n- The source token + amount being swapped\\n- Estimated USDC received (from `swap_quote`)\\n- The save APY they\'ll earn\\n- Total fees (Cetus + Audric overlay + NAVI save fee)\\n\\n**Do NOT** call swap then save in separate turns \u2014 that loses atomicity\\nand exposes the user to price drift between the legs.\\n\\n**Do NOT** auto-decide for the user. If they say \\"save 10 SUI\\", confirm\\nthe intent: \\"That requires swapping ~10 SUI to ~$XX USDC first, then\\ndepositing. Proceed?\\" Some users want to hold SUI.\\n\\n### CLI \u2014 sequential (no bundling)\\n\\nThe CLI doesn\'t support Payment Intent bundling. Run two commands:\\n\\n```bash\\nt2000 swap 1.0 SUI to USDC\\nt2000 save all\\n```\\n\\nEach command prices against on-chain state at the moment of execution,\\nso there\'s small price drift between them. For large amounts ($1k+),\\nprefer the agent path which bundles into one Payment Intent.\\n\\n### What\'s NOT saveable\\n\\nGOLD, SUI, USDT, USDe, ETH, NAVX, WAL \u2014 none of these have NAVI lending\\npools today, so they can\'t be saved directly. Must swap to USDC or\\nUSDsui first. This is enforced by the SDK\'s `assertAllowedAsset(\'save\',\\nasset)` allow-list \u2014 calling `save_deposit({ asset: \'SUI\' })` returns\\n`UNSUPPORTED_ASSET`."},{"name":"t2000-send","description":"Send USDC from the t2000 agent wallet to another address on Sui. Use when asked to pay someone, transfer funds, send money, tip a creator, or make a payment to a specific Sui address or saved contact. Do NOT use for API payments \u2014 use t2000-pay for MPP-protected services.","body":"# t2000: Send USDC\\n\\n## Purpose\\nTransfer USDC from the agent\'s available balance to any Sui address. Gas is\\nself-funded from the agent\'s SUI reserve (auto-topped up if needed).\\n\\n## Command\\n```bash\\nt2000 send <amount> <asset> to <address_or_contact>\\nt2000 send <amount> <asset> <address_or_contact>\\n\\n# Examples:\\nt2000 send 10 USDC to 0x8b3e...d412\\nt2000 send 50 USDC to Tom\\nt2000 send 50 USDC 0xabcd...1234\\n```\\n\\nThe `to` keyword is optional. The recipient can be a Sui address (0x...) or a\\nsaved contact name (e.g. \\"Tom\\"). Use `t2000 contacts` to list saved contacts.\\n\\n## Pre-flight checks (automatic)\\n1. Sufficient available USDC balance\\n2. SUI gas reserve present; if not, auto-topup triggers transparently\\n\\n## Output\\n```\\n\u2713 Sent $XX.XX USDC \u2192 0x8b3e...d412\\n Gas: X.XXXX SUI (self-funded)\\n Balance: $XX.XX USDC\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Error handling\\n- `INSUFFICIENT_BALANCE`: available balance is less than the requested amount\\n- `INVALID_ADDRESS`: destination is not a valid Sui address\\n- `CONTACT_NOT_FOUND`: name is not a saved contact or valid address\\n- `SIMULATION_FAILED`: transaction would fail on-chain; details in error message\\n\\n## Recipient resolution flow\\n\\nWhen the user provides a recipient, resolve it before broadcasting:\\n\\n1. **Name given** \u2192 look up in saved contacts. If found, use the mapped\\n address. If not found and not a valid `0x...` address, ask the user\\n to clarify (suggest `t2000 contacts add <name> <address>` first).\\n2. **Address given (`0x...`)** \u2192 validate with `isValidSuiAddress()`. If\\n invalid, refuse with `INVALID_ADDRESS`.\\n3. **Ambiguous** (looks like a name AND a valid prefix) \u2192 ask the user\\n which they meant.\\n\\nAfter a successful send to a **previously-unknown raw address** (not a\\nsaved contact), offer to save it:\\n\\n> \\"Want to save 0x8b3e\u2026d412 as a contact? Say `yes <name>` to save.\\"\\n\\nIf the user provides a name, call `t2000 contacts add <name> <address>`\\n(CLI). This makes future sends to the same person work by name\\n(`t2000 send 10 USDC to <name>`). The engine no longer ships a\\n`save_contact` tool \u2014 contacts are CLI-only state today; audric users\\nmanage contacts via the send screen.\\n\\n**Do not auto-save** without asking \u2014 the user might not want every\\none-off recipient cluttering their contacts list.\\n\\n## Engine orchestration (audric/web)\\n\\nWhen called inside the Audric chat agent:\\n\\n1. Resolve recipient (contacts lookup or address validation) \u2014 no tool call needed for contacts; resolution happens in prose.\\n2. Call `balance_check` to confirm sufficient funds.\\n3. Emit `send_transfer({ to, amount, asset })` as the write tool_use.\\n4. After the send settles, if the recipient was a raw address not already\\n in contacts, surface the \\"save as contact?\\" prompt to the user (see\\n above). The user confirms in the next turn; the host (CLI / audric)\\n handles persistence \u2014 the engine has no contact-write tool.\\n\\nSends are **single-write** \u2014 never bundle with another write in a\\nPayment Intent. Each transfer is its own intent."},{"name":"t2000-withdraw","description":"Withdraw from savings and receive USDC or USDsui. Use when asked to withdraw from savings, access deposited funds, pull money out of savings, reduce yield position, \\"close my position\\", or emergency withdraw. For sending to another address, use t2000-send.","body":"# t2000: Withdraw from Savings\\n\\n## Purpose\\nWithdraw USDC or USDsui from savings back to your checking balance.\\n\\n## Command\\n```bash\\nt2000 withdraw <amount> [--asset USDC|USDsui]\\nt2000 withdraw all [--asset USDC|USDsui]\\n\\n# Examples:\\nt2000 withdraw 25 # 25 USDC (default)\\nt2000 withdraw 25 --asset USDsui # 25 USDsui\\nt2000 withdraw all # full USDC savings position\\nt2000 withdraw all --asset USDsui # full USDsui savings position\\n```\\n\\n`--asset` defaults to USDC when omitted.\\n\\n## Fees\\n- No protocol fee on withdrawals\\n\\n## Output\\n```\\n\u2713 Withdrew $XX.XX <asset>\\n Tx: https://suiscan.xyz/mainnet/tx/0x...\\n```\\n\\n## Safety check (active when debt exists)\\n\\nIf the wallet has outstanding debt, t2000 evaluates whether the withdrawal\\nwould push the health factor below 1.5:\\n\\n| Scenario | Behavior |\\n|---|---|\\n| No debt | Withdrawal proceeds \u2014 no HF check. |\\n| Withdrawal keeps HF \u2265 1.5 | Withdrawal proceeds \u2014 note the new HF in the output. |\\n| Withdrawal would drop HF < 1.5 | **Refused** with `WITHDRAW_WOULD_LIQUIDATE`. Error data includes `safeWithdrawAmount` (the largest amount that keeps HF \u2265 1.5). |\\n\\n## Emergency / \\"close my position\\" flow\\n\\nWhen the user asks to \\"withdraw everything\\", \\"close my position\\", or\\n\\"emergency withdraw\\":\\n\\n### Step 1 \u2014 Read state\\nCall `health_check` (engine) or `t2000 balance --show-limits` (CLI) to\\nsee savings, debt, and current HF.\\n\\n### Step 2 \u2014 Decide path\\n\\n| Wallet state | Path |\\n|---|---|\\n| **No debt** | Single-write `withdraw all` for each asset held in savings. |\\n| **Has debt, savings \u2265 debt** | **Bundled repay + withdraw** \u2014 emit `repay_debt(all)` and `withdraw(remaining)` as parallel `tool_use` blocks in the SAME assistant turn. Engine compiles into one Payment Intent: atomic repay-then-withdraw, one signature. |\\n| **Has debt, savings < debt** | **Refuse** \u2014 user can\'t fully close position without first acquiring more of the borrowed asset. Tell them how much more they\'d need; do not auto-swap. |\\n\\n### Step 3 \u2014 Bundled emit (engine path)\\n\\nFor the \\"bundled repay + withdraw\\" case, emit BOTH tool_use blocks in the\\nsame assistant turn:\\n\\n```\\n[ASSISTANT TURN \u2014 emit in parallel]\\n tool_use: repay_debt({ amount: <debt>, asset: <borrowed_asset> })\\n tool_use: withdraw({ amount: <remaining>, asset: <savings_asset> })\\n```\\n\\nThe engine\'s permission gate compiles these into ONE Payment Intent. Both\\nlegs succeed or both revert \u2014 no partial close. The user signs once.\\n\\n**Do NOT** call them sequentially across turns \u2014 that loses atomicity and\\nexposes the user to a window where debt is repaid but the withdraw fails,\\nleaving the wallet in an awkward state.\\n\\n**Critical:** `repay_debt` MUST use the SAME asset as the original borrow\\n(USDsui debt \u2192 USDsui repay, USDC debt \u2192 USDC repay \u2014 see `t2000-repay`).\\nIf the user doesn\'t hold enough of the matching asset, abort with a clear\\nmessage; do not auto-swap.\\n\\n## Error handling\\n- `WITHDRAW_WOULD_LIQUIDATE` \u2014 withdrawal would push HF < 1.5. Use `safeWithdrawAmount` from error data, or repay debt first.\\n- `NO_COLLATERAL` \u2014 no savings position in the requested asset.\\n- `INSUFFICIENT_BALANCE` \u2014 requested amount exceeds savings balance.\\n- Intent failed (bundled flow) \u2014 atomic revert. No funds moved."}]';
|
|
141469
141524
|
cachedSkills = JSON.parse(raw);
|
|
141470
141525
|
return cachedSkills;
|
|
141471
141526
|
}
|
|
@@ -141553,7 +141608,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141553
141608
|
content: {
|
|
141554
141609
|
type: "text",
|
|
141555
141610
|
text: [
|
|
141556
|
-
"You are a financial advisor for a t2000
|
|
141611
|
+
"You are a financial advisor for a t2000 Agentic Wallet on Sui.",
|
|
141557
141612
|
"",
|
|
141558
141613
|
"STEP 1 \u2014 Render the account snapshot per the canonical skill:",
|
|
141559
141614
|
"",
|
|
@@ -141588,7 +141643,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141588
141643
|
content: {
|
|
141589
141644
|
type: "text",
|
|
141590
141645
|
text: [
|
|
141591
|
-
"You are a yield optimization specialist for a t2000
|
|
141646
|
+
"You are a yield optimization specialist for a t2000 Agentic Wallet on Sui.",
|
|
141592
141647
|
"",
|
|
141593
141648
|
"CONTEXT (USDC-canonical save policy \u2014 from the t2000-save skill):",
|
|
141594
141649
|
"",
|
|
@@ -141627,7 +141682,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141627
141682
|
content: {
|
|
141628
141683
|
type: "text",
|
|
141629
141684
|
text: [
|
|
141630
|
-
"You are a savings advisor for a t2000
|
|
141685
|
+
"You are a savings advisor for a t2000 Agentic Wallet on Sui.",
|
|
141631
141686
|
"",
|
|
141632
141687
|
"WHICH ASSETS CAN BE SAVED (from the t2000-save skill \u2014 canonical):",
|
|
141633
141688
|
"",
|
|
@@ -141661,7 +141716,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141661
141716
|
content: {
|
|
141662
141717
|
type: "text",
|
|
141663
141718
|
text: [
|
|
141664
|
-
"You are a money-routing assistant for a t2000
|
|
141719
|
+
"You are a money-routing assistant for a t2000 Agentic Wallet on Sui.",
|
|
141665
141720
|
"",
|
|
141666
141721
|
"SAVE ELIGIBILITY (from the t2000-save skill):",
|
|
141667
141722
|
"",
|
|
@@ -141700,7 +141755,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141700
141755
|
content: {
|
|
141701
141756
|
type: "text",
|
|
141702
141757
|
text: [
|
|
141703
|
-
"You are a risk assessment specialist for a t2000
|
|
141758
|
+
"You are a risk assessment specialist for a t2000 Agentic Wallet on Sui.",
|
|
141704
141759
|
"",
|
|
141705
141760
|
"STEP 1 \u2014 Read the account state (use the t2000-account-report skill's tool sequence):",
|
|
141706
141761
|
"",
|
|
@@ -141744,7 +141799,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141744
141799
|
content: {
|
|
141745
141800
|
type: "text",
|
|
141746
141801
|
text: [
|
|
141747
|
-
"You are a personal finance newsletter writer for a t2000
|
|
141802
|
+
"You are a personal finance newsletter writer for a t2000 Agentic Wallet on Sui.",
|
|
141748
141803
|
"",
|
|
141749
141804
|
"STEP 1 \u2014 Read the account state (use the t2000-account-report tool sequence) + t2000_history (limit: 50) in parallel:",
|
|
141750
141805
|
"",
|
|
@@ -141788,7 +141843,7 @@ function registerPrompts(server, opts = {}) {
|
|
|
141788
141843
|
content: {
|
|
141789
141844
|
type: "text",
|
|
141790
141845
|
text: [
|
|
141791
|
-
"You are a payment assistant for a t2000
|
|
141846
|
+
"You are a payment assistant for a t2000 Agentic Wallet on Sui.",
|
|
141792
141847
|
"",
|
|
141793
141848
|
context ? `Context provided by the user:
|
|
141794
141849
|
${context}
|
|
@@ -141826,7 +141881,7 @@ ${context}
|
|
|
141826
141881
|
content: {
|
|
141827
141882
|
type: "text",
|
|
141828
141883
|
text: [
|
|
141829
|
-
"You are a budget advisor for a t2000
|
|
141884
|
+
"You are a budget advisor for a t2000 Agentic Wallet on Sui.",
|
|
141830
141885
|
"",
|
|
141831
141886
|
amount2 ? `The user wants to know if they can afford to spend $${amount2}.` : "The user wants a general spending check.",
|
|
141832
141887
|
"",
|
|
@@ -141875,7 +141930,7 @@ ${context}
|
|
|
141875
141930
|
content: {
|
|
141876
141931
|
type: "text",
|
|
141877
141932
|
text: [
|
|
141878
|
-
"You are a financial scenario planner for a t2000
|
|
141933
|
+
"You are a financial scenario planner for a t2000 Agentic Wallet on Sui.",
|
|
141879
141934
|
"",
|
|
141880
141935
|
scenario ? `The user wants to evaluate: "${scenario}"` : "The user wants to explore a hypothetical financial scenario. Ask them what they're considering.",
|
|
141881
141936
|
"",
|
|
@@ -141926,7 +141981,7 @@ ${context}
|
|
|
141926
141981
|
content: {
|
|
141927
141982
|
type: "text",
|
|
141928
141983
|
text: [
|
|
141929
|
-
"You are a rewards management assistant for a t2000
|
|
141984
|
+
"You are a rewards management assistant for a t2000 Agentic Wallet on Sui.",
|
|
141930
141985
|
"",
|
|
141931
141986
|
// No dedicated claim-rewards skill — the flow is operational
|
|
141932
141987
|
// enough that a thin prompt suffices. Future: if a
|
|
@@ -141969,7 +142024,7 @@ ${context}
|
|
|
141969
142024
|
content: {
|
|
141970
142025
|
type: "text",
|
|
141971
142026
|
text: [
|
|
141972
|
-
"You are a security advisor for a t2000
|
|
142027
|
+
"You are a security advisor for a t2000 Agentic Wallet on Sui.",
|
|
141973
142028
|
"",
|
|
141974
142029
|
"CANONICAL SAFEGUARDS REFERENCE (from the t2000-safeguards skill \u2014 full body):",
|
|
141975
142030
|
"",
|
|
@@ -142004,7 +142059,7 @@ ${context}
|
|
|
142004
142059
|
content: {
|
|
142005
142060
|
type: "text",
|
|
142006
142061
|
text: [
|
|
142007
|
-
"You are a friendly onboarding guide for t2000 \u2014 an
|
|
142062
|
+
"You are a friendly onboarding guide for t2000 \u2014 an Agentic Wallet on Sui.",
|
|
142008
142063
|
"",
|
|
142009
142064
|
"STEP 1 \u2014 Read the user's current state (t2000_overview).",
|
|
142010
142065
|
"",
|
|
@@ -142052,7 +142107,7 @@ ${context}
|
|
|
142052
142107
|
content: {
|
|
142053
142108
|
type: "text",
|
|
142054
142109
|
text: [
|
|
142055
|
-
"You are an emergency response handler for a t2000
|
|
142110
|
+
"You are an emergency response handler for a t2000 Agentic Wallet on Sui.",
|
|
142056
142111
|
"",
|
|
142057
142112
|
"\u{1F6A8} EMERGENCY PROTOCOL",
|
|
142058
142113
|
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
@@ -142099,7 +142154,7 @@ ${context}
|
|
|
142099
142154
|
content: {
|
|
142100
142155
|
type: "text",
|
|
142101
142156
|
text: [
|
|
142102
|
-
"You are a full-account optimizer for a t2000
|
|
142157
|
+
"You are a full-account optimizer for a t2000 Agentic Wallet on Sui.",
|
|
142103
142158
|
"",
|
|
142104
142159
|
"STEP 1 \u2014 Read the account state in parallel: call t2000_overview AND t2000_all_rates.",
|
|
142105
142160
|
" For MCP clients with canvas rendering, also use the t2000-account-report tool sequence:",
|
|
@@ -142143,7 +142198,7 @@ ${context}
|
|
|
142143
142198
|
})
|
|
142144
142199
|
);
|
|
142145
142200
|
}
|
|
142146
|
-
var PKG_VERSION = "3.
|
|
142201
|
+
var PKG_VERSION = "3.2.0";
|
|
142147
142202
|
console.log = (...args) => console.error("[log]", ...args);
|
|
142148
142203
|
console.warn = (...args) => console.error("[warn]", ...args);
|
|
142149
142204
|
async function startMcpServer(opts) {
|
|
@@ -142234,4 +142289,4 @@ axios/dist/node/axios.cjs:
|
|
|
142234
142289
|
@scure/bip39/index.js:
|
|
142235
142290
|
(*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
|
|
142236
142291
|
*/
|
|
142237
|
-
//# sourceMappingURL=dist-
|
|
142292
|
+
//# sourceMappingURL=dist-NH7XYB4F.js.map
|