senpi-trade
Execute a DIRECT trade with the user — a one-off manual position (open / edit / close) or mirroring a specific Hyperliquid trader — ONE decision at a time. Use for "go long HYPE 10x", "short BTC", "buy SOL and set a stop", "close my ETH", "copy this wallet", "mirror this whale", "follow this trader", "find me a trader to copy". Both paths can carry protection and it is OPTIONAL: bare, a static stop/TP, or a profit-lock trailing ladder (`ratchet_stop_add`, no runtime) — but that ladder is profit-lock ONLY (no downside floor); the full two-phase DSL (a ratcheting max-loss floor + the profit locks) is runtime-only, so route to a managed strategy for real two-sided protection. Any question about a stop or a ladder, and any change to one, runs the protection protocol: read it in the same turn, quote the engine's floor (never compute one), say what a change replaces and get a yes, read it back. Steer users to a MANAGED strategy when they want ongoing autonomy — senpi-strategy-author builds their own (a managed mirror included: sized to the user, DSL on every fill), forking the closest template when one fits. Pairs with senpi-trader-research, which finds and vets the trader (this skill runs the mirror once one is chosen). NOT for authoring a strategy or deploying a template yourself.
- License 许可
- Apache-2.0
- 最近更新
- 2026-11-15
- Stars
- ★ 81
- Forks
- 17
01 前言 Front Matter
- name
- senpi-trade
- license
- Apache-2.0
- metadata
- { "author": "Senpi", "version": "1.12.0", "exchange": "hyperliquid", "platform": "senpi", "requires": [ "senpi-trader-research", "senpi-strategy-discover" ] }
- description
- Execute a DIRECT trade with the user — a one-off manual position (open / edit / close) or mirroring a specific Hyperliquid trader — ONE decision at a time. Use for "go long HYPE 10x", "short BTC", "buy SOL and set a stop", "close my ETH", "copy this wallet", "mirror this whale", "follow this trader", "find me a trader to copy". Both paths can carry protection and it is OPTIONAL: bare, a static stop/TP, or a profit-lock trailing ladder (`ratchet_stop_add`, no runtime) — but that ladder is profit-lock ONLY (no downside floor); the full two-phase DSL (a ratcheting max-loss floor + the profit locks) is runtime-only, so route to a managed strategy for real two-sided protection. Any question about a stop or a ladder, and any change to one, runs the protection protocol: read it in the same turn, quote the engine's floor (never compute one), say what a change replaces and get a yes, read it back. Steer users to a MANAGED strategy when they want ongoing autonomy — senpi-strategy-author builds their own (a managed mirror included: sized to the user, DSL on every fill), forking the closest template when one fits. Pairs with senpi-trader-research, which finds and vets the trader (this skill runs the mirror once one is chosen). NOT for authoring a strategy or deploying a template yourself.
02 资源文件 7
- 许可证LICENSE1.0 KB
- 参考文档references/mirror-monitoring.md3.0 KB
- 参考文档references/mirror-trading-explained.md7.9 KB
- 参考文档references/protection-cases.md6.1 KB
- 参考文档SOURCE.md334 B
- 脚本tests/test_trade_skill_surface.py6.0 KB
- 参考文档TRUST.auto.yaml2.2 KB
03 SKILL.md 正文
Senpi Trade — execute a direct trade with the user, one decision at a time
This skill runs the two direct trade paths: a manual one-off position (open / edit / close) and a mirror of a specific trader. You draw the trade out one question at a time, sanity-check it, execute it, and confirm the real returned result — never firing a money tool on a guess.
Protection is OPTIONAL — and know exactly what a raw position can carry
A manual position or a raw mirror can run bare, with a static stop/TP, or with a profit-lock trailing ladder (
ratchet_stop_add) — all with no runtime. But be precise about that ladder: it is profit-lock ONLY. It trails a stop up as the position gains (and never loosens) — it does NOT place a downside floor. On a raw position you are bare on the losing side until a profit tier triggers. (The MCPratchet_stop_addtool silently dropsmax_loss_pct/retrace_threshold— the Phase-1 floor is not persisted without a runtime; only the tier ladder sticks.)So without a runtime, "protection" is one of two things, never a pair you can promise: the profit-lock ladder (ratchets up as you win) or a static SL (
edit_position— fixed, does not ratchet). A position has one stop order, and once a ratchet is active the engine owns it:ratchet_stop_addREPLACES a static SL. Name the stop the user gives up, get a yes, then readstrategy_get_open_ordersback and report what actually rests. Don't call either one "DSL."The real, integrated two-phase DSL — a max-loss floor that ratchets up through breakeven into the profit locks, the engine replacing the stop at each tier — is a runtime feature (
exit.dsl_preset); a managed strategy has it built in and auto-applies it on every fill. Don't tell a user a raw position "can't be protected" (it can — profit-lock + a static SL), but don't oversell it as DSL either. When they want a true two-sided ratcheting stop → a managed strategy (author).
The protection protocol — reading and changing a stop on a position
Every question about a stop or a ladder ("show my DSL levels", "is it protected", "which is tighter") and every change to one runs the same six rules. Each one was broken on a live short, and it was the user's own arithmetic that caught it.
- Read in the same turn, or say you haven't. A claim about a live stop or ladder needs
ratchet_stop_get(the ratchet) andstrategy_get_open_orders(what actually rests) in the turn that makes the claim. Never describe a ladder from memory, from an earlier turn, or from a rule that says one "should" exist.status: DELETED(or no row) means no ratchet protection: no tier, no floor, no order — say exactly that;PAUSEDmeans the engine has stopped updating it — what still rests is whateverstrategy_get_open_ordersshows. - Quote, never compute. The floor is
tierFloorPrice.lockRoeis a share of the high-water ROE (floorRoe = highWaterRoe × lockRoe / 100) — never a share of margin, never an absolute ROE. Dollars kept at a stop are(entry − stop) × sizefor a short and(stop − entry) × sizefor a long, nothing else. If the engine did not print a number, do not print it either. - A short's stop sits above the price. Closer to the price is tighter, so for a short a LOWER trigger is tighter and keeps more; a higher trigger is looser and keeps less. A long is the mirror image. Before any "tighter / looser / locks more" sentence, work out which trigger the price reaches first.
- Leverage is the exchange's.
strategy_get_clearinghouse_state→leverage.valueand.type, never the strategy's name or a stale ratchet record; say it when they differ. The engine's ROE is on notional ÷ that leverage, not on the margin actually posted — name the base whenever you quote ROE. - A change is read → say → yes → act → read back. State what will change and what it replaces (a
ratchet replaces a static SL; a leverage change does not move a stop), get an explicit yes, act, then
read
strategy_get_open_ordersandratchet_stop_getagain and quote them. The read-back is the confirmation; a tool'ssuccess: trueis not. - Consent comes from this conversation. A saved instruction ("always add the ratchet", "mandatory on every position") is neither evidence a ratchet exists nor consent to add one — it is a reminder to ask. A spoken "no DSL" / "forget about it unless I ask" stands until the user says otherwise, in any later session. A status check ("did you finish?", "how's it going?", "run a health check") is not a yes, and a health check never changes protection.
Worked example, a short: entry $80,890, price $77,300, manual stop $77,500, ratchet floor $78,370. The
price reaches $77,500 first, so the manual stop is the tighter one and it keeps (80,890 − 77,500) × size;
the floor keeps less. Adding the ratchet would replace that stop — say so before it happens. The five
regression cases behind these rules, with the expected answers, are in
references/protection-cases.md.
When a managed strategy / template IS the better answer — steer there for the real reasons, which now explicitly include integrated two-phase DSL (a raw position gets only profit-lock + an uncoordinated static SL, per above):
- they want it managed for them going forward — DSL auto-attached to every new fill without
you babysitting, budget-relative sizing (and, if they want it, fresh-entry-only — no chasing a runner). A raw mirror
- per-position DSL means you wrap each new fill by hand; a managed strategy does all of it automatically.
- they want to mirror more than one trader at once, by signal — a managed strategy can position by where the smart-money cohort leans (the aggregate of many proven traders), not copy one trader's book. A raw mirror is strictly 1:1; multi-trader, signal-driven copying is only possible with a runtime strategy.
| The user wants… | Route to | Why (real reason) |
|---|---|---|
| Ongoing, hands-off, protected-on-every-fill | senpi-strategy-author (their own runtime) | continuous management + DSL on every fill |
| To browse what's already built | senpi-strategy-discover | DSL + risk gates + budget-relative sizing built in |
| To copy / mirror a trader, managed | senpi-strategy-author → a managed mirror of their own (author forks the closest template when one fits) | budget-relative sizing, auto-DSL, fresh-entry-only if they want |
| A genuine one-off, or to mirror one specific trader hands-on | stay here | direct execution the user is driving |
Offer the managed option once, then respect a "no." For mirror, a managed mirror fixes the exact
pains a raw mirror causes (tiny size, stale entries) — offer to build one before you reach for a raw strategy_create.
Branch A — Manual position (open / edit / close)
Opening is a FORK — ask which product, never assume
On "go long HYPE 10x" / "buy BTC" / "short NVDA", do not just place it. Ask which:
- (A) A managed strategy — named, supervised, auto-DSL. → hand to senpi-strategy-author. Stop here.
- (B) A one-off position — you place it, protection is your call. → proceed below.
No coin named — "deploy whatever you think is profitable", "trade for me", "be aggressive" — is not a one-off at all; it is a mandate, and a mandate is a strategy: hand to senpi-strategy-discover. Never pick the coins yourself and open them here.
NEVER open a manual position into a wallet a deployed runtime is managing. A hand-placed position in a scanner-managed wallet is reconciled as foreign and flattened within minutes — the order "succeeds," the position vanishes, the user eats the round-trip. A one-off goes into its own fresh wallet (
strategy_create_custom_strategycreates it) or an existing un-managed wallet.
The interview (one question at a time; pre-fill anything already said)
- Asset & direction — turn what the user said into a ticker (Nvidia →
NVDA, gold →GOLD), then look it up:market_list_instruments(query="<ticker>", fields=["max_leverage","only_isolated"]). Always passquery— the no-argument list is cut off long before the XYZ rows (stocks, metals, indices), so "not in the list I got" proves nothing.querymatches tickers only, any case, with or without the prefix; a company name matches nothing. Copy the returnednameverbatim into every later call — the other tools need it exact (kPEPEnotKPEPE,xyz:NVDAnotNVDA). Zero matches → one more lookup with a shorter or alternate ticker; only then say it isn't listed. A row withis_delisted: trueis not tradeable — say so, never open it. More than one live match and none equal to the ticker → ask which one; never pick for the user. Never call an asset unavailable — or a whole class, like stocks — without aquerylookup that came back empty. A name a tool rejected as unknown is never retried as-is. - Size & leverage — you set
marginAmount(USD collateral) +leverage; the engine derives size (notional = marginAmount × leverage). Min notional $10 (auto-bumped to $12). Look upmax_leverageper asset — never hardcode. Never invent the amount — if unstated, ASK; don't default to the balance. Then the three numbers, before the replay: the share of the account this margin takes (marginAmount ÷ withdrawable), the dollars at the stop (|entry − stop| × size, and as a share of the account), and the leverage that will actually apply (the asset'smax_leveragewhen it is lower than asked — say the clip; never name a strategy after a leverage the venue will not give). Above 50% of the account in one position or 20% of the account at the stop, put the number in its own sentence and get a fresh yes to that sentence — a yes to the setup is not a yes to the concentration. Re-run the three numbers on every add, every stop move and every leverage change, not only at open. - Entry — MARKET (immediate, taker) or FEE_OPTIMIZED_LIMIT (maker, cheaper; add
ensureExecutionAsTakerfor a guaranteed fill). - Protection — OPTIONAL, offer all three: (a) none, (b) a static stop/TP (
stopLoss/takeProfit,percentageXORprice; margin-relative %; one fixed trigger, won't trail), or (c) a profit-lock ladder viaratchet_stop_add(tiered locks that trail up as you gain — profit-lock only; NO downside floor without a runtime; it replaces (b) if one exists — say so). Explain the difference in one line; let them pick. Apriceyou send must be on the correct side of the live mark — check before the call. A long's stop sits BELOW the mark and a short's ABOVE; a take-profit is the mirror. The venue refuses the wrong side (SL trigger price 56.695 >= current price 56.180 for LONG position - would execute immediately), and onedit_positionthe size change commits first, so a refused stop leaves the position open and UNPROTECTED — the error says so in its own last line. Read the mark price fromstrategy_get_asset_trading_limits(wallet + coin) at the moment you build the call, never from entry, a percentage you applied in your head, or a price quoted earlier in the conversation. Re-sending the same price is the one thing that cannot work; recompute it from the mark.percentagepicks the side but is measured from ENTRY, so once the mark is already past that level it is refused too — say so, and let the user choose between closing and a stop on the right side of the mark.
Then replay the full spec, get an explicit "yes", and place.
Execute & manage
- Open:
strategy_create_custom_strategy(fresh wallet + position [+ static SL/TP]) orcreate_position(into an existing un-managed wallet) — and always passskillName+skillVersion(real params on both;strategy_create_custom_strategycreates a wallet outsidedeploy.py, so without them the position is orphaned / unattributed per CLAUDE.md). Async — report the real returned status, never assume success. Pollstrategy_listto ACTIVE only when a next step needs the new wallet live: you willcreate_positioninto it, protect or read back the position it opened (below), or the user asked to wait. Never poll just to confirm the create. - Protect (if chosen):
ratchet_stop_addon the open position (asset + tier config; it auto-reads the live position). - Read back the leverage: the position's
leverage.valuefromstrategy_get_clearinghouse_stateis the one that applies — quote it, not the request; when the venue clipped it, say so and fix any name or label that carries the asked-for number. - "Watch it for me" on a raw position is the ladder, never a cron:
ratchet_stop_addis the engine-side watcher at zero model cost (profit-lock only — say it has no downside floor without a runtime); a cron is a full agent turn per firing, and it is not a stop. - Edit:
edit_position—targetMarginis absolute, not a delta; a direction flip does NOT carry SL/TP over. Partial close =edit_positionwith a lowertargetMargin. - Close:
close_position(full only; best-effort cancels resting SL/TP + DSL). - "Why did it close?" is a record question. Read the close before naming a reason —
execution_get_closed_position_details, or the wallet'sdiscovery_get_trader_history. A position you closed withclose_positiondid not hit its take-profit: an agent close, a stop fill and a TP fill are three different outcomes and only the record says which. Never report a TP or stop as "hit" from the protection you configured, or from what you remember doing — a realized return far below the TP you set is the tell that something else closed it.
Branch B — Mirror a specific trader
0. Own the PICK — the user usually wants YOU to find the trader
The #1 real ask is "find me someone worth copying," not an address. Delegate the find + vet to the
senpi-trader-research skill — its engine ranks track records and reads each trader's current book;
don't hand-roll discovery_* here. Whether the trader comes back from there or the user pastes an
address, hold it to the same bar before you mirror — 2–3 vetted candidates with
max-drawdown + margin beside win-rate/ROI — never rank by ROI, never ROI alone. Two things the data
will try to fool you on:
- A 100% win rate is a warning, not a credential — it usually means near-zero closed trades or hidden unrealised drawdown. If it reads 100% for every candidate, the field is broken — don't cite it at all; judge on max-drawdown + closed-trade count + mirrorability. A "−100% / −93% max drawdown" rated "solid" is a contradiction — surface it, don't launder it.
- Mirrorability is the go/no-go — check it before you recommend anyone. Pull each candidate's current
positions (
discovery_get_trader_state) and read how far each sits from the trader's entry. That distance is the slippage gate: a trader whose winners have already run (mark far past entry) is un-mirrorable right now — the mirror opens nothing (every position slippage-skips), and a flat trader has nothing to copy. The "best track record" is often the worst mirror today for exactly this reason. When the book has already moved, lead with a managed mirror that waits for the trader's next open instead of copying the old book (built with author) — or find a trader entering now. A mirror of the current book is a valid copy style but not the fix for an already-run book — don't sell it as one.
If the user pasted an address, still run both checks on it before mirroring.
Steer the product FIRST — the copy questionnaire (lead with capital use)
Before you run a raw mirror, find the right shape. Ask one at a time, pre-fill from the opening ask; the goal is to land them on a raw mirror or a managed mirror they build — recommend the fit.
- Capital use — ask this first; it is the #1 pain. "Do you want to use most of your capital in a
few concentrated positions, or replicate the trader's exact proportional book?"
- "use most of my funds / a few big orders / not 5% sitting idle" → a budget-relative managed mirror (built with author) — it sizes to your capital and opens a few full-size positions, which a proportional mirror won't (it tracks the trader's proportions). Common answer.
- "exactly proportional to the trader" → raw mirror (below), sized via the multiplier. If the trader's account dwarfs the budget, match a closer-sized trader or raise the multiplier so positions clear the $10 floor — a proportional mirror preserves their utilization %, it doesn't shrink yours.
- Hands-on or hands-off? Drive one trader yourself → raw mirror. Set-and-forget, auto-DSL every fill → a managed mirror (author).
- What shape of copy? → one specific trader (raw) · anything managed — a whale cohort, 2–3 named traders on fresh entries only, one elite's biggest conviction bet, traders hot right now, the consensus of the top copy strategies, a rule of their own — is a managed mirror they build (→ senpi-strategy-author).
- Budget — their call; don't advise how much to trade. Just state the trader's minimum to run it
properly (
senpi-trader-researchmin_mirror_budget.min_budget_usd). If their budget is below it, say plainly it won't open their full book (belowopens_nothing_below_usd, nothing opens) and offer a closer-sized trader, a higher multiplier, or a budget-relative managed mirror. The pre-fund sim confirms it. - Protection — default follow their exits; offer an added DSL safety-net, especially if the trader runs without stops.
Route the answer: managed → senpi-strategy-author (it forks the closest template when one fits) · raw mirror of one specific trader → continue below. Offer the managed option once, then respect a "no."
How a mirror actually works — explain it from the single source
When the user needs the mechanics — and many do ("why did it open at a 30% different entry?", "why so
small?", "do I need my own stop?", "spot or perps?", "how much do I need?") — explain from
references/mirror-trading-explained.md, the one source every skill quotes. Always hit: sizing
reality (small budget vs big trader = dust; the multiplier is locked; concentrated-use → a managed mirror),
slippage is the entry gate (too tight opens nothing), you mirror their exits (unrealised PnL
doesn't transfer), protection is optional and stacks (default: follow their exits). Never paraphrase a
different version of this anywhere.
Set it up (interview; pre-fill what's given)
Vetted trader → budget → mirrorMultiplier (the size knob; immutable after creation — set it
deliberately) → slippage tolerance (explain it above; set it against where their current positions sit — not a silent 1% that opens nothing) → optional
protection (none / static strategy-level SL/TP on total PnL / per-position DSL).
The hero check — simulate BEFORE funding (a one-shot sizing estimate, not paper trading)
Senpi has no paper-trading mode; the estimate below says what would open right now, and the only live test
is running the mirror at the $10 floor. Never offer to watch a trader on a timer — a cron is a model call per firing.
Run execution_estimate_position_opening at the user's budget × multiplier × slippage before creating
anything. It returns, per position, open / skipped(slippage) / skipped(budget) + minimumBudgetRequired
— i.e. exactly what would open for them and at what size. Show the real $ and %. If little would
open, STOP and offer: (a) more budget, (b) a higher multiplier, (c) a trader closer to their size, or
(d) a managed mirror that enters only on fresh opens (author). This one check prevents the core failure: funding capital that then
barely trades.
Create + verify — don't fabricate
strategy_create with the agreed params — and always pass skillName + skillVersion (both are real
params on strategy_create and strategy_create_custom_strategy). This skill creates the wallet directly,
outside deploy.py, so without them every mirror it opens is orphaned (unattributed) per CLAUDE.md.
Report the status the call returned; never say a position opened that no read showed. Poll strategy_list
to ACTIVE and read strategy_get_clearinghouse_state only when a next step needs the opened positions: the
ladder below, or the user asked to wait or to see what opened. Never poll just to confirm the create. If that
read shows the wallet idle past a short window, tell the user and adjust target / budget / multiplier —
do not close+recreate (see below).
DSL on the mirror
ratchet_stop_add per opened position adds the profit-lock ladder (no runtime) — but that's
profit-lock only, and it takes over the position's stop order: a static SL (edit_position) is the
other option, not a companion — adding the ratchet replaces it, so say which one the user keeps. The real two-phase DSL (a ratcheting max-loss floor + the locks, integrated) needs
a runtime → a managed strategy (author) that auto-applies it on every fill. Don't
hand-wrap 40 fills a day.
Closing — present next steps as a LIST, never a paragraph
Whenever you end a mirror or template flow with options ("set it up / simulate first / compare / build a
managed mirror on a specific whale"), render them as a short numbered or bulleted list, one option per line —
never a run-on sentence with 1. 2. buried inline. Bold the action verb; one clear next step per line.
The guardrails — every one earned from real mirror-trading churn
| If you're about to… | Don't — because | Do instead |
|---|---|---|
| Fund a mirror without simulating it | It can deploy a tiny fraction of the budget — the rest sits idle | Run execution_estimate_position_opening first (Branch B) |
| Mirror a whale whose account dwarfs the budget | A small budget on a whale-sized account = dust — positions round below the $10 floor | Check trader-account ÷ budget up front; if ~100×+, raise the multiplier or pick a closer-sized trader |
Call ratchet_stop_add on a raw position "DSL protection", or say it "can't be protected" |
It's profit-lock only (no downside floor — Phase-1 is dropped); integrated two-phase DSL is runtime-only | Offer profit-lock + a static SL on a raw position; steer to a managed strategy for real two-sided DSL |
| Say funds are "stuck" / "lost" / "file a ticket" | PENDING_FUNDING self-completes; FAILED auto-refunds to the embedded wallet |
Poll transient states with backoff; check the on-chain balance before any alarm |
| Report a trade as placed off an EMPTY tool result, or keep polling for it | Trade tools run behind the agent's approval gate: a call the user does not approve in time is denied and comes back empty — nothing reached the venue, so there is nothing to poll for | Say the approval timed out and nothing was placed; offer to re-run it for approval. An errored call is different — it carries its own message: surface the verbatim tool text. Read strategy_list / positions only to confirm what actually exists |
| Fire a fund-movement tool on partial args | A bridge call with {amount:0.01} errored nan |
Build fund calls from a validated template; never proceed as if funds moved when it errored |
| Rank copy targets by raw ROI | Surfaced 100%-win / −100%-drawdown / 99.6%-margin wallets as "best" | Filter on drawdown + margin + closed-trade count + copyability first |
| Recommend a "top" trader without checking their book is mirrorable | The best track record is often the worst mirror today — the winners already ran, so the mirror opens nothing | Read current-position distance-from-entry first; if it's run, steer to a managed mirror that waits for fresh entries |
| Leave slippage at a silent / too-tight default | 1% on a trader whose positions already moved opens nothing — the mirror sits flat and looks broken | Set slippage against the trader's current distance-from-entry; warn before funding if nothing would open |
| Close + recreate a mirror to "fix" it not trading | Each round-trip skims ~$1.50 in fees; funds fragment | The fix is target / budget / multiplier, not re-create |
| Re-derive state fresh each session and misread it | User had to repeat "you didn't do what I asked" 3× | Persist intent + strategy IDs; reconcile intended-vs-actual before replying |
| Place or grow a hand position without the three numbers | A wallet went almost entirely into one thin coin and a "keep it tight" stop was widened to over 40% of the account, one small request at a time — nothing ever said the total | Share of account, dollars at the stop, applied leverage — before the replay; above 50% / 20%, a fresh yes to that sentence |
| Quote the leverage the user asked for after the venue clipped it | 10× asked, 3× applied, the position still labelled "10x" | Read leverage.value from the position; say the clip; label by what applies |
| Offer a cron as "watch it for me" on a raw position | Every firing is a full agent turn, and it is not a stop | ratchet_stop_add — the ladder watches for free (profit-lock only; say so) |
Promise a ratchet_stop_add on a runtime-managed position covers future entries |
The add binds to the position open now. The runtime arms the next one from the strategy's own exit.dsl_preset — so "it never closes below +X again" is false, and the next entry closes the old way |
Say the ladder covers this position only, then route the file half to senpi-strategy-ops (a DSL change has two targets — the file for future positions, the ratchet for open ones; the user picks) |
| Say anything about a stop or ladder, or change one, outside the protection protocol | Every rule in it was broken on a live short — the user caught each one | The six rules above, in order |
State machine is transient, not terminal — up to a point.
CREATE_WALLET→FUND_WALLET/PENDING_FUNDINGare normal in-progress states (bridging can take 30s+); don't read a fresh one as failure.SERR045("requires ACTIVE") on a pending strategy means wait, not broken.FAILEDmoney is refunded automatically. BUTPENDING_FUNDINGpast ~15 minutes is a real bridge deadlock (the Base→strategy-wallet bridge never completed) — the funds are trapped and it will NOT self-heal. Stop reassuring: tell the user plainly it's stuck, never say "it should resolve shortly," and escalate to get the funds returned. (Agents have churned users by promising a stuck deposit would clear when it never did.)
Handoff & boundaries
- A request to act on one of the user's SAVED wallets (close, open, set a stop, cancel — on a
wallet in
user_get_me'sexternal_wallets, the ones they added in Your wallets) → answer by quoting itsaccessline, and make no write-tool attempt: "Read-only. Senpi can analyze this wallet. It cannot place, change or cancel orders on it." Readinguser_get_meto recognise the address is fine. A write tool that comes backNOT_A_STRATEGY_WALLET(match the error code) is the same answer — never retry it on another tool. "Your wallet" means one of their saved wallets or one the user said is theirs in this conversation; an address pasted in chat is never described as saved — to save it, the user can add it in Your wallets on senpi.ai (web). - Finding / vetting the trader →
senpi-trader-research. It ranks records + reads current books and hands the action (set up the mirror) back to this skill; you own the mechanics — slippage, sizing, the pre-fund sim, execution. - Ongoing hands-off management / DSL-on-every-fill / fresh-entry / budget-relative sizing →
senpi-strategy-author(their own managed mirror or strategy; it forks the closest template when one fits). This skill executes the direct trade and can add per-position protection. - Mirror with custom rules — a position-count cap ("max 5; if he opens
more, don't mirror"), a per-position % cap ("each ≤ 5% of my capital"), "don't copy his shorts",
"capture his adds", or a conditional exit → a custom mirror runtime via
senpi-strategy-author. Note themirrorMultiplieris immutable after creation — a user who wants to change size live must redeploy; there is no in-place edit. - "How's my mirror doing?" / compare my mirrors / is my trader still active / why didn't it fire →
read
references/mirror-monitoring.md— it composes your mirror's state (senpi-portfolio/strategy_get_clearinghouse_state) with the OG's current book (senpi-trader-research) and diffs them (are you still tracking, did the OG go idle, which positions drifted). After you create a mirror, tell the user they can ask any time. - Close / withdraw / rebalance a mirror →
senpi-strategy-ops(close a mirror, reclaim funds, top-up, or shift budget between mirrors). A mirror is a strategy — lifecycle actions live in ops, not here. - A pasted address (
I want to mirror trade 0x…) is the single most common entry — vet it throughsenpi-trader-research(mirrorability + drawdown) before mirroring, even when it's a popular wallet everyone is asking about. Don't rubber-stamp a hot address. - Never send USDC to an external address (no tool for it — direct the user to the app), and never present a strategy wallet as a deposit target.
- Every money amount (
marginAmount,initialBudget,mirrorMultiplier, budgets) is user intent — if missing, ASK; never copy a number from a doc example or default to the balance.
Red flags — STOP and re-check
- You're about to
strategy_createa mirror without having run the deployability sim. - You're about to call
ratchet_stop_addon a raw position "DSL protection" — it's profit-lock only (no downside floor without a runtime); offer a static SL and/or a managed strategy for real two-sided DSL. - You're about to tell the user funds are "stuck", or to treat an EMPTY tool result as a placed trade — an unapproved (timed-out) call is denied and executes nothing; say so and offer the re-run.
- You're about to open a manual position into a wallet a runtime is managing.
- You're about to close+recreate a mirror that "isn't trading."
- You're about to say anything about a stop or ladder — or change one — without the protection protocol's same-turn read and yes.
- You're quoting a trader's ROI/win-rate with no drawdown beside it.
- You're about to recommend mirroring a trader whose current positions have already run past their entry — the mirror would open nothing.
- You're about to recommend a trader who trades rarely or hasn't traded in weeks (
infrequent_trader/dormant) without warning the user the mirror will sit idle until they trade again — it only fires when they do. - You're about to promise a mirror "will replicate shortly" or a stuck strategy "should resolve" — verify on-chain first; never predict a sync that hasn't happened.
All of these mean: stop, run the check, correct the framing, or route to the managed path.
04 同仓库更多 Skills
recipe-performance
Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold/warm/background-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout/paint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.
mexc-spot-websocket
MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.
mexc-spot-rest
MEXC Spot REST workflows for public data, signed account requests, orders, wallet/admin actions, and secure signing without exposing API keys.
mexc-futures-websocket
MEXC Futures WebSocket workflows for public streams, private account/order/position streams, ping/pong, subscriptions, and depth maintenance.
0xklen-version-and-refresh-sanctions-lists
暂无简介
verify-tests-cover-changed-lines
Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.