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}