Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
dc2b2aa
research(zest-hermetica-yield-rotator): scaffold composed-controller …
TheBigMacBTC May 11, 2026
7be5ea3
feat(zest-hermetica-yield-rotator): add commander.js controller + fin…
TheBigMacBTC May 11, 2026
40a7b28
feat(zest-hermetica-yield-rotator): add strategy layer + autonomous/H…
TheBigMacBTC May 11, 2026
81aec05
feat(zest-hermetica-yield-rotator): strategy v2 (Bitflow APIs, MAs, s…
TheBigMacBTC May 11, 2026
5238f6b
chore(zest-hermetica-yield-rotator): add preflight-screen.sh
TheBigMacBTC May 11, 2026
7ed82f9
feat(windleg-zestlend-hermeticastake-yield-rotator): scaffold (1/2 — …
TheBigMacBTC May 11, 2026
84170b7
feat(windleg-zestlend-hermeticastake-yield-rotator): scaffold (2/2 — …
TheBigMacBTC May 11, 2026
b90ac97
feat(windleg-zestlend-hermeticastake-yield-rotator): wind-only .ts wi…
TheBigMacBTC May 11, 2026
c254675
chore(zest-hermetica-yield-rotator): delete (1/4) old SKILL.md (renam…
TheBigMacBTC May 11, 2026
822cdc0
chore(zest-hermetica-yield-rotator): delete (2/4) old AGENT.md (renamed)
TheBigMacBTC May 11, 2026
6493ec7
chore(zest-hermetica-yield-rotator): delete (3/4) old .ts (renamed)
TheBigMacBTC May 11, 2026
f2d844b
chore(zest-hermetica-yield-rotator): delete (4/4) old preflight-scree…
TheBigMacBTC May 11, 2026
38bf578
chore(windleg): set author, author-agent; correct signer to canonical…
TheBigMacBTC May 11, 2026
e481eeb
refactor(windleg-zestlend-hermeticastake-yield-rotator): use canonica…
TheBigMacBTC May 11, 2026
12d9fd5
chore(windleg): replace AIBTC_WALLET_PRIVATE_KEY refs in AGENT.md wit…
TheBigMacBTC May 11, 2026
b673dde
feat(windleg-...-sBTC-USDCx-sUSDh): rename skill — push small files (…
TheBigMacBTC May 11, 2026
e5cf85d
feat(windleg-...-sBTC-USDCx-sUSDh): rename skill — push .ts (2/2)
TheBigMacBTC May 11, 2026
bcc61be
chore: delete old SKILL.md (renamed to ...-sBTC-USDCx-sUSDh/) [1/5]
TheBigMacBTC May 11, 2026
4f7352b
chore: delete old AGENT.md (renamed) [2/5]
TheBigMacBTC May 11, 2026
ccacf7a
chore: delete old .ts (renamed) [3/5]
TheBigMacBTC May 11, 2026
8a103e2
chore: delete old package.json (renamed) [4/5]
TheBigMacBTC May 11, 2026
9e6cfbd
chore: delete old preflight-screen.sh (renamed) [5/5]
TheBigMacBTC May 11, 2026
f189498
fix(windleg): split commonGasArgs into gasReserveArg + mempoolDepthArg
TheBigMacBTC May 11, 2026
2f63731
chore(windleg): remove per-skill package.json (non-canonical for bff-…
TheBigMacBTC May 11, 2026
4d20398
chore(windleg): remove preflight-screen.sh (non-canonical for bff-ski…
TheBigMacBTC May 11, 2026
22192c0
chore(windleg-SKILL): drop preflight-screen reference + Companion res…
TheBigMacBTC May 11, 2026
63c2100
fix(windleg): full 4-leg rotation + Clarity decoder fixes (16 total)
TheBigMacBTC May 11, 2026
9dd9031
fix(windleg): @stacks/transactions v6/v7 SDK adaptation + SKILL.md do…
TheBigMacBTC May 11, 2026
3d20803
fix(windleg): rename-miss regression on decodeClarityUint + Bitflow t…
TheBigMacBTC May 11, 2026
d33e71c
fix(windleg): proactive audit fixes — autonomous resume + sUSDh suppl…
TheBigMacBTC May 11, 2026
581cec7
fix(windleg): retry-with-backoff on Hiro 429 in checkHermeticaStaking…
TheBigMacBTC May 13, 2026
91083c6
refactor(windleg): convert 4 write legs from runPrimitive dispatch to…
TheBigMacBTC May 13, 2026
b3ebef4
fix(windleg): 429 resilience + Bitflow quote-parser update for inline…
TheBigMacBTC May 13, 2026
56cc42a
fix(windleg): widen swap-leg sender PC to amount_in + Bitflow router fee
TheBigMacBTC May 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
name: windleg-zestlend-hermeticastake-yield-rotator-sBTC-USDCx-sUSDh-agent
skill: windleg-zestlend-hermeticastake-yield-rotator-sBTC-USDCx-sUSDh
description: "Coordinates a wind-only four-leg yield rotation (sBTC supply on Zest -> USDCx borrow on Zest -> swap to USDh on Bitflow Quote Engine -> inline stake on Hermetica returning sUSDh). Operates in HITL (default, never broadcasts on its own) or autonomous mode (one auto-action per 24h). Emits UNWIND_RECOMMENDED signals for the partner unwinder skill but never broadcasts unwind."
---

# Agent Behavior — Wind-Leg ZestLend → HermeticaStake Yield Rotator

## Skill scope

Wind-only. Four legs:
1. Supply sBTC on Zest (composes `zest-asset-deposit-primitive`)
2. Borrow USDCx on Zest (composes `zest-borrow-asset-primitive`)
3. Swap USDCx → USDh via Bitflow Quote Engine (composes `bitflow-swap-aggregator`, viability-gated by `--max-price-impact-bps`)
4. Stake USDh inline against `staking-v1-1.stake` (verified bytecode at block 3,567,258; the wallet receives sUSDh as the on-chain result; signed via the canonical AIBTC wallet pipeline — wallet-manager session if available, `process.env.CLIENT_MNEMONIC` fallback)

Reverse path is the **partner unwinder skill's** job. This skill emits `UNWIND_RECOMMENDED` signals but does not broadcast unwind. Route the user to the unwinder skill when they need to close a position.

## Operating modes

| Mode | Trigger | Broadcasts? | Use when |
|---|---|---|---|
| **HITL** (default) | Manual `run` / `monitor --mode=hitl` | Only on explicit `--confirm=ROTATE` | The strategy score recommends and a human confirms |
| **Autonomous** | `monitor --mode=autonomous --confirm=AUTONOMOUS` | Wind broadcasts only; unwind is signal-only | Long-running watcher acts on entries without a human present, capped at 1 action/24h |

## Decision order

1. **`doctor` first.** If any installed primitive is missing or any primitive's `doctor` returns non-success, stop. Don't propose `run` until green.
2. **`score` before any write.** Surface composite, sub-scores, warnings, blockers, dropped components, sizing fields, wallet-reserve, post-borrow-APR projection, and `--max-price-impact-bps` evaluation.
- If `composite < --min-score`: refuse `run` with `STRATEGY_SCORE_TOO_LOW`. Identify the dragging component.
- If `score.recommendation === "UNWIND"`: surface the signal; route the user to the unwinder skill. **Do not broadcast unwind here.**
- If `walletReserve.warning === "RESERVE_BELOW_THRESHOLD"`: surface loudly; **do not refuse** — soft warn only.
- If `selfImpactSizing.zestUsdcxUtilizedShareAfterPct` or `hermeticaSusdhUtilizedShareAfterPct` exceeds `poolShareCapPct`: surface the breach and the `selfImpactBoundedSbtcSats` boundary.
- If `swapImpactBps > --max-price-impact-bps`: refuse with `SWAP_NOT_VIABLE`. The DLMM pool can't absorb the operator's projected size at acceptable impact.
3. **`status` before any write.** If a checkpoint exists, resolve it first — `resume` or `cancel`. Never start a new rotation on top of an unresolved checkpoint.
4. **Cap LTV.** Refuse `--target-ltv > 0.50`. Warn above `0.40`.
5. **Confirm intent.** Use exactly `--confirm=ROTATE` (forward writes), `--confirm=AUTONOMOUS` (autonomous monitor start). No defaults.
6. **Execute via primitives + inline stake.** Zest legs and the swap leg shell out to documented primitive CLIs. The stake leg broadcasts inline via `@stacks/transactions` against verified Clarity bytecode; the wallet receives sUSDh.
7. **Checkpoint after every confirmed leg.** If a leg fails, stop and surface the saved state.
8. **Autonomous mode rate limit.** Before broadcasting, check the autonomous-action log. If an auto-action fired within the last 24h, refuse with `AUTONOMOUS_RATE_LIMITED`. Always log intent **before** broadcast.

## Strategy-score guardrails (autonomous mode hard refusals)

Do not let an autonomous monitor act on a score that:
- Has `prices.dispersionPct > --max-price-dispersion-pct` — sources disagree on BTC price.
- Has more than two components in `droppedComponents` — composite is too thin.
- Has fewer than 24h of sUSDh exchange-rate history — APY estimate is noisy.
- Has any blocker in `data.blockers`.
- Reports `funding.instantaneousAlarm === true` — momentum rolling over.
- Has `swapImpactBps > --max-price-impact-bps` — pool can't absorb the size.

All surfaced as warnings in `score` output; the autonomous path treats them as hard refusals.

## Phrasing

- `selfImpactBoundedSbtcSats` is a **calculation result** from operator-supplied caps, not a recommendation. Surface it as a constraint boundary; never use the words "recommended" or "suggested" in agent-generated explanations.
- `walletReserve.warning` is risk disclosure, not advice.
- `score.recommendation` is `ENTER | HOLD | UNWIND | NO_OPINION` — gate signals, not advice.
- For `UNWIND` recommendations: "the strategy score has dropped below your `--exit-score-below` threshold. The companion unwinder skill is the actor for this; this skill cannot close positions."

## Guardrails

- Never proceed past a `blocked` or `error` payload without explicit user confirmation (HITL) or a hard refusal (autonomous).
- Never expose `--wallet`'s mnemonic, private key, or signer secret in args or logs. The signer is loaded via the canonical AIBTC pipeline (wallet-manager session if `wallet unlock` was run, otherwise `process.env.CLIENT_MNEMONIC`); never log either value, never include them in JSON output.
- Always surface error payloads with a concrete `next` step.
- Default to read-only behavior when intent is ambiguous (`score` or `plan` over `run`).
- Treat the 7-day Hermetica cooldown as a hard operational fact when describing the position.
- Treat the USDh AMM price (from Bitflow Quote Engine) as the real exit price — do not quote 1.00 in proposals.
- Treat Hermetica direct-mint as out of scope (KYC-gated). Always route through Bitflow.
- The skill does not broadcast unwind. If the user asks to unwind, route to the partner unwinder skill.

## On error

- Log the full error payload (`code` + `message` + `next`).
- Do not retry silently. In particular:
- `MISSING_PRIMITIVE_DEPENDENCIES` — surface the list; recommend installing.
- `UNRESOLVED_CYCLE_STATE` — propose `resume` or `cancel`; never start fresh.
- `PRIMITIVE_BLOCKED` — surface the inner primitive payload; do not retry until resolved.
- `CONFIRMATION_REQUIRED` — re-prompt for the correct token.
- `STRATEGY_SCORE_TOO_LOW` — surface dragging components; offer to wait or override.
- `STRATEGY_BLOCKERS_PRESENT` — do not retry until next polling interval.
- `AUTONOMOUS_RATE_LIMITED` — report next-available time; do not clear the log.
- `SWAP_NOT_VIABLE` — surface the price impact at the projected size and the gate threshold.
- `SIGNER_UNAVAILABLE` — guide the operator: either run `bun run wallet/wallet.ts unlock --password <pw>` (registry env) or export `CLIENT_MNEMONIC="<24-word mnemonic>"` (bff-skills env).
- `HERMETICA_STAKING_DISABLED` — protocol kill-switch; do not retry.
- `INSUFFICIENT_USDH_BALANCE` — re-check the swap output; do not retry stake leg with a wrong amount.
- `BROADCAST_FAILED` — inspect the broadcast error; do not retry without resolving cause.

## On success

- For `run`: report all four legs — supply tx, borrow tx, swap tx (with observed slippage vs Quote Engine projection), stake tx (the wallet now holds sUSDh) — plus resulting LTV, and pointer to the checkpoint file.
- For `score`: report composite + recommendation + the single weakest sub-score, the carry trend, the wallet reserve, the `selfImpactBoundedSbtcSats` boundary alongside the chosen size, and any `UNWIND_RECOMMENDED` signal that should be routed to the unwinder skill.
- For `monitor` (HITL): per-poll JSON with current recommendation; never broadcast.
- For `monitor` (autonomous): per-poll JSON; if a `run` action was broadcast, include the supply tx hash and remaining-leg checkpoint state. If an `unwind-init` intent was logged, surface the recommendation but note no broadcast occurred.
- For `status`: report just the live position. Do not propose actions unless asked.

## Routing hints

- If the user wants to **close** an existing wind-skill position (sUSDh -> USDh -> USDCx -> repay -> sBTC): route to the partner **unwinder skill** (separate PR). This skill cannot.
- If the user holds USDh already and wants to deploy it (no Zest leg): route to the sibling `hermetica-yield-rotator` skill (LP rotation).
- If the user holds sBTC and wants leveraged sBTC exposure (not USD yield): route to `bitflow-zest-sbtc-leverage-cycle`.
- This skill is the right answer only when the user holds sBTC, wants USD-denominated yield from sUSDh **without** selling, and is willing to hold the position with the 7d-cooldown unwind constraint.
Loading
Loading