Skip to main content
Glama
BijectiveLabs

trading-research-agents

Official

Language models are good at reading a market and saying what they think. They are bad at arithmetic, they don't know what a trade costs, and they will happily overrule a limit you set. This project uses them for the first part only. The system itself, fixed rules with no model involved, fetches the data and works out every figure. The agents read those figures and give an opinion. Then the system prices the trade, applies your limits, sizes it, and either writes it down or sends one order with the stop attached. Every decision and every refusal is kept on disk with its reason, so you can check afterwards what happened and why.

It's an early release, so expect settings to change between versions. What works today: a universe of perpetuals found and measured by the system, a screener that picks where to look, the full autonomous cycle on live data, four analysts and up to three validators, stops and targets the analyst names inside bounds you set, the gates that decide, sizing from your own rules, real orders on a venue's practice environment behind a mandate you sign, a risk manager that can only make the desk more careful, and two auditors that read the records.


Contents

Related MCP server: AgentBroker MCP Server

What it solves

The usual problem with trading agents

What happens here

The model invents or miscalculates a number

Models never compute. Every figure comes from the system, and a figure a model cites is checked against its brief, value included.

Nobody knows what a trade cost until it's done

The round trip (fees, spread, impact, funding, slippage) is priced before an order exists, and a trade whose claimed edge doesn't clear it is refused.

The agent sizes its own position

Size comes from your conviction ladder and your risk limit. No model can make a trade bigger.

A model "decides" to ignore your settings

Your declared thresholds decide. A model's opinion is recorded beside them, never instead of them.

Something went wrong and there is no trace

Each cycle keeps its snapshot, briefs, answers, the intent and what the venue said. Nothing is rewritten.

A crash leaves a position with no stop

The stop and take profit go to the venue attached to the entry, so they survive this process dying.

Get started

A few minutes and one model key. Every setting has a working default, so a new desk runs before you change anything; the table under step 6 says what those defaults are.

1. Install. You need Python 3.11 or newer. uv is the quickest way:

uv tool install 'trading-research-agents[ccxt,openai,anthropic,google,data]'

That brings every model provider and every exchange in. Without uv, run pip install 'trading-research-agents[ccxt,openai,anthropic,google,data]' inside a virtual environment. To move to the newest release later:

uv tool upgrade trading-research-agents      # or: pip install -U 'trading-research-agents[ccxt,openai,anthropic,google,data]'
tra --version

That is the release, and the version to run. The develop branch on GitHub is where the next one is built; a commit there is not a release (more).

2. Make a desk. A desk is a folder holding your settings and everything the agents decide. Name the provider you have a key for:

tra init my-desk --profile autonomous --agent groq
cd my-desk

--agent

Key in .env

Model, when you name none

groq

GROQ_API_KEY (free tier)

openai/gpt-oss-120b

google

GEMINI_API_KEY

gemini-flash-latest

anthropic

ANTHROPIC_API_KEY

claude-opus-5-5

openai, deepseek, xai, openrouter, ...

see Models and providers

name one with --model; tra models <provider> lists them

Add --venue okx (or any ccxt id) to trade somewhere other than Bybit.

3. Add your key. Copy the example file and put your key in it. Every command reads the .env next to strategy.toml on its own.

cp .env.example .env        # then set GROQ_API_KEY=... in .env

4. Check. tra check reads every setting against the others and names the one thing to fix next. A desk that is ready ends with:

ok    provider groq: ready
ready to run `tra run`

5. Run. tra run decides once on live market data, in the sandbox: nothing leaves your machine. tra run --every 15m keeps deciding, once per fifteen-minute bar, on the clock. Or type tra on its own for the console, which takes the same commands.

tra run
tra run --every 15m

6. When you want real orders. Start on the exchange's practice account:

  • put its keys in .env;

  • read the mandate with tra mandate, then sign it with tra mandate --sign "Your Name";

  • in [execution] of strategy.toml, set mode = "venue", a leverage and max_notional (the most one order may be worth).

tra check lists whatever is still missing. Toward real orders has the whole path.

What a new desk does before you change anything

Default

Where to change it

Orders

none: the sandbox writes each decision down and sends nothing

[execution].mode

What it trades

BTCUSDT on Bybit, as a taker

[run].instrument, [universe], --venue

Timeframe

decides on 15-minute bars, reads 1h and 4h as context

[run].bar_interval_s, context_intervals

Strategy

none fixed: the analyst picks the setup the measured regime supports, or stays flat

[agents].mechanism

Stop and target

the analyst names them; the stop is held between 0.2% and 3% and never inside one ATR, the target between 1.5x and 4x the stop

[exit]

Risk per trade

0.5% of equity lost at the stop, whatever the stop's distance

[controls].max_risk_per_trade_bps

Bad days

no new entry after a 3% loss on the day or a 10% fall from the peak

[controls]

Time limit

a position closes after 4 hours

[exit].timeout_bars

Trades worth taking

the edge at least 2x the round trip, break even at half the trades or better, at most 6 a day

[targets]

Oversight

a risk manager that can only cut, pause or halt; two auditors that report

[audit]

Working on the code itself? See Development.

What you see, in order

1. The console. Run tra inside your desk and it opens the console: what is ready, what isn't, and the next command to run. Under it is a prompt that takes every command and draws it right there. Arrow keys go back through what you typed, tab completes, help lists the commands and exit leaves. For scripts and cron, tra -c "run --now" runs one command and exits.

the console

2. The pass over your instruments. Type run --every 15m and the desk first refreshes any data series that are due, one line each. Then it looks at every instrument on your list, one data pull apiece, and measures it. The screen steps through them live:

the screen pass

3. One cycle per instrument it takes. The system found the candidates and measured them; the screener chose among them and cited each instrument's own figures; the system's own order is kept beside the choice. The instruments taken get a full cycle. The terminal shows the whole pipeline from the start and updates it as each step begins and ends. Steps that run at the same time spin at the same time, each with its own clock, and the line underneath says who is working right now:

a scheduled desk at work

4. The result. When the cycle finishes, the table gives way to the pass over the universe: what the screener took, what waited and what was held, and why. Then the cycle itself: what the analyst proposed and from which figures, and every refusal with the number behind it. Here an ETH short in a ranging market stopped at its exits: with its own stop and target and the round trip, more than half of trades like it would have had to win just to break even:

one cycle

Then the data the cycle used and how old it was, the series the reading analysts read, the stop and take profit it would have placed, and which agents answered. A cycle that goes further adds what each validator argued, how conviction weighed the analysts, the risk at the stop and the targets:

data, series, exits and agents

5. Between cycles. The desk says when the next pass is, on the clock and in minutes, for example next pass at 14:30:00 UTC, in 10m 57s, and counts down to it. An auditor woken by an alarm gets a spinner of its own.

The same cycle as plain text (--plain, a pipe or a log), from a real run on live data, shortened:

cycle 2026-09-29T02-59-16Z BTCUSDT: 5.344s of agents, 15.042s of validators
  funding        ccxt:bybit         age 4.267s
  ohlcv          ccxt:bybit         age 32.746s
  orderbook      ccxt:bybit         age 7.544s
macro      risk-off: the operator declared a bullish state for US10Y; measured correlation is
           neutral (0.0) on a modest sample, weak evidence that does not overturn the declaration
sentiment  positive: declared state is bullish, and the measured figures both support it
technical: long on range_reversion at 0.65 over 5 bars: the close is stretched low in the window
read: zscore=-0.587, vwap_gap_bps=-3.99, ret_1_bps=1.59
validator contra   oppose on 2 cited figure(s)
validator pro      support on 3 cited figure(s)
conviction: 0.800 of 1.0 (macro 1.0, sentiment 0.5, technical 1.300)
risk: 8.29 bps of equity at the stop against the declared 50 bps, size 0.010
cost: 12.87 bps round trip, 2.00 of it estimated
gate: 25.0000 bps claimed clears 12.8723 bps cost plus 0.0000 bps margin
  refused targets: the claimed edge is 1.94x the round trip and the desk declared 2.0x;
                   the cost is certain and the edge is not

That trade was refused. It cleared the cost gate and still died, because this desk asks for an edge of twice the cost and got 1.94 times. A refusal names the figure behind it, every time.

How one cycle decides

flowchart TD
    find[["the system finds the universe and measures each instrument<br/>one data pull each; every value carries its source and age"]] --> wake
    wake{"trigger<br/>has anything moved since the last look?"}
    wake -- "no" --> held["held: one data pull, no tokens spent"]
    wake -- "yes" --> pick["the screener picks among what the system admitted<br/>citing each instrument's own figures"]
    pick -- "none taken" --> held
    pick -- "taken" --> briefs
    briefs["the system writes the briefs<br/>each role sees only the figures its job needs"] --> round1
    subgraph round1["asked at the same time"]
        direction LR
        tech["technical analyst<br/>a direction, a confidence, a horizon"]
        macro["macro analyst"]
        chain["on-chain analyst"]
        mood["sentiment analyst"]
    end
    round1 --> price["the system prices the round trip<br/>fee, spread, impact, funding, slippage"]
    price --> exits{"the stop and the target<br/>the analyst's levels, held inside your bounds<br/>does the trade break even at half its kind winning?"}
    exits -- "no" --> refused
    exits -- "yes" --> round2["validators, as many as you declare<br/>a claim that cites no figure is thrown away"]
    round2 --> matrix{"confluence<br/>do your declared states agree with the direction?"}
    matrix -- "no" --> refused["a refusal that names its figure"]
    matrix -- "yes" --> size["conviction<br/>how much, from your ladder"]
    size --> risk{"risk per trade<br/>what does it lose at the stop?"}
    risk --> gate{"cost gate and targets<br/>does the edge clear the cost, by your margin?"}
    gate -- "no" --> refused
    gate -- "yes" --> intent["the intent, written into the cycle"]
    intent --> venue["venue mode only<br/>one order, the stop and take profit attached"]

Who does what:

Role

Reads

Answers

Can never

technical analyst

candles, spread, funding, book imbalance, open interest change, and the regime on its timeframe and the higher ones you declare

a direction, a setup from a fixed list, a confidence, a horizon, and where its stop and target sit

size the trade, place a level outside your [exit] bounds, run a trend setup in a range, or fade a market that is not a measured range

macro analyst

dated rates and levels, dated text

risk-on, risk-off or neutral

propose a direction

on-chain analyst

chain and derivatives figures

accumulation, distribution or neutral

propose a direction

sentiment analyst

dated scores and notes you curate

negative, neutral, positive, or not declared

invent a mood no figure supports

market screener

what the system measured for each admitted instrument: move, spread, regime, volume, correlation to BTC

which instruments to take, in what order, citing their figures

add an instrument the system did not admit

validators (pro, contra, neutral)

the proposal and the figures behind it

support, oppose or abstain, with cited claims

decide, or cite a figure it wasn't given

risk manager

what the run recorded: round trips, the losing streak, your limits, the alarm that woke it

continue, cut the size of new entries, pause instruments, or halt, each for a stated number of hours

loosen a limit you set, or add size

technology and quant auditors

the cycles this desk recorded

findings and proposed changes

change anything

The macro, on-chain and sentiment analysts read dated series you declare under sources/. Each one is either a file you keep or a feed the desk refreshes itself (FRED, the Crypto Fear & Greed Index, or any paid vendor that answers JSON over https). tra sources show lists every series with where it came from and how old its last value is, and a value older than its max_age is shown as stale and never counted. Data sources has the details.

Which validators run is yours to declare. A vote never decides on its own: it moves conviction by the weight you give it ([conviction].validator_weight), and a stance counts for what it says beyond its assignment, since a pro that supports is expected to.

Analysts are allowed to disagree. Each one's view becomes a score between -1 and 1, computed from its own figures against the lines you drew, so a macro reading barely past its line counts as a small voice and one far past it counts as a big one. Conviction adds them up: agreement grows the size, opposition shrinks it in proportion, and only opposition that outweighs the case stops the trade. A short at 0.70 confidence against a barely bullish macro and sentiment scores 0.56 and trades at half size; against a strongly bullish context it scores 0 and doesn't trade.

The technical analyst knows what kind of market it is working in before it decides. The system measures the regime on its timeframe (trending up, trending down, ranging or mixed) and on the higher timeframes you list in [run].context_intervals, and it hands over what your macro thresholds say this cycle as well. A setup that doesn't fit the regime, such as a trend trade in a sideways market, is refused by name; [regime] holds the lines.

Everything after the analysts is arithmetic over numbers you declared. No model can place, cancel or resize an order, read a file outside the project, or edit your configuration. Agents has the full table of what an agent can reach, and The cycle walks through every step.

Venues

A cycle reaches venues through ccxt, so every exchange ccxt supports is already integrated: the same order path, the same gates and the same checks, with nothing in the core naming a venue. What differs from one venue to the next is what ccxt reports it can do, the second column, and how far it has been tested, the last:

Venue

What a cycle can do there

Practice environment

Run end to end by us

Bybit (the default)

everything: orders with the stop and take profit attached

demo, testnet

yes, on demo: real orders, exits attached, a resting order cancelled

OKX

everything

demo (ccxt's testnet switch)

yes, on demo: real orders, exits attached, closed by the venue's own exits

Bitget, BingX, KuCoin Futures, Hyperliquid

everything

varies, see tra venues

ready for its run; reports wanted for Bitget, BingX, Hyperliquid

Binance, Deribit, HTX, Gate, MEXC

orders, but you carry the stop yourself (exits = "none")

varies

ready for its run

Kraken, Kraken Futures, Phemex

data for now: ccxt does not report their positions, and no order is sent into a position nobody can see

"Everything" means ccxt reports the five things a safe order needs: send it, attach the exits, read the position, read the open orders, cancel. "Run end to end" is the stronger claim, a full run with real orders on the venue's practice account, and Bybit and OKX are the two that have had it so far. Any other venue that takes orders can have that run at any time: start on its practice environment, watch a few cycles and read what it sends. Each report moves a venue into the last column.

Adding the venue you trade on is four steps, and one command writes most of it:

tra venues okx            # what it can do, and which keys it signs with
tra venues okx --setup    # the blocks to paste into envelope.toml, data.toml, strategy.toml and .env

Your fees are filled in from your account when it reports them, and from the venue's standard tier until then, labelled as such; a fee you write yourself is kept and checked against the account. Venues has the full table, the keys each venue needs, and the four steps.

Models and providers

You choose the provider and the model; nothing is hard-coded. Each provider reads its key from the environment (or the .env beside your config) and nowhere else.

Provider

Key in .env

Install with

Structured output

Tested live here

groq

GROQ_API_KEY

openai

JSON schema, falling back to JSON mode; checked by the system

yes: openai/gpt-oss-120b and openai/gpt-oss-20b, every live cycle in our records

google

GEMINI_API_KEY or GOOGLE_API_KEY

google-genai

JSON schema

yes: gemini-flash-latest, as the fallback

anthropic

ANTHROPIC_API_KEY

anthropic

JSON schema

unit-tested; default model claude-opus-5-5

openai

OPENAI_API_KEY

openai

strict JSON schema

unit-tested

deepseek

DEEPSEEK_API_KEY

openai

JSON mode

preset only

mistral

MISTRAL_API_KEY

openai

JSON schema

preset only

xai

XAI_API_KEY

openai

JSON mode

preset only

openrouter

OPENROUTER_API_KEY

openai

JSON mode

preset only

qwen

DASHSCOPE_API_KEY

openai

JSON mode

preset only; pass --base-url for your region

ollama

none

openai

JSON mode

preset only; a local server

local

none

openai

JSON mode

any OpenAI-compatible server; pass --base-url

9router

9ROUTER_API_KEY

openai

JSON schema

preset only; a local router

Whatever the provider, every answer is parsed against a closed schema by the system before anyone reads it, so a model that only offers JSON mode is held to the same shape as one with strict schemas.

[agents]
provider = "groq"
model = "openai/gpt-oss-120b"
effort = "medium"                    # minimal | low | medium | high | xhigh | max, where the
                                     # vendor takes it; left out, the vendor's default applies
fallback = ["google:gemini-flash-latest", "anthropic:claude-opus-5-5"]

[agents.roles.sentiment_analyst]     # a role that only labels can run on a cheaper model
model = "a-cheaper-model"
effort = "low"

fallback is tried in order when a provider is rate limited or down, with the same brief. A vendor's free tier meters each model on its own, so roles can share a provider across two models and each model keeps its own allowance; tra check judges the load per model and says when one is too much. Every call is a line in usage.jsonl with its tokens and latency, and nothing caps spend unless you declare a ceiling. tra keys --probe proves each key works without sending a prompt. A vendor of your own is about thirty lines (Model providers).

Toward real orders

What it trades today: linear perpetual futures (USDT- or USDC-margined swaps) on any venue ccxt reaches, long and short, with the leverage and margin mode you declare. That is where the project started, not where it stops. Spot is built too, long only and paid in full, for a desk that lists it in [execution].markets; Venues says how to set one up. Stock perpetuals and tokenized stocks on the same venues go through the same path, with the underlying exchange's hours respected, and so do prediction market outcomes, decided on a probability by their own analyst. Dated futures, inverse contracts and options are on the way, each with its own cost model, exit rules and tests. Until a market type has those, venue mode checks the type on every order and refuses it, because a market the system cannot yet price and protect is not one it should send to. Boundaries says what each one takes.

An agent desk goes through three steps, and you can stay at any of them as long as you like:

Step

How

What happens

Needs

1. Sandbox

tra run

the full cycle on live data; every decision written down, no order sent

a model key

2. Practice account

tra run with [execution].mode = "venue" and environment = "demo" or "testnet"

real orders on the exchange's practice account, exits attached, positions looked after

a signed mandate, a leverage, max_notional, practice keys

3. Real capital

the same, with environment = "mainnet"

real orders with real money

all of the above, plus the ladder at its canary tier (tra ladder promote, with evidence)

Steps 1 and 2 have been run end to end on Bybit's and OKX's practice accounts. Step 3 has not been run by us; treat it as yours to verify, small, first.

If you bring a scripted strategy of your own instead of the agents, it has a research path of its own before any of this: tra data get BTCUSDT 2025-01-01 and tra backtest replay a day of the exchange's archive net of every cost, tra paper --minutes 30 runs it on the live feed with nothing sent, and tra live is a small canary session behind hard caps. The replay of that day printed net -294.19 bps for the example core, and it is shown as it came out: a backtest that only shows good news is one nobody should believe. The live tier has the details.

Venue mode is the only mode that can lose money, so it has a door in front of it. Read the mandate with tra mandate; when you accept it, tra mandate --sign "Your Name" keeps it in the project as MANDATE.md and signs [execution] with your name and today's date, in one step. Signing does not switch anything on. tra check names whatever else is missing.

Your money, your orders, your positions

Once orders flow, three things look after the money, all of them the system's own rules and none of them a model:

Before an order

When it is sent

While it is open

the account's real equity and free margin are read

your leverage is applied at the venue and read back

at the start of every pass, each position is checked against the venue

sizing uses the smaller of the real equity and what you allow the desk

an order whose liquidation would sit inside its stop is refused

one that outlives its hold limit is closed with a reduce-only order

an order may use only part of the free margin

a taker entry is a limit IOC within your slippage band, never a naked market order

one the venue's stop or take profit closed is written up with its real fees and funding

a day's loss past your limit stops new entries

the stop and take profit go with the entry, so they outlive this process

the kill switch flattens everything before the desk stops

Who decides what, in one line each: the analysts propose the direction, your risk rule sets the size, you choose the leverage, and no model touches the last two. Leverage never makes a trade bigger. It only decides how much margin the trade ties up and how far away liquidation sits.

[execution]
mode = "venue"
environment = "demo"             # demo | testnet | mainnet
leverage = 3                     # yours to choose; it never makes a trade bigger
max_notional = 400               # the most one order may be worth, in quote currency
margin_mode = "isolated"         # isolated | cross
hold_limit = "timeout"           # close by time after [exit].timeout_bars; or horizon, or none

Underneath, on every venue: the order goes only to the environment you declared (demo, testnet or mainnet); an open position or a working order refuses a second entry; a size off the venue's step is refused rather than rounded; a clock more than a second off the venue's refuses before anything is signed; and Ctrl-C or a service stop cancels a resting order before the process leaves. Every close goes to positions.jsonl and every finished trade to round_trips.jsonl. Capital, orders and positions has every setting, every refusal and the arithmetic behind each one.

One thing to know before you rely on it: the position checks run at the start of each pass of tra run --every. With no desk running, an open position has its venue-side stop and take profit and nothing else, so a desk meant to run unattended belongs under a supervisor.

Orders cross the book by default (taker-taker): they always fill, which is how most desks trade. Point [run].venue_key at a maker-taker channel and entries rest on the book as post-only orders instead - a lower fee, fewer fills, since a resting order can be left behind by the market. Either way the cost gate prices the fee of the channel you chose.

Watching a desk, and what is kept

The console runs commands in its own process, so closing it ends what it was running. A desk that should keep running belongs under a supervisor (systemd, a service manager, tmux), and then you look at it from anywhere with:

tra watch --every 5s       # a read-only view built from the records the desk writes

tra watch opens no connection, holds no key and takes no lock, so opening and closing it does nothing to the desk.

What is kept, and where:

What

Where

Notes

everything one cycle did

runs/cycles/<id>/

snapshot, briefs, answers, intent, placed.json, cycle.json, and inputs.json.gz with the raw inputs; cycle.json holds a sha256 of each file

the pass over the universe

runs/screens/

every instrument measured, what the screener chose and why

every model call

runs/cycles/usage.jsonl

tokens, latency, price

when the desk ran and what stopped it

runs/cycles/scheduler.jsonl

one line per start and stop

every position closed, by time, by the venue or by the kill switch

runs/cycles/positions.jsonl

venue mode

every finished trade with entry, exit, fees and funding

runs/cycles/round_trips.jsonl

venue mode; what the quant auditor reads

the first equity reading of each day

runs/cycles/equity.jsonl

what the daily loss limit is measured from

what you typed at the prompt

.tra-history

a convenience only; tra -c keeps none

Command line

Every command says what it did. Exit code 0 means cleared, 1 means a gate said no, 2 is a usage error. --json gives machine-readable output and --plain gives text instead of panels.

Getting started

Command

What it does

tra

opens the console

tra init my-desk --profile autonomous

a project wired for the agents, every file commented

tra check

every setting read against the others, with what to fix

tra keys --probe

proves every key works; no key is printed, no prompt or order sent

tra models groq

the models your key can use on a provider, read from the vendor; no prompt sent

tra init my-desk --profile autonomous --venue okx

a desk wired for one exchange: data, orders, practice account, keys

tra venues

every venue the docs describe, and what each can do

tra venues okx --setup

what a venue can do, and the blocks to paste to trade on it

tra mandate

the text venue mode requires; --sign "Your Name" keeps it as MANDATE.md and signs [execution] in one step

Running

Command

What it does

tra run

one autonomous cycle

tra run --every 15m --cycles 12

twelve scheduled passes: the first now, then one on every fifteenth minute of the clock

tra run --now

ask the roster even if the trigger would have held a quiet market

tra watch --every 5s

a read-only view of a running desk

tra audit

both auditors over the records; nothing is applied

tra backtest, tra paper, tra live

replay, shadow, canary

Data

Command

What it does

tra data get BTCUSDT 2025-01-01

download a day, verify its checksum, audit it, write Parquet and funding

tra data audit export.csv --mapping mapping.toml

your own CSV, through the same audit

tra data pull BTCUSDT

one live snapshot through the chains in data.toml

tra sources show, tra sources pull

where the reading analysts' series come from and how old they are; refresh them now

tra sources add macro us10y --from fred --id DGS10 --high bearish

a series onto the shelf in one step: pulled now, its lines drawn from its own history

tra universe

which perpetuals discovery finds on the venue now, and what each filter took out

tra runs verify

every cycle's files against their hashes, and its briefs against its raw inputs

tra runs prune --keep 90d

what old cycle directories would be removed; add --yes (and --archive) to do it

The ladder, research and hosts

Command

What it does

tra ladder show, promote, demote

which tier the desk stands at; one step up with evidence, or down

tra chain floor, observe, check, validate

the research chain, layer by layer (The falsification chain)

tra ledger show

every idea that died, and what killed it

tra agent session, eval, trace

the research session, model comparison, a run read back

tra mcp serve

the read-only gates as tools for any MCP host

What it guarantees, and what is not built yet

Some rules are guarantees, enforced by the system and tests, and every change has to keep them:

  • No model touches an order or a key. Models read figures and answer; the system sizes, prices, limits and sends.

  • No model can loosen a control. A model can tighten a limit, step the ladder down or arm the kill switch; never widen, promote or disarm.

  • One decision, at most one order. A venue error is recorded and the next cycle decides again; nothing is retried around real capital.

  • Stale or missing data is refused, never read as zero or as current.

Other things are simply not built yet, and contributions are welcome: inverse, dated futures and options; on-chain venues outside ccxt; more than one account; transfers and treasury; routing and execution algorithms; portfolio accounting. Boundaries lists each one with what it does today and what a contribution would need. The example strategy cores are examples: your edge is yours to declare.

Liability says plainly where responsibility sits when real capital is involved.

Where it is going

The project is in active development, and what this page describes is where it stands today, not where it stops.

  • More market types. Spot, stock perpetuals, tokenized stocks and prediction markets are built; inverse and dated futures and options follow, each added with its own cost model, exit rules, sizing and tests before venue mode accepts it.

  • More venues run end to end. Every venue ccxt supports already goes through the same order path and gates. Each one joins Bybit and OKX in the last column of the venues table after a full run on its practice account, ours or yours.

  • The rest of the not-built-yet list, one piece at a time, without weakening a guarantee.

Use the release. What PyPI installs is the latest release, and it is the version to run. Releases come from master. The develop branch is where the next release is built: it moves often, a commit there is not a release, and it can carry work that is unfinished or changed again before it ships. A set of changes becomes a release when it is merged into master, tagged and published, and CHANGELOG.md says what each one brought.

Documentation

The full documentation is at docs.bijectivelabs.dev. Its source is in docs/, so a change in behaviour and the page that describes it go in the same pull request.

Read this

For

The cycle

the cycle step by step, and every setting that shapes it

Agents

each role, what it reads, and what an agent can and cannot reach

Data sources

where the macro, on-chain and sentiment figures come from, fetching them, and freshness

Capital, orders and positions

equity, margin, leverage, liquidation, daily loss, time exits, the kill switch, and the records they leave

Venues

which venues work, and adding yours

Working with language models, Model providers

how models are used: fallback, spend, adding a provider

The live tier, The trading agent

the ladder from replay to a live session

The data gate

the data gate, and bringing your own data

Boundaries, Liability

what is guaranteed, what is not built yet, and who is responsible

The agent, The MCP server

the research agent, and the MCP server

Architecture

packages, import rules, file formats

The falsification chain, Execution realism, The kill ledger

the research chain, execution realism, verdicts

Command line

every tra command

CHANGELOG.md

what changed

Development

git clone https://github.com/BijectiveLabs/trading-research-agents && cd trading-research-agents
uv sync --all-extras
uv run ruff check . && uv run ruff format --check .
uv run mypy
uv run pytest

CONTRIBUTING.md has the branch flow and the standards the code is held to.

Where it comes from

This repository opened to the public in October 2026. Its history starts on 12 September 2026, when the code was separated from Bijective's internal work, and every commit, tag and contributor since then is here. The ideas it is built on are older: the falsification chain, the cost model and the controls in front of every order come from Bijective's research and from the trading platform it was building before this repository existed. The language-model agents came later and sit on top of those gates, which is why they can propose but never size, price or send.

License

MIT. See LICENSE; NOTICE lists the third-party software this package builds on.

Built by Bijective Labs.

Available Tools

10 tools
audit_datasetAudit a dataset (data gate)A
Read-only

Audit a raw trade archive before anything is tested on it.

Normalises the file through a venue plugin (`venue`) or a column map (`mapping_path`), exactly
one of the two, and checks it: rows that do not become trades, gaps longer than
`max_gap_minutes`, price and size scales that change inside the file, and days that carry most
of the rows. Use it on any new dataset; `observe_events` and a backtest assume a file that
passed. Read-only. Returns `passed`, accepted and rejected row counts, the first and last
timestamps, and each finding with its severity ("fail" or "warn").
ParametersJSON Schema
NameRequiredDescriptionDefault
venueNoan archive venue plugin name; leave empty when giving mapping_path
instrumentYesthe instrument the archive should contain, e.g. BTCUSDT
archive_pathYespath to the raw trade archive (csv, csv.gz or zip)
mapping_pathNopath to a column map (mapping.toml); leave empty when giving venue
max_gap_minutesNoa gap between trades longer than this is reported

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint=true, openWorldHint=false), and the description's 'Read-only.' is partly redundant with that. It does add real behavioral context by enumerating the specific checks performed and the 'fail'/'warn' severity model on findings, which annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the exclusivity rule are front-loaded in two tight paragraphs with no filler. The trailing list of return fields is somewhat redundant because an output schema exists, keeping it short of perfect.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

It covers the purpose, the precondition chain to observe_events/backtest, the checks performed, the parameter exclusivity rule, and the severity vocabulary. Return-value detail is already handled by the output schema, so 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.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by stating the venue/mapping_path parameters are mutually exclusive and one is required, a constraint the schema only hints at. It otherwise leaves format/permission details to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource and scope: 'Audit a raw trade archive before anything is tested on it.' It also spells out exactly what the audit covers (non-trade rows, gaps, scale changes, dominant days), which separates it from siblings like validate_trades and observe_events.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use it on any new dataset' plus 'observe_events and a backtest assume a file that passed' gives an explicit precondition and names the downstream tools that depend on it. It also states the venue/mapping_path choice is 'exactly one of the two', removing a real invocation ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_cost_floorCost floor (layer 0)A
Read-only

Check whether a claimed edge can pay for trading it, before any data is touched.

Reads the fee channels declared in envelope.toml, takes the cheapest round trip (on `venue`
when given, else across every channel) and compares the claimed magnitude with it. Use it
first: an idea whose edge is below the round trip stops here, and no backtest can rescue it.
Read-only. Returns `outcome` ("cleared" or "stop"), the channel used, its round trip and the
margin (magnitude minus round trip) in bps as decimal strings, and the measured round trip
when the channel records one.
ParametersJSON Schema
NameRequiredDescriptionDefault
venueNoonly this venue's channels; empty for the cheapest across all
envelope_pathYespath to envelope.toml, the declared fee channels
magnitude_bpsYesthe claimed edge per round trip, in basis points, as a decimal string

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description restates read-only. It adds real behavioral context beyond the annotations: it reads fee channels from envelope.toml, takes the cheapest round trip restricted to `venue` or across all channels, and emits an outcome of 'cleared' or 'stop' with margin in bps. It never states failure modes (e.g., unparsable envelope or missing channel), which is the remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core decision in the first sentence, followed by mechanism, usage, and return shape. The 'no backtest can rescue it' clause is slightly rhetorical but reinforces the gate; overall it is tight with no dead weight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a read-only, three-parameter tool with a full schema and an output schema, the description supplies everything needed to call it correctly: inputs consumed, the decision rule, the ordering constraint, and the outcome vocabulary. Return-value detail is a bonus rather than a necessity here.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already documents all three parameters, including the 'empty for the cheapest across all' semantics of `venue`. The description's 'on `venue` when given, else across every channel' merely restates that, and `magnitude_bps` gets no format detail beyond what the schema says, so this is baseline territory.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: it gates a claimed edge against the cost of trading it, before any data is touched. This is clearly distinguishable from the sibling tools (list_runs, show_ledger, audit_dataset, validate_trades), which are ledger/report inspection rather than a pre-trade economic gate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit sequencing guidance ('Use it first') and the decisive condition ('an idea whose edge is below the round trip stops here, and no backtest can rescue it'). It does not name a sibling as the alternative for cases that clear the floor, so it stops short of full when/when-not/alternatives coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_registrationCheck a pre-registration (layer 3)A
Read-only

Read a sealed pre-registration: its hypothesis, universe, power and kill criteria.

Use it before `validate_trades`, to see what a validation will be judged against, or to
confirm that a registration has not been edited since it was sealed: the seal is recomputed
from the file. Read-only. Returns the name, the seal, the horizon, the instruments, the sample
the power analysis requires, each kill criterion (metric, comparison, threshold, verdict) and
the registration it amends, if any. A file that does not parse is refused with the reason.
ParametersJSON Schema
NameRequiredDescriptionDefault
registration_pathYespath to a preregistration.json

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered. The description adds genuinely new behavioral context beyond that: the seal is recomputed from the file (an integrity check, not a cached value), and a file that fails to parse is refused with the reason rather than returning partial data. It does not discuss permissions or limits, but for a local read tool that is a minor omission.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the action and followed by the sequencing guidance and the failure mode. Every clause carries information; the return-field list is the only slightly padded part but it still earns its place by framing what a caller receives.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With annotations covering safety and an output schema covering return shape, the description only needs to supply placement in the workflow and edge-case behavior, both of which it does. The enumeration of return fields is partly redundant against the output schema, and no guidance is given about what to do when the integrity check fails, which keeps it short of a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single parameter, and the schema already states it is a path to a preregistration.json. The description adds no format, default, or path-resolution detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read a sealed pre-registration') and immediately names the sibling it relates to (validate_trades), so an agent can place it in the workflow without opening either schema. The scope is further sharpened by naming the artifacts read (hypothesis, universe, power, kill criteria).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives two explicit when-to-use conditions: before running validate_trades to see what a validation is judged against, and to confirm a registration was not edited since sealing. It names the alternative tool and the condition that selects this one over it, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_runsList past runsA
Read-only

List past runs under a directory, newest first, with the summary of each.

Finds every run.json below `runs_dir` and returns its directory, label, instrument, strategy,
round trips, net bps, what stopped it and when it finished; at most 50, with the total.
Filter by `instrument` to compare runs on one market. Use `read_run_report` for one run in full.
Read-only.
ParametersJSON Schema
NameRequiredDescriptionDefault
runs_dirYesdirectory to search for run.json files, e.g. runs
instrumentNoonly runs on this instrument; empty for all

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint, openWorldHint=false), and the description's 'Read-only' only echoes them. It does add genuinely new behavior: results are sorted newest first, capped at 50 entries plus a total, and are discovered by scanning for run.json beneath the given directory.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and ordering, then the return contents, then routing to the sibling tool. Dense but nearly every clause earns its place; only the trailing 'Read-only.' is redundant with the annotation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter read tool with an output schema, the description covers the essentials: discovery scope, sort order, result cap, filterable field, and the alternative tool for full detail. No ambiguity that would cause a mis-invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 meaning: 'below runs_dir' implies a recursive scan for run.json files (the schema only says 'directory to search'), and `instrument` is framed as a comparison filter rather than a generic field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb and resource ('List past runs under a directory'), plus scope details (newest first, summary of each) that tell an agent exactly what comes back. It names a sibling (read_run_report) so the agent can distinguish it from the related report tool 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context for use: scan a runs directory, optionally filter with `instrument` to compare runs on one market, and switch to `read_run_report` when a single run must be read in full. It names the alternative and the condition that selects it, though it gives no explicit when-not/negative cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

observe_eventsMarket observation (layer 1)A
Read-only

Layer 1: count whether the event declared in observation.toml recurs in a dataset.

Marks every occurrence of the declared event in a Parquet trade dataset, measures the
response over the declared horizon and counts it per subperiod, so an event that happened in
one week only is seen as such. Use it after `check_cost_floor` and before writing a
pre-registration. Read-only. Returns the declaration and the report: events found, their
spread across subperiods and whether the declared recurrence holds.
ParametersJSON Schema
NameRequiredDescriptionDefault
dataset_pathYespath to a Parquet trade dataset written by `tra data get`
observation_pathYespath to observation.toml, the declared event and recurrence

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description reinforces 'Read-only,' which usefully disambiguates the potentially mutating-sounding 'marks every occurrence.' It also discloses the analytical behavior (per-subperiod counting so a one-week-only event is exposed), adding context beyond the annotations, though nothing about error modes or limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the layer label and the core operation, then workflow placement, then read-only and return summary. Efficient overall, though the clause 'so an event that happened in one week only is seen as such' is slightly redundant with the subperiod-counting statement before it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't detail return values, and it still sketches the report contents. Combined with full parameter coverage, annotations, and workflow placement, an agent has enough to invoke it correctly; only edge-case behavior (missing files, non-Parquet input) is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and both parameters are documented in the schema, so the baseline is 3. The description explains the semantics of the observation declaration (event, horizon, recurrence) but adds only marginal syntax or format detail beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — count whether the event declared in observation.toml recurs in a Parquet trade dataset — and elaborates the mechanics (marks occurrences, measures the response over the declared horizon, counts per subperiod). This is distinguishable from ledger/audit siblings like audit_dataset or validate_trades at a glance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly places the tool in a workflow: 'Use it after `check_cost_floor` and before writing a pre-registration,' naming a sibling tool and a downstream stage. It gives clear context but no exclusion conditions (when not to use it, or what to do if the recurrence check is inconclusive).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_run_reportRead a run reportA
Read-only

Read one run's report: what a replay, shadow or canary run did, and how it ended.

Returns run.json as written (label, instrument, strategy, prints, bars, intents, refusals,
fills, net bps, what stopped it) and the count of closed round trips in its trades.jsonl. Use
`list_runs` to find the run directory first. Read-only.
ParametersJSON Schema
NameRequiredDescriptionDefault
run_dirYesa run's directory, the one holding run.json

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description reinforces this with 'Read-only.' It adds value beyond annotations by disclosing the return shape: run.json as written (label, instrument, strategy, prints, bars, intents, refusals, fills, net bps, stopping condition) plus a count of closed round trips in trades.jsonl. It does not mention cost, latency, or truncation behavior for large runs, so it is not fully exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action in the first clause, then a compact enumeration of returned data. The trailing 'Read-only.' is slightly redundant given the readOnlyHint annotation, but it is one word and does no harm.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

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 explained, yet the description summarizes them usefully, and it covers the one required input and its acquisition path. For a single-parameter read tool, nothing an agent needs in order 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.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is already documented as 'a run's directory, the one holding run.json'. The description's 'Use list_runs to find the run directory first' reinforces how to obtain the value but adds no format or validation semantics beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (read one run's report) and immediately scopes what a 'run' means (replay, shadow, canary) plus what the report covers (what it did and how it ended). It also names a sibling tool (list_runs), so an agent can distinguish it from the other ledger/run tools 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly directs the agent to call `list_runs` first to obtain the run directory, which is the key prerequisite for this tool. It does not state when-not to use it or contrast with the remaining siblings (e.g., show_ledger, validate_trades), so it stops just 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.

search_ledgerSearch the kill ledgerA
Read-only

Search the kill ledger for verdicts that mention the words in query.

Matches the subject, note, evidence and axis of every row that stands, and ranks rows by how
many words they contain. Ask here before proposing an idea: if it already died, the row says
of what and at which fee it would reverse. Read-only. Returns the query, the number of rows
matched and up to `limit` of them, best first.
ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomost rows to return
queryYeswords to look for; a row matches when it contains any of them
ledger_pathYespath to the kill ledger, ledger.jsonl

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

'Read-only' merely restates readOnlyHint, so it earns no credit, but the description adds real behavior beyond annotations: which fields are matched, that ranking is by word-overlap count rather than recency, and that results come back 'best first'. It does not discuss pagination or cost of a large ledger scan, which is the main remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the matching scope, then the ordering guarantee. It runs five sentences and the domain-flavored clause about 'at which fee it would reverse' is slightly ornamental, but nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A search tool with three params, 100% schema coverage, full annotations and an output schema needs little more; the description still covers trigger context, matching fields and result ordering. An agent has everything required to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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, but the description adds the ranking/ordering semantics ('ranks rows by how many words they contain', 'up to limit of them, best first') that determine which rows survive the limit. That is meaning the schema itself does not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('search') plus resource ('the kill ledger') and narrows the scope to 'verdicts that mention the words in query', then names the exact fields searched (subject, note, evidence, axis). This is distinguishable from siblings like show_ledger or list_runs 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Ask here before proposing an idea: if it already died, the row says of what and at which fee it would reverse' gives a clear trigger condition for when to reach for this tool. It does not explicitly name an alternative (e.g. show_ledger for a full dump), so it stops short of full when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

show_ladderShow the promotion ladderA
Read-only

Show the promotion ladder: the tier a strategy is on and how it got there.

Tiers run research, paper, shadow, canary, production; canary and production send real
orders. Use it before acting on a run, to know what the strategy is allowed to do. Read-only:
promotion is never available through this surface. Returns the tier and every promotion and
demotion with its reason.
ParametersJSON Schema
NameRequiredDescriptionDefault
ladder_pathNopath to the promotion ladder, ladder.jsonladder.json

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true and openWorldHint=false; the description goes well beyond them by enumerating the tier ladder (research, paper, shadow, canary, production) and flagging the consequential fact that canary and production send real orders. It also confirms no mutation path exists here, which is behaviorally material.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then tier semantics, then usage, then return shape — all in tight sentences. The return-value sentence ('Returns the tier and every promotion and demotion with its reason') duplicates the output schema and is the one line that does not fully earn its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read-only lookup with an output schema and safety annotations, the description covers everything an agent needs: what it returns, the tier vocabulary, the risk implication of canary/production, and the absence of any mutation path.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter ladder_path has 100% schema description coverage, so the schema already documents its meaning and default. The description adds nothing about the parameter, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Show the promotion ladder') and immediately specifies the payload: 'the tier a strategy is on and how it got there.' That is clearly distinct from siblings like show_ledger, read_run_report, or list_runs, which an agent can tell apart 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit context: 'Use it before acting on a run, to know what the strategy is allowed to do,' plus a clear exclusion that promotion is never available through this surface. It does not name a specific sibling alternative for the promotion action, so it falls 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.

show_ledgerShow the kill ledgerA
Read-only

List the kill ledger: every verdict that stands, and the count per verdict.

The ledger is the research memory: what was falsified, closed, not proven or validated, on
which axis, and at which fee it would reverse. A retracted row is left out. Use it for the
whole picture; `search_ledger` finds the rows about one idea. Read-only.
ParametersJSON Schema
NameRequiredDescriptionDefault
ledger_pathNopath to the kill ledger, ledger.jsonlledger.jsonl

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description reinforces with 'Read-only.' Beyond that it discloses non-obvious behavior: retracted rows are excluded, and it explains what each row encodes (what was falsified, closed, not proven or validated, axis, reverse fee). It does not cover pagination or volume limits, so not 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and contents; the exclusion and the routing hint are tight. The middle sentence is expository domain framing ('the research memory') that is useful but slightly longer than strictly necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

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 needn't be spelled out. The description covers scope, what is included/excluded, and how to choose between it and `search_ledger`, which is everything an agent needs to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single `ledger_path` parameter has a default documented in the schema, so structured data carries the semantics. The description never mentions the path argument or its default, adding nothing on this dimension — baseline 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the kill ledger') plus the exact contents returned (every standing verdict and the count per verdict). It also implicitly separates itself from `search_ledger` by naming the alternative and its narrower scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit usage rule: 'Use it for the whole picture; `search_ledger` finds the rows about one idea.' The condition selecting this tool versus the sibling is unambiguous, and the exclusion rule ('A retracted row is left out') further bounds expected results.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_tradesValidate trades (layer 5)A
Read-only

Layer 5: judge a set of closed trades against the registration sealed before them.

Rejects trades outside the registered universe or era, subtracts `cost_bps` from every trade,
then runs the eight requirements of layer 5, among them a block bootstrap interval, a
permutation test against a null (`null_mode` "sign" or "cross_sectional") and the power
achieved against the power required, and applies the registration's kill criteria.
Deterministic for a given `seed`. Use it once per registration; running it again with other
settings is the forking the seal exists to prevent. Read-only: the verdict is returned, never
written to the ledger.
ParametersJSON Schema
NameRequiredDescriptionDefault
seedNorandom seed; the same seed gives the same verdict
n_permNopermutations of the null
cost_bpsYesround-trip cost subtracted from every trade, in bps, as a decimal string
null_modeNo"sign" (flip each trade's sign) or "cross_sectional"sign
n_resamplesNobootstrap resamples
trades_pathYespath to trades.jsonl, the closed trades to judge
block_lengthNoblock length of the bootstrap, in trades
registration_pathYespath to the sealed preregistration.json

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and closed-world, but the description adds real behavioral context: determinism tied to `seed`, rejection of trades outside the registered universe, the analysis performed, and the explicit guarantee that the verdict is returned but never written to the ledger. The single-use/forking warning is operational guidance that annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the layer-5 framing and organized as purpose → pipeline → constraints → safety. The middle sentence is dense with enumerated sub-behaviors, which is justified for an eight-parameter statistical tool but slightly reduces scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

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 explained, and the description covers scope, determinism, data prerequisites (registration_path/trades_path pairing), and side-effect profile. The 'eight requirements of layer 5' are only partially enumerated, leaving some ambiguity about failure modes, but nothing essential to correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 meaningfully frames `cost_bps` (subtracted from every trade), `null_mode` (sign vs cross_sectional null construction), and `seed` (same seed gives the same verdict) inside the workflow. It stops short of clarifying `n_perm`, `n_resamples`, or `block_length` beyond what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('judge a set of closed trades against the registration sealed before them') and enumerates what validation entails: universe/era rejection, cost subtraction, eight layer-5 requirements, kill criteria. An agent can distinguish this from check_registration or show_ledger 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('once per registration') and a strong when-not ('running it again with other settings is the forking the seal exists to prevent'). It does not, however, cross-reference sibling tools such as check_registration or read_run_report for inspecting the verdict, so the alternative routing 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.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 16 tool updates
    • Changedaudit_dataset5 fields changed
      • addedInput schema / properties / archive_path / description
        Added value: +"path to the raw trade archive (csv, csv.gz or zip)"
      • addedInput schema / properties / instrument / description
        Added value: +"the instrument the archive should contain, e.g. BTCUSDT"
      • addedInput schema / properties / mapping_path / description
        Added value: +"path to a column map (mapping.toml); leave empty when giving venue"
      • addedInput schema / properties / max_gap_minutes / description
        Added value: +"a gap between trades longer than this is reported"
      • addedInput schema / properties / venue / description
        Added value: +"an archive venue plugin name; leave empty when giving mapping_path"
    • Addedcheck_cost_floor
    • Changedcheck_registration1 field changed
      • addedInput schema / properties / registration_path / description
        Added value: +"path to a preregistration.json"
    • Removedcost_floor_check
    • Removedladder_show
    • Removedledger_search
    • Removedledger_show
    • Addedlist_runs
    • Changedobserve_events2 fields changed
      • addedInput schema / properties / dataset_path / description
        Added value: +"path to a Parquet trade dataset written by `tra data get`"
      • addedInput schema / properties / observation_path / description
        Added value: +"path to observation.toml, the declared event and recurrence"
    • Addedread_run_report
    • Removedrun_report
    • Removedruns_index
    • Addedsearch_ledger
    • Addedshow_ladder
    • Addedshow_ledger
    • Changedvalidate_trades8 fields changed
      • addedInput schema / properties / block_length / description
        Added value: +"block length of the bootstrap, in trades"
      • addedInput schema / properties / cost_bps / description
        Added value: +"round-trip cost subtracted from every trade, in bps, as a decimal string"
      • addedInput schema / properties / n_perm / description
        Added value: +"permutations of the null"
      • addedInput schema / properties / n_resamples / description
        Added value: +"bootstrap resamples"
      • addedInput schema / properties / null_mode / description
        Added value: +"\"sign\" (flip each trade's sign) or \"cross_sectional\""
      • addedInput schema / properties / registration_path / description
        Added value: +"path to the sealed preregistration.json"
      • addedInput schema / properties / seed / description
        Added value: +"random seed; the same seed gives the same verdict"
      • addedInput schema / properties / trades_path / description
        Added value: +"path to trades.jsonl, the closed trades to judge"
  2. 10 tool updatesv0.7.1
    • First observedaudit_dataset
    • First observedcheck_registration
    • First observedcost_floor_check
    • First observedladder_show
    • First observedledger_search
    • First observedledger_show
    • First observedobserve_events
    • First observedrun_report
    • First observedruns_index
    • First observedvalidate_trades

TDQS

A4.4/5.0

Scored across 10 tools

Disambiguation5/5

Every tool targets a distinct artifact or pipeline stage: run listings vs. a single run report, full ledger vs. ledger search, ladder, cost floor, event observation, registration reading, dataset audit, and trade validation. Overlap-prone pairs like list_runs/read_run_report and show_ledger/search_ledger are explicitly distinguished in the descriptions (list vs. detail, full picture vs. one idea). No two tools could plausibly be mistaken for each other.

Naming Consistency5/5

All ten tools follow a strict verb_noun snake_case convention (list_runs, show_ledger, read_run_report, search_ledger, check_cost_floor, observe_events, audit_dataset, validate_trades). Verbs are chosen sensibly and no convention mixing or vague naming appears.

Tool Count5/5

Ten tools is well within the healthy range and each maps to a concrete research step or view. Nothing feels redundant or padded, and no obvious operation is missing from the count alone.

Completeness4/5

The read-only research lifecycle is well covered end to end: audit dataset, check cost floor, observe events, read registration, validate trades, plus run/ledger/ladder views. Gaps exist only on the write side (sealing registrations, promoting tiers, writing verdicts), which the descriptions state is intentionally out of scope for this surface.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    F
    maintenance
    AI-native cryptocurrency exchange built for autonomous agents. Register, deposit USDC, select a strategy, and trade 8 crypto pairs (BTC, ETH, SOL + more) programmatically — no KYC required. Includes sandbox with 10,000 virtual USDC for testing.
    -
  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables AI agents to execute prediction-market trades through a risk-control gateway that enforces signed mandates and generates proof trails for accountability.
    0
    MIT
  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables AI agents to execute complex DeFi strategies safely and atomically with double-entry ledger accounting and atomic basket swaps.
    1
    -