robinhood-for-agents
AI-native Robinhood trading interface. No MCP server required — this skill works standalone via the TypeScript client API and bun.
How to Use
Run Robinhood operations by executing TypeScript code with bun. The robinhood-for-agents npm package provides a full client library — just import it and call methods:
bun -e '
import { getClient } from "robinhood-for-agents";
const rh = getClient();
await rh.restoreSession();
// call any method, print results as JSON
const holdings = await rh.buildHoldings();
console.log(JSON.stringify(holdings, null, 2));
'
See client-api.md for all available methods and signatures.
MCP users: If you have the robinhood-for-agents MCP server configured, you may use MCP tools instead. See reference.md for tool parameters. MCP is optional — the client API above does everything the MCP tools do. Pick one mode per session and stay in it: the MCP server and a bun -e script are two separate token-refreshing processes, and refresh tokens are single-use, so interleaving them can poison one of them. In MCP mode, robinhood_check_session is the session check — it probes the API rather than just reading the keychain.
CRITICAL SAFETY RULES
- Always confirm before placing any order — show order preview, get explicit "yes"
- Show current price before order confirmation so user knows the cost
- Never place orders without user confirmation
- Fund transfers and bank operations are BLOCKED — refuse these requests
- Never place bulk cancel operations — cancel orders one at a time
- Never turn a "sell" into a short.
sell closes a long; sell_short opens a short with unlimited loss potential. Only short when the user asked to short, and label it SHORT SELL when confirming. A negative position quantity is a short — close it by buying, never by selling more. See trade.md
- Name the trading session. Outside regular hours, only limit orders execute; an order tagged to the wrong session silently queues for the next open instead of filling. Check with
robinhood_get_market_hours / getMarketHours() — never infer the session from the local clock
BLOCKED Operations (never use)
- Bulk cancel operations
- Fund transfers (withdraw/deposit)
- Bank unlinking
Routing
| User Intent |
Domain File |
Example Triggers |
| Auth / login / connect |
setup.md |
"setup robinhood", "connect to robinhood", "robinhood login" |
| Portfolio / holdings / positions |
portfolio.md |
"show my portfolio", "my holdings", "account summary" |
| Stock research / analysis |
research.md |
"research AAPL", "analyze TSLA", "due diligence on NVDA" |
| Buy / sell / short / orders / cancel |
trade.md |
"buy 10 shares of AAPL", "sell my TSLA", "short 10 SPY", "cancel my order" |
| Options / calls / puts / chains |
options.md |
"show AAPL options", "SPX calls", "0DTE options", "covered calls" |
| Watchlists / lists / "add to my list" |
watchlists.md |
"my watchlists", "add NVDA to my tech list", "remove TSLA from watchlist" |
| Scanners / screeners / saved screens |
reference.md |
"my scanners", "my saved screens", "what filters can I scan on" |
| Realized P&L / gains / "how did my trades do" |
reference.md |
"my realized gains", "P&L this year", "how did my trades do" |
| Tax lots / cost basis per holding |
reference.md |
"tax lots for AAPL", "cost basis of my NVDA lots", "which lots are long-term" |
Read the corresponding domain file for detailed workflow instructions.
Authentication Prerequisite
Before any data-fetching or trading operation, verify the session actually works. restoreSession() only loads tokens from the store — it does not prove they are still valid, so probe with a real call:
bun -e '
import { getClient, AuthenticationError } from "robinhood-for-agents";
const rh = getClient();
try {
await rh.restoreSession();
await rh.getAccountProfile(); // the probe — this is what proves the token works
console.log("logged_in");
} catch (e) {
console.log(e instanceof AuthenticationError ? `expired: ${e.name}` : `unknown: ${e}`);
}
'
logged_in → proceed.
expired (TokenExpiredError / AuthenticationError) → the tokens are dead and could not be refreshed. Follow setup.md to re-authenticate.
unknown → a transient/network failure. The session may well be fine — do not send the user through a browser re-login on this; retry once first.
MCP mode: call robinhood_check_session instead — it probes the API and returns logged_in / expired / unknown / not_authenticated. Only expired and not_authenticated warrant robinhood_browser_login.
Client Methods
The client exposes 70+ async methods across auth, portfolio, research, options, orders, watchlists, scanners, P&L, and tax lots.
- client-api.md — full method reference (signatures, options, examples) and the MCP↔client mapping table
- reference.md — MCP tool parameters (if using MCP mode instead of the client)
Important Notes
- Do NOT use
phoenix.robinhood.com — use api.robinhood.com endpoints only
- Multi-account is first-class: always ask which account when multiple exist
- Session tokens renew themselves: the client refreshes proactively (
24h before expiry) and again on a 401, so a session in regular use stays alive without a re-login. Access-token TTL varies (6-8.5 days observed) — never quote a fixed number
- Refresh tokens are single-use: every renewal issues a new one and instantly kills the old (and revokes the previous access token). Run one client at a time — MCP server or a
bun -e script, not both; a second process gets poisoned. It self-heals by re-reading the token store, but there is no cross-process lock
- Renewal only happens while the client is being used. A session left idle past the refresh-token lifetime lapses and needs a new browser login — see setup.md
1---2name: robinhood-for-agents3description: Trade stocks, options, and crypto on Robinhood — dual mode (MCP tools or TypeScript client).4---56# robinhood-for-agents78AI-native Robinhood trading interface. **No MCP server required** — this skill works standalone via the TypeScript client API and `bun`.910## How to Use1112Run Robinhood operations by executing TypeScript code with `bun`. The `robinhood-for-agents` npm package provides a full client library — just import it and call methods:1314```bash15bun -e '16import { getClient } from "robinhood-for-agents";17const rh = getClient();18await rh.restoreSession();19// call any method, print results as JSON20const holdings = await rh.buildHoldings();21console.log(JSON.stringify(holdings, null, 2));22'23```2425See [client-api.md](client-api.md) for all available methods and signatures.2627> **MCP users:** If you have the `robinhood-for-agents` MCP server configured, you may use MCP tools instead. See [reference.md](reference.md) for tool parameters. MCP is optional — the client API above does everything the MCP tools do. Pick **one** mode per session and stay in it: the MCP server and a `bun -e` script are two separate token-refreshing processes, and refresh tokens are single-use, so interleaving them can poison one of them. In MCP mode, `robinhood_check_session` is the session check — it probes the API rather than just reading the keychain.2829## CRITICAL SAFETY RULES301. **Always confirm before placing any order** — show order preview, get explicit "yes"312. **Show current price** before order confirmation so user knows the cost323. **Never place orders without user confirmation**334. **Fund transfers and bank operations are BLOCKED** — refuse these requests345. **Never place bulk cancel operations** — cancel orders one at a time356. **Never turn a "sell" into a short.** `sell` closes a long; `sell_short` opens a short with unlimited loss potential. Only short when the user asked to short, and label it **SHORT SELL** when confirming. A **negative** position quantity *is* a short — close it by **buying**, never by selling more. See [trade.md](trade.md#short-selling)367. **Name the trading session.** Outside regular hours, only limit orders execute; an order tagged to the wrong session silently queues for the next open instead of filling. Check with `robinhood_get_market_hours` / `getMarketHours()` — never infer the session from the local clock3738### BLOCKED Operations (never use)39- Bulk cancel operations40- Fund transfers (withdraw/deposit)41- Bank unlinking4243## Routing4445| User Intent | Domain File | Example Triggers |46|---|---|---|47| Auth / login / connect | [setup.md](setup.md) | "setup robinhood", "connect to robinhood", "robinhood login" |48| Portfolio / holdings / positions | [portfolio.md](portfolio.md) | "show my portfolio", "my holdings", "account summary" |49| Stock research / analysis | [research.md](research.md) | "research AAPL", "analyze TSLA", "due diligence on NVDA" |50| Buy / sell / short / orders / cancel | [trade.md](trade.md) | "buy 10 shares of AAPL", "sell my TSLA", "short 10 SPY", "cancel my order" |51| Options / calls / puts / chains | [options.md](options.md) | "show AAPL options", "SPX calls", "0DTE options", "covered calls" |52| Watchlists / lists / "add to my list" | [watchlists.md](watchlists.md) | "my watchlists", "add NVDA to my tech list", "remove TSLA from watchlist" |53| Scanners / screeners / saved screens | [reference.md](reference.md) | "my scanners", "my saved screens", "what filters can I scan on" |54| Realized P&L / gains / "how did my trades do" | [reference.md](reference.md) | "my realized gains", "P&L this year", "how did my trades do" |55| Tax lots / cost basis per holding | [reference.md](reference.md) | "tax lots for AAPL", "cost basis of my NVDA lots", "which lots are long-term" |5657Read the corresponding domain file for detailed workflow instructions.5859## Authentication Prerequisite60Before any data-fetching or trading operation, verify the session actually works. `restoreSession()` only loads tokens from the store — it does **not** prove they are still valid, so probe with a real call:61```bash62bun -e '63import { getClient, AuthenticationError } from "robinhood-for-agents";64const rh = getClient();65try {66 await rh.restoreSession();67 await rh.getAccountProfile(); // the probe — this is what proves the token works68 console.log("logged_in");69} catch (e) {70 console.log(e instanceof AuthenticationError ? `expired: ${e.name}` : `unknown: ${e}`);71}72'73```74- `logged_in` → proceed.75- `expired` (`TokenExpiredError` / `AuthenticationError`) → the tokens are dead and could not be refreshed. Follow [setup.md](setup.md) to re-authenticate.76- `unknown` → a transient/network failure. The session may well be fine — **do not** send the user through a browser re-login on this; retry once first.7778> **MCP mode:** call `robinhood_check_session` instead — it probes the API and returns `logged_in` / `expired` / `unknown` / `not_authenticated`. Only `expired` and `not_authenticated` warrant `robinhood_browser_login`.7980## Client Methods8182The client exposes 70+ async methods across auth, portfolio, research, options, orders, watchlists, scanners, P&L, and tax lots.8384- [client-api.md](client-api.md) — full method reference (signatures, options, examples) and the MCP↔client mapping table85- [reference.md](reference.md) — MCP tool parameters (if using MCP mode instead of the client)8687## Important Notes88- **Do NOT use `phoenix.robinhood.com`** — use `api.robinhood.com` endpoints only89- Multi-account is first-class: always ask which account when multiple exist90- Session tokens renew themselves: the client refreshes proactively (~24h before expiry) and again on a 401, so a session in regular use stays alive without a re-login. Access-token TTL varies (~6-8.5 days observed) — never quote a fixed number91- Refresh tokens are **single-use**: every renewal issues a new one and instantly kills the old (and revokes the previous access token). Run one client at a time — MCP server *or* a `bun -e` script, not both; a second process gets poisoned. It self-heals by re-reading the token store, but there is no cross-process lock92- Renewal only happens while the client is being used. A session left idle past the refresh-token lifetime lapses and needs a **new browser login** — see [setup.md](setup.md)