Chazle is an approve/reject trade-proposal engine for algorithmic options and prediction-market trading. A Claude orchestrator and four sub-agents do the analysis; a deterministic guard layer the model cannot talk its way around vets every proposal against hard caps; and no trade reaches a broker without your tap. The guard is the point of the whole thing.
“An LLM is a phenomenal analyst and a bad fuse. It is never the fuse here.”A proposal travels a fixed path: a scheduled review wakes the orchestrator, its sub-agents gather and disagree, the orchestrator synthesizes proposals, the guard fuses them, survivors queue for your tap, and only what you approve — after a second guard check — ever touches a broker. Every step is written to an append-only ledger.
Triggers a review every few hours during market hours (08:00–18:00 ET, weekdays). Deliberately periodic, not event-driven — the goal is more deliberation per trade, not reacting fastest to a headline.
Four focused sub-agents (news, sentiment, technical, positions) run concurrently and make the case for trades. Then an adversary agent argues the case against — why each idea won't work. The orchestrator (the "father") weighs both sides, synthesizes conservative proposals, and lowers confidence where the case is contested. It can only propose; it is never handed anything that executes.
A pure function checks each proposal against hard caps: per-trade size, daily loss limit,
daily deployment, per-symbol / total / per-asset-class exposure, and the kill switch.
Anything over a cap is turned away and logged as a capped row before it
ever reaches your queue.
Survivors wait for you to approve or reject. On approval the guard re-checks against live state, so a queue of individually-fine proposals can't collectively bust a cap.
Plain code places the order through the asset class's connector (mock by default), records the fill, and writes every event — proposal, cap rejection, intent, fill — to a tamper-evident JSONL log.
Chazle runs entirely on Anthropic's Claude models, matched to each job: the heavy synthesis runs on the most capable model, web-search reconnaissance on a mid-tier model, cheap reasoning-over-known-data on the fastest, and a dedicated skeptic that argues the bear case. With no API key present the whole pipeline still runs in mock mode — crafted illustrative proposals, zero model calls.
Synthesizes the sub-agents' often-conflicting findings into conservative, right-sized proposals, lowering confidence and stating the disagreement where they diverge. Runs with adaptive extended thinking at high effort, constrained to a JSON-schema output, with the system prompt prompt-cached. Read-only tools only — the model is never handed anything that can execute a trade.
Cross-references recent material news per symbol, distinguishing corroborated reporting from a single unconfirmed source. Uses the server-side web-search tool (capped at 4 searches per cycle), so it needs a model that supports it.
Gauges retail/social vs analyst sentiment and — crucially — flags where they diverge, because that divergence is itself a signal. Also web-search-enabled.
Reads the technical setup — trend, key levels, volatility regime — from price context we already hold, and states what would invalidate the read. No web search needed, so it runs on the fastest, cheapest model.
Looks at the current book — positions, exposures, room left under the caps, daily P&L — and flags concentration or room-remaining concerns that should shape or veto new proposals. Also Haiku, also no web search.
Runs last, over the other four's findings, with a single job: argue the strongest case against each trade — the underweighted risk, the crowded-trade objection, the disconfirming read of the same evidence. The orchestrator must engage it head-on, because a proposal that survives a real attempt to kill it is worth more than one that was never challenged. Reasons over the assembled findings, no web search — the value is the counter-argument, not fresh data.
The four gathering sub-agents run concurrently, so their wall-clock is the slowest single agent, not the sum; the adversary then runs once over their combined findings. Each call has a hard timeout and one retry, and any agent that stalls or fails is simply dropped — the orchestrator synthesizes from what it has rather than letting one slow step wedge the cycle.
Every proposal carries one of three confidence labels, assigned by the orchestrator and calibrated to how much the sub-agents agree and how good the evidence is — not to how exciting the idea sounds. It's a read on conviction, written for the human who has to judge it.
How it's set. Each of the four sub-agents attaches its
own confidence to every finding. The orchestrator weighs them and, crucially,
lets disagreement pull confidence down — when retail sentiment is bullish
but analysts are cooling, that divergence is named explicitly in the proposal's dissent
field and the proposal lands at moderate, not high. A system that always
reports unanimous high confidence is one to distrust.
The guard layer never reads confidence. It changes no cap, gates no
execution, and influences no sizing in code — it only informs your approve/reject decision and
shows as a chip on the proposal card. The proof is built into the demo: an intentionally oversized
high-confidence proposal is still turned away as capped. A confident model
does not buy its way past a plain function.
This is the part the whole architecture exists to protect. It's a pure function — given a proposal, a snapshot of current exposure, and the caps, it returns a decision. No I/O, no state, no network, deterministic, and critically not a prompt. The LLM produces proposals; this code decides whether they may execute, and a model cannot talk its way around a plain function.
It runs in two places. At propose() time it pre-checks every
proposal and turns away anything already over a cap, writing the capped ledger row
that proves the cap was enforced before the trade reached your queue. Then at
approve() time it re-checks authoritatively against live state — so queuing
a hundred individually-fine proposals cannot collectively bust a cap. Each is re-evaluated the
moment you try to approve it.
Every check the guard runs, in order — it collects all violations rather than stopping at the first, so the ledger shows you exactly why something was blocked:
Landing exactly on a cap is allowed — a check rejects only
when the resulting value would exceed the cap. The daily loss limit is the deliberate
exception (it blocks at >=). And de-risking is never
blocked: a closing or reducing trade adds zero new deployed notional, so the deployment and
exposure caps never stand in the way of getting out of a position.
Caps are plain data, loaded once from the environment at startup. The guard reads
them; the LLM never sees or sets them. Changing a cap is a deliberate config-and-restart action,
never something that happens mid-conversation. These are the shipped defaults — tune them in
.env.
| Limit | Default | What it bounds |
|---|---|---|
| Per-trade notional (global) | $500 | Largest single order, gross |
| Daily loss limit | $1,000 | Realized loss that halts new risk for the day |
| Daily notional cap | $2,000 | Newly-deployed capital per day |
| Total exposure | $5,000 | Open exposure across the whole book |
| Per-symbol exposure | $1,500 | Open exposure to any one symbol |
| Pending queue | 25 | Proposals awaiting review at once |
Per-asset-class pools isolate risk by instrument type, so a bad stretch in prediction markets can't bleed into the equities/options book:
| Asset class | Per-trade | Pool exposure |
|---|---|---|
| Equity | $500 | $4,000 |
| Option | $400 | $2,000 |
| Prediction market | $200 | $1,000 |
Three operator controls sit alongside the kill switch — all persisted on disk, all enforced by the guard in code, none of them something the model can talk its way around — plus a notification layer that pushes decisions to you the moment they're needed.
Each proposal can carry the orchestrator's forecast: a target price, a horizon in days, and — crucially — the condition that invalidates the idea. Notifications and cards word it as an expectation ("expect ~$230 within 7 days, moderate confidence; invalid below the 50-day"), never as a certainty, so you can size a holding period with honest inputs. A forecast that can't be invalidated is a promise, and this system doesn't make promises.
Four operator tools sit around the queue. Every one of them is read-only or steering-only — they choose what the desk looks at and help you read what it found. None of them can approve, size, or execute a trade; the guard and your tap remain the only path to a position.
The assistant and the brief are the same kind of thing as the orchestrator: phenomenal analysts, never fuses. They read the snapshot, summarize news, explain a cap — and stop. Nothing they output moves money. The equity curve and executions come straight off the ledger, so the numbers you read are the numbers that happened, not a model's estimate of them.
Options are the core differentiator — and the asset class the guard treats most carefully, because their leverage makes notional easy to underestimate. They run through the same propose → guard → approve → log loop as everything else, with option-specific economics.
Real contract economics. Options carry a
100× contract multiplier, so the guard sizes against true
exposure: notional is quantity × limit_price × 100. One contract at $3.20 is
$320 of notional, not $3.20 — and the per-trade and pool caps are
measured against that, never the per-contract premium. Their pool is the tightest of the three
($400 per trade, $2,000 exposure) and fully
isolated, so an options drawdown can't bleed into the equities or prediction-market books.
The shipped mock set includes a worked example: a covered-call — sell one slightly-OTM weekly call to harvest premium into elevated implied volatility — sized at one contract ($320 notional), comfortably under the $400 option per-trade cap.
Today, options proposals flow through the full guard-and-approval loop but settle on the
mock connector — no real option order is placed. The live OptionsConnector
is a deliberate fail-loud stub that raises rather than fake a fill, because the Robinhood Agentic MCP
is equities-only at launch. Going live means choosing, funding, and testing a real options API
(Tradier / Tastytrade / IBKR) behind the same connector interface.
Each option proposal now carries a first-class contract — strike, expiration, and put/call right — validated at construction and re-checked by the guard. Positions key on full contract identity, so two contracts on the same underlying never net against each other, and the connector can render the standard OCC symbol for a broker. What's left before live options trading is purely the broker adapter: choosing, funding, and testing a real options API behind the (still fail-loud) connector above.
Every proposal is only ever a request. It becomes a position only after the guard passes it and you approve it. Here is every state it can land in:
One connector interface, swappable adapters, everything defaulting to a mock connector so the full propose → guard → approve → execute → log loop runs end to end without credentials or real money. An adapter goes live only when you fund the account and wire it in config.
Chazle never hands execution tools to the LLM. The
orchestrator only proposes; execution is invoked here, in plain code, after the guard
passes and you approve — including, for the Robinhood path, calling the broker's place-order
tool programmatically rather than letting the model call it. Before touching the broker the
engine writes a fsync'd execution_intent row and removes the proposal from the
durable queue, so a crash mid-execution can never double-fill.
| Asset class | Connector | Status |
|---|---|---|
| Prediction markets | Kalshi (RSA-PSS signed, idempotent) | Implemented; CFTC-regulated; verify against the demo API before real money |
| Equities | Robinhood Agentic MCP | Fail-loud stub — raises rather than fake a fill |
| Options | Tradier / Tastytrade / IBKR | Broker-agnostic fail-loud stub |
| All of the above | Mock (default) | Simulated fills — the loop runs with no credentials |
Every meaningful event is written to an append-only JSONL log — not just fills, but
the proposal and its full reasoning, every cap rejection, every kill-switch flip, and every
recorded P&L line. A trading system earns trust through the legibility and exactness of its
record; money is tracked in Decimal everywhere, never floats, so no cents are
silently lost.
The events you'll see: proposed, capped,
execution_intent, executed, rejected_by_user,
rejected_by_guard, execution_failed, kill_switch_engaged,
kill_switch_released, pnl_recorded, symbol_blocked,
symbol_unblocked, and mode_changed. The capped and
rejected_by_guard rows are the whole point — they are proof the limits were enforced
in code the model couldn't drift around.
The dashboard is a thin client over these endpoints. Humans sign in with a
username and password (invite-only accounts, admin or read-only
viewer) and get an HttpOnly session cookie plus a CSRF token;
automation uses the bearer token (CHAZLE_API_TOKEN), which is treated as admin.
Writes require admin; the whole surface can approve trades and flip the kill switch.
Every decision here follows from one priority: don't lose money, and keep control.
| Decision | Why |
|---|---|
| Approve / reject every trade (v1) | The only mode that satisfies “don't lose money” and “I control access” on day one. Autonomy-within-limits is a v2 graduation, earned after weeks of watching proposal quality — not a starting position. |
| Periodic review, not event-driven | “More deliberation per trade” is incompatible with an event listener that rewards reacting fast. A scheduled cycle gives the sub-agents time to cross-reference sources. |
| Guard in code, outside the LLM | Caps and the kill switch must be enforced where the model literally cannot drift from them over a long session — a plain function, not a system prompt. |
| Guard re-checks at approval | Queuing 100 individually-fine proposals can't collectively bust a cap: each is re-evaluated against live state the moment you approve it. |
| Decimal money everywhere | Trust comes from exact numbers. No binary float ever touches a dollar amount. |
| Dissent is first-class | The orchestrator surfaces sub-agent disagreement instead of averaging it away. A system that always reports unanimous high confidence is one to distrust. |
Even with hard caps, manual approval, and a kill switch, this system will lose money sometimes — that's true of trading, not a flaw in the design. The caps bound how much a bad stretch costs you; they don't prevent one. And this is a personal engine: pooling other people's money to trade on their behalf triggers real regulation (RIA / fund formation, a qualified custodian, CFTC/NFA exposure for the prediction-markets side) and is a separate legal track — not something to code around. None of this is legal advice.