| name | Polymarket Trade |
| description | Place a position on a Polymarket market through Simmer. SIMULATES by default (nothing moves); real orders are opt-in and require an activated Simmer trading wallet within a bounded-spend mandate. Powered by Simmer. |
| category | crypto |
| var | |
| requires | ["SIMMER_API_KEY","SIMMER_MCP_ALLOW_LIVE?"] |
| mcp | ["simmer"] |
| tags | ["crypto"] |
${var} — "<market_id> <side> <sizeUsd> [live]"
e.g. 0x1a2b… yes 2 (simulate a $2 YES) · 0x1a2b… yes 2 live (real order).
<side> is yes / no. Get a market_id from polymarket-markets or polymarket-intel. If ${var} is empty, read skills/polymarket-trade/strategy.md if present, else report and stop.
Read memory/MEMORY.md for context.
⚠️ Money safety — read this first
- Default is SIMULATE. An order only reaches Polymarket when the literal word
live is present and SIMMER_MCP_ALLOW_LIVE=true is set on the Simmer MCP env and the Simmer account has an activated trading wallet with funds. Miss any one and the trade stays paper — by design (the MCP enforces this triple gate and coerces anything else to dry-run).
- Stay inside the operator's bounded-spend mandate. Never place a real order larger than the mandate the operator set. Treat unset as "simulate only."
- One order per run. Do not loop or retry a real order — a submitted order may already be resting/filled; check positions before re-trying.
- Polymarket is a real-money prediction market, not investment advice. Odds are a probability, never a guarantee — no "risk-free" anything.
Prerequisite: the Simmer MCP wired (see .mcp.json.example) with a SIMMER_API_KEY. Live trading also needs SIMMER_MCP_ALLOW_LIVE=true and an activated wallet (run the simmer-wallet-setup skill once, on simmer.markets).
Steps
1. Parse the request
From ${var}: MARKET (market_id), SIDE (yes/no), SIZE (USD), and whether the literal word live is present (LIVE=1). If SIZE is missing or non-numeric, stop and ask. If SIZE exceeds the operator's mandate, refuse and report.
2. Simulate (always)
Call the simmer_trade MCP tool with the paper shape — nothing moves:
simmer_trade({ market_id: MARKET, side: SIDE, size: SIZE, venue: "polymarket", dry_run: true })
The response is a paper receipt: the would-be position (shares, avg price), venue, and any coercion warning. Report it. If LIVE is not set, stop here — this is the safe default.
3. Place for real (only if LIVE=1)
Only when the operator asked for live AND the mandate allows this size, call simmer_trade with the live shape:
simmer_trade({ market_id: MARKET, side: SIDE, size: SIZE, venue: "polymarket", dry_run: false })
- The MCP gate decides: if
SIMMER_MCP_ALLOW_LIVE isn't true, the tool blocks and returns the dry-run path with a notice — surface that notice, don't try to bypass it.
- On success the receipt carries the order id + fill/position. Report it verbatim.
- Do not retry on ambiguity. If the call errors after submission, call
get_positions to check whether it landed before any retry.
4. Report
Notify via ./notify: the verdict (simulated vs live), the market, side, size, the receipt (price/shares/order id), and the Polymarket link. Make it unambiguous whether real money moved.
Fallback (human-in-the-loop): if live isn't enabled or no wallet is activated, do not place an order. Report the paper receipt and emit the Polymarket market link so a human can finish it manually.
Constraints
- Never flip
dry_run to false unless the operator's request literally included live. Absent that word, always paper.
- One real order per run; never loop a live trade.
- No "guaranteed profit" / "risk-free" / "can't lose" language, ever.
- Don't expose or invent internal sizing/scoring logic — pass the operator's size through; the MCP handles execution.