Skip to main content

schwab_cli/
instructions.rs

1use crate::plan::llm_prompt;
2use crate::safety_config::{config_path, SafetyConfig};
3use serde_json::{json, Value};
4
5pub fn instructions_json(safety: &SafetyConfig) -> Value {
6    json!({
7        "role": "Schwab Trader API operator",
8        "product": "Trader API - Individual (Accounts and Trading Production v1.0.0)",
9        "base_url": schwab_api::TRADER_BASE_URL,
10        "discovery_sequence": [
11            "schwab --help --json",
12            "schwab capabilities --json",
13            "schwab env schema --json",
14            "schwab instructions --json",
15            "schwab disclaimer show",
16            "schwab disclaimer accept --yes"
17        ],
18        "operating_mode": {
19            "default": "agent",
20            "flags": ["--mode agent", "--mode human"],
21            "note": "Always prefer --json or --output json for automation"
22        },
23        "auth_flow": [
24            "Ensure SCHWAB_APP_KEY and SCHWAB_APP_SECRET are set (see env schema)",
25            "Run `schwab auth login` once; tokens persist on disk",
26            "Use `schwab auth status --json` before API calls",
27            "Access tokens expire ~30 minutes; refresh via `schwab auth refresh` or automatic refresh on API call"
28        ],
29        "account_ids": {
30            "rule": "Use encrypted hashValue from `schwab accounts numbers --json` as {accountNumber} in trading endpoints",
31            "never": "Do not confuse plain accountNumber with hashValue"
32        },
33        "output_contract": {
34            "envelope_fields": ["success", "command", "inputs", "data", "warnings", "errors", "next_actions", "timestamp"],
35            "formats": ["pretty", "json", "md"]
36        },
37        "trading_safety": {
38            "config_path": config_path(),
39            "config_command": "schwab safety show --json",
40            "disclaimer": {
41                "show": "schwab disclaimer show",
42                "accept": "schwab disclaimer accept --yes",
43                "status": "schwab disclaimer status --json",
44                "required_before_live_trading": true,
45                "docs": "README.md#disclaimer"
46            },
47            "hard_limits": safety.limits,
48            "require_preview_before_place": safety.require_preview_before_place,
49            "agent_rules": safety.agent_rules,
50            "safe_mode_default": true,
51            "trust_mode": {
52                "flag": "--trust",
53                "description": "Required with --yes for autonomous agent trading (non-interactive). Human mode uses interactive confirmation.",
54                "note": "CLI enforces safety.json limits even in trust mode"
55            },
56            "autonomous_trade_flags": ["--trust", "--yes"],
57            "dry_run_flag": "--dry-run"
58        },
59        "mutation_safety": {
60            "auth_policy": "auth refresh/logout require --yes in non-interactive mode",
61            "trading_policy": "orders place/cancel/replace and trade buy/sell require --trust --yes in agent mode, or interactive confirmation in human mode",
62            "preview_first": "Use `schwab orders preview --json` or rely on built-in preview before place"
63        },
64        "recommended_read_path": [
65            "schwab market info SGOV --json",
66            "schwab market hours --markets equity --json",
67            "schwab portfolio summary --json",
68            "schwab portfolio buying-power --account-number <hash> --json",
69            "schwab accounts numbers --json",
70            "schwab orders list <hash> --json"
71        ],
72        "market_data": {
73            "base_url": schwab_api::MARKET_DATA_BASE_URL,
74            "requires_portal_product": "Market Data Production",
75            "primary_research_command": "schwab market info <SYMBOL> --json",
76            "commands": {
77                "info": "schwab market info SGOV --json (quote + fundamentals + history + research hints)",
78                "info_multi": "schwab market info SGOV,JPST,AAPL --json",
79                "quotes": "schwab market quotes --symbols SGOV,JPST --fields quote,fundamental --json",
80                "quote": "schwab market quote SGOV --fields all --json",
81                "history": "schwab market history AAPL --period-type month --period 1 --frequency-type daily --json",
82                "company_info": "schwab market instrument --symbol AAPL --projection fundamental --json",
83                "hours": "schwab market hours --markets equity --json"
84            },
85            "agent_workflow": [
86                "schwab market info <symbol> --json for Schwab-side facts",
87                "Web search using data.researchHints.recommendedWebQueries for narrative, holdings, news",
88                "schwab portfolio summary --json for account context",
89                "schwab plan prompt --json → validate → dry-run → run with --trust --yes"
90            ],
91            "quote_fields": ["all", "quote", "fundamental", "reference", "extended", "regular"],
92            "instrument_projections": ["symbol-search", "fundamental", "search", "desc-search"]
93        },
94        "recommended_trade_path": [
95            "schwab portfolio buying-power --account-number <hash> --json",
96            "schwab market quotes --symbols <SYMBOL> --fields quote --json",
97            "schwab orders schema --json",
98            "schwab safety show --json",
99            "schwab orders validate --order '<json>' --json",
100            "schwab orders preview --account-number <hash> --order '<json>' --json",
101            "schwab orders place --account-number <hash> --order '<json>' --trust --yes --json"
102        ],
103        "buying_power": {
104            "rule": "Before any BUY, check cashAvailableForTrading via `schwab portfolio buying-power --account-number <hash> --json`",
105            "cli_enforcement": "trade buy and orders place reject buys when estimated cost exceeds available cash",
106            "funding_sequence": [
107                "If buying power is insufficient, sell source holdings first",
108                "Wait for sell fill: `schwab orders wait <hash> <order_id> --until filled --json`",
109                "Re-check buying power, then place the buy"
110            ]
111        },
112        "orders": {
113            "schema": "schwab orders schema --json",
114            "validate": "schwab orders validate --order '<json>' --json",
115            "supported_asset_types": ["EQUITY", "OPTION"],
116            "complexOrderStrategyType": ["NONE", "VERTICAL", "IRON_CONDOR", "CUSTOM", "..."],
117            "conditionalStrategies": ["OCO", "TRIGGER"],
118            "safety_flags": {
119                "allow_option_orders": "single-leg and spread option legs",
120                "allow_complex_orders": "multi-leg spreads (NET_DEBIT/NET_CREDIT)",
121                "allow_conditional_orders": "OCO and TRIGGER childOrderStrategies"
122            },
123            "option_symbology": "UNDERLYING(6) | YYMMDD | C/P | STRIKE(8) — e.g. XYZ   240315C00500000"
124        },
125        "trade_plans": {
126            "description": "LLMs generate YAML/JSON plans; CLI validates and executes them",
127            "schema": "schwab plan schema --json",
128            "llm_prompt": "schwab plan prompt --json",
129            "docs": "plans/TRADE_PLAN.md",
130            "llm_schema_reference": "docs/LLM_SCHEMA_REFERENCE.md",
131            "workflow_summary": llm_prompt().get("workflow")
132        },
133        "options_trading": {
134            "schema": "schwab options schema --json",
135            "chain": "schwab options chain --symbol SPY --json",
136            "positions": "schwab options positions --account-number <hash> --json",
137            "strategies_v1": ["vertical", "iron_condor"],
138            "workflow": [
139                "schwab options chain --symbol <UNDERLYING> --json",
140                "schwab options validate --strategy vertical --params '<json>' --json",
141                "schwab options preview --account-number <hash> --strategy vertical --params '<json>' --json",
142                "schwab options open --account-number <hash> --strategy vertical --params '<json>' --trust --yes --json"
143            ],
144            "skill": ".cursor/skills/schwab-options/SKILL.md",
145            "docs": "docs/OPTIONS_RULES.md"
146        },
147        "options_agent": {
148            "rules_schema": "schwab agent schema --json",
149            "validate": "schwab agent validate rules.yaml --json",
150            "dry_run_tick": "schwab agent run rules.yaml --dry-run --once --json",
151            "live_daemon": "schwab agent run rules.yaml --trust --yes",
152            "status": "schwab agent status --rules-file rules.yaml --json",
153            "example_rules": "rules/options-rules.example.yaml",
154            "llm_schema_reference": "docs/LLM_SCHEMA_REFERENCE.md",
155            "note": "Agent auto-executes vertical and iron condor entries/exits within safety.json and rules.yaml risk limits"
156        },
157        "system_prompt": "You operate the `schwab` CLI against Charles Schwab's Trader API. This is experimental software — use at your own risk. Before live trading, ensure the user has run `schwab disclaimer accept --yes`. Discover capabilities before acting. Use JSON output. Authenticate first. Use account hash values for trading. Read schwab safety show --json and obey agent_rules and hard limits. Preview before placement. Never pass --trust unless the user explicitly requests autonomous trading. For live agent trades use --trust --yes together."
158    })
159}