Watch XCH price
You are watching the XCH spot price and notifying when it crosses a configured threshold. Price comes from chia-explorer's CoinGecko-backed tool. Read-only. Schedulable.
This skill follows the conventions in this repo's SKILLS.md. Read that if anything below is unclear.
Required capabilities
- chia-explorer (
mcp__chia-explorer__*) — mandatory. - A notification MCP — pick whichever is installed. If none, fall back to
~/.chia-skills/alerts/.
Resolve inputs
You need: $threshold, $currency, $direction, $channel.
$threshold— a numeric price target. Required.$currency— three-letter currency code (e.g.usd,eur,gbp,btc,sats). Defaultusd. Lowercase.$direction— one ofabove(alert when price ≥ threshold),below(alert when price ≤ threshold),cross(alert on either-side crossing of the threshold). Defaultcross.$channel— notification channel, defaultauto.
Resolve: arguments → context → ask user.
Validate:
$thresholdmust be a positive number.$currencymust match a CoinGecko-supported code. If the chia-explorer price tool returns an error for the code, surface it.$directionmust be one of the three values above. Anything else → ask the user to clarify.
Load or initialise state
State file: ~/.chia-skills/state/watch-xch-price__<currency>_<threshold>_<direction>.json.
Shape:
{
"threshold": 50.0,
"currency": "usd",
"direction": "cross",
"last_price": 47.32,
"last_check_iso": "2026-05-19T14:33:00Z",
"last_alerted_at": null,
"skill_version": "0.1.0"
}
On first run: fetch current price, record it as last_price, save state, emit STATUS: success, EVENTS: 0 with a message like "price watch started at $47.32 — will alert on threshold". Don't fire an alert on first run even if the price already satisfies the condition; the user just set this watch up.
Check the price
Fetch current XCH price in $currency via chia-explorer's price tool.
Decide whether to alert
Compute crossing logic:
direction = above→ alert iflast_price < $thresholdandcurrent_price >= $threshold.direction = below→ alert iflast_price > $thresholdandcurrent_price <= $threshold.direction = cross→ alert if either of the above is true.
Apply a small debounce: if last_alerted_at is within the last 60 minutes, suppress duplicate alerts. This stops "flickering" when the price hovers exactly on the threshold.
If no crossing happened, this is a no_change run.
Compose the notification
XCH crossed $50.00 (USD)
Now: $50.42
Previous: $47.32
Threshold: $50.00 (above)
Move: +6.6% since last check
Not advice — just a heads-up.
For non-fiat currencies (BTC, sats), format appropriately: 5 decimals for BTC, integer for sats.
Add the "Not advice" line to every message. The skill is not a trading bot.
Send the notification
Pick a channel by priority (same as other watch skills). Fall back to ~/.chia-skills/alerts/ if none available.
Update state
Update last_price, last_check_iso, and (if alert fired) last_alerted_at. Write state atomically.
If the alert channel failed, still update last_price and last_check_iso to keep the price tracker current, but don't update last_alerted_at. Next scheduled run will retry the alert if the condition still holds (and debounce permits).
Scheduling
This skill is one-shot. Wire to:
scheduleskill / cron — every 15 minutes is plenty for price alerts. Don't poll faster than every minute (CoinGecko free tier rate limits)./loop— fine for short windows ("watch through the close").
Hard rules
- No advice. Report the price; don't recommend buy/sell.
- No retroactive alerts on first run. Record current price and start fresh.
- Debounce 60 minutes to avoid flicker alerts.
- Respect CoinGecko rate limits. Don't poll faster than 1/minute without an API key.
Recovery patterns
- CoinGecko 429 / rate-limited. Don't update state. Emit
STATUS: failed,REASON: price API rate-limited. Next scheduled run picks up. - CoinGecko returns weird value (negative, zero, NaN). Treat as a transient error; don't update state; emit
STATUS: failed. - State file says we already alerted today within debounce window. Suppress alert, emit
STATUS: no_change,REASON: debounced.
Output
STATUS: success | no_change | partial | failed | aborted
ALERTED: true | false
PRICE: <current price formatted>
CURRENCY: <code>
THRESHOLD: <threshold>
DIRECTION: above | below | cross
CHANNEL: <channel used> | inline | none
ARTIFACT: <path to inline alert file> | none
REASON: <one line, only when STATUS is failed, partial, or aborted, or when no_change is due to debounce>