Cubicle: anti-hallucination trading for AI agents.
Prove any strategy before an agent trades it.
An MCP trading toolkit and backtesting client for AI agents: reverse-engineer a TradingView Pine script or a strategy you found online, compile it into a deterministic state machine, and backtest it on recorded bars of NQ, ES, YM, BTC, ETH and SOL, with the result checked against a random null instead of quoted. For agent builders (Claude, Cursor, any MCP client), quant hobbyists and traders who want an agent that refuses to trade what it cannot reproduce.
Paste a strategy you found (a rule in words, a Pine script, a chart). Cubicle takes it apart into what is observed, what is inferred and what is unknown, builds it into a state machine, and runs it over recorded bars. The number you get back is measured on real tape, not quoted from whoever posted it.
Part of Cubicle, by AlgoTrada. MIT. Two packages with the same verbs: JavaScript (js/, Node 18+, zero dependencies) and Python (3.10+, standard library only).
npm install -g cubicle-sdk # Node 18+, zero dependencies (js/)
# or: pip install git+https://github.com/yawningmonsoon/cubicle-sdk (Python 3.10+, standard library only)
cubicle join my-agent # a free key, saved to ~/.cubicle/key (0600), never printed
cubicle reverse examples/strategies/opening-range-breakout.pine
cubicle reconstruct examples/strategies/opening-range-breakout.txt --market NQ --acceptBoth packages install the same cubicle command and speak to the same server. New here? Read the
walkthrough (ten minutes, every line of output explained) and the
article on why this exists. Were you given a code? cubicle join my-agent --code CODE, or
cubicle redeem CODE for an account you already have: more free turns with the house agents.
from cubicle_sdk.mcp import Cubicle
c = Cubicle() # reads CUBICLE_KEY or ~/.cubicle/key
dossier = c.reverse(open("strategy.pine").read()) # observed / inferred / unknown, the checklist, the ceiling
bars = c.call("tape", market="BTC", tf="1h", **{"from": "2026-10-10T00:00:00Z", "to": "2026-10-11T00:00:00Z"})A refusal is a CubicleError with a stable kind (unauthenticated, studio_gate, plan_required,
unknown_tool, bad_arguments) and, when the server gave one, next: the step that lifts it.
Open https://cubicle.algotrada.com/deck, sign in with your email (a magic link) or a key, and post the strategy
in the studio. /reverse takes apart what you posted, /forge builds it, /rehearse runs it on the tape. The key
you sign in with is the same key an agent uses: one identity for both.
cubicle reconstruct examples/strategies/rsi2-pullback.txt --market ES --acceptThe chain is the studio's own and the server decides every gate; the script only follows it:
reverse (nothing is run) → workflow_read (the seven parts, from the rule's own words) → the studio's moves
(accept the parts, choose how it is measured) → forge → rehearse on the last week of real bars.
Measured on production, 2026-10-12, as a brand-new free account (the chronicle):
| public rule | market | trades in 168 h | sum | the studio's gate |
|---|---|---|---|---|
| Opening range breakout | NQ | 5 | +2.5R | at least 10 trades are needed to judge it |
| RSI-2 pullback | ES | 4 | +1R | at least 10 trades are needed to judge it |
| Bollinger mean reversion | BTC | 37 | +0.5R | not yet told apart from chance (p 0.33 to 0.38) |
The window is the trailing week, so the numbers move: an hour later, after a fall in BTC, the same Bollinger rule read 37 trades, −2R, p 0.67. None of the three is shown to work. That is the result: a week of bars does not support any of them yet, and the tool says so instead of printing a win rate.
reverse answers with one JSON object (strategy-dossier.v1):
- route: what was posted and which tool reads it first. A chart is read then checked against the tape; a script is read, never run; words go to the reader.
- findings: each is an
observation(read or measured), aninference(computed from what was read, and said to be a guess) or anunknown(with what would settle it). Each has an id (E1,E2, …) to cite. - checklist: market, bar size, trigger, direction, stop, target, stand aside, do its numbers match the tape, was it run over recorded bars. Each is answered, partial or unresolved.
- ceiling: a screenshot is an
anecdote; a rule that was never run is ahypothesis.
The method is adapted from morluto/rea (MIT), whose subject is shipped software: route the target first, summary first, separate observation from inference from unknown, and never let a static reading claim an execution. No code was taken.
One server, streamable HTTP: https://cubicle.algotrada.com/deck/api/mcp. Listing its tools needs no key; a
call needs Authorization: Bearer <your Cubicle key>.
# Claude Code
claude mcp add --transport http cubicle https://cubicle.algotrada.com/deck/api/mcp --header "Authorization: Bearer $CUBICLE_KEY"{ "mcpServers": { "cubicle": { "type": "http", "url": "https://cubicle.algotrada.com/deck/api/mcp",
"headers": { "Authorization": "Bearer YOUR_CUBICLE_KEY" } } } }Cursor, VS Code and Cline take that shape in their MCP settings (field names differ slightly between clients:
check yours). Claude Desktop and other stdio-only clients bridge with
npx mcp-remote https://cubicle.algotrada.com/deck/api/mcp --header "Authorization: Bearer ${CUBICLE_KEY}".
Anything else: POST JSON-RPC 2.0 (initialize, tools/list,
tools/call), which is all cubicle_sdk/mcp.py does.
The tools, as the live server lists them: python -m cubicle_sdk.mcp tools (39 on 2026-10-12: the studio chain,
the tape, plans, strategies, copy-trading, vaults on Robinhood Chain).
Read keyless from each channel on 2026-10-12; the manifest is server.json.
| channel | state |
|---|---|
| Official MCP registry | listed as com.algotrada.cubicle/cubicle (the registry holds 1.1.0, the server reports 1.0.0) |
| Glama | listed: https://glama.ai/mcp/connectors/com.algotrada.cubicle/cubicle |
| PulseMCP | ingests the official registry; not readable without a browser |
| Smithery | not listed yet |
| mcp.so | not listed yet |
| a2aregistry.org | not listed yet (the card is served at /.well-known/agent-card.json) |
Cubicle's three services (studio, candles, copy) are listed as hireable sellers on the Taifoon coordination layer, each with an ERC-8004 identity, so another agent can find and hire them where agents look for sellers. Every sale through the layer is one tracked run on one ledger; its public summary is https://api.taifoon.dev/coordination/sale-run.json. What is not live: a trader being paid for a strategy they published. That path is designed, not open; nothing here should be read as an earnings offer.
Seven runnable checks for a claim you already have numbers for. Stdlib only, deterministic, JSON out, each with a --self-test.
Every one answers a documented way that trading research fools itself.
| Counter | Answers |
|---|---|
null_panel |
Does this beat always-up, seeded random, with-prev, and buy-and-hold on the same window? |
deflated_sharpe |
Does the Sharpe survive the number of variants actually tried? |
calibration |
Do the stated probabilities track observed frequency — and do they carry information? |
pushback |
Does the decision survive pressure that carries no new evidence? |
pass_k |
Do identical reruns agree, and does the score exceed its own dispersion? |
corpus_flag |
Does the evaluation window sit before or after the model's cutoff? |
one_switch |
Toggle one input — if the alpha vanishes, it was never alpha. |
python3 -m cubicle_sdk.lab.null_panel --file candles.jsonl
python3 -m cubicle_sdk.lab.calibration --file forecasts.jsonl
python3 -m cubicle_sdk.lab.deflated_sharpe --sr 2.5 --trials 100 --obs 1250Each prints one JSON object. Each returns exit 0 clean, 2 on a typed
error — so a caller routes on error.kind, never on message text.
Nulls before trust. No harness result counts until the null panel ran on
the same window. A strategy that barely beats always_up rediscovered the
drift.
Trials are counted, not recalled. With five years of data, ~45 independent configurations almost guarantees an in-sample Sharpe of 1.0 whose true out-of-sample Sharpe is zero. If an agent iterates, N explodes silently.
Calibration alone is not enough. A forecaster that always says the base
rate is perfectly calibrated and carries zero information. calibration
reports Murphy's resolution beside reliability so that case cannot pass.
Seven rungs. Exactly one may carry a price.
from cubicle_sdk import GateState
GateState.LIVE.may_be_priced # False — dispatching real money is not expectancy
GateState.RESELLER_ELIGIBLE.may_be_priced # True
GateState.parse("Certifiedd") # GateState.DRAFT — fails closedUnknown input degrades to Draft, the least-privileged rung, rather than
raising. Every caller of parse is deciding what an algo may do; an exception
tempts callers into or SOMETHING_PERMISSIVE. A typo, a truncated file, or a
future rung this version does not know about all fail in the safe direction.
None means not run — never passed.
from cubicle_sdk import HonestyBlock
HonestyBlock().unmeasured()
# ['determinism', 'one_switch', 'pass_k', 'corpus']
HonestyBlock(corpus="pre_cutoff").corpus_is_clean # FalseA pre-cutoff window is contaminated. Directional accuracy collapses from 99.26% to 52.94% across a model's training cutoff, and instructing a model to respect an artificial cutoff does not work — roughly 98% accuracy is retained. Only a data-layer control counts.
SignedReceipt.verify_shape() reports structural problems. It does not
verify cryptography and says so: a well-formed envelope with a forged
signature passes that check.
Is this a trading bot? No. It is the part that comes before one: it tells you whether a strategy is supported by recorded data. A strategy can then be hired to run a vault you own, under a signed, capped mandate.
Can I backtest a TradingView Pine script with it? It reads Pine statically (entries, sides, stops, targets,
sessions, repaint risks) and never runs it. To test it, write the rule in words (or let the studio read it) and
cubicle reconstruct: the test runs on our own recorded bars, not TradingView's.
Which AI clients work? Any MCP client over streamable HTTP: Claude Code, Claude Desktop (through mcp-remote),
Cursor, VS Code, Cline. Or this SDK from Node or Python.
Does it give signals or predictions? No. It never gives a direction or a price target. The expected-range indicator it draws is a size, never a direction.
What does it cost? Signing up and running the examples is free. Plans are paid on chain in USDG on Robinhood Chain.
- Not investment advice. These tools tell you when a claim is unsupported. They never tell you a strategy will make money, and a rehearsal is the past, not a forecast.
- A forge is built from the gates the tape can measure. When a rule names something the tape cannot evaluate, the studio says which part and builds an approximation only if you choose it.
- Tape coverage is NQ / ES / YM futures and BTC / ETH / SOL. No equities, no options.
- No signer and no session driver. Receipts are signed venue-side; a client-side signer would let anything
mint one.
SignedReceipt.verify_shape()checks structure, not cryptography. - Pine is read by pattern, not parsed. Multi-line calls and functions that wrap
strategy.entryare undercounted; a drawing-only indicator yields mostly unknowns, which is the honest answer. - Free sign-ups are limited to a few a day per client.
python3 -m pytest tests/ -qThe MCP client against a local stand-in server (protocol shape, refusals as kinds, the key never printed), the ladder invariants, the honesty-block semantics and every counter's self-test.
MIT.

