-
Notifications
You must be signed in to change notification settings - Fork 0
Reference README
Architecture | Current installation guide | Guide home
This page preserves the complete README.md from revision 9626273.
It contains earlier measurements, examples, diagrams, and explanations.
Installation steps, platform support, test counts, and status claims describe that edition and can differ from the current guides.
Repository links and images point to the same revision, so later file changes do not change the referenced material.
The original body is retained, with relative file links expanded for this wiki page.
Option analytics that an AI agent can drive, and that a person can read.
Import a permitted chain, compute the full Greek ladder, measure where dealer hedging concentrates, build and rank multi-leg structures, simulate the underlying forward from its own behaviour, test a rule against history, and track what you actually took. Every step writes a schema-validated artifact. A local dashboard renders them.
curl -fsSL https://raw.githubusercontent.com/Iman/agent-driven-options-desk-and-skills/main/install.sh | bash
optiondesk chain SPY --from-file chain.csv --data-source "broker export" --accept-data-rights
optiondesk greeks && optiondesk dashboard
Then ask your agent "where are the gamma walls on SPY?" and it will use the skills this installs. Eight other ways in, including Codex, ChatGPT and a container, are in INSTALL.md.
docker run --rm -v "$PWD/artifacts:/artifacts" \
ghcr.io/iman/agent-driven-options-desk-and-skills chain SPY
The image is the CLI and the dashboard, for a machine with no Python. It cannot install skills into an agent running outside it, and it refuses to run without a mounted artifact directory rather than writing your results into a container that is about to be deleted.

Every screenshot on this page is one live run against free data, taken on
2026-09-03: SPY at the 2026-10-16 expiry with 2026-09-30 and 2026-11-30
also on disk, 394, 576 and 386 contracts, all twenty-three structures built
and fifteen of them backtested over five years, one of which, the ratio
spread, refused to divide by an unbounded loss and says so.
None of it has been cleaned up. Ten of the 394 contracts fall back to the
provider's published volatility and fifteen carry none at all, and the
page says both for itself rather than presenting a chain that solved
perfectly; the month-end 2026-09-30 chain, with wider wings, carries a
degradation banner because 127 of its 576 contracts fell back. An earlier
version of this run showed 48 fallbacks on the monthly expiry and an amber
banner; an audit found the solver was refusing contracts it could
identify, and fixing that took the fallbacks from 48 to 2 on the August
chain and to 10 on this one. The images are captured by
scripts/screenshots.py, which anyone can rerun.
To reproduce all of it in one command:
./demo.sh
It pulls two expiries for SPY and QQQ, computes the ladder and the
positioning, builds and ranks every structure, simulates the underlying
forward, backtests each structure over five years, opens and marks a paper
position, then serves the dashboard over the result. --dry-run prints
every command without running one, and --help lists the rest.
Research software. Not investment advice, not a recommendation, not a solicitation. Modelled premiums are not fills, backtested results are not achievable results, and nothing here knows your circumstances. Read DISCLAIMER.md first.
Free for any noncommercial purpose. Commercial use needs a written agreement: see LICENSES.md. Contributing · Backlog · Code of conduct · Security
- Install
- Usage
- Use the skills
- Hosted example prompts
- Five minutes to a full desk
- Architecture
- How data flows
- Command reference
- Using it from an agent
- The rules this project holds itself to
- Artifacts and contracts
- Data providers
- Asset classes
- The dashboard
- Extending it
- Loops and the graph
- Development
- Documentation map
- What has been verified
- Licensing
Pick by what you want. The first gives you the whole desk; the second and third give you the skills alone, which work as knowledge with no Python installed at all.
curl -fsSL https://raw.githubusercontent.com/Iman/agent-driven-options-desk-and-skills/main/install.sh | bash
Or from a checkout, ./install.sh. Either way it creates a virtualenv
under ~/.optiondesk, installs the shell and the analytics engine, links
optiondesk and optiondesk-mcp into ~/.local/bin, copies the skills
into ~/.claude/skills and ~/.agents/skills, so Claude Code and Codex
each find them, and registers the MCP server with every agent runtime CLI
it finds. Re-running is safe. ./install.sh --uninstall
reverses it and removes only what it created.
Useful flags: --dry-run to see the plan and change nothing, --no-engine
for the shell alone, --skills-only for no Python at all, --no-mcp
to leave runtime configs untouched, --prefix to install elsewhere.
Installer 0.1.0 completed a checkout installation on macOS with Python 3.13.13. It installed the shell and analytics engine at version 0.2.0 and linked both commands.
It copied all six skills to both user skill directories. Claude Code and Codex both reported that the MCP server was connected. Gemini CLI did not register automatically, and the installer printed its manual registration command.
The live test listed SPY expiries, wrote a chain artifact, computed a Greek
ladder, and returned HTTP 200 from the dashboard. The delayed Yahoo results
reported degraded: false.
The reused environment contained x86_64 scientific wheels. On Apple silicon, use the same process architecture for installation, CLI, and MCP execution.
npx skills add Iman/agent-driven-options-desk-and-skills
npx skills add Iman/agent-driven-options-desk-and-skills --skill options-greeks options-strategy
npx skills add Iman/agent-driven-options-desk-and-skills --list
The CLI detects which agents you have and asks where to install. Claude
Code reads .claude/skills/; universal agents share .agents/skills/.
If you run that from inside an agent session, by asking Claude Code to
install them for you, the CLI runs non-interactively and may install only
to .agents/skills/, which Claude Code does not read. Name the agent:
npx skills add Iman/agent-driven-options-desk-and-skills -a claude-code
codex plugin marketplace add Iman/agent-driven-options-desk-and-skills
codex plugin add option-desk@option-desk
Codex also finds the skills with no plugin at all. It scans, in order,
.agents/skills in the working directory, the same in the parent
directory, the same at the repository root, then ~/.agents/skills for
your user and /etc/codex/skills for the machine. This repository
symlinks the repository-root one to shell/skills, and symlinked skill
folders are documented as followed, so cloning it is enough.
Browser ChatGPT cannot run the local MCP process. It can use the hosted MCP service after the plugin owner registers that service. The hosted service can process a user attachment privately. It does not fetch Yahoo or personal Alpha Vantage data.
The public submission is one Option Desk plugin with hosted MCP and four
supporting skills. Build it with python3 scripts/package.py.
dist/option-desk-hosted.zip contains the complete plugin.
dist/option-desk-skills.zip contains the four skills for the MCP submission's
Skills page. Configure https://optiondesk.avidquant.com/mcp separately in
the portal. See the submission pack for listing text,
starter prompts, and evaluation cases.
The build retires the standalone skills-only plugin archive. Local skill archives remain available for advanced use. The public listing covers snapshot validation, Greeks, positioning, and strategy plots. Simulation and backtesting remain local capabilities. Test the hosted workflows before publishing.
/plugin marketplace add Iman/agent-driven-options-desk-and-skills
/plugin install option-desk@option-desk
That adds the six skills, six commands, two agents and the MCP server declaration in one step. The commands and agents come only through this path; the skills CLI installs skills.
/plugin marketplace add Iman/agent-driven-options-desk-and-skills
/plugin install option-desk-hosted@option-desk
The same marketplace carries a second plugin, option-desk-hosted, which
declares the remote Streamable HTTP MCP at
https://optiondesk.avidquant.com/mcp and brings the four skills that
match it. Codex reads the same manifest. The service serves a synthetic
sample and privately processes an option-chain snapshot you are permitted
to send; it fetches no market data and places no orders, and its own
privacy policy and terms are linked from PRIVACY.md. Install one plugin
or the other, not both: the two servers expose tools with the same names.
git clone https://github.com/Iman/agent-driven-options-desk-and-skills.git
cd agent-driven-options-desk-and-skills
python -m venv .venv && . .venv/bin/activate
pip install -e "shell[yahoo,dev]" -e engine
optiondesk doctor
Add -e agent for the LangChain bindings and the graph.
INSTALL.md covers two more paths, zip upload for claude.ai in the browser
and the MCP server on its own, along with the flags in full.
Python 3.11 or newer is required for the tools. User-data imports need no API key or provider request. The skill-only paths need no Python.
Ask for what you want. The skill that fits loads itself.
"What are the Greeks on SPY for the September expiry?" options-greeks
"Where are the gamma walls on QQQ?" options-positioning
"What would an iron condor on TLT pay?" options-strategy
"What is the downside on SPY over the next month?" options-simulation
"Has selling condors on SPY actually worked?" options-backtest
Or drive it directly, either as a command in an agent runtime or on the terminal:
/desk-open SPY a chain, a ladder, positioning, every structure ranked
/desk-risk SPY 30 project forward, then hand it to the risk reviewer
/desk-test SPY iron_condor backtest and forward test, with the benchmark
/desk-watch SPY report only what materially changed
/desk-complete SPY drive the artifact set to completeness
optiondesk expiries SPY what is listed, and what you already hold
optiondesk chain SPY pull it
optiondesk compare every structure, ranked
optiondesk plots SPY write PNG charts for chat or reports
optiondesk dashboard serve the charts at 127.0.0.1:8787
Only upload data that you can send for private analysis. A user statement does not change the provider licence.
optiondesk chain SPY \
--from-file chain.csv \
--data-source "broker export" \
--accept-data-rights
optiondesk greeks
optiondesk exposure
optiondesk strategy iron_condor
optiondesk plots SPY --snapshot ~/TradingDesk/option-desk/chain_SPY_2026-09-18.json
optiondesk dashboard
The importer accepts CSV and JSON. It normalizes documented column aliases,
C or P codes, numeric commas, and clear percentage units. The artifact
lists each repair in normalization.
The importer does not invent market values. It rejects missing spot, expiry,
strike, option type, source, duplicate contracts, and invalid numeric values.
If chat receives an unclear attachment, it calls option_snapshot_schema.
Then it corrects safe format errors and asks only for missing required values.
The imported chain uses the existing artifact path. Greeks, positioning, strategies, plots, comparisons, and the local dashboard use that same artifact. User-data plot images include a solid private-research warning.
Ask a normal question. You do not have to type a skill name. Codex, Claude, or ChatGPT selects the matching skill from the request. You can name a skill when you want to force a specific workflow.
Every skill reports missing facts. It does not fill them in. No skill places an order, selects a trade for you, or gives investment advice.
Install the full desk before you use these skills. The installer adds the skills and connects the local MCP server.
| Skill | Ask this | Result |
|---|---|---|
desk-setup |
"Install Option Desk and check why its MCP tools are missing." | Runs the setup and health checks. It does not analyze options. |
options-greeks |
"Show the Greek ladder and Greek plots for SPY's nearest expiry." | Imports or retrieves a chain, calculates sixteen Greeks, and returns charts. |
options-positioning |
"Show SPY dealer gamma exposure, walls, max pain, and volatility smile." | Calculates chain-wide geometry and states the assumed dealer-sign convention. |
options-strategy |
"Build and plot a 30-day SPY iron condor, with both breakevens and maximum loss." | Builds a structure from the chain and reports legs, payoff, Greeks, and quoted-spread friction. |
options-simulation |
"Simulate SPY for 30 days and show value at risk and expected shortfall." | Fits the GARCH-t model to price history and returns the predictive distribution. |
options-backtest |
"Backtest a 30-day SPY iron condor and compare it with buy and hold." | Reports modelled results, uncertainty tests, drawdown, and the benchmark. |
Local provider access is subject to the provider's terms. Yahoo access is for acknowledged personal research only. Do not use a personal provider key in a hosted or public service.
The public plugin has a smaller skill set because its MCP server does not
fetch market data. It supports the SYNTH sample and permitted user-supplied
CSV or JSON data.
| Skill | Ask this | Result |
|---|---|---|
option-data-import |
"Validate my attached option chain. Its source is [source], and I confirm that I may send it for private analysis." | Checks the schema, makes only safe format repairs, and explains all remaining errors. |
options-greeks |
"Plot the Greeks from my attached chain." | Returns a Greek PNG in the conversation. |
options-positioning |
"Show gamma exposure and the volatility smile from my attached chain." | Returns positioning figures or plots with the source and capture time. |
options-strategy |
"Build an iron-condor payoff plot from my attached chain." | Returns a payoff PNG, legs, breakevens, limits, and model assumptions. |
Use this sequence in ChatGPT:
- Mention the Option Desk plugin.
- Attach one permitted CSV or JSON option-chain snapshot.
- Name the source. Confirm that you may send it for private analysis.
- Ask Option Desk to validate the file before it calculates results.
- Ask for a Greek, positioning, or strategy plot.
- Ask Option Desk to delete a private dashboard when you finish with it.
Do not attach account numbers, credentials, API keys, names, or portfolio positions. A rights confirmation does not override the source provider's licence. The hosted service does not describe an attachment as live or verified.
To try the hosted tools without an upload, ask: "Show the SYNTH dealer gamma plot." The answer must identify the result as synthetic sample data.
Run python3 scripts/package.py. Use each artifact for its stated purpose:
| Archive | Use it for |
|---|---|
dist/option-desk-skills.zip |
The OpenAI plugin Skills page. It contains the four hosted skill roots. |
dist/option-desk-local-skills.zip |
Local skill import. It contains all six local skills. |
dist/option-desk-hosted.zip |
Complete public plugin with hosted MCP, four skills, manifests, and images. |
The hosted MCP URL is a separate plugin setting:
https://optiondesk.avidquant.com/mcp. Uploading a skills ZIP does not connect
the MCP server by itself.
Use these prompts with the Option Desk hosted MCP connection. SYNTH is synthetic sample data.
Show the SYNTH Greek ladder plot.
Show the SYNTH market plot, including dealer gamma exposure, open interest, volume, and volatility smile.
Show the SYNTH option strategy comparison plot.
Show the payoff plot for a SYNTH iron condor. Explain its breakevens and maximum gain and loss.
Use option_plots with plot="all" to show the SYNTH market chart, Greek ladder, and strategy comparison in one widget.
Is SYNTH live market data? State its source, expiry, and spot price.
Show today’s live AAPL Greek ladder.
Expected: Requests a user-supplied chain and explains that this service does not fetch live data.
Backtest the SYNTH iron condor over the last year.
Expected: Explains that SYNTH has no price history and does not invent backtest results.
Run a complete options research demonstration using only the SYNTH sample.
1. Check the service status. State the data source, expiry, spot price, and available capabilities.
2. Use option_report_plots once to return the market chart, Greek ladder, strategy comparison, and payoff charts for an iron condor, bull put spread, and straddle. Return all six charts in one widget. Do not make separate or parallel plot calls.
3. Explain how gamma, theta, and vega vary across strikes. Distinguish per-contract Greeks from assumed dealer positioning.
4. Compare the three strategies using the same expiry. Show their legs, premiums, breakevens, maximum gain and loss, net delta, gamma, theta, and vega in one table. Include quoted-spread cost estimates only if available.
5. Compare expiration outcomes at underlying prices of 90, 100, and 110. Use returned calculations or explicitly label calculations derived from the returned legs. State contract multipliers and units.
6. Explain how each structure responds to a rise in implied volatility before expiry. Keep this separate from expiration payoff.
7. Identify missing inputs and modeling assumptions. If a tool fails or a metric is unavailable, report that limitation. Do not invent values or substitute another strategy silently.
Use actual plot tools for every chart. Do not treat a successful tool call as proof that I can see the images. Keep synthetic-data labels visible. Do not fetch live prices, claim historical performance, place orders, or recommend a trade.
optiondesk expiries SPY # what is listed, what you have
optiondesk chain SPY --expiry 2026-09-18 # pull it
optiondesk greeks --band 0.06 # sixteen Greeks per contract
optiondesk exposure # walls, flip, max pain, smile
optiondesk plots SPY # market and Greek charts as PNG files
optiondesk compare # every structure, ranked
optiondesk simulate SPY --horizon 14 # GARCH-t posterior and fan
optiondesk backtest SPY iron_condor # five years, modelled premiums
optiondesk forward open --strategy iron_condor --thesis "range bound"
optiondesk dashboard # http://127.0.0.1:8787
Each command prints a JSON summary and writes one artifact. The dashboard reads artifacts and writes nothing.
If an MCP user asks for plots, option_plots returns PNG images in the tool
result. The user does not need the dashboard or a localhost URL.
Three packages under one licence, joined by one adapter. Eight ways in, one set of artifacts out.
flowchart TB
subgraph clients["Ways in"]
claude["Claude Code<br/>reads SKILL.md"]
codex["Codex<br/>reads .agents/skills"]
gemini["Gemini CLI<br/>reads GEMINI.md"]
human["A person<br/>types commands"]
end
mcp["MCP server<br/>stdio, standard library only<br/>12 tools"]
cli["CLI<br/>optiondesk chain, greeks, exposure, plots,<br/>strategy, compare, simulate,<br/>backtest, forward"]
subgraph shell["shell"]
providers["Provider registry<br/>resolve by capability,<br/>not by vendor"]
contracts["JSON contracts<br/>8 schemas + validator"]
artifacts["Artifact writer<br/>atomic, provenance,<br/>degraded and notes"]
bridge["engine_bridge<br/>THE ONLY IMPORT<br/>OF THE ENGINE"]
end
subgraph engine["engine (the numbers)"]
pricing["pricing<br/>Black-Scholes-Merton,<br/>16 Greeks, implied vol"]
strategies["strategies<br/>payoff, playbook,<br/>outlook, friction"]
analytics["analytics<br/>gamma exposure, walls,<br/>max pain, smile, ranking"]
simulation["simulation<br/>GARCH-t by MCMC,<br/>paths, VaR and ES"]
backtest["backtest<br/>runner, statistics,<br/>forward marking"]
end
yahoo[("Yahoo<br/>free, delayed")]
disk[("Artifact directory<br/>~/TradingDesk/option-desk")]
dash["Dashboard<br/>FastAPI or stdlib,<br/>ECharts vendored"]
claude --> mcp
codex --> mcp
gemini --> mcp
human --> cli
mcp --> cli
cli --> providers
cli --> bridge
providers --> yahoo
bridge --> pricing
bridge --> strategies
bridge --> analytics
bridge --> simulation
bridge --> backtest
cli --> contracts
contracts --> artifacts
artifacts --> disk
disk --> dash
style engine fill:#2d1b3d,stroke:#7c3aed
style shell fill:#0f2942,stroke:#2f6feb
style bridge fill:#3d2b1b,stroke:#b45309
Why the boundary exists. The shell fetches data, validates it and
writes files. The engine turns numbers into analytics. They are separate
packages with separate licences, and engine_bridge is the only place the
shell imports the engine, so the boundary is checkable with one grep. An
audit caught a command importing the engine directly; it was harmless at
runtime and it broke the invariant every document here asserts, so it was
routed back through the bridge.
Without the engine installed, the shell still runs: chain writes a
degraded snapshot using the provider's published volatility, and greeks
returns a structured error telling you to install the engine.
Every arrow is an artifact on disk. Nothing is held in memory between commands, so any step can be re-run, inspected, or replaced.
flowchart LR
provider[("Provider")] -->|quotes| chain["chain<br/><i>chain_SYM_EXPIRY.json</i>"]
provider -->|daily closes| sim["simulate<br/><i>simulation_SYM_Nd.json</i>"]
provider -->|daily closes| bt["backtest<br/><i>backtest_SYM_STRAT.json</i>"]
chain --> greeks["greeks<br/><i>greeks_SYM_EXPIRY.json</i>"]
chain --> exposure["exposure<br/><i>exposure_SYM_EXPIRY.json</i>"]
chain --> strategy["strategy<br/><i>strategy_SYM_NAME_EXPIRY.json</i>"]
strategy --> compare["compare<br/><i>comparison_SYM_EXPIRY.json</i>"]
strategy --> forward["forward<br/><i>forward_ledger.json</i>"]
chain --> forward
strategy --> sim
greeks --> dash["dashboard"]
exposure --> dash
compare --> dash
sim --> dash
bt --> dash
forward --> dash
Two commands take a different input on purpose. simulate and backtest
read the underlying's price history, not the option chain, because they
answer questions about the underlying's own behaviour. That is why the
dashboard files them under the symbol rather than under an expiry.
sequenceDiagram
participant A as Agent
participant M as MCP server
participant C as CLI command
participant P as Provider
participant E as Engine
participant D as Disk
A->>M: tools/call option_chain_snapshot {symbol: SPY}
M->>C: chain.run(args)
C->>P: resolve(option_chain) then fetch
P-->>C: 607 contracts, spot, listed expiries
C->>E: implied_vol per contract (via bridge)
E-->>C: 595 solved, 12 refused as unidentified
C->>C: validate against chain_snapshot schema
C->>D: atomic write, tmp then replace
C-->>M: {artifact, contracts, with_iv, degraded, notes}
M-->>A: JSON summary
Those counts are one real pull, SPY expiring 2026-09-18, taken on 2026-08-30. They are an illustration rather than an invariant: the next chain has different numbers, and the artifact they came from is regenerated by the next run.
The twelve refusals matter. A contract whose price carries no volatility
information gets iv: null and is counted, never defaulted, because a
guessed volatility produces a complete and entirely fictional Greek ladder
that looks exactly as authoritative as a real one.
optiondesk simulate fits a GARCH(1,1)-t posterior by Metropolis-Hastings
in pure Python: single threaded, no vectorisation, no progress output
between starting and finishing. The work is (draws + burn) x chains
iterations, each walking every observation in the history.
Measured here, on an eighteen core arm64 machine with 1253 daily observations:
draws 3000 burn 1000 chains 2 about 8 seconds
draws 6000 burn 2000 chains 4 about 27 seconds
A slower or single core machine takes proportionally longer, and a long history at a high draw count runs for minutes. The command prints one line to stderr before it starts, naming the iteration count and a rough duration, so you can tell a working run from a stuck one. Wait for it.
Killing the run writes nothing. Lowering --draws to make it finish
sooner is the surest way to produce converged: false, and an unconverged
posterior is one whose quantiles must not be quoted.
| Command | What it does | Writes |
|---|---|---|
optiondesk expiries [SYM] |
Every expiry a provider lists, with days to expiry, and which you already hold. No symbol lists on-disk only, with no network. | nothing |
optiondesk chain SYM |
Retrieve a permitted chain or import private user data. --expiry, --rate, --dividend-yield, --from-file, --data-source, --accept-data-rights
|
chain_SYM_EXPIRY.json |
optiondesk greeks |
Sixteen Greeks per contract from its own volatility. --band, --type, --snapshot
|
greeks_SYM_EXPIRY.json |
optiondesk exposure |
Dealer gamma by strike, walls, flip, max pain, put-call ratios, smile geometry. | exposure_SYM_EXPIRY.json |
optiondesk plots SYM |
Retrieve or read a chain and write opaque PNG charts. --snapshot, --from-file, --data-source, --accept-data-rights, --expiry, --band
|
plots_SYM_EXPIRY_market.png, plots_SYM_EXPIRY_greeks.png
|
optiondesk strategy NAME |
Build one structure. --list, --recommend N, --vol-view, --size, --owns-underlying, --direction-unknown; and for time spreads --far-snapshot, --kind, --offset
|
strategy_SYM_NAME_EXPIRY.json |
optiondesk compare |
Every buildable structure, ranked by expected return on capital at risk. | comparison_SYM_EXPIRY.json |
optiondesk simulate SYM |
GARCH-t posterior by MCMC, predictive fan, VaR and ES, per-structure distributions. --horizon, --paths, --draws
|
simulation_SYM_Nd.json |
optiondesk backtest SYM STRAT |
A structure across real history with modelled premiums, plus significance tests and a benchmark. | backtest_SYM_STRAT_Nd.json |
optiondesk forward ACTION |
Paper ledger: open, mark, close, status. |
forward_ledger.json |
optiondesk keys ACTION |
Provider credentials: list, set, unset, path. Values are prompted for with hidden input and never printed in full. |
~/.optiondesk/config.env |
optiondesk doctor |
Engine, providers, credentials, artifact directory. | nothing |
optiondesk dashboard |
Serve the dashboard. --host, --port
|
nothing |
Twelve build from a single expiry: long_call, long_put,
bull_call_spread, bear_put_spread, cash_secured_put, covered_call,
protective_put, straddle, strangle, iron_condor, iron_butterfly,
long_call_butterfly. Two more need a second expiry and build from a
pair of snapshots: calendar_spread and diagonal_spread, through
--far-snapshot, or by letting the command find the next expiry on disk
itself.
Three more are asymmetric by design: ratio_spread, financed by selling
more than you buy and therefore uncapped on the short side;
broken_wing_butterfly, whose unequal wings remove the risk on one side
and often open for a credit; and jade_lizard, a short put against a short
call spread, which carries no upside risk when the credit collected exceeds
the width of that spread. The jade lizard reports whether that condition
actually holds for the legs it selected rather than claiming it
structurally.
Seventeen in all.
Each is tagged with which of the five directions it needs, which is what
--recommend ranks against:
flowchart LR
sb["-2<br/>strong bearish"] --- mb["-1<br/>mild bearish"] --- n["0<br/>neutral"] --- mu["+1<br/>mild bullish"] --- su["+2<br/>strong bullish"]
sb -.-> lp["long put<br/>protective put"]
mb -.-> bps["bear put spread"]
n -.-> ic["iron condor<br/>iron butterfly<br/>butterfly<br/>cash-secured put"]
mu -.-> bcs["bull call spread<br/>covered call"]
su -.-> lc["long call<br/>straddle, strangle"]
Three of the five sit inside the one standard deviation expected move and two are extreme. A spread reaches maximum profit on a normal move, while a naked long option needs an extreme one.
The same capabilities reach every runtime, three different ways.
flowchart TB
skill["shell/skills/*/SKILL.md<br/>one source of truth"]
gen["shell/tools/gen_runtime_docs.py"]
agents["AGENTS.md<br/>rules and commands<br/>for Codex"]
gemini["GEMINI.md<br/>for Gemini CLI"]
claude["Claude Code reads<br/>SKILL.md directly"]
mcpserver["optiondesk-mcp<br/>typed tool schemas"]
skill --> gen
gen --> agents
gen --> gemini
skill --> claude
skill -. "same capabilities" .-> mcpserver
mcpserver --> claude
mcpserver --> agents
mcpserver --> gemini
Edit a skill, run the generator, and every runtime gets the change. A test
compares the generated text against what is on disk, so a stale
AGENTS.md fails the suite.
Those files also carry a command reference read from the argparse parsers
themselves rather than written by hand. Four commands, expiries, keys,
plots and dashboard, have no skill of their own, so without that section a
Codex or Gemini user had no way to learn they were there. A test asserts
every subcommand the real parser exposes appears in both copies, so a
command added later without documentation fails the suite.
The two files differ in what else they carry, and the difference is the
point. Gemini CLI has no skill discovery, so GEMINI.md compiles all six
skills into itself. Codex scans .agents/skills, which this repository
symlinks to shell/skills, so it loads them progressively on its own and
AGENTS.md names where they are instead of repeating them. That took it
from 25,851 bytes to 4,366. Embedding them was not merely wasteful, it
defeated the progressive disclosure the skill format exists for.
MCP is the better path where the runtime supports it, because it gives typed tool schemas instead of prose describing a command line:
claude mcp add optiondesk -- /abs/path/to/.venv/bin/optiondesk-mcp
codex mcp add optiondesk -- /abs/path/to/.venv/bin/optiondesk-mcp
gemini mcp add -s user optiondesk /abs/path/to/.venv/bin/optiondesk-mcp
Twelve tools are exposed: option_snapshot_schema, option_chain_snapshot, option_greeks_ladder,
option_plots,
option_expiries, option_strategy_build, option_strategy_compare,
option_positioning, option_simulate, option_backtest,
option_forward_test, option_desk_status.
Six local skills ship: desk-setup, options-greeks, options-strategy,
options-positioning, options-simulation, and options-backtest. Each
carries the reporting rules an agent must follow, not only the commands.
These are enforced in code and covered by tests, not merely stated.
A missing number is never a guessed one. A contract whose price does
not identify a volatility gets iv: null and is counted in counts.without_iv
on a chain snapshot, and in skipped.no_iv on a Greek ladder. The
solver refuses, where it used to hand back its own starting guess for any
contract dominated by intrinsic value. A leg with no later quote makes a
forward position unmarkable instead of marking it at zero. Contracts with
no open interest are excluded from exposure rather than
counted as zero.
degraded and notes are different fields. Degraded means the output
is lower quality than the pipeline can produce: a provider fell back, a
rate could not be fetched, the engine was absent, the snapshot expiry has
passed. Notes record ordinary observations, such as wing contracts with no
quotes. Collapsing them would make every artifact degraded and the flag
worthless.
Unbounded is not a number. Maximum gain or loss on a naked structure
serialises as the string "unlimited". JSON has no infinity, null would
erase the distinction between unbounded and unknown, and a large number
would invent a floor that does not exist.
Modelled premiums are labelled everywhere they appear. Backtests use real closes and Black-Scholes premiums at trailing realised volatility. The artifact carries a statement saying there is no spread, no slippage, no assignment, no early exercise, and that entry and exit priced by the same model cannot detect the market disagreeing with that model.
Assumptions travel with the numbers. Gamma exposure signs assume dealers are long calls and short puts, which is often wrong for a single name. The strategy ranking states that a positive expectation largely measures the gap between one at-the-money volatility and the market's smile. Both statements are fields in the artifact, not footnotes in a document nobody opens.
Convergence is reported, never assumed. The MCMC posterior carries
split R-hat and effective sample size per parameter, and a converged
flag. When it is false, the quantiles are still written and the artifact
says they should not be quoted.
Eight schemas under shell/src/optiondesk/contracts/. The schema is the
interface: skills, the MCP server, the dashboard and any third-party
consumer read artifacts, never internal Python objects.
| Schema | Artifact | Carries |
|---|---|---|
chain_snapshot |
chain_*.json |
contracts, quotes, per-contract implied volatility and its source |
greeks_ladder |
greeks_*.json |
16 Greeks per contract, units block, skip counts |
exposure |
exposure_*.json |
gamma by strike, walls, flip, max pain, smile, ratios |
strategy_plan |
strategy_*.json |
legs, risk graph, probabilities, net Greeks, friction, payoff curve |
strategy_comparison |
comparison_*.json |
every structure scored, ranked, with the caveat |
simulation |
simulation_*.json |
posterior, diagnostics, fan, VaR and ES, per-structure distributions |
backtest |
backtest_*.json |
trades, statistics, significance, benchmark, honesty statement |
forward_ledger |
forward_ledger.json |
positions, marks, settlements, thesis |
Every artifact carries the same meta block: schema, timestamp, tool,
shell and engine versions, provider used, degraded with its reason,
notes, the disclaimer and the licence note.
Filenames are keyed by underlying and expiry, so re-pulling the same chain replaces the previous one. That used to be the end of it, and it is a quieter problem than it looks: the chain behind the "595 solved, 12 refused" figures above reported 590 and 17 six hours later, so a sentence that was carefully measured had become unprovable from anything on disk, with nothing to say so.
The outgoing artifact now moves into archive/<date>/ first, under a name
carrying the time it was generated:
~/TradingDesk/option-desk/
chain_SPY_2026-09-18.json the newest
archive/2026-08-30/
chain_SPY_2026-09-18_20260830T141217Z.json the one it replaced
The live name never changes. Every consumer resolves artifacts by that
name, so the dashboard, expiries, the plan reuse in compare and the
graph's stage check are all untouched. The
timestamp goes on the copy that is leaving. Identical bytes are not
archived, because re-running a command is not a new measurement.
OPTIONDESK_ARCHIVE=0 turns it off, and pruning is left to you: nothing
here deletes your data.
docs/evidence.json records each documented number with the artifact it
came from, when that artifact was generated, which provider answered, and
whether it was degraded. scripts/evidence.py record writes it, deliberately
and by hand; scripts/evidence.py check verifies the documents still agree,
and the refresh runs the check but never the record. A refresh that
re-recorded would make the documented number follow whatever is on disk
today, which is the failure this file exists to prevent.
A claim pins the measurement it describes, so the recorder reads the
archived artifact rather than the newest one with the same name. What is
stored is derived figures only, a few kilobytes, no provider data:
LICENSES.md tells you redistribution is governed by the provider's terms,
and this project should not then ship a chain.
Validation uses jsonschema when installed and a small built-in subset
validator when not, so a fresh clone validates its own output with nothing
but the standard library. Cross-file references are refused outright rather
than skipped silently, which is what previously left two artifact types
with an unvalidated meta block.
Skills and commands never name a provider. They ask for a capability, and a registry answers.
flowchart LR
need["A command needs<br/>option_chain"] --> reg{"Registry<br/>priority order"}
reg -->|"key present"| paid["Alpha Vantage<br/>key required, history and quotes"]
reg -->|"local acknowledgement"| yahoo["Yahoo<br/>local personal research<br/>delayed"]
reg -->|"nothing can answer"| err["ProviderUnavailable<br/>naming every candidate<br/>and why each was skipped"]
paid --> art["artifact records<br/>provider_used"]
yahoo --> art
Capabilities: option_chain, underlying_quote, risk_free_rate,
underlying_history, dividend_yield. Yahoo supplies all four after a local
personal-use acknowledgement. Alpha Vantage covers history and quotes when a
key is present. Its ordinary access is not approved for the hosted service.
A provider without technical access or data permission is skipped.
Naming a provider with --provider is strict: if it cannot answer, the
command fails rather than quietly serving a different source. Pass
strict=False in code to allow the fallback.
Keys resolve from a CLI flag, then the environment, then .env in the
working directory, then ~/.optiondesk/config.env. They are read, never
written, never logged and never copied into an artifact.
A licence on this software grants no rights over the data it retrieves. Each provider's terms govern that.
Every class below works today through the same pipeline. Nothing needed adding for them; what was missing was anyone saying so, and a dividend yield that was wrong for the ones that pay.
| Class | Reach it through | Chain size measured 2026-08-30 |
|---|---|---|
| Index options |
^SPX, European and cash settled |
843 contracts |
| Equity and ETF |
SPY, AAPL, any listed name |
492 |
| Rates and bonds |
TLT, IEF, SHY
|
43 |
| Metals |
GLD, SLV
|
145 |
| Energy |
USO, UNG
|
71 |
| Crypto |
BITO, IBIT
|
35 |
| FX |
FXE, FXY, FXB
|
56 |
Two limits. The free provider carries
no option chains for futures or FX spot: ES=F, CL=F, GC=F,
EURUSD=X and ^TNX all return price history and zero expiries, which is
why the exchange-traded proxies are the route. And the engine prices
European exercise, which is exact for index options and an approximation
for the American-style ETF options above, understating the value of a deep
in-the-money put most.
--dividend-yield used to default to zero, which sounds conservative and
is simply wrong for anything that pays. Measured on a real 173-day TLT
chain against its actual 4.7 percent trailing yield:
| assumed zero | real yield | |
|---|---|---|
| at-the-money implied volatility | 0.0737 | 0.1133 |
| delta | 0.635 | 0.491 |
Understated by 54 percent and overstated by 23 percent respectively, and every Greek, probability and structure built on it inherits that.
The yield now comes from dividends actually paid over the trailing year,
divided by spot, with the provider's own published figure as a cross-check.
When the two disagree by more than a quarter, neither is used: BITO's
option-income distributions compute to 38.8 percent against a published
61.7, and picking a side there would be a guess wearing a number's
clothing. A cash index is refused too, because it carries no dividend
series of its own and reporting zero would be indistinguishable from gold,
which genuinely pays nothing. In both cases the artifact is degraded, the
reason says so, and --dividend-yield remains the override.
engine/pricing/forwards.py has Black-76 for options on futures and
Garman-Kohlhagen for currency options, both as substitutions into the same
Black-Scholes-Merton core so they inherit its guards and its numerics. They
are tested against the published formulae written out independently, on put
call parity, and on the identity that a currency option equals a futures
option on the forward those rates imply.
No command calls them, because no provider here can feed them. They are capability for someone bringing their own quotes, and the module says so in its first paragraph rather than looking like part of a working pipeline.
optiondesk dashboard # http://127.0.0.1:8787
FastAPI when installed, standard library otherwise. Apache ECharts is vendored, so the page renders with no network access and no third-party request from the viewer's browser. It reads artifacts and never writes them, so it cannot corrupt a run in progress.
Sections: a selector for underlying and expiry built from what is on disk, the pipeline (every command, the artifact it writes and which artifact feeds which, drawn inline), structure comparison, composite support (one score per structure under a printed formula, with the model, the simulation and five years of history side by side and their disagreements marked), time spreads (the two-expiry family with the delta ratio, the giveback, the carry each was priced at and where its maximum sits), positioning (gamma by strike, cumulative profile, open interest, max pain), volatility (smile with 25-delta wings, six Greek small multiples), structures (payoff with spot, breakevens and expected move), the ladder, condor search, simulation (posterior fan, terminal distribution, parameter table with diagnostics, realised against implied), and backtest (statistics table, equity curves, drawdown and the per-trade outcome distribution).
Under every section sits a printed block of the arithmetic behind it, in the same plain monospace form the composite panel uses for its formula: the pricing model and the solver's acceptance rule, dealer gamma exposure and max pain, the smile figures and the expected move, the payoff engine and the lognormal law behind P(profit), time-spread marking, GARCH-t by MCMC with its diagnostics and tail figures, and the backtest's block-aware tests. Every constant in those blocks is read from the engine, and a test fails if the text and the code part company.
Every view is addressable: ?u=SPY&e=2026-09-18.
Ten views below. Every section, panel and chart, ninety images in all, is
in docs/SCREENSHOTS.md, captured from one live run
by scripts/screenshots.py.
The pipeline. One box per command, the artifact each writes, and which artifact feeds which; the page reads all of them and writes nothing. The maths of each stage is printed in the section that shows it.

Positioning. Dealer gamma by strike with the walls marked, the cumulative profile and where it crosses zero, open interest before any assumption about who holds it, and the max pain curve. The sign convention is stated on the panel rather than buried, because it is the assumption most likely to be wrong for a single name.

Volatility. The surface by strike and expiry from two expiries on file, the smile with its 25-delta wings, and the first and second order Greek curves drawn on one axis each.

Composite support. Every structure on one axis under a printed formula, with the four components shown separately so the ordering can be disagreed with by component, and with the model, the simulation and the five-year history side by side. Where those three disagree the row says so rather than averaging them into one confident number. It is an ordering under stated weights, not an estimate of edge and not a view on what to do.

Time spreads. The structures whose legs live on two expiries, kept apart from the rest because their numbers mean something different: they are marked at the near expiry with the surviving leg priced at today's volatility. Delta ratio and giveback are the two columns that separate a ratio diagonal from a plain one.

Structures. A picker for every structure built from this chain, the plan's numbers, the payoff at expiry with spot, breakevens and the expected move drawn on it, and the legs it would take with their own quotes.

The ladder, and every structure on one axis. Sixteen Greeks per contract, then the payoff curves overlaid so the shapes can be compared directly, and each structure placed by model probability of profit against expected return on risk.

Simulation. A GARCH-t posterior with R-hat and effective sample size beside every parameter, the predictive fan, the terminal distribution, and the profit distribution of each saved plan priced at expiry from the underlying the simulation actually produced.

Backtest. Entered on a fixed schedule and held to expiry, against a buy-and-hold benchmark over the same windows, with the drawdown and the per-trade outcome distribution beside it. The panel states what it is not before it states what it found: 233 iron condors on SPY over five years, 62.2 percent of them winners, and a total of minus 34 units of risk.
Those 233 windows overlap. A thirty day hold entered every five trading days shares twenty-five of its thirty days with its neighbour, so the significance test flips signs a block at a time and the interval resamples blocks. The artifacts carry the block, six here. It matters: when the correction landed, on the August chain, it moved four structures from below the conventional 0.05 to above it, and one from 0.0005 to 0.148. On this run the iron condor's block p-value is 0.016, and the maths block under the panel prints the test.

A new provider. Subclass Provider, declare capabilities and whether
it requires_key, implement the methods, register it, add its name to
PRIORITY above yahoo. Nothing else changes: it is selected when its key
is present and skipped when it is not.
A new structure. Write a builder that takes a split chain and returns
legs, add an entry to PLAYBOOK with its trade type, the outlooks it needs
and when to use it. The payoff engine, the comparison, the backtest and the
forward test all pick it up automatically.
A new skill. Add shell/skills/<name>/SKILL.md with name and
description frontmatter, run python3 shell/tools/gen_runtime_docs.py. Codex
and Gemini get it in the same commit.
A new artifact type. Add the schema, register it in
contracts/__init__.py, write the command, and add it to the dashboard's
KINDS.
Five ways to make this repeat, and they are not the same thing.
| kind | how | command |
|---|---|---|
| turn based | you ask, it finishes | /desk-open SPY |
| goal based | stop when a checkable condition holds | `/goal run /desk-complete SPY until every criterion is met, stop after |
| 5 tries.` | ||
| time based | run again every so often | /loop 6h run /desk-watch SPY |
| scheduled | outside the session entirely |
cron or launchd, because /schedule runs in the cloud and cannot reach a local desk |
| graph | inside an application you build | open_desk("SPY", budget=8) |
Two commands exist specifically to be looped. /desk-complete has six
mechanical exit criteria, so an evaluator can check them without judgement.
/desk-watch has six named thresholds and stays silent below all of them,
because a recurring command that restates everything trains you to ignore
it.
The graph is separate: a LangGraph state machine in
agent/src/optiondesk_agent/graph.py whose gather node runs one missing
stage per visit and loops until the artifact set is complete, the step
budget is spent, or a stage fails. Three distinct outcomes, no model in the
loop, every node deterministic.
LOOPS.md covers what makes a good loop here and what does not. No loop in
this project places an order.
One command rebuilds everything generated and then proves it still holds together:
python3 scripts/refresh.py
Ten stages in a full run, and the exit code reflects all of them: runtime docs from the
skills, docs/INVENTORY.md from the source, the installable forms in
dist/ and plugins/option-desk/, the CodeGraph index, the three test suites, and a
house-rules scan that fails on an ANSI escape, an emoji, an em dash or
anything shaped like a provider key. --fast skips the suites, --no-index
skips the index.
All three at once, from the repository root:
./shell/.venv/bin/python -m pytest -q # 1037 tests
That works because of pytest.ini, and it did not until recently: the
default import mode puts every test directory on sys.path as a top level
namespace, so the agent package's conftest shadowed the shell's and the
two test_artifacts.py files collided. Nine modules failed to collect and
the project looked broken when it was not.
Or one suite at a time:
./shell/.venv/bin/python -m pytest engine/tests -q # 355 tests
./shell/.venv/bin/python -m pytest shell/tests -q # 521 tests
./shell/.venv/bin/python -m pytest agent/tests -q # 161 tests
Those three counts are checked by shell/tests/test_documented_counts.py, which
fails when a number in the documentation stops matching the thing it counts.
Every count in the docs rotted at least once before that test existed.
One local hazard before you edit anything here. If cat is
aliased to a syntax highlighter, as it is on the development machine
(highlight -O ansi --force), then reading a file through the shell and
writing the result back embeds ANSI colour codes into the source. It has
happened three times in this tree. Use /bin/cat, and let the refresh's
rules stage catch what slips through.
Breaking the code on purpose, to check the tests notice:
python3 scripts/mutate.py ninety-nine mutations, killed or survived
python3 scripts/mutate.py --list what it would try
A survivor is a hole in the suite rather than a bug in the code. A mutant that provably cannot change behaviour is recorded as equivalent with the argument for why, so that "we could not kill it" never quietly becomes "we chose not to".
The code index is CodeGraph,
npm i -g @colbymchenry/codegraph. It turns the tree into symbols and call
edges, so codegraph explore "implied volatility guard",
codegraph node all_greeks, codegraph impact bs_price and
codegraph affected <file> answer structural questions without grepping.
It is optional, the refresh skips it with a note when it is absent, and
.codegraph/ is machine-local and git-ignored. codegraph install registers
it as an MCP server so an agent can query the index directly, and
codegraph sync -q in a post-commit hook keeps it current between
refreshes. Neither is done for you: an index is the developer's choice, not
the project's.
The engine is standard library only, with no network access and no file system opinions, which is what makes it testable against closed-form and finite-difference benchmarks. The shell holds everything that touches the outside world.
Test conventions, before you add one. Greeks are checked
against central finite differences of the price function they claim to
differentiate, with relative tolerances and no absolute floor: an earlier
version scaled by max(1, |expected|), which left three Greeks untested
with nothing to show for it, and mutation testing found fourteen surviving
defects.
That harness is in the tree as scripts/mutate.py, so it is checkable
rather than a claim about the past. It breaks the code fifty-six ways and
reports
which breakages the tests notice. Run it. Its current result is forty-two
killed and one proven equivalent, and getting there closed two real holes
it found, the inner vega guard in the implied volatility solver and the
ranking of a non-finite expectation. Every defect fixed since then has a
mutation of its own, because a fix without one is a fix nobody notices
being undone. Statistical
properties are tested as frequencies across several datasets rather than as
outcomes on one, because a 90 percent interval is supposed to miss one time
in ten. The MCMC is validated by recovering parameters it was given.
Measured, not asserted:
- Fifteen of sixteen Greeks match central finite differences of
bs_priceacross five parameter sets, both option types, with and without a dividend yield. Elasticity is a ratio, so it is checked against its definition. Mutation testing confirms a sign flip, a zeroing or a dropped term in any of the sixteen now fails the suite. - The GARCH-t sampler recovers parameters it was given, with coverage measured across three datasets, and reports non-convergence honestly when effective sample size falls short.
- Closed-form probability of profit and tail statistics agree with a seeded Monte Carlo draw from the same distribution.
- The MCP server answers a real stdio session: the tool list, a status
call, and both time spreads built end to end over JSON-RPC. That is
reproducible from
shell/tests/test_mcp_server.py, which drives every tool rather than only the one that reads nothing. - Audits by a grounded-engineering agent found defects that are now fixed and covered by regression tests. The ones worth naming, each with its test: an implied volatility solver that returned its own seed as a measurement and a second identifiability guard that had no test at all, a mid-price rule that substituted stale trades on 37 percent of a live chain, an uninstaller that could delete a directory it did not create, an MCP server that executed notifications and answered them, LangChain tool bindings that discarded every argument they were given, and six commands that wrote a degraded flag into the artifact and printed a summary with no trace of it.
In September 2026 three agents recomputed this project's arithmetic from scratch, against implementations written from the definitions rather than from this source, and reported only what disagreed. The suite was green at the time: more than nine hundred tests, ten refresh stages, a mutation harness with no survivors.
Most of the arithmetic held, and these figures are worth quoting because they were measured rather than assumed. All twenty-three payoff analyses reproduced from their own legs, including every breakeven and both unbounded cases. Probability of profit and the tail statistics agreed with 400,000 Monte Carlo draws per structure and then with Simpson quadrature over eight million nodes, worst residual 5.75e-11. All sixteen Greeks matched high-precision central differences to 9.95e-13 on a live ladder, with every scaling convention confirmed: per calendar day for theta, charm, veta and color, per 1.00 rather than per point for vega and rho. Put-call parity held to 6.55 double epsilon across 40,040 pairs. The exposure figures reproduced to 3.5e-16. R-hat matched the standard split definition to 0.00e+00. The comparison ranking reproduced exactly, margin over the runner-up to 0.00e+00.
Eleven things did not hold, and all eleven are fixed:
- The implied volatility solver tested sensitivity at its 0.30 starting guess and refused contracts it could identify from there. On one live chain that was 41 contracts, it drove the provider-volatility fallback to 12.2 percent, and it was the sole reason the chain and its ladder were marked degraded. The same chain now solves 380 of 394 and is not degraded.
- A risk-free rate of exactly zero was falsy, so it was silently replaced by four percent while the flag reporting a missing rate stayed false.
- The published payoff curve was drawn at the module defaults while the analysis beside it in the same file used the snapshot's rates. One calendar carried a maximum gain of 8.136160 and a curve peaking at 9.030645 at the same price.
- Every simulation artifact said
antithetic: true. Of ten thousand pairs, none shared a shock sequence: the construction had never run. The test guarding it asserted the artifact's own flag. - The significance tests assumed independent trades. The windows overlap by 83 percent and the effective sample is 64 to 88 rather than 233.
- Two-expiry maxima were published as properties of the structure when they are properties of the scan window: one reward to risk read 1.47, 4.90 and 12.02 at three window widths, and the shipped figure sat eleven standard deviations from spot.
-
delta_ratiowas documented in five places, one of them a JSON schema, as the thing keeping a large move uncapped. One long against two short satisfies it and is a net short call with unbounded loss. - The exposure artifact reported eight contracts skipped for missing open interest when all 394 carried it and the missing thing was volatility.
- The dashboard rendered a confident zero trades for a structure that entered 233 and correctly refused a return on risk it cannot define.
- The composite panel ranked a structure the comparison beside it excluded, so one page showed sixteen ranked and seventeen ranked.
- Five tests passed against deliberately broken code, every one caught by the mutation harness and none by review.
The lesson is in LOOPS.md as a fourth kind of loop, and the work it left behind is in docs/BACKLOG.md. The short form: a test checks what its author thought to check, and none of these lived where anyone had thought to look.
Two things that were claimed here and could not be checked from the
repository have been dealt with rather than left standing. "Mutation
tested" is now scripts/mutate.py, in the tree and runnable. A claim that
Codex had been observed driving the tools live, and a note about a Gemini
account tier, rested on a terminal session that no longer exists; both are
gone, replaced by the test above, which anyone can run.
| file | what it holds |
|---|---|
README.md |
this: architecture, flow, conventions, the reasoning |
docs/CAPABILITIES.md |
the complete catalogue of every feature and surface |
docs/INVENTORY.md |
every public function and class, generated from the source |
docs/BACKLOG.md |
what is known, measured and not done, with the evidence and what finished means |
CHANGELOG.md |
what changed between releases, and which published figures moved |
docs/SCREENSHOTS.md |
every panel and chart the dashboard renders, from one live run |
scripts/refresh.py |
rebuild everything generated, then prove it holds |
scripts/mutate.py |
break the code on purpose and check the tests notice |
INSTALL.md |
nine install paths, each verified |
LOOPS.md |
the four loop kinds, and what makes a good loop here |
FAQ.md |
the questions people actually ask |
AGENTS.md |
project rules and the command inventory for Codex, which loads the skills itself from .agents/skills
|
GEMINI.md |
the same plus all six skills compiled in, because Gemini CLI discovers none |
DISCLAIMER.md |
what this is not, and what you are responsible for |
LICENSES.md |
what noncommercial covers, and what needs an agreement |
THIRD-PARTY.md |
what is vendored and under what terms |
CLA.md, CONTRIBUTORS.md
|
contribution terms |
SECURITY.md |
what is in scope, and how to report it privately |
PRIVACY.md |
what leaves your machine, which is one request to a market data provider |
docs/SUBMISSION.md |
the Anthropic and OpenAI directory submission packs and evaluation cases |
CODE_OF_CONDUCT.md |
how to disagree here, and the one rule about not asking where anyone is |
CONTRIBUTING.md |
measure first, test what you claim, and what gets sent back |
The generated ones are rebuilt by python3 scripts/refresh.py. Editing
them by hand is wasted work.
PolyForm Noncommercial 1.0.0, one licence over the whole repository.
Free, with nothing to ask, for any noncommercial purpose: personal study, research, experiment, hobby projects, and use by charitable, educational, public research, health, environmental or government organisations whatever their funding. Modify it, build on it, pass it on, as long as these terms travel with it.
A separate written agreement is required first for anything done for commercial advantage or private monetary compensation. That includes use inside a fund or a trading business, selling it or access to it, paid consulting or signals produced with it, charging for a course built on it, and raising investment, grants, donations or crowdfunding on the back of it. Ask; terms are negotiable and a share is one of the shapes they take.
flowchart LR
free["Noncommercial use<br/>study, research, hobby,<br/>charities, schools, government"]
work["option desk<br/>engine, shell, agent, skills"]
paid["Commercial use<br/>funds, products, paid research,<br/>fundraising on the back of it"]
free -->|"no permission needed"| work
paid -.->|"written agreement first"| work
This is deliberately not open source in the OSI sense, and the trade is real: fewer users, fewer contributors, and some directories treat a noncommercial licence as unfree. The previous arrangement, MIT plus AGPL, allowed the exact thing it was meant to stop, since AGPL permits commercial use and selling and only asks that a modified network service publishes its source.
Copies taken before 2026-08-31 keep the terms they were given. A licence already granted cannot be withdrawn, and this file does not pretend otherwise.
Full detail in LICENSES.md, provenance of every borrowed line in THIRD-PARTY.md, and contribution terms in CLA.md.
Read DISCLAIMER.md. It states that this is software rather than advice, that the author holds no regulated status, that modelled results are not achievable results, and what your responsibilities are.
Guide home · Examples · Troubleshooting · Repository
Research software. Source available for noncommercial use. Read the license and disclaimer.