OpenInvest
OpenInvest is a self-hosted investment decision engine/MCP server for portfolio tracking, market context, committee-based verdicts, and auditable decision records.
Inspect portfolio status, cash, holdings, live P&L/performance, investment strategy, recent trades, decision history, discipline stats, and live market quotes.
Simulate what-if P&L scenarios, compute rebalance plans, and audit committee reasoning for past verdicts.
Run or coordinate the 4-role investment committee, submit transcripts, view pending committee re-runs, and assemble daily reports.
Record ledger bookkeeping for buys, sells, existing positions, deposits/withdrawals, dividends, fees/taxes, splits, returns of capital, and off-exchange fund orders.
Track assets, set target allocations and alerts, manage news sources, and ingest/normalize finance news for committee recall.
Record whether the user executed or declined a verdict, and run setup/health checks.
It never places real trades; it records, analyzes, and supports human execution.
Integrates with Hermes Agent as a plugin, allowing Hermes to leverage OpenInvest's multi-agent investment committee and auditable decision trails.
openInvest
A self-hosted investment decision engine built for modern AI agents. Multi-agent information isolation and cross-challenge protocol, providing an auditable decision trail (Audit Trail).
๐ Full Architecture Wiki ยท ๐จ๐ณ ไธญๆ็
What is OpenInvest?
OpenInvest is a self-hosted investment decision engine built for modern AI agents.
It provides a verifiable investment committee, evidence-based reasoning, long-horizon backtesting, and auditable decision records. Instead of replacing Claude Code, Codex, Hermes, or OpenClaw, OpenInvest is designed to power them.
Related MCP server: Decker
Live Performance & PnL
Benchmark Portfolio: The system introduces 8 standard control benchmarks across 4 quadrants (AI advisors / Mutual funds / Wealth management / Broad market index). For details on the comparison methodology and data cleaning logic, see docs/wiki/README.md.
Research & Falsification
System Self-Disclosure: This system is an auditing tool to eliminate human investment cognitive biases and enforce reasoning transparency, not a return-amplifying black box. Latest automated audit (docs/verdict_accuracy.md): Directional verdicts (excluding HOLD) have a true hit rate of 42.2% (n=56, below random); HOLD accounts for 56% of all decisions. The system's value lies in transparency and discipline (mostly staying inactive, low turnover), not directional prediction. Detailed log stream can be found in docs/verdict_accuracy.md.
This project systematically attempts to falsify its own edge and publishes negative results as-is. The deterministic features the committee reads, and the timing signals around them, were tested against pre-registered statistical gates โ none survived as tradable alpha.
Test | Result | Verdict |
Q1 cross-sectional stock picking | 6 features, mean-IC 0.025โ0.067, Holm-corrected p=0.397 | No significant stock-picking signal |
M1 multivariate GBM (out-of-sample) | mean OOS IC +0.003, p=0.925 | Feature combination doesn't help either โ no signal |
Q2 gold MA200 trend | p_holm=0.016, significant โ but | Statistically significant, economically untradable |
Per-asset multi-signal families | 3 assets ร 4 signal families ร parameter grid = 24 variants per asset; after costs + DSR deflation, none passes DSR > 0.95 | No tradable signal in any family |
Positive control | A cheating perfect-foresight timing signal scores DSR = 1.00 | The harness can detect a real signal |
Methodology: Newey-West HAC t-statistics, Deflated Sharpe Ratio (Bailey & Lรณpez de Prado 2014, re-derived equation by equation), Holm correction, zero lookahead, and LLM training-cutoff probes.
Details: experiments/signal-eval/README.md ยท docs/verdict_accuracy.md ยท ADR-022 ยท ADR-023
Product Philosophy
Most AI investment assistants try to become better chatbots. OpenInvest instead builds a transparent, verifiable, and auditable decision engine that plugs into personal agents such as Claude Code, Codex, Hermes, and OpenClaw โ every improvement in those agents automatically makes OpenInvest more capable.
The division of labor is deliberate: your agent handles long-term memory, natural conversation, and user understanding; OpenInvest handles the verifiable investment committee, evidence-based reasoning, long-horizon backtesting, and auditable decision records.
User
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โผ โผ
Your Agent OpenInvest
(User Understanding) (Market Understanding)
โ โ
โโโโโโโโโโโโโฌโโโโโโโโโโโโ
โผ
Better Investment DecisionsYour agent knows you. OpenInvest knows investing.
Avoiding User Ownership
OpenInvest intentionally avoids "owning" the user. Most AI products try to own everythingโmemory, persona, chat history, and workspaces. OpenInvest takes a back seat. It exposes clean APIs, CLI commands, and agent skills (Claude Code / Codex / Hermes / OpenClaw), letting your primary agent manage the conversation and context while OpenInvest powers the underlying investment intelligence.
Features
Multi-Agent Investment Committee: Isolated analysis and round-rebuttal debate.
Coordinator-Worker Architecture: Prevents context contamination and role hallucination.
Information Isolation: Rigidly blocks quant and risk analysts from out-of-boundary contexts.
Auditable Decision Trail: Clean logs showing exactly "why" each decision was made.
Markdown-as-a-Database: Frontmatter (YAML) + Markdown (Body) as the single source of truth.
Long-Horizon Backtesting: Built-in test harness with lookahead bias protections.
Dreaming-Based Memory Consolidation: Nightly memory distillation to prevent context drift.
Self-Hosted / Zero-Cost: Powered directly by your local agent's reasoning resources.
Agent Skill: Lightweight plugin for Claude Code / Codex / Hermes / OpenClaw, with interactive bootstrap wizard.
Automated Deployment: GitHub Actions workflow to run the committee and email reports daily.
Quick Start
1. Integrate with your agent (Recommended)
Add the lightweight skill from your agent's plugin registry. The host agent will automatically pull the core code and align dependencies on first run:
# Claude Code
/plugin marketplace add longsizhuo/openInvest
/plugin install invest@openinvest
# Codex
codex plugin marketplace add longsizhuo/openInvest
codex plugin add invest@openinvest
# Hermes Agent (official plugin catalog)
hermes plugins install openinvest --enable
# older Hermes without the catalog: hermes plugins install longsizhuo/openInvest/plugin --enable
# OpenClaw
openclaw plugins install clawhub:openinvestAny other MCP client: register the MCP server from step 2 below (full walkthrough in the agent tutorial).
2. Standalone โ MCP server or CLI (no clone needed)
The backend ships on PyPI; ~/openInvest holds only your data:
# MCP (any MCP client; add --http for a remote streamable-HTTP server โ BETA)
claude mcp add openinvest -e INVEST_HOME=~/openInvest -- uvx openinvest-mcp
# or plain CLI
INVEST_HOME=~/openInvest uvx openinvest statusSend set up invest (or ๅธฎๆๅๅงๅ invest) to any skill-enabled AI terminal. The system will trigger an interactive bootstrap wizard to guide you through:
Detecting the
memory/state storage path and.envconfiguration.5-dimensional profiling (Legal name, Risk capacity, Debt structure, Initial holdings, and optional keys).
Running static data migration to immediately generate your first asset exposure memo.
๐ก Zero-Cost Execution: In skill interactive mode, the committee's underlying reasoning relies entirely on the host agent's (e.g. Claude Code) reasoning pipeline. No third-party API Key is consumed. You only need to configure an API key when setting up automated crons or calling independent Web APIs.
For self-hosting details, see docs/QUICK_START.md. (The bundled Web GUI was retired on 2026-07-05 โ all capabilities are exposed via CLI/MCP; a standalone frontend may return later.)
3. Serverless Self-Hosting (GitHub Actions)
Run the committee automatically via GitHub Actions and receive daily digest emails.
โ ๏ธ Fork must be set to Private: State files (holdings, verdicts) will be committed back to your fork. Public forks will leak your private financial information.
Fork this repository and change its visibility to Private (Settings -> Visibility).
Run
set up investlocally to generate the initialmemory/folder, then commit and push it to your private fork:git add -f memory/ && git commit -m "chore: init memory state" && git pushIn your fork's Settings -> Secrets and variables -> Actions, add the following Secrets:
LLM_API_KEY(orDEEPSEEK_API_KEY): API key to run the committee.EMAIL_SENDER/EMAIL_PASSWORD: Gmail address + App Password.DIGEST_EMAIL_TO: Recipient email address.
Enable Workflows under the Actions tab. The workflow runs automatically at 10:00 AM (Beijing time) daily; you can also manually trigger
daily-reportvia Run workflow.
Architecture & Multi-Agent Orchestration
openInvest does not run a mock debate in a single LLM session. The system enforces an Information Isolation Contract at the core/committee/ layer, orchestrating 4 independent LLM processes in a directed acyclic graph (DAG):
[ Macro Data Injection ]
โ
โผ 1. Macro Alignment Context
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Macro Strategist โ (VIX / Interest rate spread / Currency momentum)
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโ
โ
โผ 2. Async Multi-Dimensional Scrutiny (Async DAG)
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโ
โผ โผ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ Quant Analyst โ โ Risk Officer โ
โ (RSI / Momentum) โ โ (Concentration) โ
โ โ โ โ
โ ๐ No Holdings โ โ ๐ No Indicators โ
โโโโโโโโโโโฌโโโโโโโโโ โโโโโโโโโโโฌโโโโโโโโโ
โ โ
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ 3. Round 2 Rebuttal & Cross-Challenge
โ Mutual feedback loop for signal correction
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Chief Investment Officer (CIO) โ
โโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ 4. Deterministic State Persistence
[ BUY / ACCUMULATE / HOLD / TRIM / SELL ]Macro Strategist: Assesses the global macro landscape (VIX, yield curve spread, core currency matrix) to establish the portfolio's risk threshold.
Quant Analyst: A pure mathematical momentum and technical indicator filter. Strictly blocked from knowing portfolio holdings to eliminate human attachment and loss-aversion biases.
Risk Officer: Focuses entirely on tail risks (drawdown buffers, concentration limits, solvency multipliers). Strictly blocked from technical indicators to make objective asset exposure rulings.
Round 2 Rebuttal: Quant and Risk analysts are fed each other's Round 1 reports in Round 2, challenging boundaries until signals converge or safety valves trigger.
CIO (Chief Investment Officer): Synthesizes the audited reports and outputs a structured
Verdict(BUY / ACCUMULATE / HOLD / TRIM / SELL) with a confidence level. No auto-order execution occurs; final action remains strictly up to the human auditor.
Key trade-offs behind this design are recorded as ADRs in docs/wiki/adr/ (24 to date), including rulings that overturned our own earlier designs โ ADR-007 retired the few-shot CIO route, and ADR-009 rejected TA-style analyst agents after a pre-registered experiment.
Core Design
Coordinator-Worker Pattern: Workers operate in isolated namespaces. Boundary constraints are hardcoded at the framework layer in Python to prevent attention contamination in large multi-role prompts.
Markdown-as-a-Database: The system uses Frontmatter (YAML) + Markdown (Body) as the single source of truth. Leveraging
fcntl.flockprocess file locks and temporary atomic file replacement, it provides a tamper-proof investment audit trail natively tracked by Git.Three-Phase Dreaming Consolidation: Distills daily decisions against actual market outcomes nightly (Light Sleep $\rightarrow$ REM $\rightarrow$ Deep Sleep) to consolidate long-term insights, preventing Large Language Model (LLM) context drift over long execution spans.
Configuration
The system defaults to DeepSeek endpoints and supports any standard OpenAI-compatible API. LLM provider setup and all tunable runtime overrides (ADR-017) are documented in docs/wiki/22-configuration.md.
Disclaimers & Backtest Limitations
No Financial Advice: This system is a decision-support tool powered by LLMs. Output memos represent simulated reasoning based on deterministic data and do not constitute asset allocation advice.
Backtest Time-Lock & Lookahead Guard: The backtest engine (
scripts/backtest_runner.py) has a hardcoded safety valve: it rejects backtests fordecision_date > 2024-06-30by default (override with--allow-lookahead). Since mainstream foundation models have training cutoff dates around mid-2024, backtesting on later intervals introduces severe Lookahead Bias (model pre-training leakage). Parameter tuning, Optuna sweeps, and prompt optimization must run strictly on historical windows prior to June 30, 2024.
Acknowledgments
Equibles โ Optional data provider for A-share and Hong Kong financial statements, and a daily-price fallback when Yahoo Finance is unreachable. Yahoo Finance stays the default; set your own free
EQUIBLES_API_KEYto turn it on (setup).MiMo โ Special thanks to MiMo Quantitative Lab for sponsoring production-grade high-performance LLM inference (powering
mimo-v2.5-prolong-horizon sweeps).OpenClaw Dreaming Guide โ Theoretical foundation for the three-phase sleep-cycle memory distillation framework.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Available Tools
36 toolsadd_news_sourceAIdempotent
Add an RSS/Atom feed to the crawler's source list. The URL must be http(s) on a public host (fetched directly, not via HTTP(S)_PROXY), and is live-probed before saving โ a URL that doesn't parse as a feed is rejected. Idempotent: re-adding an existing URL returns the existing entry. Capped so the list can't grow unbounded.
Use when someone says "follow 's news" / "ๅ ไธชๆฐ้ปๆบ".
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | RSS/Atom feed URL (a real feed, not a webpage). | |
| name | Yes | Short slug for the feed, [a-z0-9_] (e.g. 'wsj_markets'). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the proxy-bypass fetch path, the live-probe validation that rejects non-feed URLs, the idempotent return-existing behavior (consistent with idempotentHint=true), and the list cap. These are real operational traits an agent cannot infer from readOnlyHint/destructiveHint alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action, then constraints, then the trigger phrase. Every sentence carries a distinct fact (validation, idempotency, cap) with no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers validation/failure behavior, idempotency and the growth cap; an output schema exists so return-value detail is unnecessary. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both params are already described, but the description adds non-obvious constraints not in the schema โ the URL must be http(s) on a public host and must parse as a feed. That meaningfully sharpens how 'url' should be supplied.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource ('Add an RSS/Atom feed to the crawler's source list'), which is clearly distinct from siblings news_sources and remove_news_source. An agent can tell exactly what this creates without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit trigger phrasing ('Use when someone says "follow <site>'s news" / "ๅ ไธชๆฐ้ปๆบ"'), which grounds when to call it. It stops short of naming alternatives or when-not conditions (e.g., listing via news_sources, removal via remove_news_source), so it is clear context but not full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
buyADestructive
Record a buy in the local ledger: adds to an existing position with weighted-average cost, or opens a new position for an unseen symbol. This bookkeeps a trade the user already placed with their broker โ openInvest never places real orders.
Confirm symbol, units, and price with the user before calling; this
moves ledger cash. A position the user already held before using
openInvest is not a purchase: record it with record_existing_position.
Off-exchange China mutual funds (FUND:<6 digits>) settle T+1 or later
at the NAV of the pricing day: use place_fund_order +
confirm_fund_order instead (buy books them as instantly filled and
total assets dip by the amount until the real confirmation).
Args:
symbol: yfinance ticker (e.g. "AAPL", "510300.SS"). Gold = "GC=F", booked in
CNY per gram only (units = grams, currency "CNY", kind "metal", unit_label "ๅ
").
units: Quantity bought; must be > 0.
price: Execution price per unit, in currency.
currency: Currency of price; omitted = the existing position's currency (CNY if new).
kind: Asset kind tag: "equity", "etf", "metal" (gold), "crypto", "bond", "fund", "other".
unit_label: Human display label for units (default "่ก", i.e. shares).
idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Updated position summary, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Asset kind tag: 'equity', 'etf', 'metal' (gold), 'crypto', 'bond', 'fund', 'other'. | equity |
| price | Yes | Execution price per unit, in `currency`. | |
| units | Yes | Quantity bought; must be > 0. | |
| symbol | Yes | yfinance ticker, e.g. 'AAPL', '510300.SS'. Gold is 'GC=F' and must be booked per gram in CNY: units = grams, price = CNY/gram, currency='CNY', kind='metal', unit_label='ๅ ' (USD/oz bookings are rejected). | |
| currency | No | Currency of `price`, e.g. 'CNY', 'USD', 'AUD'. Omit to use the existing position's currency (CNY for a new position); a different currency than the position's is rejected. | |
| unit_label | No | Human display label for units (default '่ก', i.e. shares). | ่ก |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. | |
| existing_position | No | Not supported on buy. For a position held before using openInvest call `record_existing_position`; passing true here returns an error instead of deducting cash. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the write/cash impact is partly covered. The description still adds real value beyond them: it is pure bookkeeping (no real orders are placed), it moves ledger cash, it requires user confirmation first, and it discloses the fund-settlement distortion. It does not cover edge cases like failure modes when cash is insufficient, but with annotations carrying the safety profile this is strong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The prose is front-loaded with purpose and the routing caveats before the Args listing, and the Returns line is brief because an output schema exists. The Args section, however, duplicates the input schema nearly verbatim, which is expendable length even though each individual sentence is well-formed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter write tool with an output schema, the description covers everything an agent needs: what it does, what alternatives exist for the two important edge cases, the confirmation prerequisite, the gold special case, and idempotency on retry. Nothing material is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3; the Args block is largely a restatement of the schema's own parameter descriptions (gold ticker/units/currency, idempotency reuse, unit_label default). It adds minor framing value, such as tying `currency` omission to the existing position, but nothing the schema does not already say.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource โ 'Record a buy in the local ledger' โ and immediately explains both branches (weighted-average add to an existing position, or new position for an unseen symbol). It also states what the tool is not: 'openInvest never places real orders,' which sharply separates it from a real brokerage order path.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing rules: pre-existing holdings go to `record_existing_position`, off-exchange China mutual funds go to `place_fund_order` + `confirm_fund_order`, and it explains why (buy would book them as instantly filled, distorting totals). It even specifies a pre-call obligation โ confirm symbol, units, and price with the user โ which is actionable usage guidance, not just context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancel_fund_orderADestructive
Cancel an in-transit off-exchange fund order that was never executed
(the user withdrew it on the fund platform): the amount returns to ledger
cash. Only orders still in transit can be cancelled โ a confirmed order
already holds shares (use sell to book a redemption).
Confirm with the user before calling; this moves ledger cash.
Args: order_id: The in-transit order to cancel.
Returns: Cash returned and new balance, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| order_id | Yes | order_id of an in-transit order (status 'placed'). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, but the description adds substantive context: the amount returns to ledger cash, the side effect touches ledger cash so user confirmation is required, and the error return shape is disclosed. It stops short of covering idempotency or failure-recovery behavior, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Scope, preconditions, and the alternative are front-loaded in the first two sentences, before the Args/Returns blocks. The Returns section partially duplicates the existing output schema, which is minor waste, but the overall structure is clean.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive tool with an output schema already present, the description covers the state precondition, the side effect, the alternative tool, and the error case. Any remaining gaps are minor and would be covered by the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already explains that order_id is an in-transit order with status 'placed'. The description's 'The in-transit order to cancel' adds no meaning beyond that, so it sits at the baseline for a schema-documented parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Cancel an in-transit off-exchange fund order') with a precise qualifier ('that was never executed'). It explicitly distinguishes itself from the confirm/sell siblings by noting that confirmed orders hold shares instead.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition ('Only orders still in transit can be cancelled'), names the alternative path for confirmed orders ('use `sell` to book a redemption'), and adds an operational directive ('Confirm with the user before calling'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
confirm_fund_orderADestructive
Second leg of an off-exchange fund purchase: turn an in-transit order
into shares at the pricing day's NAV (units = (amount - fee) / nav; average
cost updates, cash unchanged). The fund_confirm job does this
automatically every weekday evening, so call it manually only to supply a
NAV / fee yourself or to confirm early.
Safe to call twice: an order that is already confirmed returns {"status": "already_confirmed"} (a cancelled one {"status": "cancelled"}) and nothing changes. If the pricing-day NAV is not published yet the result is {"status": "pending_nav"} and the order stays in transit.
Args: order_id: The order to confirm. nav: Unit NAV; omit to use the published NAV of the pricing day. fee: Subscription fee in CNY (default 0).
Returns: Units added, NAV used and new average cost, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| fee | No | Subscription fee in CNY, taken out of the order amount (units = (amount - fee) / nav). Default 0. | |
| nav | No | Unit NAV to confirm at. Omit to fetch the pricing day's published NAV (if it isn't published yet the call returns status 'pending_nav' and changes nothing). | |
| order_id | Yes | order_id from place_fund_order / status.pending_fund_orders. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description says the tool is 'Safe to call twice' and that an already-confirmed order changes nothing, which is idempotent behavior, but annotations declare `idempotentHint: false`. It also frames the operation as safe/idempotent while `destructiveHint: true`, creating a direct annotation contradiction despite otherwise useful behavioral detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the automatic-job caveat are front-loaded, and the edge-status details earn their place. However, the Args and Returns blocks duplicate schema/output-schema content, making it slightly longer than necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a state-changing financial operation, the description covers purpose, manual-use conditions, duplicate-call behavior, pending NAV, fee/NAV semantics, and status returns. An output schema exists, so detailed return-shape explanation is not needed; completeness is strong.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents `order_id`, `nav`, `fee`, defaults, and the pending-NAV behavior. The description's Args section largely restates those fields, adding little beyond the units formula already present in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names the exact operation and accounting effect: turning an in-transit fund order into shares at the pricing day's NAV. It clearly positions itself as the second leg after place_fund_order and is distinguishable from place_fund_order and cancel_fund_order.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says the `fund_confirm` job runs automatically every weekday evening and manual calls are only for supplying NAV/fee or confirming early. It also gives conditions for duplicate calls and unpublished NAV.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
daily_reportA
Assemble today's daily report (portfolio, verdicts, performance,
holdings digest) and return it as full_report Markdown for you to deliver.
Agent mode (keyless backend): run prepare_committee โ roles โ
submit_committee for every target asset FIRST; this tool then only reads
today's submitted verdicts โ nothing is re-run by a backend model. Assets
without a submitted verdict are listed in missing_verdicts: treat any
entry there as a failure and report it. Backend mode: runs the backend
committee itself (needs a backend LLM key, takes minutes).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: agent mode only reads today's submitted verdicts (nothing re-run), backend mode runs the committee itself, requires a backend LLM key, and takes minutes. It also discloses the `missing_verdicts` failure semantics. These auth, latency, and side-effect details explain why readOnlyHint=false and are exactly the context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and every subsequent sentence carries load-bearing workflow or failure information. Slightly dense (backticks, arrows, mode labels) and the bare "roles" step is ambiguous, but there is no filler to cut.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be re-explained, and the description covers the mode split, prerequisites, key requirement, latency, and failure handling. Nothing an agent needs to invoke this correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to disambiguate; baseline 4 applies. No parameter meaning is missing because the schema is empty.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ("Assemble") and resource ("today's daily report") and enumerates the report's contents (portfolio, verdicts, performance, holdings digest), plus the return artifact (`full_report` Markdown). This clearly distinguishes it from siblings like decisions, run_committee, and status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly separates two operating modes and gives the exact precondition for agent mode (run prepare_committee โ roles โ submit_committee for every target asset FIRST) versus backend mode. It also tells the agent what to do with `missing_verdicts` entries (treat as failure and report). No inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
decisionsARead-only
Get the unified decision ledger: every committee verdict joined with rule interventions, the user's actual executions or refusals (with reasons), and post-hoc outcome data โ plus an adoption-rate summary.
Answers "how often did I follow the advice", "which recommendations did
I skip", and "what did the safety rules rewrite". Read-only. Filter by
symbol / verdict to answer questions about one asset or one kind of
call; the list is capped at limit (newest first) so a year of history
doesn't flood the context โ count and summary still cover every match.
Args: days: Look-back window in days (default 90). symbol: Only decisions on this ticker (case-insensitive). verdict: Only decisions with this verdict. limit: Max decisions listed (default 20; 0 = all).
Returns:
Object with count (all matches), returned (listed), summary
(adoption rate and aggregates over all matches), and decisions
(newest first; each entry has decision_id, verdict, confidence,
intervention, executed flag, matched trades, and outcome).
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Look-back window in days. | |
| limit | No | Max decisions listed, newest first; 0 = all. | |
| symbol | No | Only this ticker (case-insensitive), e.g. 'GC=F'. | |
| verdict | No | Only this verdict, e.g. 'ACCUMULATE', 'HOLD', 'TRIM'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description's 'Read-only' line merely repeats that. The genuine added value is behavioral: the list is capped at `limit` newest-first so a year of history doesn't flood context, while `count` and `summary` still cover every match โ a non-obvious pagination/aggregation contract the agent would otherwise have to guess.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the resource and its purpose, then use cases, then args and returns in clearly labeled blocks. The Returns block is partly redundant given the output schema exists, but the structure is scannable and every other sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter, zero-required read tool with a full output schema, nothing needed to invoke it correctly is missing: the agent knows the default window, the cap semantics, how to filter, and that aggregates cover all matches. Return-value detail is arguably redundant but not a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description largely restates the schema (default 90 days, limit 0 = all, case-insensitive symbol, verdict examples) and adds only the 'newest first' ordering and the rationale for the cap, which is modest incremental meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (the unified decision ledger) and enumerates its composition โ committee verdicts joined with rule interventions, executions/refusals with reasons, and outcome data โ plus an adoption-rate summary. This is clearly distinguishable from siblings like `history`, `discipline`, and `explain_decision`, which an agent can rule out from the text alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete usage contexts via the quoted questions it answers ('how often did I follow the advice', 'which recommendations did I skip') and tells the agent to use `symbol`/`verdict` for single-asset or single-verdict questions. It never explicitly names an alternative tool or states a when-not condition, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
depositADestructive
Record a cash deposit into the ledger, in any currency. Bookkeeping only โ no real payment system is connected.
Args: currency: ISO-style currency code, e.g. "CNY", "USD", "AUD". amount: Amount to add; must be > 0. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Updated cash balances, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| amount | Yes | Amount to add; must be > 0. | |
| currency | Yes | ISO-style currency code, e.g. 'CNY', 'USD', 'AUD'. | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as a non-read-only mutation, and the description adds important context beyond them: no real payment system is connected, idempotency-key retry behavior is documented, and return behavior is summarized. It does not fully address the destructiveHint annotation or discuss reversibility/permissions, so it is strong but not complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and scope, then uses short Args/Returns sections. It is appropriately sized, though the Args and Returns sections partly duplicate the input and output schemas.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the toolโs complexity, rich input schema, existing annotations, and output schema, the description provides everything an agent needs: it clarifies bookkeeping-only behavior, amount/currency expectations, idempotency retry semantics, and error/return shape at a high level.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains currency format, amount constraints, and idempotency-key behavior in detail. The descriptionโs Args section largely mirrors that information rather than adding substantial new semantics, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: โRecord a cash deposit into the ledger,โ and clarifies scope with โin any currencyโ and โBookkeeping only.โ This is clearly distinguishable from sibling tools like withdraw, buy, or record_fee.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides useful context that this is bookkeeping-only and not connected to a real payment system, which implies when it should be used. However, it does not explicitly name alternatives or state when not to use this tool versus withdraw, buy, or other ledger mutation tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disciplineARead-only
Get the committee's discipline ledger: how often it chose inaction (HOLD ratio), how many impulsive user trades its rules intercepted, and the counterfactual money saved/lost by those interventions (ADR-023: the system's proven value is discipline and transparency, not alpha).
Use when the user asks "what has the committee blocked" or "is this tool actually helping". Read-only.
Returns:
Object with summary (structured stats) and markdown (the same
ledger pre-rendered for direct display to the user).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so description adds value by detailing return structure (summary + markdown) and the specific metrics computed. Does not contradict annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with zero waste. Front-loaded purpose, then usage, then return structure. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters, read-only annotation, and existence of an output schema, the description fully explains what the tool returns and its purpose without needing more detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters in input schema (100% coverage), so baseline is 4. Description does not need to add param info; it correctly focuses on behavior and return format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the verb 'Get' and resource 'discipline ledger', specifying exact metrics (HOLD ratio, intercepted trades, money saved/lost). Distinguishes from siblings like 'decisions' and 'explain_decision' by focusing on blocked interventions and counterfactual value.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use: when user asks 'what has the committee blocked' or 'is this tool actually helping'. Also marks as 'Read-only', which implies it should not be used for modifications.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
doctorARead-only
Health check, the first call of a session (same output as run.sh doctor,
for agents without shell access): is onboarding done, and which optional
pieces are missing.
status is "ready" when memory (user / strategy / portfolio) is initialized,
or "needs_setup" when it is not (or portfolio.md is still the v1 format) โ
only then hand over to the invest-setup skill. A missing LLM key or mail
credentials never makes it "needs_setup": those checks entries are marked
optional_for_coordinator / optional_for_email. The Coordinator path
(prepare_committee + subagents) works without a key; only the Direct path
(run_committee, cron) needs one, see direct_ready.
Read-only; makes one short HTTP probe to the configured LLM endpoint when a key is set.
Returns:
Object with status, version, coordinator_ready, direct_ready,
next_step, and checks (name / status / detail / hint per check).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, and the description adds value beyond that: it discloses a side effect ('makes one short HTTP probe to the configured LLM endpoint when a key is set') and explains the nuanced readiness semantics (optional_for_coordinator / optional_for_email, coordinator vs direct path). This is rich behavioral context not available from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in the first sentence, and the remaining content is dense but mostly earns its place. The closing 'Returns:' block is somewhat redundant given an output schema exists, costing a little conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only health check with an output schema, the description covers everything an agent needs: when to call it, how to interpret `status`, the optional-check semantics, and the probe side effect. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There are no parameter semantics to clarify, and the description correctly does not fabricate any.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource and action โ a session health check โ and equates it to `run.sh doctor` for agents without shell access. It clearly distinguishes itself from siblings by defining what `status` values mean and what the tool's overall job is.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states explicitly that this is 'the first call of a session' and when to hand over to the `invest-setup` skill (`needs_setup`). It also clarifies that missing LLM key/mail credentials do NOT trigger `needs_setup`. It does not explicitly differentiate from the sibling `status` tool, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_decisionARead-only
Get the full reasoning behind one committee verdict: the complete 4-role debate transcript with the CIO memo, plus the path-probability snapshot the CIO saw at decision time.
Use when the user asks "why was today's verdict HOLD" or wants to audit a past decision. Read-only.
Args:
decision_id: "/", e.g. "2026-07-03/GC=F" โ exactly as
returned in the decisions tool output.
Returns:
Object with verdict, confidence (the CIO's self-reported number, kept
for the record), confidence_lookup (show this to the user instead:
how similar verdicts (live + paper fleet) turned out 30 days later), alloc_cny,
transcript_markdown (render this to the user), and path_snapshot
(may be null).
| Name | Required | Description | Default |
|---|---|---|---|
| decision_id | Yes | "<date>/<symbol>", e.g. "2026-07-03/GC=F" โ exactly as returned by the decisions tool. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint already covers the safety profile, but the description adds meaningful behavioral context: which return fields to surface to the user (confidence_lookup over the raw confidence, transcript_markdown rendering) and that path_snapshot may be null. This goes beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence followed by clearly labeled when-to-use, Args, and Returns sections makes it easy to scan. It is somewhat verbose and the decision_id format is repeated in both Args and the schema, but every section carries useful signal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool returning a complex multi-part object, the description supplies enough to invoke and interpret it, and an output schema exists as backup. Coverage of invocation, usage, and return handling is solid, though naming a sibling for the 'list decisions' case would fully close the loop.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already documents the decision_id format and example. The Args section largely restates that same '<date>/<symbol>' format, so the description adds little beyond the structured field. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: retrieve the full reasoning behind one committee verdict, enumerating the concrete artifacts (4-role debate transcript, CIO memo, path-probability snapshot). This clearly distinguishes it from sibling tools like decisions (list) and run_committee (execute).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete trigger phrasings ('why was today's verdict HOLD') and the audit scenario, which tells the agent exactly when to reach for it. It doesn't name a specific alternative tool or a when-not condition, so it falls short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
historyARead-only
Get the most recent trade records and committee verdict history.
Use when the user asks "what did I buy recently" or "what did the committee decide lately". Read-only.
Args: n: Maximum number of recent trades to return (default 10).
Returns:
Object with trades (each with symbol, direction, units, price,
timestamp, status) and recent committee verdict records.
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | Maximum number of recent trades to return. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true. The description adds the read-only label and details the return structure (trades with specific fields and committee verdict records), providing useful behavioral context beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the main purpose. Every sentence adds value, and the docstring style for Args and Returns is well-structured without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one optional parameter, no nested objects) and the existence of an output schema, the description is sufficiently complete. It outlines what is returned without needing to detail the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with the parameter 'n' already described as 'Maximum number of recent trades to return.' The description repeats this and adds no additional semantics, so it meets the baseline for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves 'the most recent trade records and committee verdict history.' It uses a specific verb ('Get') and resource, and distinguishes itself from siblings like 'live_prices' or 'status' by focusing on historical data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides usage context with example queries like 'what did I buy recently' and notes it is read-only. It does not explicitly mention when not to use or suggest alternatives, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ingest_eventAIdempotent
Feed a finance news item you (the host agent) found into the event ledger, graded and mapped to affected symbols, stored for committee RAG recall.
Preferred: normalize it yourself โ pass one_line_claim, stance,
severity (and ideally affected_symbols). The backend then only
validates and stores it; no backend model is involved. Without those
fields the backend model normalizes it, which fails when the backend runs
keyless (agent mode) โ you get an error telling you which fields to add.
You have far better search reach than the self-hosted crawler (including Chinese-language sources) โ proactively feed news relevant to the user's holdings, especially A-share/regional coverage the crawler misses. Idempotent: re-sending the same url or claim does not double-insert. Requires a backend LLM key.
Args:
title: Headline of the news item.
url: Canonical source URL (also the dedup key).
snippet: Short excerpt or summary of the article body.
source: Publisher name (e.g. "Reuters") โ the news outlet.
published_at: ISO 8601 publication time, if known.
ingested_by: Your own agent identity (e.g. "hermes") for provenance;
distinct in meaning from source.
Returns:
Ingestion result with the normalized event id(s), dedup status, and
committee_task_id โ set when a new holding-relevant event (severity
โฅ mid, non-neutral) triggered a rate-limited committee re-run. In
agent mode it is "queued:": the re-run waits for you in
pending_committees. This tool is disabled in advisory mode.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Canonical source URL (also the dedup key). | |
| title | Yes | Headline of the news item. | |
| source | No | Publisher name (e.g. 'Reuters') โ the news outlet. | |
| stance | No | For the holdings: 'risk', 'opportunity' or 'neutral'. Required with one_line_claim. | |
| snippet | No | Short excerpt or summary of the article body. | |
| entities | No | Key entities (countries, companies, central banks), lowercase. | |
| severity | No | 'low', 'mid' or 'high'. Required with one_line_claim. | |
| event_type | No | e.g. 'macro', 'policy', 'earnings', 'geopolitics', 'commodity', 'other'. | |
| ingested_by | No | Your own agent identity (e.g. 'hermes') for provenance; distinct from source. | host-agent |
| published_at | No | ISO 8601 publication time, if known. | |
| one_line_claim | No | Your one-sentence factual summary. Fill this (plus stance and severity) to ingest without any backend model โ preferred. | |
| affected_symbols | No | yfinance tickers the event materially affects, e.g. ['GC=F']. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it explains that the tool requires a backend LLM key, is disabled in advisory mode, is idempotent over url/claim, and that a new holding-relevant event can trigger a rate-limited committee re-run whose id is returned as 'queued:<id>' awaiting the agent in pending_committees. That is rich, decision-relevant behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and the preferred invocation path, then organizes detail into Args and Returns sections. It is long, but for a 12-parameter ingestion tool with mode gating and an error path, nearly every sentence carries weight; a few clauses are mildly redundant with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for the tool's complexity: it covers the preferred vs. fallback normalization, key requirement, idempotency, mode gating, error behavior, and the committee-trigger return semantics, so an agent can call it correctly and anticipate outcomes without reading the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter meaning the schema does not: the stance/severity/one_line_claim coupling and the preferred self-normalization bundle, plus the provenance distinction between ingested_by and source and the url-as-dedup-key role. It does not tie every parameter together, keeping it just below top marks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (feed/ingest) plus resource (finance news item) and the full downstream effect: graded, mapped to affected symbols, stored for committee RAG recall. It is clearly distinguishable from siblings such as news_sources, pending_news, and the committee tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance (proactively feed news the self-hosted crawler misses, especially A-share/regional coverage) and names the alternative normalization path (self-normalize vs. rely on the backend model), including the failure mode when keyless. Exclusions are stated too: disabled in advisory mode.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
live_pricesARead-only
Fetch a one-shot market backdrop: spot gold (USD/oz and CNY/gram),
USDCNY and AUDCNY FX rates, the NDQ.AX ETF price, the VIX volatility
index, and the 10-year US Treasury yield (TNX). A fixed set of reference
instruments, independent of what the user holds (use status for the
user's own positions).
Use for quick market context before analysis or when the user asks "how is the market / what's the gold price". Read-only; single batch, no arguments.
Returns:
Object keyed by instrument (GC_F_usd_per_oz, gold_cny_per_gram_spot,
USDCNY, AUDCNY, NDQ_AX, VIX, TNX) plus as_of ISO timestamp. A field
is null when its upstream quote is unavailable.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true, and the description reinforces this ('Read-only; single batch, no arguments') rather than contradicting it. It adds genuine behavioral context beyond annotations: the fixed-instrument scope and the null-field semantics when an upstream quote is unavailable. It stops short of stating freshness/latency guarantees, so not quite a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and routing constraint are front-loaded in the first paragraph, which is ideal. The trailing 'Returns' block enumerates every key and duplicates what the output schema already documents, making it the one part that doesn't fully earn its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-argument read-only tool this is complete: scope, sibling routing, read-only guarantee, batch behavior, and null handling are all covered, and an output schema exists to carry the return structure. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4. The description correctly states 'no arguments', which is consistent with the empty schema and leaves nothing ambiguous for the caller.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Fetch) and a precise, enumerated resource (spot gold, USDCNY/AUDCNY FX, NDQ.AX, VIX, TNX) as a fixed reference set. It also explicitly distinguishes itself from the sibling `status`, which covers the user's own positions. An agent can route correctly without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (quick market context before analysis; user asks 'how is the market / what's the gold price') and an explicit when-not, naming the alternative tool (`status`) for user-held positions with the condition that selects it. No inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
news_sourcesARead-only
List the news feed sources the crawler pulls from: the built-in default feeds plus user-added extra feeds. Extra feeds can be added/removed with add_news_source / remove_news_source; defaults are fixed.
Use when someone asks "what news sources do you follow" or before adding/removing a source.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true. Description adds context about built-in vs extra feeds and mentions related mutating tools, which is helpful but not extensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action and resource, no redundancy. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and zero parameters, the description fully explains what the tool returns (list of sources with types). No gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist; schema coverage is 100% (empty). Description correctly omits param details, as none are needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the verb 'list' and resource 'news feed sources', clearly distinguishing between built-in defaults and user-added extras. References sibling tools add_news_source and remove_news_source to differentiate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use: when someone asks 'what news sources do you follow' or before adding/removing a source. Provides clear context for invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pending_committeesAIdempotent
Committee re-runs that events or price moves requested while reasoning
is delegated to you (agent mode). For each item run prepare_committee,
the roles, then submit_committee; an item is done once a newer verdict
for that symbol is submitted. Requests expire after 24h.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true, destructiveHint=false, and readOnlyHint=false; the description usefully adds the 24h request expiry and the rule for when an item is considered done. However, it never explains why the tool is flagged non-read-only (does calling it claim or consume items?), leaving a real behavioral gap against its own annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with no filler, and the workflow instruction is front-loaded after the purpose. The opening sentence is a dense fragment with an awkward line break, which slightly hurts immediate parseability, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With zero parameters and an output schema present, the description does not need to describe return values, and it supplies the mode, workflow, completion rule, and TTL an agent needs to service the queue. The only missing piece is whether invoking it mutates state, which matters given readOnlyHint=false.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the schema imposes no semantic burden and the baseline is 4. There is nothing about arguments the description could or should clarify.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource (pending committee re-runs) and its trigger conditions (requested by events or price moves) and the operating mode (agent mode). It is a fragment rather than a verb-led statement, but an agent can tell it is the queue of committee work items it must service. It stops short of naming a sibling like run_committee to sharpen the contrast.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit follow-up procedure: for each item run `prepare_committee`, then the roles, then `submit_committee`, plus the completion condition (a newer verdict for that symbol) and the 24h expiry. What it does not state is when to call this tool itself versus run_committee or pending_news, so routing guidance is inferred rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pending_newsAIdempotent
News the backend fetched but did not normalize because reasoning is
delegated to you (agent mode). For each relevant item call ingest_event
with one_line_claim / stance / severity / affected_symbols; pass
the irrelevant ones back here as dismiss_urls. Items leave the queue once
ingested or dismissed, and expire after 48h.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max items to return. | |
| dismiss_urls | No | URLs you reviewed and judged irrelevant to the holdings; they won't be offered again. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=true), and the description adds real context beyond that: the queue-draining behavior, the 48h expiry, and the fact that dismissal permanently suppresses the URL. It doesn't explain pagination or ordering, but the mutation and lifecycle semantics are well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then gives the per-item workflow in one compact thought. Efficient and well ordered, though the path-like parameter listing (`one_line_claim` / `stance` / ...) is slightly dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. Together with the annotations, the description covers the workflow, the sibling handoff, the queue lifecycle, and the expiry window โ everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both limit and dismiss_urls are already documented. The description reinforces the intent of dismiss_urls (irrelevant items passed back), which is marginal added value over the schema's own 'they won't be offered again'. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (news the backend fetched but did not normalize) and the reason it exists (reasoning is delegated to the agent). It is distinguishable from ingest_event and the other news siblings by scope: this is the raw intake queue, not the ingestion or source-management tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: call ingest_event for relevant items, pass irrelevant ones back as dismiss_urls. It also states the lifecycle condition (items leave the queue once ingested or dismissed, expire after 48h), so when-to-use and when-it-disappears are both answered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
place_fund_orderADestructive
Record the first leg of an off-exchange fund purchase the user already
placed with the fund platform: cash - amount, and the order is tracked as
in transit (status.pending_fund_orders). Total assets do not change
(the in-transit amount counts at face value), so there is no fake dip
between order day and confirmation. Shares arrive when the pricing-day NAV
is published: the fund_confirm job confirms automatically, or call
confirm_fund_order. Bookkeeping only โ openInvest never places orders.
The expected confirm date uses a Monday-Friday calendar (no China holiday
table) and a lag by fund type (QDII / FOF are slower, read from the fund's
profile); the result says so (calendar, lag_source).
Confirm fund, amount, and order time with the user before calling; this moves ledger cash.
Args: symbol: FUND:<6 digits>. amount: Subscription amount in CNY; must be > 0. currency: Currency of the amount (CNY). order_ts: Order time, ISO 8601 Beijing time (default now). note: Free-text note. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns:
order_id, pricing day (nav_date), expected confirm date, and new cash
balance, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Free-text note stored with the order and ledger row. | |
| amount | Yes | Subscription amount in CNY (cash deducted now); must be > 0. | |
| symbol | Yes | Off-exchange China mutual fund: 'FUND:<6-digit code>' (a bare 6-digit code is also accepted). | |
| currency | No | Currency of the amount; off-exchange funds are CNY. | CNY |
| order_ts | No | When the order was placed, ISO 8601 in Beijing time (e.g. '2026-10-19T14:30:00'); default now. Before 15:00 on a trading day the order is priced at that day's NAV, otherwise at the next trading day's. Pass the real time when back-filling an order placed earlier. | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, destructiveHint=true) by spelling out the actual ledger effect: cash is deducted now, the in-transit amount counts at face value so total assets don't move and there is no fake dip. It also discloses the confirm-date calendar limitation (MondayโFriday, no China holiday table), the lag_source, and the idempotency-key retry semantics, which is exactly the kind of side-effect detail an agent needs for a mutating tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and ledger effect, then supporting caveats, then args/returns. Efficient for the amount of information conveyed, though the Returns block is partially redundant given an output schema exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutating, non-idempotent bookkeeping tool with 6 params, this covers side effects, timing/NAV rules, confirmation workflow, retry semantics, and the sibling used to confirm. With an output schema present, the extra return-value summary is harmless and nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema descriptions are more detailed than the description's Args block (e.g. the 15:00 NAV cutoff and the idempotency-key duplicate behavior live in the schema). The description restates symbol/amount/currency without adding format or edge-case meaning beyond what the schema already provides, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource ('record the first leg of an off-exchange fund purchase') and immediately draws the boundary that distinguishes it from siblings: 'Bookkeeping only โ openInvest never places orders.' An agent can tell it apart from buy/confirm_fund_order/record_execution without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when-to-use context ('the user already placed' the order, confirm fund/amount/time before calling) and names the alternative path for confirmation (the `fund_confirm` job or `confirm_fund_order`). It stops short of explicitly excluding the look-alike `buy` tool, so routing is good but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prepare_committeeAIdempotent
Step 1 of the agent-run committee (Coordinator path): get everything YOU need to play the 4 roles yourself โ no backend LLM key involved.
Returns the deterministic data blocks (regime, sentiment / defense flag,
valuation, macro, events, portfolio, path reference) plus the 6 role
prompts and instructions describing the 3 rounds. Run Macro / Quant /
Risk (cheap subagents are fine), write the CIO memo yourself, then call
submit_committee with the full transcript.
The backend keeps its own copy of the deterministic facts from this call and uses them when you submit (defense downgrade, regime, path snapshot), so a fact you forget to paste cannot silently switch a rule off. Submit within 6 hours of preparing.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | A symbol already in strategy target_assets, e.g. 'GC=F', 'NDQ.AX'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false), the description discloses genuinely important behavior: the backend retains its own copy of the deterministic facts and reuses them at submit time (defense downgrade, regime, path snapshot) so omitted facts can't silently disable a rule, and the prepared data expires after 6 hours. This is exactly the kind of stateful/expiry/auth-adjacent context the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The step-by-step structure is front-loaded with the purpose and then the sequence, and each statement adds value. It runs a bit long with parentheticals, but nothing is truly wasted given the multi-step workflow described.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex prep tool with no output schema, the description enumerates the returned payload (regime, sentiment/defense flag, valuation, macro, events, portfolio, path reference, the 6 role prompts, and instructions for the 3 rounds), which is exactly what an agent needs to proceed. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and there is a single well-documented parameter, so the schema already carries the semantics. The description adds no syntax or format guidance for `symbol` beyond what the schema states, making a baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb+resource+scope: 'Step 1 of the agent-run committee (Coordinator path): get everything YOU need to play the 4 roles yourself.' It distinguishes itself from sibling paths by explicitly ruling out a 'backend LLM key' and by naming the follow-up tool submit_committee, so an agent can place it relative to run_committee and submit_committee immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear sequencing: run Macro/Quant/Risk subagents, write the CIO memo, then call submit_committee, plus a concrete 6-hour submission window. It never explicitly states when NOT to use it versus the alternative run_committee path, so the choice between the two coordinator/backend paths is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rebalance_planARead-only
Compute a rebalance list against the target allocation in strategy.md: what to BUY / SELL, how much, in whole lots, and why. Only produces the list, places no order โ the human executes. No LLM call.
Use when the user asks "do I need to rebalance", "how far am I from my
target allocation" or "what should I buy/sell to get back on target".
Per-asset targets come from target_assets[].target_pct in strategy.md;
assets without one split target_allocation_stock equally
(target_source: "equal_split"). Lot sizes: A-shares 100, convertible
bonds 10, off-exchange funds by amount, HK/others 1 (HK lot size is
unknown โ see lot_note).
Args: mode: "cash_only" | "sell_to_rebalance" | "hybrid" (default). band_pct: Drift band in percentage points, default 5.
Returns:
rows (per target asset: current_pct / target_pct / drift_pct /
action BUY|SELL|NONE / amount in base currency / units / reason),
totals (cash_after, turnover, n_trades), unmanaged holdings,
warnings; or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | cash_only: buy underweights with cash above the target cash ratio, never sell. hybrid (default): use that cash first, sell overweights only to cover the shortfall. sell_to_rebalance: sell every overweight back to target and buy underweights with the proceeds plus spare cash. | hybrid |
| band_pct | No | Drift band in percentage points (default 5): holdings within ยฑband of target are left alone. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond readOnlyHint: it places no order, makes no LLM call, explains target sourcing, equal-split fallback, lot-size rules, and return/error shape. This is rich context for a read-only planning tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads what the tool computes and the key no-order boundary, then provides useful usage and return details. It is somewhat long, and the returns section is partly redundant because an output schema exists, but overall it is structured and mostly earns its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich input schema, output schema, and readOnlyHint annotation, the description covers the remaining agent-relevant context: target allocation sourcing, lot-size constraints, human execution, no LLM call, and error returns. Nothing critical is missing for correct selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters already have detailed schema descriptions, including mode semantics, defaults, and band_pct range. The description repeats the mode/band basics rather than adding much parameter-specific meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: compute a rebalance list against target allocation, with explicit scope that it only produces BUY/SELL/NONE recommendations and places no orders. This clearly distinguishes it from execution-oriented siblings such as buy, sell, and record_execution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit user-question triggers ('do I need to rebalance', 'how far am I from target', 'what should I buy/sell'). It also clarifies the human-execution boundary, though it does not explicitly name all relevant alternatives such as what_if for scenario analysis.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_dividendADestructive
Record a dividend (or interest) the user already received: credits ledger cash by amount - tax_withheld, positions unchanged. It counts as account return (inside NAV), not as a deposit. Bookkeeping only โ openInvest never moves money.
Confirm symbol, gross amount, withholding tax, and the date with the user before calling; this moves ledger cash. A symbol that is neither held nor in the ledger is rejected (typo guard).
Args:
amount: Gross amount before withholding tax; must be > 0.
currency: Currency of the cash credited.
symbol: Ticker (required for dividends; optional for interest).
kind: "dividend" (default) or "interest".
tax_withheld: Tax withheld at source; credited cash = amount - tax_withheld.
reinvest: DRIP โ buy more symbol with the net amount.
reinvest_price: Price per unit for the reinvestment (default: stored raw close).
trade_date: YYYY-MM-DD the cash arrived (default today).
note: Free-text note.
idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Cash credited and new balance, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | 'dividend' (default) or 'interest' (money-market / cash-account interest). | dividend |
| note | No | Free-text note stored with the ledger row. | |
| amount | Yes | Gross amount before withholding tax (for kind='interest': the interest credited); must be > 0. | |
| symbol | No | yfinance ticker the dividend belongs to (required for kind='dividend'; optional for interest = account-level). | |
| currency | Yes | Currency the cash was credited in, e.g. 'CNY', 'USD', 'AUD'. | |
| reinvest | No | DRIP: use the net cash to buy more of `symbol` (adds a second ledger row, source='drip'). The holding must exist and be in `currency`. | |
| trade_date | No | Date the event happened, YYYY-MM-DD (default: today). Account performance books it on this date, so pass the real date when back-filling history. | |
| tax_withheld | No | Tax already withheld at source (kind='dividend' only); cash credited = amount - tax_withheld. | |
| reinvest_price | No | Reinvestment price per unit. Omit to use the stored raw close for the date (run `backfill_raw_close` first). | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnlyHint=false, destructiveHint=true, idempotentHint=false), the description discloses rich behavioral detail: exactly how cash is credited, that positions are unchanged, that it counts as account return inside NAV, that it is bookkeeping-only and never moves money, that a non-held/ledger symbol is rejected, and how the idempotency_key produces a duplicate response on retry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded: the core effect appears in the first sentence, followed by a confirmation directive, then an Args block and a brief Returns note. It is somewhat long because the Args section duplicates the 100%-covered schema descriptions, but the structure remains clear and each section is purposeful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (10 parameters, mutation with ledger effects, idempotency, reinvestment, typo guard), the description covers all necessary context. An output schema exists, so the minimal 'Returns' line is sufficient without describing return values in detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all ten parameters. The description largely restates those schema descriptions (e.g., amount > 0, tax_withheld formula, reinvest meaning) and adds only minor emphasis, so it does not meaningfully extend parameter semantics beyond the structured data.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource ('Record a dividend (or interest)') and immediately clarifies the accounting treatment ('credits ledger cash by amount - tax_withheld, positions unchanged'). It also distinguishes the action from a sibling concept by explicitly saying it 'counts as account return (inside NAV), not as a deposit.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly scopes usage to dividends or interest 'the user already received' and adds a prerequisite ('Confirm symbol, gross amount, withholding tax, and the date with the user before calling'). It rules out deposit-like behavior and warns about the typo guard, but does not name or route to alternative sibling tools for other income events (e.g., record_return_of_capital).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_executionAIdempotent
Record whether the user executed or declined a committee verdict, with their reason. Appends to the execution ledger; idempotent โ replaying the same record is a no-op, so retries are safe.
Call when the user says "I bought it / I didn't buy / I disagree". When
they decline, ask one short question for the reason first โ this closes
the adoption-rate loop that decisions reports on.
Args:
decision_id: "/" from the decisions output.
executed: True if the user acted on the verdict, False if declined.
reason: The user's stated reason (especially when declined).
trade_ids: Optional trade record IDs to link explicitly.
Returns: The stored execution record, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No | The user's stated reason (especially when declined). | |
| executed | Yes | True if the user acted on the verdict, False if they declined. | |
| trade_ids | No | Optional trade record IDs to link explicitly. | |
| decision_id | Yes | "<date>/<symbol>" from the decisions tool output. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description complements the annotations by explaining the idempotent behavior: 'replay the same record is a no-op, so retries are safe'. It also notes that the tool appends to the execution ledger and returns the stored record or error, providing full behavioral disclosure beyond the annotations' flags.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: first sentence states purpose, then behavioral note, usage guidance, Args, and Returns. Every sentence serves a purpose, and the structure is easy to parse. No unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 4 parameters (2 required), an output schema, and annotations, the description covers all necessary context: purpose, when to call, how to handle edge cases (decline), parameter details, and return value format. It is complete for effective agent use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds value by explaining the format of `decision_id` ("<date>/<symbol>") and the context for `reason` (especially when declined). While the Args section is somewhat redundant with the schema, it provides a clear, contextual listing that helps the agent understand parameter relationships.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the verb 'Record' and the resource 'execution of committee verdict'. It distinguishes itself by specifying the scope (whether the user executed or declined) and mentions idempotency and retry safety, which are unique traits among siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-call scenarios: 'when the user says "I bought it / I didn't buy / I disagree"'. It also gives specific guidance for the decline case: ask one short question for the reason first, referencing the sibling tool `decisions` and the adoption-rate loop.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_existing_positionADestructive
Record a position the user already held before using openInvest
(onboarding backfill) WITHOUT touching ledger cash. History is marked
funding_source: external_funding, source: mcp:existing_position.
Only for positions that status does not list yet โ calling it for a
symbol already there adds the units again (double count). A new purchase
paid from ledger cash is buy. Does not add the symbol to the tracked
list; use track_asset for committee coverage.
Args:
symbol: yfinance ticker (e.g. "AAPL", "510300.SS"). Gold = "GC=F", booked in
CNY per gram only (units = grams, currency "CNY", kind "metal", unit_label "ๅ
").
units: Quantity held; must be > 0.
price: Average cost per unit, in currency.
currency: Currency of price; omitted = the existing position's currency (CNY if new).
kind: Asset kind tag: "equity", "etf", "metal" (gold), "crypto", "bond", "fund", "other".
unit_label: Human display label for units (default "่ก", i.e. shares).
idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Updated position summary, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Asset kind tag: 'equity', 'etf', 'metal' (gold), 'crypto', 'bond', 'fund', 'other'. | equity |
| price | Yes | Average cost per unit, in `currency`. | |
| units | Yes | Quantity held; must be > 0. | |
| symbol | Yes | yfinance ticker, e.g. 'AAPL', '510300.SS'. Gold is 'GC=F' and must be booked per gram in CNY: units = grams, price = CNY/gram, currency='CNY', kind='metal', unit_label='ๅ ' (USD/oz bookings are rejected). | |
| currency | No | Currency of `price`, e.g. 'CNY', 'USD', 'AUD'. Omit to use the existing position's currency (CNY for a new position); a different currency than the position's is rejected. | |
| unit_label | No | Human display label for units (default '่ก', i.e. shares). | ่ก |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations covering readOnly=false/destructive=true, the description adds substantial behavior the annotations cannot convey: no cash is touched, history is tagged `funding_source: external_funding` / `source: mcp:existing_position`, duplicate calls double-count unless retried with the same idempotency key, and the symbol is not added to the tracked list. This is consistent with idempotentHint=false rather than contradicting it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose paragraph is well front-loaded and high value, but the trailing Args/Returns block repeats schema descriptions verbatim (units, price, currency, kind, unit_label, idempotency_key) at 100% coverage, inflating an otherwise tight definition for no new information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still surfaces the error envelope; combined with the cash-neutrality guarantee, duplicate-counting hazard, gold booking convention, and alternatives, nothing material an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all seven parameters (including the gold-in-CNY-per-gram rule and the idempotency_key semantics) are already documented in the schema. The Args block largely restates those same descriptions, adding little that isn't already structured, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (record an already-held position) with its precise niche: onboarding backfill, no ledger cash movement. It explicitly distinguishes itself from `buy` (new purchase from cash) and `track_asset` (committee coverage), so an agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when (positions the user held before openInvest, not yet in `status`) and an explicit when-not (calling it for a symbol already in `status` adds units again โ double count). It also names the two alternative tools and the conditions that select them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_feeADestructive
Record a fee or a tax the user already paid: debits ledger cash, positions unchanged. It is an account cost (inside NAV), not a withdrawal. Trade commissions need no separate entry โ buy / sell already book the trade. Fails if the currency's cash balance is lower than the amount.
Confirm the amount and date with the user before calling; this moves ledger cash.
Args: amount: Amount paid; must be > 0. currency: Currency of the cash debited. kind: "fee" (default) or "tax". symbol: Related ticker (optional). trade_date: YYYY-MM-DD it was charged (default today). note: Free-text note. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Cash debited and new balance, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | 'fee' (default: account / remittance / standalone commission) or 'tax' (e.g. dividend tax settled afterwards). | fee |
| note | No | Free-text note stored with the ledger row. | |
| amount | Yes | Amount paid (positive number); must be > 0. | |
| symbol | No | Ticker the fee/tax relates to (optional; omit for account-level). | |
| currency | Yes | Currency the cash left in, e.g. 'CNY', 'USD', 'AUD'. | |
| trade_date | No | Date the event happened, YYYY-MM-DD (default: today). Account performance books it on this date, so pass the real date when back-filling history. | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=false, but the description adds the actual failure mode ('fails if the currency's cash balance is lower than the amount'), the ledger semantics (cash debited, positions untouched, inside NAV), and the human-confirmation requirement. It slightly softens the non-idempotent annotation by describing conditional safety via idempotency_key without reconciling the two, which is a minor gap rather than a contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the accounting distinction and the failure condition, then a compact Args/Returns block. The Args section duplicates schema text almost verbatim, which is mild waste, but the overall structure is easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers what matters for a destructive mutation: prerequisite confirmation, the cash-balance failure condition, what is and is not affected, and idempotent retry behavior. With an output schema present it doesn't need to explain return values, though it does so briefly anyway.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented, including the enum for kind and the idempotency_key retry semantics. The Args block mostly restates the schema ('must be > 0', 'YYYY-MM-DD') and adds little syntax or format detail of its own, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Record a fee or a tax the user already paid') and immediately scopes the accounting effect: 'debits ledger cash, positions unchanged. It is an account cost (inside NAV), not a withdrawal.' That explicitly separates it from withdraw and from buy/sell siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not guidance: trade commissions need no separate entry because buy/sell already book them, and it is not a withdrawal. It also imposes a procedural rule the agent must follow โ confirm amount and date with the user before calling โ which is the kind of routing detail siblings can't express.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_return_of_capitalADestructive
Record a return of capital (some ETF / REIT distributions): credits ledger cash, lowers the holding's average cost by amount / units (a cost reduction, not income), units unchanged. Cost floors at 0; any excess is reported as excess_over_cost (treat as a capital gain).
Confirm symbol, amount, and date with the user before calling; this moves ledger cash and changes average cost.
Args: symbol: Held ticker. amount: Cash received; must be > 0. currency: Currency of the cash (must match the holding's cost currency). trade_date: YYYY-MM-DD received (default today). note: Free-text note. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: New average cost, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Free-text note stored with the ledger row. | |
| amount | Yes | Cash received as return of capital; must be > 0. | |
| symbol | Yes | yfinance ticker of an existing holding. | |
| currency | Yes | Currency received; must equal the holding's cost currency. | |
| trade_date | No | Date the event happened, YYYY-MM-DD (default: today). Account performance books it on this date, so pass the real date when back-filling history. | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only generic annotations (readOnlyHint=false, destructiveHint=true, idempotentHint=false), the description carries the real burden and does: it explains the exact ledger effect (credits cash, lowers average cost by amount/units, units unchanged), the floor-at-0 edge case, how excess is surfaced as excess_over_cost (capital gain), and the retry semantics of idempotency_key including the 'duplicate' response. This is substantive disclosure well beyond what the annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The behaviorally important material (mutation effect, cost floor, confirmation prompt) is front-loaded before the Args/Returns sections, which is good. The Args block duplicates the schema nearly verbatim, costing some space, but nothing is misleading and the prose is tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a mutation tool with rich annotations and an existing output schema, the description supplies everything an agent needs: the precise accounting effect, the excess-over-cost special case, the required user confirmation, and idempotent-retry guidance. Nothing material is left undefined.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already documents each parameter thoroughly (including the detailed idempotency_key semantics). The description's Args block largely restates that information, adding only marginal framing ('must match the holding's cost currency'), so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Record a return of capital'), scopes it to 'some ETF / REIT distributions', and immediately distinguishes it from income events by noting it is 'a cost reduction, not income' โ enough to separate it from siblings like record_dividend or record_fee without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear precondition ('Confirm symbol, amount, and date with the user before calling') and the qualifying context ('some ETF / REIT distributions', 'not income'), which implies when this tool applies versus a dividend recorder. It stops short of explicitly naming an alternative tool or stating a when-not-to-use case, so it lands just below the top.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_splitADestructive
Record a stock split / reverse split: units x ratio, average cost / ratio, cash unchanged (market value is unchanged). Call it once per split โ a second call multiplies the position again; use an idempotency_key if unsure whether an earlier attempt landed. Rejected when the ledger already has trades / corrections for the symbol on or after trade_date (their units are already post-split, so multiplying the whole snapshot would invent shares) โ pass ledger_only=true if the snapshot is already correct.
Confirm symbol, ratio, and ex-date with the user before calling; this rewrites the position's units and average cost.
Args: symbol: Ticker that split. ratio: New / old shares (10-for-1 = 10; 1-for-10 reverse = 0.1). trade_date: Ex-date YYYY-MM-DD (default today). note: Free-text note. ledger_only: Write the ledger row only; do not change units / average cost. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns:
New units / average cost (plus a follow_up hint), or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | Free-text note stored with the ledger row. | |
| ratio | Yes | New shares per old share: a 10-for-1 split is 10, a 1-for-10 reverse split is 0.1. Must be > 0 and not 1. | |
| symbol | Yes | yfinance ticker that split (must be held now or appear in the ledger). | |
| trade_date | No | Ex-date of the split, YYYY-MM-DD (default: today). Pass the real ex-date when back-filling: account performance uses it to restate earlier trades. | |
| ledger_only | No | Only write the ledger row, leave the holding's units / average cost untouched. Use it when the snapshot already reflects the split (e.g. you fixed the units by hand, or later trades were booked in post-split units). | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=false; the description is consistent with both and adds real context: it rewrites units and average cost, the rejection condition, and the duplicate-return behavior when reusing an idempotency_key. Return shape is mentioned but an output schema already covers that, so it is a modest addition rather than a gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core behavior and mutation warning, then the rejection rule, then a caution. The trailing Args/Returns block duplicates the JSON schema descriptions verbatim, which is redundant, but the prose paragraphs themselves are tight and every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, non-idempotent mutation with 6 parameters, the description covers the arithmetic effect, the confirmation requirement, the double-apply hazard, the rejection condition with its workaround, and retry semantics. An output schema exists, so the brief Returns line is sufficient rather than insufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all six parameters, and the Args block largely restates it. What the description adds beyond the schema is the derived semantics โ that units multiply by ratio while average cost divides by it, with cash untouched โ which tells the agent the actual effect of the ratio value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Record a stock split / reverse split") and immediately gives the arithmetic effect: units x ratio, average cost / ratio, cash unchanged. This clearly separates it from sibling mutation tools like record_dividend, record_return_of_capital, and record_fee.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to call it once per split and warns that a second call multiplies the position again. It also names the precondition that causes rejection (existing trades/corrections on or after trade_date) and the escape hatch (ledger_only=true), plus a confirmation-before-calling instruction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_news_sourceADestructive
Remove a user-added news feed by name or URL. Built-in default feeds cannot be removed.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Feed name or URL to remove (extra feeds only; defaults can't be removed). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as destructive (destructiveHint: true). The description adds specific behavioral context: only user-added feeds can be removed, default feeds are protected. This goes beyond the annotation's binary flag.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with the main purpose, followed by a key limitation. No unnecessary words or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description adequately covers the tool's function and main constraint for a simple delete operation. With an output schema present, return values are not needed. Minor gap: no mention of behavior for non-existent keys or confirmation requirements.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a description for the 'key' parameter that already specifies it can be a feed name or URL and excludes defaults. The tool description adds no additional semantic value beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description uses specific verb 'Remove' and resource 'user-added news feed', clearly distinguishing from sibling tools like add_news_source and news_sources. It also explicitly states that built-in default feeds cannot be removed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Description indicates when to use (remove user-added feeds) and when not (defaults cannot be removed). It provides clear context but does not explicitly name alternative tools for adding or listing feeds, though those are implied by sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_committeeAIdempotent
Run the 4-role LLM investment committee on a symbol (Direct path): Macro Strategist, Quant Analyst, and Risk Officer debate from isolated evidence, then a CIO synthesizes one calibrated BUY/HOLD/SELL-style verdict with a written memo.
Requires a backend LLM key (e.g. DEEPSEEK_API_KEY) and takes 30-90s on
a cache miss. If the symbol was already analyzed today, the cached
verdict is returned instantly unless force is set. Sends MCP progress
notifications per debate phase when the client asks for them. Decision
support only โ the human always executes.
Args: symbol: Symbol to analyze. Listed assets use yfinance tickers: US "AAPL", A-share "603083.SS" (Shanghai) / "000001.SZ" (Shenzhen), HK "0700.HK", exchange ETF "510300.SS", crypto "BTC-USD", futures "GC=F". China off-exchange (OTC) mutual funds use "FUND:<6-digit code>", e.g. "FUND:110011". A bare 6-digit code is rejected โ add the suffix or the FUND: prefix. force: Re-run even if a verdict already exists for today. max_rounds: Cross-challenge debate rounds (default 1).
Returns:
Object with decision_id, cached flag, verdict and
confidence_lookup (show this to the user instead of the
self-reported confidence). The shape differs by path:
- cached: false (fresh run): verdict is an object (verdict,
confidence, suggested allocation, ...).
- cached: true (today's transcript): verdict is the verdict string,
with confidence, alloc_cny, alloc_currency alongside, plus the
CIO memo as cio_memo and the deterministic input_health block
(empty inputs, rewrite rules applied, forced HOLD) โ no need to call
explain_decision just to read them.
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | Re-run even if a verdict already exists for today. | |
| symbol | Yes | Symbol to analyze. Listed assets use yfinance tickers: US 'AAPL', A-share '603083.SS' (Shanghai) / '000001.SZ' (Shenzhen), HK '0700.HK', exchange ETF '510300.SS', crypto 'BTC-USD', futures 'GC=F'. China off-exchange (OTC) mutual funds use 'FUND:<6-digit code>', e.g. 'FUND:110011'. A bare 6-digit code is rejected โ add the suffix or the FUND: prefix. | |
| max_rounds | No | Cross-challenge debate rounds. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past annotations: discloses the hard dependency on a backend LLM key, the 30-90s cache-miss latency, caching semantics keyed to the day plus `force`, and streaming progress notifications per debate phase. It also adds a safety framing ('Decision support only โ the human always executes') and warns that `confidence_lookup` should supersede the self-reported confidence, which the annotations say nothing about.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and latency/caching caveats are front-loaded in the first two paragraphs, and the Args/Returns structure is easy to scan. It is somewhat long and the Args block duplicates schema text that is already 100% covered.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers everything an agent needs before calling: symbol formatting edge cases (bare 6-digit code rejected, FUND: prefix), auth dependency, latency, cache-busting, and the fact that the return shape differs between cached:false and cached:true including the input_health block. Even with an output schema present, the path-dependent shape difference is essential context that the schema alone would not convey.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every parameter is already documented; the description's Args block largely restates the symbol and force text verbatim and adds only the effective default for max_rounds. A baseline 3 is appropriate when the schema carries the full parameter burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Run the 4-role LLM investment committee on a symbol') and spells out the roles and the output (a CIO-synthesized BUY/HOLD/SELL memo). The '(Direct path)' label hints at a staged alternative but never names prepare_committee/submit_committee, so sibling differentiation is implied rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: a backend LLM key is required, a fresh run takes 30-90s, and today's cached verdict is returned unless `force` is set. It also steers the agent away from a sibling ('no need to call explain_decision just to read them'). What's missing is an explicit statement of when to prefer the staged/alternate committee path over this direct one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sellADestructive
Record a sell in the local ledger: reduces the position's units (average cost unchanged) and credits cash in the holding's cost currency. Bookkeeps a trade already executed at the user's broker โ openInvest never places real orders.
Confirm symbol, units, and price with the user before calling; this moves ledger cash.
Args: symbol: yfinance ticker of an existing holding. units: Quantity sold; must be > 0. price: Execution price per unit, in the holding's cost currency. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Updated position summary, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| price | Yes | Execution price per unit, in the holding's cost currency. | |
| units | Yes | Quantity sold; must be > 0. | |
| symbol | Yes | yfinance ticker of an existing holding. | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare destructiveHint=true and idempotentHint=false, but the description adds substantive context beyond them: which ledger fields change (units down, average cost unchanged, cash credited in cost currency), the warning that cash moves, and the retry/dedupe behavior of the idempotency key. No contradiction with the annotations โ a fresh call with a new key legitimately sells more, consistent with idempotentHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the ledger effect and the pre-call confirmation, then organizes details under Args/Returns headings. Slightly redundant with the schema's parameter descriptions, but every section earns its place for a cash-moving mutation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, cash-affecting mutation with an output schema present, the description covers what the tool does, what it alters, the confirmation requirement, and retry semantics. Nothing an agent needs in order to call it safely is missing, and return values needn't be expanded since the output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters including idempotency_key semantics are already documented in the schema. The Args block largely restates those same definitions with no added syntax, format, or edge-case guidance. Baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Record a sell in the local ledger') and immediately describes the ledger effect: reduces units with average cost unchanged, credits cash in the holding's cost currency. It also distinguishes itself from order-placing siblings by stating openInvest never places real orders, so an agent can tell it apart from place_fund_order or record_execution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit pre-call guidance ('Confirm symbol, units, and price with the user before calling; this moves ledger cash') and scopes the tool to bookkeeping already-executed trades, which routes the agent away from real-order tools. It stops short of naming a specific sibling to use instead in ambiguous cases, so it is strong but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_allocationsAIdempotent
Update the strategy's target allocation: the stock/cash ratio and/or
the per-asset target weights that rebalance_plan reads, and/or the
per-asset alert lines the price sentinel watches. The stock and
cash values must sum to โ1.0, and the per-asset weights must sum to at
most the stock target; schema validation rejects and rolls back any write
that would corrupt the strategy file. Everything in one call is validated
and written atomically โ to lower the stock target below the current sum
of per-asset weights, pass the new weights in the same call.
Use when the user says e.g. "set my target to 70% stock / 30% cash" or "put 30% in 510300.SS and 20% in gold".
Args: target_allocation_stock: Stock weight in [0, 1], e.g. 0.7 (with cash). target_allocation_cash: Cash weight in [0, 1], e.g. 0.3 (with stock). target_pcts: {symbol: weight in [0, 1]} per tracked asset; null clears. alerts: {symbol: {rule: value}} alert lines per tracked asset; null clears a rule (or, for a whole symbol, all its rules).
Returns: The updated allocation and target assets, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| alerts | No | Per-asset alert lines as {symbol: {rule: value}}, rule in price_above / price_below / day_drop_pct / day_rise_pct / drawdown_from_cost_pct, e.g. {'GC=F': {'price_below': 900, 'day_drop_pct': 2}}. Rules you name overwrite, a null rule value clears just that rule, rules you don't mention stay; a null for the whole symbol clears all its alerts. Symbols must already be tracked. *_pct values are percentage points (3 = 3%), unlike target_pct. Alerts are only delivered when INVEST_EVENT_ALERT=1 is set on the server. | |
| target_pcts | No | Per-asset target weights as {symbol: fraction of total assets in [0, 1]}, e.g. {'510300.SS': 0.3, 'GC=F': 0.2}. Symbols must already be tracked (see track_asset). A null value clears that asset's target (back to an equal split). The weights must sum to <= target_allocation_stock (the new one if you pass it in the same call). | |
| target_allocation_cash | No | Cash weight in [0, 1], e.g. 0.3. Pass together with target_allocation_stock; omit both to leave the split unchanged. | |
| target_allocation_stock | No | Stock weight in [0, 1], e.g. 0.7. Pass together with target_allocation_cash (they must sum to ~1.0); omit both to leave the stock/cash split unchanged. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare mutation (`readOnlyHint: false`), idempotency, and non-destructiveness, but the description adds substantial behavioral context: writes are validated and atomic, invalid writes roll back, clearing semantics differ for rules vs whole symbols, and alerts are only delivered when `INVEST_EVENT_ALERT=1` is set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and usage, then organized into Args and Returns. Some Args content duplicates the already rich schema descriptions, but the structure remains clear and the extra detail is not harmful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a mutation tool with four optional parameters, rich annotations, an output schema, and nested alert/target maps, the description supplies the remaining operational context: atomic validation, rollback behavior, sum constraints, and alert delivery prerequisites. Nothing critical appears missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents each parameter thoroughly, including examples, clearing behavior, and percentage-point semantics for alerts. The description's Args section largely restates those constraints rather than adding new parameter-level meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (update) and resource (strategy target allocation) with the exact fields affected: stock/cash ratio, per-asset target weights, and alert lines. It also names related consumers (`rebalance_plan` and the price sentinel), making the tool distinguishable from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete user-utterance examples such as 'set my target to 70% stock / 30% cash' and 'put 30% in 510300.SS and 20% in gold'. It also explains a key conditional workflow: lowering the stock target below current per-asset weights requires passing new weights in the same call. It does not provide explicit when-not-to-use guidance or name sibling alternatives for adjacent tasks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusARead-only
Get a full snapshot of the user's portfolio: cash balances per currency, every holding with units / average cost / live price, and unrealized P&L per position and in total.
Use when the user asks "show my portfolio", "how is my P&L", or before proposing any trade. Read-only; fetches live quotes, so values change between calls.
Returns:
Object with cash (currency โ amount), all_holdings (every position,
priced the same way whatever the symbol: units, avg_cost, live price,
market value, pnl_pct; null price fields when a quote is unavailable;
each carries alerts, the user's per-asset alert lines with the
distance still to go, e.g. "่ท price_below ่ฟๆ 3.2%" โ a tracked asset
with alert lines but no holding row appears as an is_tracking_only row),
total_assets_cny, fx (rate to CNY per non-CNY currency in use), an
optional gold summary when a gold-per-gram holding exists, and
performance (real-account TWR 30d / YTD / since inception, XIRR, max
drawdown with peak/trough dates, annualised volatility, return vs the
configured benchmark, price_basis per symbol (raw | adjusted), and data_quality;
or {"status": "insufficient_history"} until the ledger spans 2 trading days),
income_30d (dividends / interest received in the last 30 days by currency;
only present when there are any), and pending_fund_orders +
pending_fund_orders_line (off-exchange fund orders placed but not yet
confirmed โ cash already deducted, total_assets_cny counts them at face
value; only present when there are any).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint; the description adds the operationally important fact that it fetches live quotes so values change between calls โ an agent must know not to cache or compare stale snapshots. It also discloses degradation behavior (null price fields on unavailable quotes, {"status": "insufficient_history"} until two trading days of ledger exist) and conditional field presence, none of which is inferable from the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Structure is good โ purpose, then when-to-use, then returns, front-loaded correctly. But the Returns block runs long for a zero-argument tool and largely re-enumerates fields the output schema already defines (fx, total_assets_cny, performance, income_30d, pending_fund_orders), burying the genuinely useful caveats (null quotes, is_tracking_only rows, insufficient_history) inside field-by-field detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-complexity portfolio snapshot the description covers the full surface an agent needs: what is returned at a summary level, how missing quotes and tracking-only assets appear, the insufficient-history state, and that figures shift between calls. An output schema exists, so it is not required to enumerate returns โ doing so makes it more than complete, not less.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so there is no parameter semantics to explain; the baseline for a no-arg tool applies. Nothing in the description misdescribes or implies hidden inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource plus an enumeration of scope: cash per currency, units/avg cost/live price per holding, unrealized P&L per position and total. That is far more than a restatement of the name. It stops short of a 5 because it never names the overlapping siblings (live_prices, daily_report, history) that an agent might otherwise reach for when it just needs quotes or a summary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete trigger phrases ("show my portfolio", "how is my P&L") and a forward-looking trigger ("before proposing any trade"), which is real routing guidance rather than implied usage. No exclusions or named alternatives, so it sits at a clear 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
strategyARead-only
Get the user's investment strategy: target stock/cash allocation, the list of tracked assets (per-asset investment cap, purchase channel, fee settings), and long-term insights distilled by the nightly Dreaming memory-consolidation job.
Use when deciding whether a proposed trade fits the user's plan, or when the user asks "what is my strategy / what am I tracking". Read-only.
Returns:
Object with target_allocation (stock/cash ratios), target_assets
(tracked symbols with constraints), and insights (distilled
lessons from past decisions).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide readOnlyHint=true. The description adds context about the return value structure and the nightly Dreaming job, enhancing transparency beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-organized with clear sections and bullet points, though slightly verbose. Every sentence adds value, making it effective without being overly long.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters and an existing output schema, the description fully covers the tool's purpose, usage, and return structure. No gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist, so baseline 4 applies. The description does not need to add parameter information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it retrieves the user's investment strategy, including target allocation, tracked assets, and insights. This distinguishes it from sibling tools like set_allocations, track_asset, and untrack_asset.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use: 'Use when deciding whether a proposed trade fits the user's plan, or when the user asks "what is my strategy / what am I tracking".' Also marks as read-only, differentiating from mutating tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_committeeA
Step 2 of the agent-run committee: hand in the transcript you produced
from prepare_committee. The backend parses the CIO memo, applies the same
deterministic rules as the backend-run committee (single-investment cap,
defense downgrade, sanity checks), saves the decision and returns it.
If the CIO section has no parseable verdict, nothing is saved and this returns an error โ fix the CIO section and submit again.
Returns:
decision_id, the post-rule verdict object, saved path and
facts_source ("prepare" = rules used the facts saved at prepare time;
"transcript" = no recent prepare found, facts were read from your text).
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | Model that actually played the roles, e.g. 'claude-sonnet-5-5'; omitted -> recorded as 'unknown'. The scorecard buckets verdicts by provider:model. | |
| symbol | Yes | Same symbol you passed to prepare_committee. | |
| provider | No | Which agent played the roles, e.g. 'hermes', 'claude', 'codex'. | agent |
| transcript | Yes | All sections, each starting with its separator line: === MACRO ===, === QUANT_R1 ===, === RISK_R1 ===, === QUANT_R2 ===, === RISK_R2 ===, === CIO ===. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false / idempotentHint=false / destructiveHint=false, and the description is consistent with the mutation claim ('saves the decision'). It adds real behavior beyond annotations: the no-parseable-verdict error path, the deterministic rules applied, and the facts_source distinction. It does not clarify whether resubmitting creates a duplicate decision, which matters given idempotentHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the workflow step, then error handling, then returns. The Returns section restates what the output schema presumably carries, but the whole thing is compact and each section does useful work.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the happy path, the error path, and the facts_source semantics, which is enough for an agent to call and recover correctly. With an output schema present, the returns prose is redundant, and the repeat-submission/idempotency question is left open.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents symbol, transcript sections, model, and provider. The description confirms the symbol must match prepare_committee but adds no syntax or constraint detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('hand in the transcript', 'Step 2 of the agent-run committee') and anchors itself to the workflow step, naming prepare_committee as the predecessor. An agent can distinguish it from prepare_committee and run_committee without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly frames itself as step 2 following prepare_committee and contrasts the agent-run path with the 'backend-run committee'. It also states the failure condition and remediation. It never explicitly says when to prefer run_committee over this path, so it stops short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
track_assetAIdempotent
Add a symbol to the tracked-asset list, or update an existing entry (idempotent upsert: only the fields you pass are changed). The tracked list decides which symbols the committee and DCA jobs cover. The alert_* parameters set per-asset alert lines the price sentinel checks every few minutes (price lines: 24h cooldown; day-move lines: once per trading day); each one you pass overwrites that line only. To clear a line use set_allocations with a null value. Delivery needs INVEST_EVENT_ALERT=1 on the server (default off โ without it a hit is only logged to the event store, nothing is sent).
Use when the user says "track AAPL", wants to change a tracked asset's cap/channel/fees/target weight, or says "alert me when X drops below N" / "tell me if it falls 3% in a day".
Args: symbol: yfinance ticker to track (e.g. "AAPL", "0700.HK", "BTC-USD"). max_single_invest_cny: Per-decision investment cap in CNY. On a new entry it defaults to the strategy-level max_single_invest_cny; optional on update. display_name: Human-friendly name shown in reports. channel: Where the user actually buys it (broker/app name). price_offset_pct: Systematic offset between the quote and the user's actual fill price, in percent (e.g. bank gold spread). sell_fee_pct: Sell-side fee in percent, used by fee-aware math. target_pct: Target weight as a fraction of total assets in [0, 1] (read by rebalance_plan); all tracked assets' weights must sum to <= target_allocation_stock or the write is rejected. alert_price_above / alert_price_below: price lines (status.current_price basis). alert_day_drop_pct / alert_day_rise_pct: the latest daily bar's move vs the previous close, percentage points. alert_drawdown_from_cost_pct: held position below average cost, percentage points.
Returns: The stored asset entry, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | yfinance ticker to track, e.g. 'AAPL', '0700.HK', 'BTC-USD'. | |
| channel | No | Where the user actually buys it (broker/app name). | |
| target_pct | No | Target weight of this asset as a fraction of total assets, in [0, 1] (0.3 = 30%); read by rebalance_plan. The weights of all tracked assets must sum to <= target_allocation_stock, otherwise the write is rejected and the current sum is reported. Assets without one split the remainder equally. To clear a target use set_allocations with a null value. | |
| display_name | No | Human-friendly name shown in reports. | |
| sell_fee_pct | No | Sell-side fee in percent, used by fee-aware math. | |
| price_offset_pct | No | Systematic offset between quote and actual fill price, in percent (e.g. bank gold spread). | |
| alert_price_above | No | Alert when the price reaches or exceeds this level. Same price basis as status.current_price (held: cost currency, gold booking = CNY per gram; tracked-only: the quote source's own price). | |
| alert_price_below | No | Alert when the price falls to or below this level (same price basis as alert_price_above). Must be below alert_price_above if both are set. | |
| alert_day_drop_pct | No | Alert when the latest daily bar's drop vs the previous close reaches this many percentage points (3 = 3%, not a 0-1 fraction). On a closed market that is the last session; each trading day is reported once. | |
| alert_day_rise_pct | No | Alert when the latest daily bar's rise vs the previous close reaches this many percentage points (3 = 3%); each trading day is reported once. | |
| max_single_invest_cny | No | Per-decision investment cap in CNY. On a new entry, defaults to the strategy-level max_single_invest_cny; optional on update. | |
| alert_drawdown_from_cost_pct | No | Alert when a held position is this many percentage points below its average cost (10 = 10%). Only evaluated for assets you hold. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false) by disclosing alert cooldowns (24h for price lines, once per trading day for day-move lines), that each passed alert line overwrites only that line, the target-weight sum rejection condition, and the server-side INVEST_EVENT_ALERT=1 delivery gate that silently degrades to logging. This is exactly the kind of non-obvious operational context the description should carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and usage sentences are front-loaded and earn their place, but the long Args section duplicates parameter descriptions already present at 100% schema coverage, adding bulk without new information for most fields.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter mutation with a full output schema, the description covers the mutation semantics, alert lifecycle, failure modes (weight-sum rejection), and the error return shape, leaving no significant gap an agent would need to guess at.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the Args block largely restates the schema descriptions verbatim, so baseline 3 applies. A few additions are real ('3 = 3%, not a 0-1 fraction' caveat, overwrite-per-line behavior), but most parameter meaning is already in the structured schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Add a symbol to the tracked-asset list, or update an existing entry') and immediately characterizes the operation as an idempotent upsert with per-field semantics. It clearly differentiates itself from untrack_asset and set_allocations, which it names explicitly for the clearing case.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete trigger phrases ('track AAPL', 'alert me when X drops below N', 'tell me if it falls 3% in a day') plus the update cases (cap/channel/fees/target weight). It also routes the agent elsewhere for clearing a line ('use set_allocations with a null value'), so when-to-use and when-not-to-use are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
untrack_assetADestructiveIdempotent
Remove a symbol from the tracked-asset list โ the committee and DCA jobs stop covering it. Holdings and trade history are untouched; schema validation guarantees at least one tracked asset remains.
Args: symbol: yfinance ticker currently in the tracked list.
Returns: The updated tracked list, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | yfinance ticker currently in the tracked list. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (destructiveHint=true, idempotentHint=true), the description adds critical context: holdings and trade history are untouched, and schema guarantees at least one tracked asset remains.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short paragraphs, no redundancy, and front-loaded with the main action. Very efficient, though the Args and Returns could be integrated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one parameter, good annotations, and mention of output schema, the description covers effects, safety, validation, and error handling fully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a clear description of the 'symbol' parameter. The description repeats the same info without adding new meaning, meeting the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses specific verbs ('Remove', 'stop covering') and clearly identifies the resource ('tracked-asset list'). It distinguishes itself from the sibling 'track_asset' and other trading tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the action and notes a validation constraint (at least one asset remains), but does not explicitly provide when to use this tool versus alternatives or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
what_ifARead-only
Simulate portfolio P&L for a hypothetical price move: "what happens to my portfolio if moves ยฑpct% / reaches ". Pure arithmetic over current holdings โ no LLM call, instant, free.
Use when the user asks scenario questions like "if the Nasdaq drops 10%,
how much do I lose". Provide exactly one of pct or price.
Args: symbol: yfinance ticker held or tracked by the user (e.g. "NDQ.AX", "GC=F", "510300.SS"). pct: Hypothetical percent change, e.g. -10 for a 10% drop. price: Hypothetical absolute target price (alternative to pct).
Returns: Object with the position's simulated value change and the resulting portfolio-level P&L delta.
| Name | Required | Description | Default |
|---|---|---|---|
| pct | No | Hypothetical percent change, e.g. -10 for a 10% drop. Provide exactly one of pct or price. | |
| price | No | Hypothetical absolute target price (alternative to pct). | |
| symbol | Yes | yfinance ticker held or tracked by the user, e.g. 'NDQ.AX', 'GC=F', '510300.SS'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, and the description adds significant behavioral context: 'pure arithmetic over current holdings โ no LLM call, instant, free.' It clarifies the tool has no side effects, is fast, and free, which goes well beyond the annotations. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: a short intro, usage guidance, parameter explanations, and return description. It is front-loaded with the key purpose and contains no unnecessary words. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has only 3 parameters, an output schema exists, and the description covers purpose, usage, parameters, and returns, it is fully complete. Additional details like 'instant, free' provide useful context. No gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema description coverage, baseline is 3. The description adds value by reiterating the mutual exclusivity constraint 'Provide exactly one of pct or price' and clarifying the symbol parameter as 'yfinance ticker held or tracked by the user' beyond the schema's description. This earns a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Simulate portfolio P&L for a hypothetical price move' and distinguishes it from siblings by emphasizing it is a pure arithmetic simulation with no LLM call, instant, and free. This specificity and differentiation from tools like buy/sell/track earns a top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when to use: 'when the user asks scenario questions like "if the Nasdaq drops 10%, how much do I lose"' and provides clear guidance on parameters: 'Provide exactly one of pct or price.' While it does not explicitly state when not to use, the context makes it clear for hypotheticals, so it earns a 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
withdrawADestructive
Record a cash withdrawal from the ledger, in any currency. Fails if the balance is insufficient. Bookkeeping only โ no real payment system is connected.
Args: currency: ISO-style currency code, e.g. "CNY", "USD", "AUD". amount: Amount to remove; must be > 0. idempotency_key: Reuse the same key when retrying this exact call; recorded once.
Returns: Updated cash balances, or {"status": "error", "error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| amount | Yes | Amount to remove; must be > 0. | |
| currency | Yes | ISO-style currency code, e.g. 'CNY', 'USD', 'AUD'. | |
| idempotency_key | No | Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {"status": "duplicate"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (destructiveHint=true, readOnlyHint=false, idempotentHint=false) it discloses the insufficient-balance failure mode, the bookkeeping-only scope, and dedup behavior on key reuse. The idempotency_key emphasis sits in mild tension with idempotentHint=false, though the annotation describes default no-key behavior, so it is not a contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening one-line summary is well front-loaded, but the Args block duplicates fields already fully covered by the schema, and the Returns line overlaps an existing output schema. Several sentences do not earn their place, diluting an otherwise tight core.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive ledger mutation with annotations and an output schema present, the description supplies the mutation intent, failure behavior, scope caveat, and idempotency guidance an agent needs to call it correctly. Return-value explanation is redundant given the output schema, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents currency, amount, and the idempotency_key dedup semantics in far more detail. The description's Args block largely restates the schema and adds no syntax or format information beyond it, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb + resource ("Record a cash withdrawal from the ledger") makes the operation unmistakable and distinguishable in nature from deposit/buy/sell siblings. It stops short of explicitly naming any sibling or routing rule, so it is clear but not sibling-differentiating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when it applies (recording an outflow) and states a failure condition ("Fails if the balance is insufficient") and a scope caveat ("no real payment system is connected"). However it never says when to prefer this over deposit/buy/record_fee or how to sequence it, so usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.68.1- Changed
run_committee1 field changed- changed
Input schema / properties / symbol / descriptionPrevious value: -"Any yfinance ticker (US / HK / A-share / ETF / crypto / commodities), e.g. 'AAPL', 'GC=F', '510300.SS'."New value: +"Symbol to analyze. Listed assets use yfinance tickers: US 'AAPL', A-share '603083.SS' (Shanghai) / '000001.SZ' (Shenzhen), HK '0700.HK', exchange ETF '510300.SS', crypto 'BTC-USD', futures 'GC=F'. China off-exchange (OTC) mutual funds use 'FUND:<6-digit code>', e.g. 'FUND:110011'. A bare 6-digit code is rejected โ add the suffix or the FUND: prefix."
22 tool updates
v0.45.1- Changed
buy3 fields changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {\"status\": \"duplicate\"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry.", + "title": "Idempotency Key" +} - changed
Input schema / properties / kind / descriptionPrevious value: -"Asset kind tag, e.g. 'equity', 'etf', 'commodity'."New value: +"Asset kind tag: 'equity', 'etf', 'metal' (gold), 'crypto', 'bond', 'fund', 'other'." - changed
Input schema / properties / symbol / descriptionPrevious value: -"yfinance ticker, e.g. 'AAPL', '510300.SS', 'GC=F'."New value: +"yfinance ticker, e.g. 'AAPL', '510300.SS'. Gold is 'GC=F' and must be booked per gram in CNY: units = grams, price = CNY/gram, currency='CNY', kind='metal', unit_label='ๅ ' (USD/oz bookings are rejected)."
- Added
cancel_fund_order - Added
confirm_fund_order - Added
daily_report - Changed
deposit1 field changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {\"status\": \"duplicate\"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry.", + "title": "Idempotency Key" +}
- Added
doctor - Changed
ingest_event6 fields changed- added
Input schema / properties / affected_symbolsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "yfinance tickers the event materially affects, e.g. ['GC=F'].", + "title": "Affected Symbols" +} - added
Input schema / properties / entitiesAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Key entities (countries, companies, central banks), lowercase.", + "title": "Entities" +} - added
Input schema / properties / event_typeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "e.g. 'macro', 'policy', 'earnings', 'geopolitics', 'commodity', 'other'.", + "title": "Event Type" +} - added
Input schema / properties / one_line_claimAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Your one-sentence factual summary. Fill this (plus stance and severity) to ingest without any backend model โ preferred.", + "title": "One Line Claim" +} - added
Input schema / properties / severityAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "'low', 'mid' or 'high'. Required with one_line_claim.", + "title": "Severity" +} - added
Input schema / properties / stanceAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "For the holdings: 'risk', 'opportunity' or 'neutral'. Required with one_line_claim.", + "title": "Stance" +}
- Added
pending_committees - Added
pending_news - Added
place_fund_order - Added
prepare_committee - Added
rebalance_plan - Added
record_dividend - Changed
record_existing_position3 fields changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {\"status\": \"duplicate\"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry.", + "title": "Idempotency Key" +} - changed
Input schema / properties / kind / descriptionPrevious value: -"Asset kind tag, e.g. 'equity', 'etf', 'commodity'."New value: +"Asset kind tag: 'equity', 'etf', 'metal' (gold), 'crypto', 'bond', 'fund', 'other'." - changed
Input schema / properties / symbol / descriptionPrevious value: -"yfinance ticker, e.g. 'AAPL', '510300.SS', 'GC=F'."New value: +"yfinance ticker, e.g. 'AAPL', '510300.SS'. Gold is 'GC=F' and must be booked per gram in CNY: units = grams, price = CNY/gram, currency='CNY', kind='metal', unit_label='ๅ ' (USD/oz bookings are rejected)."
- Added
record_fee - Added
record_return_of_capital - Added
record_split - Changed
sell1 field changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {\"status\": \"duplicate\"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry.", + "title": "Idempotency Key" +}
- Changed
set_allocations15 fields changed- added
Input schema / properties / alertsAdded value: +{ + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Per-asset alert lines as {symbol: {rule: value}}, rule in price_above / price_below / day_drop_pct / day_rise_pct / drawdown_from_cost_pct, e.g. {'GC=F': {'price_below': 900, 'day_drop_pct': 2}}. Rules you name overwrite, a null rule value clears just that rule, rules you don't mention stay; a null for the whole symbol clears all its alerts. Symbols must already be tracked. *_pct values are percentage points (3 = 3%), unlike target_pct. Alerts are only delivered when INVEST_EVENT_ALERT=1 is set on the server.", + "title": "Alerts" +} - added
Input schema / properties / target_allocation_cash / anyOfAdded value: +[ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } +] - added
Input schema / properties / target_allocation_cash / defaultAdded value: +null - changed
Input schema / properties / target_allocation_cash / descriptionPrevious value: -"Cash weight in [0, 1], e.g. 0.3. Must sum to ~1.0 with stock."New value: +"Cash weight in [0, 1], e.g. 0.3. Pass together with target_allocation_stock; omit both to leave the split unchanged." - removed
Input schema / properties / target_allocation_cash / maximumRemoved value: -1 - removed
Input schema / properties / target_allocation_cash / minimumRemoved value: -0 - removed
Input schema / properties / target_allocation_cash / typeRemoved value: -"number" - added
Input schema / properties / target_allocation_stock / anyOfAdded value: +[ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } +] - added
Input schema / properties / target_allocation_stock / defaultAdded value: +null - changed
Input schema / properties / target_allocation_stock / descriptionPrevious value: -"Stock weight in [0, 1], e.g. 0.7. Must sum to ~1.0 with cash."New value: +"Stock weight in [0, 1], e.g. 0.7. Pass together with target_allocation_cash (they must sum to ~1.0); omit both to leave the stock/cash split unchanged." - removed
Input schema / properties / target_allocation_stock / maximumRemoved value: -1 - removed
Input schema / properties / target_allocation_stock / minimumRemoved value: -0 - removed
Input schema / properties / target_allocation_stock / typeRemoved value: -"number" - added
Input schema / properties / target_pctsAdded value: +{ + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Per-asset target weights as {symbol: fraction of total assets in [0, 1]}, e.g. {'510300.SS': 0.3, 'GC=F': 0.2}. Symbols must already be tracked (see track_asset). A null value clears that asset's target (back to an equal split). The weights must sum to <= target_allocation_stock (the new one if you pass it in the same call).", + "title": "Target Pcts" +} - removed
Input schema / requiredRemoved value: -[ - "target_allocation_stock", - "target_allocation_cash" -]
- Added
submit_committee - Changed
track_asset6 fields changed- added
Input schema / properties / alert_day_drop_pctAdded value: +{ + "anyOf": [ + { + "exclusiveMinimum": 0, + "maximum": 100, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Alert when the latest daily bar's drop vs the previous close reaches this many percentage points (3 = 3%, not a 0-1 fraction). On a closed market that is the last session; each trading day is reported once.", + "title": "Alert Day Drop Pct" +} - added
Input schema / properties / alert_day_rise_pctAdded value: +{ + "anyOf": [ + { + "exclusiveMinimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Alert when the latest daily bar's rise vs the previous close reaches this many percentage points (3 = 3%); each trading day is reported once.", + "title": "Alert Day Rise Pct" +} - added
Input schema / properties / alert_drawdown_from_cost_pctAdded value: +{ + "anyOf": [ + { + "exclusiveMinimum": 0, + "maximum": 100, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Alert when a held position is this many percentage points below its average cost (10 = 10%). Only evaluated for assets you hold.", + "title": "Alert Drawdown From Cost Pct" +} - added
Input schema / properties / alert_price_aboveAdded value: +{ + "anyOf": [ + { + "exclusiveMinimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Alert when the price reaches or exceeds this level. Same price basis as status.current_price (held: cost currency, gold booking = CNY per gram; tracked-only: the quote source's own price).", + "title": "Alert Price Above" +} - added
Input schema / properties / alert_price_belowAdded value: +{ + "anyOf": [ + { + "exclusiveMinimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Alert when the price falls to or below this level (same price basis as alert_price_above). Must be below alert_price_above if both are set.", + "title": "Alert Price Below" +} - added
Input schema / properties / target_pctAdded value: +{ + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Target weight of this asset as a fraction of total assets, in [0, 1] (0.3 = 30%); read by rebalance_plan. The weights of all tracked assets must sum to <= target_allocation_stock, otherwise the write is rejected and the current sum is reported. Assets without one split the remainder equally. To clear a target use set_allocations with a null value.", + "title": "Target Pct" +}
- Changed
withdraw1 field changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional client-generated key (e.g. a UUID4). When retrying this SAME call after a timeout or an unknown result, reuse the same key: the ledger records it once and later calls return {\"status\": \"duplicate\"} without touching cash or holdings. Only the key is compared, not the arguments โ a different order (other symbol/units/price/amount) needs a new key, or it is silently treated as the retry.", + "title": "Idempotency Key" +}
3 tool updates
v0.42.4- Changed
buy4 fields changed- added
Input schema / properties / currency / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / currency / defaultPrevious value: -"CNY"New value: +null - changed
Input schema / properties / currency / descriptionPrevious value: -"Currency of `price`, e.g. 'CNY', 'USD', 'AUD'."New value: +"Currency of `price`, e.g. 'CNY', 'USD', 'AUD'. Omit to use the existing position's currency (CNY for a new position); a different currency than the position's is rejected." - removed
Input schema / properties / currency / typeRemoved value: -"string"
- Changed
record_existing_position4 fields changed- added
Input schema / properties / currency / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / currency / defaultPrevious value: -"CNY"New value: +null - changed
Input schema / properties / currency / descriptionPrevious value: -"Currency of `price`, e.g. 'CNY', 'USD', 'AUD'."New value: +"Currency of `price`, e.g. 'CNY', 'USD', 'AUD'. Omit to use the existing position's currency (CNY for a new position); a different currency than the position's is rejected." - removed
Input schema / properties / currency / typeRemoved value: -"string"
- Changed
track_asset1 field changed- changed
Input schema / properties / max_single_invest_cny / descriptionPrevious value: -"Per-decision investment cap in CNY. Required when creating a new entry; optional on update."New value: +"Per-decision investment cap in CNY. On a new entry, defaults to the strategy-level max_single_invest_cny; optional on update."
3 tool updates
v0.41.2- Changed
buy1 field changed- added
Input schema / properties / existing_positionAdded value: +{ + "default": false, + "description": "Not supported on buy. For a position held before using openInvest call `record_existing_position`; passing true here returns an error instead of deducting cash.", + "title": "Existing Position", + "type": "boolean" +}
- Changed
decisions4 fields changed- added
Input schema / properties / days / minimumAdded value: +1 - added
Input schema / properties / limitAdded value: +{ + "default": 20, + "description": "Max decisions listed, newest first; 0 = all.", + "minimum": 0, + "title": "Limit", + "type": "integer" +} - added
Input schema / properties / symbolAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Only this ticker (case-insensitive), e.g. 'GC=F'.", + "title": "Symbol" +} - added
Input schema / properties / verdictAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Only this verdict, e.g. 'ACCUMULATE', 'HOLD', 'TRIM'.", + "title": "Verdict" +}
- Added
record_existing_position
19 tool updates
v0.34.0- Added
add_news_source - Added
buy - Added
deposit - Added
discipline - Added
explain_decision - Added
history - Added
ingest_event - Added
live_prices - Added
news_sources - Added
record_execution - Added
remove_news_source - Added
run_committee - Added
sell - Added
status - Added
strategy - Added
track_asset - Added
untrack_asset - Added
what_if - Added
withdraw
9 tool updates
v0.31.7- Removed
buy - Removed
discipline - Removed
explain_decision - Removed
ingest_event - Removed
live_prices - Removed
record_execution - Removed
sell - Added
set_allocations - Removed
what_if
5 tool updates
v0.31.6- Removed
history - Removed
run_committee - Added
sell - Removed
track_asset - Removed
untrack_asset
6 tool updates
v0.31.5- Removed
deposit - Removed
sell - Removed
set_allocations - Removed
status - Removed
strategy - Removed
withdraw
14 tool updates
v0.31.4- Changed
buy8 fields changed- added
Input schema / properties / currency / descriptionAdded value: +"Currency of `price`, e.g. 'CNY', 'USD', 'AUD'." - added
Input schema / properties / kind / descriptionAdded value: +"Asset kind tag, e.g. 'equity', 'etf', 'commodity'." - added
Input schema / properties / price / descriptionAdded value: +"Execution price per unit, in `currency`." - added
Input schema / properties / price / exclusiveMinimumAdded value: +0 - added
Input schema / properties / symbol / descriptionAdded value: +"yfinance ticker, e.g. 'AAPL', '510300.SS', 'GC=F'." - added
Input schema / properties / unit_label / descriptionAdded value: +"Human display label for units (default '่ก', i.e. shares)." - added
Input schema / properties / units / descriptionAdded value: +"Quantity bought; must be > 0." - added
Input schema / properties / units / exclusiveMinimumAdded value: +0
- Changed
decisions1 field changed- added
Input schema / properties / days / descriptionAdded value: +"Look-back window in days."
- Changed
deposit3 fields changed- added
Input schema / properties / amount / descriptionAdded value: +"Amount to add; must be > 0." - added
Input schema / properties / amount / exclusiveMinimumAdded value: +0 - added
Input schema / properties / currency / descriptionAdded value: +"ISO-style currency code, e.g. 'CNY', 'USD', 'AUD'."
- Changed
explain_decision1 field changed- added
Input schema / properties / decision_id / descriptionAdded value: +"\"<date>/<symbol>\", e.g. \"2026-07-03/GC=F\" โ exactly as returned by the decisions tool."
- Changed
history1 field changed- added
Input schema / properties / n / descriptionAdded value: +"Maximum number of recent trades to return."
- Changed
ingest_event6 fields changed- added
Input schema / properties / ingested_by / descriptionAdded value: +"Your own agent identity (e.g. 'hermes') for provenance; distinct from source." - added
Input schema / properties / published_at / descriptionAdded value: +"ISO 8601 publication time, if known." - added
Input schema / properties / snippet / descriptionAdded value: +"Short excerpt or summary of the article body." - added
Input schema / properties / source / descriptionAdded value: +"Publisher name (e.g. 'Reuters') โ the news outlet." - added
Input schema / properties / title / descriptionAdded value: +"Headline of the news item." - added
Input schema / properties / url / descriptionAdded value: +"Canonical source URL (also the dedup key)."
- Changed
record_execution4 fields changed- added
Input schema / properties / decision_id / descriptionAdded value: +"\"<date>/<symbol>\" from the decisions tool output." - added
Input schema / properties / executed / descriptionAdded value: +"True if the user acted on the verdict, False if they declined." - added
Input schema / properties / reason / descriptionAdded value: +"The user's stated reason (especially when declined)." - added
Input schema / properties / trade_ids / descriptionAdded value: +"Optional trade record IDs to link explicitly."
- Changed
run_committee4 fields changed- added
Input schema / properties / force / descriptionAdded value: +"Re-run even if a verdict already exists for today." - added
Input schema / properties / max_rounds / descriptionAdded value: +"Cross-challenge debate rounds." - added
Input schema / properties / max_rounds / minimumAdded value: +1 - added
Input schema / properties / symbol / descriptionAdded value: +"Any yfinance ticker (US / HK / A-share / ETF / crypto / commodities), e.g. 'AAPL', 'GC=F', '510300.SS'."
- Changed
sell5 fields changed- added
Input schema / properties / price / descriptionAdded value: +"Execution price per unit, in the holding's cost currency." - added
Input schema / properties / price / exclusiveMinimumAdded value: +0 - added
Input schema / properties / symbol / descriptionAdded value: +"yfinance ticker of an existing holding." - added
Input schema / properties / units / descriptionAdded value: +"Quantity sold; must be > 0." - added
Input schema / properties / units / exclusiveMinimumAdded value: +0
- Changed
set_allocations6 fields changed- added
Input schema / properties / target_allocation_cash / descriptionAdded value: +"Cash weight in [0, 1], e.g. 0.3. Must sum to ~1.0 with stock." - added
Input schema / properties / target_allocation_cash / maximumAdded value: +1 - added
Input schema / properties / target_allocation_cash / minimumAdded value: +0 - added
Input schema / properties / target_allocation_stock / descriptionAdded value: +"Stock weight in [0, 1], e.g. 0.7. Must sum to ~1.0 with cash." - added
Input schema / properties / target_allocation_stock / maximumAdded value: +1 - added
Input schema / properties / target_allocation_stock / minimumAdded value: +0
- Changed
track_asset6 fields changed- added
Input schema / properties / channel / descriptionAdded value: +"Where the user actually buys it (broker/app name)." - added
Input schema / properties / display_name / descriptionAdded value: +"Human-friendly name shown in reports." - added
Input schema / properties / max_single_invest_cny / descriptionAdded value: +"Per-decision investment cap in CNY. Required when creating a new entry; optional on update." - added
Input schema / properties / price_offset_pct / descriptionAdded value: +"Systematic offset between quote and actual fill price, in percent (e.g. bank gold spread)." - added
Input schema / properties / sell_fee_pct / descriptionAdded value: +"Sell-side fee in percent, used by fee-aware math." - added
Input schema / properties / symbol / descriptionAdded value: +"yfinance ticker to track, e.g. 'AAPL', '0700.HK', 'BTC-USD'."
- Changed
untrack_asset1 field changed- added
Input schema / properties / symbol / descriptionAdded value: +"yfinance ticker currently in the tracked list."
- Changed
what_if3 fields changed- added
Input schema / properties / pct / descriptionAdded value: +"Hypothetical percent change, e.g. -10 for a 10% drop. Provide exactly one of pct or price." - added
Input schema / properties / price / descriptionAdded value: +"Hypothetical absolute target price (alternative to pct)." - added
Input schema / properties / symbol / descriptionAdded value: +"yfinance ticker held or tracked by the user, e.g. 'NDQ.AX', 'GC=F', '510300.SS'."
- Changed
withdraw3 fields changed- added
Input schema / properties / amount / descriptionAdded value: +"Amount to remove; must be > 0." - added
Input schema / properties / amount / exclusiveMinimumAdded value: +0 - added
Input schema / properties / currency / descriptionAdded value: +"ISO-style currency code, e.g. 'CNY', 'USD', 'AUD'."
18 tool updates
v0.31.0- First observed
buy - First observed
decisions - First observed
deposit - First observed
discipline - First observed
explain_decision - First observed
history - First observed
ingest_event - First observed
live_prices - First observed
record_execution - First observed
run_committee - First observed
sell - First observed
set_allocations - First observed
status - First observed
strategy - First observed
track_asset - First observed
untrack_asset - First observed
what_if - First observed
withdraw
TDQS
Scored across 36 tools
Most tools target clearly distinct resources or lifecycle steps: ledger cash movements, trade booking, fund-order legs, committee stages, and read-only reporting are well separated. The main ambiguity is between the two committee paths (run_committee vs prepare_committee/submit_committee) and some overlap between track_asset and set_allocations for targets/alerts, but the descriptions generally disambiguate them.
The naming is consistently snake_case and mostly follows clear verb_noun conventions such as record_fee, place_fund_order, track_asset, and submit_committee. The deviations are read-only tools named as bare nouns (status, strategy, history, decisions), which is predictable enough but not a strict verb_noun pattern throughout.
The server covers several substantial subsystems โ portfolio ledger, fund orders, committee orchestration, news ingestion, reporting, and strategy โ but 36 tools is a very large surface for an agent to navigate. While each tool may earn its place in a broad product, the count is heavy and increases selection and context costs.
Coverage is strong: cash deposits/withdrawals, buy/sell, fees, dividends, splits, return of capital, existing positions, off-exchange fund order lifecycle, strategy targets, alerts, committee decisions, execution tracking, and news source management are all present. Remaining gaps are minor, such as no general arbitrary-symbol quote lookup and no obvious correction/delete operation for erroneous ledger entries beyond idempotency safeguards.
Maintenance
Related MCP Connectors
Portfolio analytics + US-equity market research for AI clients. ChatGPT deep-research compat.
- mcpOAuthmarkets.tally
AI risk officer: private trading theses, evidence, exit criteria and decision history. No execution.
Read-only PAPER market research for autonomous agents; no live trading or alpha claim.
Read-only crypto strategy backtest & verification verdicts. No trading tools; every result is cited.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenancePersonal investment management advisor that exposes tools for accounts, portfolios, trades, market data, strategies, risk control, and advice, enabling AI agents to analyze and provide structured investment recommendations.MIT
- AlicenseNot gradedqualityCmaintenanceDeterministic market-state engine for trading agents โ zero LLM in the signal path. 8 tools: structural market state & phase, action gate (GO/WATCH/HOLD), entry/target/invalidation coordinates, bar-by-bar state timeline, composed view cards, and pre-trade intent validation. Every output traces to a bar-stamped ledger with a public daily self-scoring track record.3MIT
- AlicenseNot gradedqualityDmaintenancePortfolio & trading-strategy stress diagnostics for AI agents: multi-asset stress with hedge-break detection, a daily preregistered regime outlook and deflated-Sharpe backtest-integrity checks. Remote streamable-HTTP endpoint with a free tier (no key); this repo is the public server card.MIT
- FlicenseAqualityBmaintenanceProvides multi-agent equity research for US markets with provenance-backed financial data from SEC EDGAR, technicals, macro, and Alpaca paper trading, enforcing risk limits and journaling theses.27-