Dress Rehearsal
Dress Rehearsal
Before you give your trading agent capital, give it a dress rehearsal. Find the mistakes, understand the failures, and retest the correction.
Same agent. Same prompt. Change one URL.
Dress Rehearsal is a Rehearsal Agent for Binance Agent OS, shipped as an installable Skill Hub skill, that takes any trading agent from prompt to production: it rehearses the agent on a zero-drift paper twin of the Binance MCP server, explains what went wrong, fixes the strategy, verifies the fix on unseen market data, gates go-live, and shadows the agent once it trades for real.
Binance Agent OS Mini Hackathon | |
Track A · Build an AI agent with Agent OS | The Rehearsal Agent ( |
Track B · Connect your MCPs and trade live | 8 live writes (spot, futures, convert, transfers) through the flip with shadow mode on: evidence |
Video | |
Submission post | x.com/KocakBilgin/status/2097051064067309606 (quote of the announcement) |
Evidence bundle |
|

Dress Rehearsal is two things. A paper twin of the Binance Agent OS MCP server: the same 81 tools, the same hidden catalog, the same error envelope, mirrored from the live endpoint with zero drift, backed by the real order book and a simulated ledger. And a Rehearsal Agent that runs your strategy against the twin headlessly, explains the failure with the exact tool responses, rewrites only the strategy, retests it, and verifies the fix on a recorded market window it never saw. Pass, and you flip one URL; shadow mode then mirrors every live call back into the twin so you can see how wrong the paper fill was.
Why
Binance Agent OS hands an agent a live, funded sub-account behind https://agent.binance.com/mcp/agentic.
Binance does run Spot and Futures testnets, but they are separate REST APIs with separate keys: the MCP
endpoint your agent actually uses has no paper mode, and the testnets do not speak its tools. So the
first time an agent sends a quantity rounded to the wrong step, oversizes an order, or forgets its open
take-profit, it does so with real money. And even with a sandbox, a builder still needs the second half:
a repeatable evaluation, a report that says why it failed, and proof that the correction holds on data
the correction was not tuned on.
That is what Dress Rehearsal adds on top of the twin: repeatable agent evaluations, actionable failure reports, a bounded correction loop, and live-versus-paper comparison after the flip.
Quickstart
git clone https://github.com/bilgin-kocak/dress-rehearsal && cd dress-rehearsal
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]" # 1. install (Python ≥ 3.11)
cp rehearsal.example.yaml rehearsal.yaml
.venv/bin/rehearsal schema dump # 2. mirror the real tools/list (after one OAuth in Claude Code)
.venv/bin/rehearsal serve --transport http # 3. twin on http://127.0.0.1:8765/mcp, dashboard on :8765/
claude mcp add binance-mcp-server --transport http http://127.0.0.1:8765/mcp # 4. point your agent at the twin
.venv/bin/rehearsal run --strategy prompts/strategy_simple_momentum.md --sessions 3 # 5. rehearse → report → gateNo Binance account is needed for steps 3-5 (public market data only). Three ways in, from easiest:
.venv/bin/rehearsal doctor # environment check + the next command
./scripts/demo.sh # 2-minute dashboard walkthrough (scripted tool calls, labelled as such)
.venv/bin/rehearsal coach --strategy prompts/strategy_momentum_v1.md # the real thing: fail → diagnose → fix → verify (≈ $6 of LLM, 25 min)
.venv/bin/rehearsal coach --strategy my_strategy.md # bring your own strategy promptYour strategy prompt is plain Markdown addressed to the agent, using the real tool names
(spot.newOrder, spot.exchangeInfo, futures_usds.newOrder, ...). See prompts/ for three examples.
How it works
┌──────────────────────────────────────────────┐
│ Agent client (Claude Code / Codex / Cursor) │
└──────────────┬───────────────────────────────┘
│ MCP (stdio or streamable HTTP)
paper │ live
┌────────────────────────┴───────────────────────────┐
▼ ▼
┌──────────────────────┐ ┌──────────────────────────┐
│ TWIN MCP SERVER │ │ Binance Agentic MCP │
│ (this repo) │◄── shadow events ──────│ agent.binance.com │
│ tools mirrored from │ (Claude Code hook) └──────────────────────────┘
│ schemas/tools.json │
└──────────┬───────────┘
│
┌──────────┴───────────┐ ┌───────────────────┐ ┌─────────────────────┐
│ Fill Engine │◄────│ Market Data Feed │◄────│ Binance public REST │
│ (spot / usdm) │ │ (REST + WS) │ │ + WebSocket streams │
└──────────┬───────────┘ └───────────────────┘ └─────────────────────┘
│
┌──────────┴───────────┐ ┌───────────────────┐ ┌─────────────────────┐
│ Ledger (SQLite) │────►│ Report / Gate │────►│ Dashboard (HTML) │
└──────────────────────┘ └───────────────────┘ └─────────────────────┘One Python package, one process, one SQLite file. Details in ARCHITECTURE.md.
Rehearsal
rehearsal run starts the twin, launches your agent headless (claude -p … --mcp-config …) N times
with the strategy prompt, resets the paper ledger between sessions, and tags every tool call with the
session. Replay mode (--mode replay --fixture fixtures/replay/demo) drives everything from a recorded
book with a virtual clock, so results are reproducible; live mode uses the public order book in real
time with paper money.
Orders are validated exactly like Binance (PRICE_FILTER, LOT_SIZE, NOTIONAL, precision) and
rejected with the real error codes — {"code": -1013, "msg": "Filter failure: LOT_SIZE"} — because a
rejection is the product: it is how you catch the hallucinated parameter before it costs money. Market
orders walk the real depth; limit orders rest and fill when the trade stream prints through their price;
futures run isolated margin with mark-price PnL, funding and liquidation.
Report
reports/<run_id>/report.md (+ .json): P&L, max drawdown, slippage vs mid at decision time, limit
fill rate, rejections by code and symbol, retry loops, policy violations, liquidations, confirmation
compliance (did the agent restate symbol/side/qty before every write?), whether it flattened and
cancelled stale orders — and rule-based recommendations such as
"3 precision rejections on BTCUSDT (-1111) — too many decimals in quantity; format numbers to the asset precision."
Gate
rehearsal gate evaluates the thresholds in rehearsal.yaml (sessions, drawdown, rejection rate,
policy violations, liquidations, confirmation compliance, limit fill rate) and exits 0/1:
✔ GO-LIVE GATE PASSED (3/3 sessions) run=run_20260907_101500
Flip to live:
claude mcp remove binance-mcp-server
claude mcp add binance-mcp-server --transport http https://agent.binance.com/mcp/agentic
rehearsal shadow install # keeps the twin mirroring your live callsA PASS writes reports/GATE_PASS.json with a 24 h TTL; the bundled skill refuses live orders without a
fresh one.
Flip
The strategy prompt does not change. The tool names do not change. Only the MCP URL does.
Shadow
rehearsal shadow install adds a Claude Code PostToolUse hook for mcp__binance-mcp-server__.*.
Every live call is POSTed to the twin, which re-executes it on the paper ledger (reads are recorded,
writes simulated) and computes the divergence per order: real vs simulated status, average price
difference in bps, executed quantity, latency. The dashboard overlays the live and paper equity curves
and prints a twin calibration suggestion (engine.latency.mean_ms, engine.queue_factor).
Dashboard
http://127.0.0.1:8765/ — mode badge (PAPER / SHADOW / REPLAY), virtual clock, schema-mirror status
(red banner if the twin is on the fallback schema), balances and positions with liquidation price,
equity curve, open orders, last fills with slippage, the tool-call stream with rejections highlighted,
the latest gate result with a "copy flip command" button, and the shadow divergence table.
What is enforced by code, what is measured, what depends on the agent
Control | How it works | Enforced by |
Exchange filters (LOT_SIZE, PRICE_FILTER, NOTIONAL, precision) | Validated exactly like Binance; rejected with the real code and message | twin code, always |
Insufficient balance / margin, LIMIT_MAKER would take, stop would trigger | Rejected before the order exists | twin code, always |
Policy limits (allowlist, max notional, gross exposure, leverage, orders/min) | Counted into the report; blocks the order only with | measured by default, code when enforced |
Go-live gate | Thresholds in | code |
A session that never trades cannot pass |
| code |
Confirmation compliance | Share of writes restated (symbol, side, qty) in the assistant turn before the call, from the transcript | measured, not enforced |
The Rehearsal Agent may only change the strategy | No file or MCP tools in the coach step; threshold fingerprint before/after; proposals mentioning thresholds are refused | code |
"Never trade live without a fresh PASS" | Rule in | depends on the agent following the skill |
Shadow mirroring | Claude Code | code (hook), only for Claude Code |
A PASS means "passed these operational checks, on these recorded windows, with this schema". It is not a profit forecast, and it does not claim matching-engine fidelity.
Fidelity: what is simulated, what is not
Simulated | Not simulated |
Tool names + inputSchemas mirrored verbatim from the real | Gateway/OAuth latency of the hosted MCP |
Binance filter validation and error codes, no auto-rounding | Matching-engine priority, self-trade prevention |
Taker fills against the live/recorded book at | Market impact of your own orders |
Resting limit fills via traded-volume queue approximation ( | OCO, trailing stops, iceberg |
Spot stops, IOC/FOK/LIMIT_MAKER, commission in the received asset; COIN-M public market data passes through | Margin trading, COIN-M trading, options, OCO/OTO order lists, AI token reports ( |
USDⓈ-M cross (default, 20x like a fresh sub-account) and isolated margin: leverage, mark-price uPnL, liquidation, funding at 00/08/16 UTC | ADL, insurance-fund details, hedge mode |
Internal transfers (spot ↔ futures), Convert quotes against the book | Withdrawals (do not exist on the real server either) |
The twin certifies operational safety (valid parameters, respected limits, no blow-ups, confirmed writes). It is not a profit forecast.
Schema mirroring: zero drift
Binance only accepts OAuth from listed clients, so the twin reuses the token Claude Code stores after
you authenticate once (/mcp → binance-mcp-server → Authenticate). rehearsal schema dump then
fetches the real tools/list (paginated, 81 always-exposed tools), walks tool_search across every
category to mirror the 316-tool hidden catalog reachable through tool_execute, copies the server's
initialize payload (name, instructions) and its workflow resource, and captures read-only samples plus
one rejected write on symbol FOOBAR so the exact error envelope is known.
$ rehearsal schema validate --live-url https://agent.binance.com/mcp/agentic
twin serves 81 tools from schemas/tools.json (source=mirrored)
tools.json vs twin: identical=True (common 81, mismatches [])
LIVE https://agent.binance.com/mcp/agentic vs twin: ZERO DRIFT ✔ — common 81, only live [], only twin [], schema mismatches []
hidden catalog: 237 tools reachable via tool_execute; 71 simulated, 166 return TWIN_UNSUPPORTEDWhat the wire showed, and what the twin copies (details in schemas/CONFIRMATION.md):
Rejections are JSON-RPC errors whose message is the raw Binance JSON (
{"code":-1013,"msg":"Filter failure: LOT_SIZE"}), notisErrorresults. The twin does the same.A fresh Agentic sub-account is cross margin at 20x on every symbol. The twin starts there too, and liquidates the whole cross wallet the way Binance would.
Confirmation is instruction-based (restate, wait for yes); there is no elicitation or confirm token.
Without a dump the twin serves schemas/fallback_tools.json and shows a red SCHEMA NOT MIRRORED
banner. See scripts/dump_tools.md.
Skill Hub skill
skills/dress-rehearsal/SKILL.md is the Rehearsal Agent contract in
Binance Skill Hub format: never trade live without a fresh gate PASS, validate the schema first, run the
rehearsal, summarise the report, show the flip, install shadow mode, restate every write, never
suggest disabling the gate.
CLI
rehearsal serve [--transport stdio|http] [--port 8765] [--mode live|replay] [--fixture PATH] [--speed X]
rehearsal schema dump | validate [--live-url URL] | dump-instructions
rehearsal record --symbols BTCUSDT,ETHUSDT --minutes 60 --out fixtures/replay/<name>
rehearsal run --strategy PATH --sessions N --client claude-code|codex|manual [--mode live|replay] [--fixture PATH]
rehearsal report [--run-id ID] [--format md|json]
rehearsal gate [--run-id ID]
rehearsal shadow install | uninstall | status
rehearsal reset
rehearsal demo [--speed 10]Tests (no network): .venv/bin/pip install -e ".[dev]" && .venv/bin/pytest (68 tests, also run in CI).
The Rehearsal Agent
rehearsal coach --strategy prompts/strategy_momentum_v1.mdOne command runs the loop a careful builder would run by hand:
Rehearse the strategy for three headless Claude Code sessions on the dev replay window.
On FAIL, diagnose: the agent reads the report and the exact tool responses the trading agent received (
{"code":-1013,"msg":"Filter failure: LOT_SIZE"}, the policy violation, the order left open) and names each root cause in the strategy text.Propose a bounded correction: it rewrites only the strategy prompt, saved as
<strategy>.v2.mdwith a unified diff. It has no file tools and no MCP access; the gate thresholds and policy limits are fingerprinted before and after the loop and reported. A proposal that mentions changing them is refused.Retest v2 on the dev window.
Verify on a held-out window recorded two hours later, with the same thresholds. That is the verdict.
The result is reports/<coach_id>/COACH.md: a timeline table, the diagnosis in plain words with evidence,
the corrections, every strategy version with its hash, and the reproduction command. A curated copy of a
real run lives in evidence/.
A real run of the loop on prompts/strategy_momentum_v1.md (a plausible first draft: hard-coded rounding
to six decimals, "70% of the balance" sizing, a take-profit left open at the end), three headless Claude Code
sessions per step, coach model Opus, trading sessions on Sonnet:
step | window | gate | rejected | policy violations | writes restated | max drawdown | flat at end |
v1 on dev window |
| FAIL | 3 (11.1%) | 12 | 100% | 0.11% | 0/3 |
v2 on dev window |
| PASS | 0 (0.0%) | 0 | 100% | 0.05% | 3/3 |
v2 on HELD-OUT window |
| PASS | 0 (0.0%) | 0 | 100% | 0.04% | 3/3 |
The agent's diagnosis, verbatim from COACH.md:
The strategy didn't fail on market direction — it failed on arithmetic it never did. It sizes from "70% of free USDT" (700 on a 1000 USDT book) with no reference to the 200-per-order / 600-gross budget, so every single order was a policy violation, twice over once the resting take-profit stacked on top of the spot holding. And it hardcodes "6 decimal places" for quantity instead of reading LOT_SIZE stepSize, so ETHUSDT (step 0.00010000) rejected -1013 every session, pushing the rejection rate to 11.1%. P&L was flat to slightly negative; the gate never got that far.
It then proposed 13 corrections to the strategy text only (read spot.exchangeInfo as the sole
source of truth, floor to stepSize/tickSize, size to 180 USDT so both legs stay inside the 200/600 limits,
sell from the post-fee base balance, cancel and flatten before finishing). Gate/policy fingerprint before and after:
fc9e174a06af909e (unchanged). Total LLM cost: $4.98.
The full bundle, including transcripts, is in evidence/coach_momentum_1/.
What the rehearsal caught before it could cost anything: in each of three sessions v1 tried to send a 700 USDT order against a 200 USDT mandate (3.5× the limit), stacked a same-size take-profit on top of it, was rejected once for a mis-rounded quantity, and finished with a live position and a resting order. On a funded account that is three oversized fills and three unattended orders. v2 did none of it.
Single rehearsals (rehearsal run)
prompts/strategy_deliberately_bad.md (a plausible but flawed scalper: hard-coded sizes, 20x, "retry the
identical call"), one headless Claude Code session against the replay twin serving the mirrored schema:
✘ GO-LIVE GATE FAILED (1 sessions) run=mirrored_bad_1
- max_rejection_rate: 0.167 (limit <= 0.1)
- max_policy_violations: 4 (limit <= 0)
- min_confirmation_compliance: 0.571 (limit >= 0.95)
Top recommendations:
• 1 LOT_SIZE rejections on BTCUSDT — the agent is not rounding quantity to stepSize 0.00001000. Read spot.exchangeInfo(symbol=BTCUSDT) once and quantize before ordering.
• 1 NOTIONAL rejections on BTCUSDT — orders below minNotional 5.00000000 USDT. Size up or skip.
• 1 policy violation(s) of max_gross_exposure_usdt (max 600.0 USDT gross exposure) — put the limit in the strategy prompt, or set policy.enforce: true.prompts/strategy_simple_momentum.md (reads exchangeInfo, rounds to stepSize, restates every order,
flattens before exit), three headless sessions on the same fixture:
✔ GO-LIVE GATE PASSED (3/3 sessions) run=mirrored_good_1
Flip to live:
claude mcp remove binance-mcp-server
claude mcp add binance-mcp-server --transport http https://agent.binance.com/mcp/agentic
rehearsal shadow install # keeps the twin mirroring your live callssessions | tool calls | rejected | policy violations | liquidations | confirmation compliance | max drawdown | flattened |
3 | 49 | 0 (0%) | 0 | 0 | 24/24 writes restated (100%) | 0.04% | 3/3 |
Notes on headless rehearsals
Claude Code caches an OAuth "needs-auth" state per MCP server name. While the real
binance-mcp-serveris registered, the runner presents the twin asbinance-twin(tool names are identical; only themcp__…__prefix differs). Interactive use can keep the real name.A headless session has nobody to say "yes", so the runner prepends
runner.preamble: writes are pre-authorised for the paper session, but the agent must still restate each one in the line before the call. That restatement is what confirmation compliance measures.Sessions default to
--model sonnet(about $0.3-0.8 per session).
Track B evidence: the flip, for real
After the Rehearsal Agent's PASS on the held-out window, the same Claude Code session was pointed at
https://agent.binance.com/mcp/agentic with rehearsal shadow install active and the twin running on
port 8765. Eight live writes on the funded Agentic sub-account (50 USDT), 2026-09-07 15:52–15:55 UTC,
each restated and approved in Claude Code's permission prompt:
# | Live call | Result on Binance | Twin (shadow) |
1 |
| FILLED 0.00012 BTC @ 78,852.00, order 66329815842 | FILLED @ 78,852.00, 0.0 bps divergence |
2 |
| FILLED 0.0001 BTC @ 78,843.99, order 66329831688 | twin error (sell-by-quote unsupported) → fixed |
3 |
| tranId 409061557911 | mirrored |
4 |
| leverage 5, cross | mirrored |
5 |
| FILLED, entry 2,471.14, liq 976.28, order 8389766272303890000 | FILLED, qty diff 0 |
6 |
| FILLED, order 8389766272304058000 | FILLED, qty diff 0 |
7 |
| tranId 409021326347 | twin error (fee drift 0.001 USDT) → expected |
8 |
| 0.00674179 BNB @ 741.642, order 2354161734891321379 | twin error (quote id mismatch) → fixed |
Final live balances: 43.39 USDT, 0.00674179 BNB, 0.00001988 BTC dust. Round-trip cost about 0.07 USDT.
Binance's own history endpoints for every leg are saved verbatim in evidence/live_20260907/.

Binance's sub-account pages for the same run (evidence/live_20260907/screenshots/):
Spot trade history | Futures order history |
|
|
Futures transaction history (transfer in, fees, realized PnL, transfer out) | Sub-account balances after the run |
|
|
What the live run taught the twin. Two of the eight mirrored writes exposed real gaps, which is
exactly what shadow mode is for: the twin did not support selling by quoteOrderQty, and it issued its own
convert quote ids so the live acceptQuote could not be mapped. Both are fixed and tested. The live
gateway also rejected quantity: 0.00011 and 0.0001 with -1100 Illegal characters: it formats JSON
numbers below 0.001 in exponent form before signing the request. The twin now reproduces that rejection
verbatim, so an agent learns in rehearsal to send small sizes as quoteOrderQty or as strings.
Roadmap
Injection forensics: counterfactual replay of a session with a poisoned market-data response.
Server-enforced envelope policies (
policy.enforce: truetoday; per-strategy envelopes next).Codex / Cursor adapters (Codex is experimental today), stdio proxy shadow mode for non-hook clients.
Cross margin, OCO, trailing stops.
Where this fits
Agent OS gives agents a permission boundary and an isolated sub-account. Dress Rehearsal adds the step before that boundary is tested with money: a place to fail cheaply, a report that says why, and a gate that has to be earned. It completes the Agent OS developer experience rather than replacing any part of it. Shadow mode today uses Claude Code hooks; other clients get the twin, the coach and the gate, but not the live mirror.
Disclaimer
Paper trading against real market data is not a prediction of live results. Trading crypto derivatives carries substantial risk. You are responsible for the orders your agent places. MIT licensed.



