Back to site

ARSA Guard · documentation

Docs

ARSA Guard is an MCP server that sits between your AI client (Claude, Cursor, Codex) and Robinhood Agentic Trading. Reads pass straight through. Every order is checked against your rules first, in plain code with no model in the loop. A broken rule is a HOLD, and a hold is final.

The guard only ever stops orders. None of its rules can place one.

Quick start

Needs Node.js 20 or newer.

npm install -g arsaguard
arsaguard                           # status: mode, sign-in, rules
arsaguard web                       # this dashboard, 127.0.0.1:4320
arsaguard try buy AAPL 1 --limit 180
arsaguard serve                     # MCP server, paper mode

Or run any command without installing: npx -y arsaguard <command>.

Modes

ModeCommandWhat happens to an order that passes
PaperserveFills in the local paper account at the last real price. No Robinhood account needed.
Live, dry-runserve --liveSent to Robinhood's review_equity_order, never placed. Reads pass through.
Live, armedserve --live --armedPlaced for real on your Robinhood account.

--armed without --live is refused.

Connect a client

Point the client at the guard instead of at Robinhood.

Claude Desktop, Cursor

claude_desktop_config.json or ~/.cursor/mcp.json

{
  "mcpServers": {
    "robinhood-guarded": { "command": "npx", "args": ["-y", "arsaguard", "serve"] }
  }
}

Claude Code

claude mcp add robinhood-guarded -- npx -y arsaguard serve

Add "--live" to the args for your Robinhood account, and "--armed" after it to place real orders.

Rules

Ten rules, all on by default. Change them in the app, or with set, on, off, block in the CLI. The agent can read them through guard_rules, never edit them.

IDDefaultHolds an order whenSet
max_order_usd$100a buy is larger than the cap (dollars, shares x limit, or shares x last price)usd=
daily_buy_usd$300today's buys plus this one go over the capusd=
daily_orders10this many orders were already let through todayn=
daily_loss$50a buy comes after this much in logged losses todayusd=
cool_down30 mina buy comes within this many minutes of a logged losing exitminutes=
limit_onlyonthe order is a market orderon/off
regular_hoursonit is outside Mon-Fri 9:30-16:00 New York, on an exchange holiday, or after 13:00 on an early-close dayon/off
earnings_block48 ha buy comes this many hours before the company reports (Nasdaq calendar)hours=
equities_onlyonit is an option, crypto or option exerciseon/off
blocklistemptya buy is for a symbol on your listblock SYM

How an order is decided

  1. Classify the tool. Order tools (place_equity_order, place_option_order, place_crypto_order, place_advanced_order, exercise_option) are checked. Cancels and declines pass. Any unknown tool whose name sounds like it moves money (place, submit, transfer, withdraw…) is treated as an order.
  2. Read the order. If the symbol or side cannot be read, it is held.
  3. Run every rule that is on. Buys are sized first; if the size cannot be worked out, or the earnings calendar cannot be read, it is held.
  4. Verdict. CLEAR only when every rule passes. Otherwise HOLD, with the reason returned to the agent.
  5. Record. Every decision is written to the hash-chained log.

Sells are checked by the rules that apply to every order (equities only, limit only, hours, daily orders). Size, loss and earnings rules apply to buys.

MCP tools

ToolModeDoes
guard_rulesallYour rules and whether each is on.
guard_log_lossallLog a losing exit: starts the cool down, counts toward the daily loss.
guard_auditallThe latest decisions.
get_equity_quotespaperLast price (Yahoo Finance).
get_portfolio, get_equity_orderspaperThe paper account and its fills.
get_earnings_calendarpaperUpcoming reports (Nasdaq).
review_equity_orderpaperRun the rules without placing.
place_equity_orderpaperRules first, then a paper fill.
Robinhood's toolslivePassed through; order tools are marked as checked by the guard.

CLI

arsaguardStatus: mode, sign-in, market, rules.
serve [--live] [--armed]The MCP server for your AI client.
try buy|sell SYM n [--limit 180] [--dollars 50] [--market]Test an order. Nothing is sent or logged. Exit code 2 on HOLD.
set ID key=valuee.g. set max_order_usd usd=250
on ID · off IDTurn a rule on or off.
block SYM · unblock SYMEdit the blocklist.
loss USD [note]Log a losing exit.
audit [n] [--verify]Recent decisions, or check the chain.
paper [reset CASH]The paper account; reset defaults to $1,000.
web [--port 4320]This dashboard, local only.
login · logoutRobinhood sign-in in your browser.

Add --json for machine-readable output.

The record

Each decision is one JSON line holding the hash of the line before it. Editing or deleting any past line breaks the chain from that point. Check it with audit --verify or Verify chain in the app.

Paper account

Starts with $1,000. Orders that pass fill at the last real price. Only marketable orders fill (a buy limit at or above the last price, a sell limit at or below); others are rejected, not queued.

Robinhood sign-in

login opens Robinhood's own sign-in page (OAuth with PKCE). The guard never sees your password. Tokens are saved on this machine only, readable by your user alone. logout deletes them. Live mode needs a Robinhood account with Agentic Trading access.

Dashboard security

The dashboard listens on 127.0.0.1 only. Each run creates a new session token that the page sends with every request. Requests without it, or from another host name, are refused.

Limits

  • Exchange holidays and 13:00 early closes follow the NYSE rules, computed each year. One-off closures the exchange announces at short notice are not known in advance.
  • Prices come from Yahoo Finance and earnings dates from Nasdaq's public calendar. Both are unofficial and can be late.
  • Losses made outside the guard only count once you log them.
  • Not financial advice. Not affiliated with Robinhood.

Files

~/.arsaguardEverything the guard keeps. Override with ARSAGUARD_HOME.
guard.jsonRules, losses, paper account.
guard-audit.jsonlThe record.
guard-oauth.jsonRobinhood tokens (mode 600).