{"id":49319317,"url":"https://github.com/major/schwab-agent","last_synced_at":"2026-05-05T13:02:03.029Z","repository":{"id":353165423,"uuid":"1218244418","full_name":"major/schwab-agent","owner":"major","description":"CLI tool for AI agents to trade via Charles Schwab APIs","archived":false,"fork":false,"pushed_at":"2026-04-22T18:45:12.000Z","size":206,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-22T19:28:50.578Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/major.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-22T17:20:00.000Z","updated_at":"2026-04-22T18:45:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/major/schwab-agent","commit_stats":null,"previous_names":["major/schwab-agent"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/major/schwab-agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/major%2Fschwab-agent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/major%2Fschwab-agent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/major%2Fschwab-agent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/major%2Fschwab-agent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/major","download_url":"https://codeload.github.com/major/schwab-agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/major%2Fschwab-agent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32305039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T09:34:17.070Z","status":"ssl_error","status_checked_at":"2026-04-26T09:34:00.993Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-26T17:00:41.827Z","updated_at":"2026-05-05T13:02:03.018Z","avatar_url":"https://github.com/major.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# schwab-agent\n\n[![CI](https://github.com/major/schwab-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/major/schwab-agent/actions/workflows/ci.yml)\n[![Go](https://img.shields.io/github/go-mod/go-version/major/schwab-agent)](https://go.dev/)\n[![codecov](https://codecov.io/gh/major/schwab-agent/branch/main/graph/badge.svg)](https://codecov.io/gh/major/schwab-agent)\n[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/major/schwab-agent/badge)](https://scorecard.dev/viewer/?uri=github.com/major/schwab-agent)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\nCLI tool for AI agents to trade via the Charles Schwab API. Single binary, JSON-first output, built-in safety guards.\n\n\u003e **Disclaimer:** This project is not affiliated with, endorsed by, or sponsored by Charles Schwab \u0026 Co., Inc. or any of its subsidiaries. \"Schwab\" and \"thinkorswim\" are trademarks of Charles Schwab \u0026 Co., Inc. This is an independent, open-source tool that uses Schwab's publicly available APIs.\n\n## Why\n\nAI agents need a reliable way to interact with brokerage APIs. schwab-agent wraps the Schwab Retail Trader and Market Data APIs behind a straightforward CLI with structured JSON output that agents can parse without guessing.\n\n## Install\n\n### From source\n\n```bash\ngo install github.com/major/schwab-agent/cmd/schwab-agent@latest\n```\n\n### From releases\n\nPre-built binaries for Linux and macOS (amd64/arm64) are available on the [releases page](https://github.com/major/schwab-agent/releases).\n\n### Build locally\n\n```bash\ngit clone https://github.com/major/schwab-agent.git\ncd schwab-agent\nmake build\n```\n\n## Getting started\n\n### 1. Create a Schwab developer app\n\nRegister at [developer.schwab.com](https://developer.schwab.com/) and create an app. You'll need your client ID and client secret.\n\n### 2. Configure\n\nCreate `~/.config/schwab-agent/config.json`:\n\n```json\n{\n  \"client_id\": \"your-client-id\",\n  \"client_secret\": \"your-client-secret\",\n  \"base_url\": \"https://api.schwabapi.com\",\n  \"base_url_insecure\": false,\n  \"callback_url\": \"https://127.0.0.1:8182\"\n}\n```\n\n`base_url` is the single outbound endpoint root for REST API calls and Schwab OAuth authorize/token requests. Leave it at the default for direct Schwab access, or point it at a Schwab-compatible proxy.\n\nIf your proxy terminates TLS with a local self-signed certificate, set `base_url_insecure` to `true` so outbound REST and OAuth token/refresh requests skip certificate verification. This is intentionally opt-in for local development only.\n\nOr use environment variables (these take priority over the config file):\n\n```bash\nexport SCHWAB_CLIENT_ID=your-client-id\nexport SCHWAB_CLIENT_SECRET=your-client-secret\nexport SCHWAB_BASE_URL=https://api.schwabapi.com   # default\nexport SCHWAB_BASE_URL_INSECURE=false              # default\nexport SCHWAB_CALLBACK_URL=https://127.0.0.1:8182  # default\n```\n\n### 3. Log in\n\n```bash\nschwab-agent auth login\n```\n\nOpens your browser for Schwab's OAuth2 flow. After authorization, tokens are stored locally and refreshed automatically.\n\n### 4. Check status\n\n```bash\nschwab-agent auth status\n```\n\n## Usage\n\nEvery command returns structured JSON. Success responses use a `{\"data\": ..., \"metadata\": ...}` envelope. Errors use structcli's top-level `StructuredError` shape, for example `{\"error\":\"unknown_flag\",\"exit_code\":12,\"message\":\"unknown flag: --bogus\",\"command\":\"schwab-agent quote get\",\"flag\":\"bogus\"}`. Domain errors use the same shape, with remediation text in `hint` when available.\n\nRun any command with `--help` to see detailed usage, examples, and available flags.\n\n### Quick examples\n\n```bash\n# Get a stock quote\nschwab-agent quote get AAPL\n\n# Get an option quote by contract details (instead of OCC symbol)\nschwab-agent quote get --underlying AAPL --expiration 2025-06-20 --strike 200 --call\n\n# List compact account identifiers for agent workflows\nschwab-agent account summary\n\n# List compact account identifiers and holdings in one response\nschwab-agent account summary --positions\n\n# List full account details and balances\nschwab-agent account list\n\n# Get option chains\nschwab-agent chain get AAPL\n\n# Get a compact option planning ticket\nschwab-agent option ticket get AAPL --expiration \u003cYYYY-MM-DD\u003e --strike 200 --call\n\n# Get the latest row for multiple moving averages in one technical-analysis run.\n# Technical-analysis output is always keyed by symbol under data.\u003cSYMBOL\u003e.\nschwab-agent ta sma AAPL --period 21,50,200\n\n# Batch the latest technical indicator row across several symbols\nschwab-agent ta atr AAPL MSFT NVDA\n\n# Get a compact technical-analysis dashboard in one history fetch\nschwab-agent ta dashboard AAPL\n\n# Place a limit order (requires safety config)\nschwab-agent order place equity \\\n  --symbol AAPL \\\n  --action BUY \\\n  --quantity 10 \\\n  --type LIMIT \\\n  --price 150.00 \\\n  --duration DAY\n\n# Preview an order without placing it, then save the exact reviewed payload\nschwab-agent order preview equity \\\n  --symbol AAPL \\\n  --action BUY \\\n  --quantity 10 \\\n  --type MARKET \\\n  --save-preview\n\n# Place the exact payload returned by previewDigest.digest\nschwab-agent order place --from-preview \u003cdigest\u003e\n\n# Show recent order activity, including filled/canceled/replaced orders\nschwab-agent order list --recent\n\n# Build order JSON offline\nschwab-agent order build equity \\\n  --symbol AAPL \\\n  --action BUY \\\n  --quantity 10 \\\n  --type LIMIT \\\n  --price 150.00 \\\n  --duration DAY\n\n# Use flag aliases (--instruction for --action, --order-type for --type)\nschwab-agent order place equity \\\n  --symbol AAPL \\\n  --instruction BUY \\\n  --quantity 10 \\\n  --order-type LIMIT \\\n  --price 150.00 \\\n  --duration DAY\n\n# Replace an option order by contract details\nschwab-agent order replace option 123456789 \\\n  --underlying AAPL \\\n  --expiration 2025-06-20 \\\n  --strike 200 \\\n  --call \\\n  --action BUY_TO_OPEN \\\n  --quantity 5 \\\n  --type LIMIT \\\n  --price 3.50 \\\n  --duration DAY\n\n# Use account nickname or number instead of hash\nschwab-agent account get -a \"My Roth IRA\"\nschwab-agent position list -a 12345678\n\n# Filter holdings for portfolio triage\nschwab-agent position list --all-accounts --symbol AAPL --symbol MSFT --sort value-desc\nschwab-agent position list --losers-only --min-pnl -500 --sort pnl-asc\n\n# Place from a JSON spec\nschwab-agent order place --spec @order.json\n```\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `auth` | Login, status, token refresh |\n| `account` | Compact summaries, full account details, hashes, set default, transactions |\n| `position` | List, filter, and sort positions for one or all accounts (with computed cost basis and P\u0026L) |\n| `quote` | Get quotes for one or more symbols (supports structured option flags) |\n| `order` | List, get, place, preview, build, cancel, replace (equity and option) |\n| `chain` | Option chain data (`get`, `expiration`) |\n| `option` | Option planning tickets that combine quote, chain, and OCC symbol context |\n| `history` | Price history for a symbol (alias: `price-history`) |\n| `ta` | Technical analysis with symbol-keyed JSON output (dashboard, sma, ema, rsi, macd, atr, bbands, stoch, adx, vwap, hv, expected-move) |\n| `indicators` | Technical analysis dashboard shortcut with symbol-keyed JSON output |\n| `analyze` | Combined quote and technical analysis dashboard |\n| `market` | Market hours and top movers |\n| `symbol` | Build and parse OCC option symbols (no auth required) |\n| `instrument` | Search instruments |\n\n### Global flags\n\n```text\n--account   Override the default account by hash, account number, or nickname\n--verbose   Enable verbose logging\n--config    Path to config file (default: ~/.config/schwab-agent/config.json)\n--token     Path to token file (default: ~/.config/schwab-agent/token.json)\n```\n\n## Safety\n\nschwab-agent has two layers of protection for operations that modify your account:\n\n1. **Config flag**: Set `\"i-also-like-to-live-dangerously\": true` in your config file to enable mutable operations (order placement, cancellation, replacement).\n2. **Preview digest flow**: Add `--save-preview` to `order preview` to store the exact payload locally for 15 minutes, then submit that same payload with `order place --from-preview \u003cdigest\u003e`. The digest is bound to the account, operation, endpoint, and canonical order JSON. It is a local safety reference, not a Schwab reservation or idempotency key.\n\nThis prevents accidental trades from misconfigured agents.\n\n## Agent integration\n\nschwab-agent is built for coding agents and LLM tools that need a reliable command contract instead of prose-only instructions. Use the generated files in this repo for workflow guidance, but use JSON Schema from the binary as the source of truth for commands and flags.\n\n### Claude Code and other skill-aware tools\n\nUse the checked-in `SKILL.md` when your tool supports Agent Skills, including Claude Code. It contains trigger phrases, command descriptions, flag tables, examples, and MCP server hints generated from the live CLI command tree.\n\nFor Claude Code, copy or symlink this repository's generated skill into your skills directory if you want it available outside this repo:\n\n```bash\nmkdir -p ~/.claude/skills/schwab-agent\nln -sf \"$(pwd)/SKILL.md\" ~/.claude/skills/schwab-agent/SKILL.md\n```\n\nIf you already have a custom skill at that path, review or back it up first because `ln -sf` replaces the existing file or symlink.\n\nYou can also keep using the checked-in `SKILL.md` directly when working inside this repository. Regenerate it after command, flag, example, or help text changes:\n\n```bash\nmake docs\n# or\ngo run ./cmd/generate-docs/\n```\n\n`make docs` updates both `SKILL.md` and `llms.txt`. Commit the regenerated files with the code change so agents see the same command surface as the binary.\n\n### OpenCode and Codex\n\nOpenCode and Codex use `AGENTS.md` as project instructions. This repo keeps `AGENTS.md` hand-written because it contains architecture, build, test, safety, and project-convention context that cannot be generated from the CLI tree.\n\nWhen using OpenCode or Codex, start in the repository root so the tool can load `AGENTS.md`, then point it at `SKILL.md` or `llms.txt` when it needs the full generated command reference. Update `AGENTS.md` by hand when project structure, conventions, build commands, or safety rules change.\n\n### llms.txt\n\n`llms.txt` follows the llms.txt convention for LLM-friendly documentation indexes. Treat it as a compact generated command reference for tools or workflows that prefer a single Markdown index. It is generated by the same `make docs` target as `SKILL.md`.\n\n### Command discovery for shell automation\n\nFor shell-based automation, run `schwab-agent --jsonschema=tree` first when you need to discover commands, flags, enum values, defaults, config keys, or environment variable bindings. Treat this JSON Schema tree as the authoritative command contract, then use `SKILL.md`, `llms.txt`, and `--help` for workflow guidance and examples after choosing the command and flags from the schema.\n\n```bash\n# Canonical shell-agent discovery path for the full CLI contract\nschwab-agent --jsonschema=tree\n\n# Schema for a specific subcommand\nschwab-agent quote --jsonschema\n\n# Flat JSON Schema for the entire CLI, useful for tools that do not need hierarchy\nschwab-agent --jsonschema\n```\n\n## Development\n\n```bash\nmake build      # Build binary\nmake test       # Run tests (race detector + coverage)\nmake lint       # Run golangci-lint\nmake install    # Install to /usr/local/bin\nmake clean      # Remove binary\n```\n\nTests use `httptest.NewServer()` for API mocking, testify for assertions, and `t.TempDir()` for file I/O. No external services needed.\n\n### Project layout\n\n```text\ncmd/schwab-agent/       Entry point, command tree construction\ninternal/\n  auth/                 OAuth2 flow, token lifecycle, config\n  client/               Schwab API HTTP client\n  commands/             CLI command handlers\n  apperr/               Typed error hierarchy with exit codes\n  models/               API data structures\n  orderbuilder/         Order construction and validation\n  output/               JSON success envelopes and structured error output\n```\n\n## Exit codes\n\n| Code | Meaning |\n|---|---|\n| 0 | Success |\n| 1 | Validation or order build error |\n| 2 | Symbol or account not found |\n| 3 | Authentication required, expired, or failed |\n| 4 | HTTP error from Schwab API |\n| 5 | Order rejected |\n| 10-19 | structcli input errors, such as missing flags, invalid flag values, and unknown commands |\n| 20-29 | structcli config or environment errors |\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmajor%2Fschwab-agent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmajor%2Fschwab-agent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmajor%2Fschwab-agent/lists"}