The Draw Tree Protocol
A protocol for AI-native equity research. It defines what a falsifiable hypothesis tree is, how its branch weights are derived from valuation impact, how valuation is reduced to two human decisions, how a weekly judge may and may not change a verdict, and how every write is recorded as a signed, append-only version. Any MCP-compatible client — ChatGPT, Claude.ai, Claude Desktop, Claude Code, Codex, Perplexity — can drive it.
0 · Protocol vs MCP — two different layers
MCP (Model Context Protocol) is a transport: how a client lists tools, calls one, and authenticates. It knows nothing about investment research. The Draw Tree Protocol is the domain contract: what a valid tree is, how verdicts aggregate, which valuation methods are admissible, what the weekly judge may do.
| Layer | What it defines | Where it lives |
|---|---|---|
| MCP | Transport, discovery, auth. | drawtree-mcp (hosted and stdio) |
| Protocol kernel | Schema, validator, aggregator, condition sweep, verdict-change gate, migration. | drawtree_mcp/_kernel and drawtree-api/core — the same code |
| State | Drafts, trees, versions, valuation decisions, subscriptions. | drawtree-api (FastAPI + Postgres) |
Why this protocol is open
A tool that claims to bring scientific method to investment research cannot itself be a black box. The schema, the formulas, the rules the judge obeys and the client contract are all public and MIT-licensed. The kernel ships with a golden test: a real research tree from the maintainer's fleet aggregates to exactly the fleet engine's score, verdict, conviction and probabilities. If drawtree.capital disappears, committed trees remain readable against this spec.
1 · The tree
Consensus → What the market believes and what the price already assumes.
H-0 → One question, one question mark, ≤120 characters, naming the
bear outcome ("…rather than being pushed back to …").
Branches → 3–5 necessary conditions. Each carries an impact grade derived
from what happens to the valuation if it fails.
Leaves → Observable questions with a six-level reading guide, structured
conditions on disclosed numbers, an append-only evidence ledger.
Valuation → Three scenarios from two human decisions (rules R1–R12).- Branch weight is derived, not authored. Each branch declares a falsification consequence (where the scenario goes if the branch fails). The gate computes how far that moves the implied value as a share of price and assigns the grade: ≥25% 致命 (2.5), 10–25% 重創 (1.6), 4–10% 明顯受損 (0.9), 1–4% 輕微 (0.4), <1% 邊緣 (0.15). A branch whose weight differs from its derived grade fails validation. At least one branch must be fatal, and one must carry numerator delivery.
- Conditions are structured.
{cid, kind, metric, operator, threshold, unit, window, due, status}withkind∈ falsification / verification / deadline andstatus∈ open / breached / met / superseded / expired_unfulfilled. Every condition is assessed at every judgement (gates E1–E7: no moved goalposts, no unaddressed breach, no unassessed condition, no unsupported downgrade). - Evidence is a ledger. Rows are appended, never edited:
eid, date, text, source_name, url, tier, impact, bears_on. Tier is filing > earnings > trade_press > news > synthetic; impact is supports / challenges / neutral. - Reader fields sit next to the machine fields: a one-line
short_question, a six-levelreading_guide, and the reader block 「現時判斷 → 甚麼會推翻這個假設 → 推翻之後」.
2 · Verdicts and aggregation
| Verdict | Score | Meaning |
|---|---|---|
| ✅ Validated | +2 | The reading guide's top level has been observed. |
| 🟢 Trending positive | +1 | Direction supports the leaf; threshold not yet reached. |
| ⚪ Inconclusive | 0 | No decisive reading yet. The default for a new leaf. |
| 🟡 Trending negative | −1 | Direction works against the leaf. |
| 🟠 Approaching falsification | −2 | A listed condition is close; one more reading flips it. |
| ✗ Falsified | −3 | A listed condition was met, on a primary or wire source. |
branch score = weighted mean of leaf scores (leaf weights, default equal)
branch verdict = thresholds ≥1.5 / ≥0.5 / >−0.5 / >−1.5; kill at ≤−2.0,
or when any leaf in necessity_leaves is Falsified
branch conviction = σ( logit(0.40) + 1.5 · score )
H-0 score = impact-weighted mean of branch scores; kill at ≤−2.0
H-0 conviction = σ( logit(0.40) + Σ w · score/3 ), positive terms halved,
clamped to [0.005, 0.95]
p_bull = h0/2, p_bear = −h0/3 (verdict-based); price-implied probabilities
from the three targets and the current price (Max-Base)Both probability readings are model outputs on the author's targets, reported side by side. Neither is a calibrated probability, and the protocol never produces a weighted target price.
3 · Valuation — two decisions, rules R1–R12
numerator(scenario) = street consensus × ratio(scenario) ratio(base) = 1
multiple(scenario) = median of the scenario's peer tier, today
target(scenario) = numerator × multiple (per share)
= (numerator × multiple + net cash) ÷ diluted shares (EV rulers)The author decides only two things: the bear and bull ratios to consensus (each with a one-sentence economic reason, an anchor, sourced inputs, assumptions and a cross-check), and the bear and bull peer-tier identities. The base tier is the tier whose band contains the company's own multiple. Everything else is derived by the server, and the human approves the report before anything is committed.
- R5 hard gate: bear < price < bull. The only fix is the economics — never a shifted multiple.
- R10 / AX7 own multiple outside every band must be declared (base impure).
- R12 forward-table multiples are re-based to the stated close when the table's implied price is more than 2% away.
- n-rules one peer needs an idiosyncrasy note; two use the midpoint with ratio ≤1.30; three or more use the median with max/min ≤2.5.
- Banned DCF, reverse DCF, DDM, inverted scenarios, weighted target prices — rejected everywhere.
Tools: evaluate_valuation (free, stateless), report_two_decisions (stores and returns the report), approve_decisions (records the reply verbatim and builds the schema-2.1 document the commit attaches).
4 · Procedure — four steps, two human gates
1 RESEARCH background brief (400–700 characters) · pricing pack · narrative
start_draft → frame_narrative → save_narrative
2 BUILD five questions → scenario ladder → H-0 → necessary-condition path
frame_h0 → save_h0 → design_branches → fetch_framework_details
→ save_branches → design_leaves / save_leaves (per branch)
preview_tree ■ FRAMEWORK GATE — the human reads the framework
confirm_framework
3 GATE evaluate_valuation until no errors
report_two_decisions ■ TWO-DECISION GATE — the human replies
approve_decisions(reply verbatim)
research_phase2 → research_phase2_status → compute_scenarios
commit_draft_tree (validated, aggregated, signed, versioned)
4 REPORT summarize_tree → reader report (§1 industry → company → why now;
§2 what it sells / how it charges / where the money goes / last
quarter; §3 consensus; §4 price chart with narrative bands)
setup_monitoring?The client contract (the skill) enforces the gates: nothing downstream of preview_tree or report_two_decisions is called until the human answers in the conversation. Download it from /api/skill/skill.md.
5 · Weekly monitor — what the judge may do
sweep deterministic: overdue deadlines expire, crossed thresholds breach and latch
search broad + targeted; every result tagged source_tier
(primary · wire · trade · aggregator · other)
judge sees only the evidence pool, the standing verdict, the conditions
gate a proposed change is kept only if it
1 cites a URL that was in this week's pool
1b–1c cites verifiable rows with known ids
1d is not an upgrade on all-challenging (or downgrade on all-supporting) rows
2 quotes a real listed condition when entering the falsification zone
3 is not a price-only argument
+ Falsified needs a primary or wire source
otherwise the standing verdict is kept and the proposal is recorded
latch met / breached / expired conditions cannot be assessed back to not_met;
only "superseded" with a reason releases them
freshness first_public graded 首發 / 補課 / 未能確認
write append-only: ledger rows, verdict_history, conditions; a signed versionA daily scheduler calls the API; weekly subscriptions run on Saturday 09:00 HKT. Rejected proposals and condition events are shown to the owner, in the email and on the tree page — nothing disappears silently.
6 · Point in time — signed, append-only versions
Every write — commit, edit, weekly judgement, price refresh, narrative refresh — appends a tree_versions row: the full payload, sha256(canonical_json), an Ed25519 signature by the operator key, and provenance (source, actor, previous version, protocol version, key_kind). Nothing is rewritten in place.
GET /v1/view/trees/by-id/{id}/versions history, newest first
GET /v1/view/trees/by-id/{id}/versions/{version_id} one version, with payload
GET /v1/view/trees/by-id/{id}/state_at?at=ISO the tree as held at or before a cutoff
GET /v1/view/trees/by-id/{id}/versions/diff?from_version=&to_version=
GET /v1/server_pubkey public key and key_kindstate_at is the only read a backtest or a dispute may use. A version signed by a development key is marked key_kind: dev and is not an attestation.
7 · The MCP tool surface
- validate_tree / aggregate_tree
- migrate_tree / sweep_conditions
- evaluate_valuation
- report_two_decisions / approve_decisions
- read_valuation_draft
- read_tree_versions / read_tree_version
- read_tree_state_at / diff_tree_versions
- commit_tree / read_tree / read_history
- suggest_framework
- start_draft → frame_* / save_* → preview_tree
- confirm_framework (Phase 2 bundle)
- research_phase2 / research_phase2_status
- compute_scenarios / commit_draft_tree
- summarize_tree / read_committed_report
- my_workspace / list_my_drafts / list_my_trees
- read_branch / propose_edit / apply_edit
- setup_monitoring / pause / resume / cancel
- search / fetch (ChatGPT-compat)
The stdio server ships the kernel, the valuation gate, publish and point-in-time reads (20 tools). The hosted server adds the draft flow and view mode. Read-only and kernel tools never charge; the client never mentions credits — the balance is at /account.
8 · Architecture
┌──────────────┐ MCP (stdio / Streamable HTTP) ┌──────────────────────────┐
│ AI client │ ───────────────────────────────▶ │ drawtree-mcp (Render) │
│ ChatGPT │ │ kernel v0.3 · OAuth │
│ Claude.ai │ └────────────┬─────────────┘
│ Claude Code │ │ REST, Bearer dt_…
│ Codex · … │ ▼
└──────────────┘ ┌──────────────────────────┐
│ drawtree-api (Render) │
│ core/ = same kernel │
│ valuation R1–R12 │
│ weekly judge + gate │
│ Ed25519 · tree_versions │
│ Postgres (Neon) │
└──────┬─────────────┬─────┘
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ drawtree-dashboard│ │ daily scheduler │
│ (Vercel) reads │ │ → admin_run_cron │
│ the same API │ │ (Saturday judge) │
└──────────────────┘ └──────────────────┘- The kernel is one codebase imported by both the MCP server and the API; a tree validates and aggregates identically on either side.
- The API owns all state and signing. Replacing the transport does not touch user data.
- The dashboard renders the same records the AI reads — including versions, the two-decision report and the judge's rejected proposals.
9 · What is not in the protocol
- Recommendations. The protocol produces structured evidence, verdicts and scenario arithmetic. It never produces a position, a target price or advice.
- DCF, reverse DCF, DDM, inverted scenarios. Rejected by the validator and the valuation gate.
- A public directory. Trees are private by default; a public tree is the owner's explicit choice.
- Model lock-in. Any model that can follow the skill's hard rules produces compliant trees; the kernel contains no model calls.