Skip to main content
Glama

Server Details

GTO poker solver data: NLHE and PLO preflop ranges, postflop strategy and EV. 6-max NL is free.

If you are the author of this connector, you can claim ownership by verifying the domain or GitHub account it belongs to. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A3.7/5.0

Scored across 29 tools

Disambiguation4/5

Tools cover distinct resources such as preflop ranges, postflop nodes, hand uploads, opponent stats, and tournament results. Some overlap exists between get_node/get_range and get_postflop_node/get_postflop_range, but descriptions clearly distinguish granularity and return types.

Naming Consistency5/5

All 29 tools follow a consistent snake_case verb_noun convention (e.g., get_range, list_games, upload_hand_history). Minor variations like list_my_opponents still fit the pattern and remain predictable.

Tool Count3/5

29 tools is heavy for an MCP server, though the poker domain is inherently broad. Several discovery/metadata tools (list_datasets, list_games, list_spots, get_range_metadata, get_tree_docs) and queue tools (enqueue_solve, get_queued_solve, list_queued_solves) could potentially be consolidated.

Completeness4/5

Core workflows are well covered: preflop/postflop range queries, hand upload and analysis, opponent tracking, and tournament results. Minor gaps like deleting uploaded hands or managing opponent lists are acceptable for a primarily read-only analytics server.

Available Tools

29 tools
compare_strategiesCompare two strategiesA
Read-onlyIdempotent
Inspect

Preferred tool for differences between two preflop or postflop contexts. The server fetches both strategies and returns action-frequency/EV deltas plus the largest postflop combo changes, avoiding two large node payloads.

ParametersJSON Schema
NameRequiredDescriptionDefault
anteBbNoRequested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage.
domainYesPreflop contexts use game/stack/history/hand. Postflop contexts use pack/board/path/combo.
formatNoRequested poker format. "cash" uses the cash trees. "mtt" is supported only for preflop chip-EV against game nlmtt8; ICM, PKO, and satellite remain unsupported.
baselineYesThe context deltas are measured from. One side of the comparison. Preflop contexts use game, stack, history and optional hand; postflop contexts use pack, board, path and optional combo.
objectiveNoRequested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage.
comboLimitNoMaximum largest-changing combos for aggregate postflop comparisons (default 12, maximum 50)
comparisonYesThe context deltas are measured to. One side of the comparison. Preflop contexts use game, stack, history and optional hand; postflop contexts use pack, board, path and optional combo.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultNoBoth snapshots, the per-action frequency and EV deltas, and the largest combo changes for postflop comparisons. Null when the request is unsupported.
contextNoCanonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.
coverageNoWhether the request was answered exactly, aggregated, or refused as out of coverage.
warningsNoCaveats that must survive into any answer built on this result.
schemaVersionNoEnvelope version, currently "1.0".

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower. The description still adds genuinely useful behavior: the server performs both fetches internally and returns deltas plus largest combo changes, sidestepping two large node payloads. It does not mention limits or failure modes, 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.

Conciseness5/5

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

Two sentences, no filler, and the core value proposition (preferred tool, what it returns, why it is cheaper) is front-loaded. Every clause earns its place.

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 the safety profile and a full output schema, the description does not need to enumerate return fields, yet it usefully summarizes them. Combined with 100% schema coverage and nested contexts documented in the schema, an agent has what it needs; only the internal limits (e.g. comboLimit capping) are left to the schema.

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%, so the schema carries baseline semantics, including nested baseline/comparison contexts, comboLimit defaults, and enum constraints. The description adds no parameter-level detail beyond the schema, 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: computing differences between two preflop or postflop contexts, with a concrete return (action-frequency/EV deltas plus largest postflop combo changes). This clearly separates it from single-node siblings like get_node and get_postflop_node without needing to open their 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 labels itself the 'Preferred tool for differences between two ... contexts' and implies the alternative (fetching both nodes separately) by noting it avoids 'two large node payloads.' No hard exclusions or prerequisites are stated, 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.

enqueue_solveRecord a solve requestAInspect

Record a heads-up postflop solve request. Required: title, board, pot (bb), effective_stack (bb). The job stays pending: solver dispatch and billing are not configured, so this does not start a solve.

ParametersJSON Schema
NameRequiredDescriptionDefault
potYesStarting pot in big blinds.
tagsNoFree-form tags stored with the job.
boardYesBoard to solve, e.g. "3h 3d 2s".
titleYesLabel for the job, 1 to 120 characters.
ip_rangeNoIn-position range in the same weights format.
add_allinNoAdd an all-in branch alongside the bet sizes.
bet_sizesNoBet sizes as fractions of the pot, e.g. [0.33, 0.75].
oop_rangeNoOut-of-position range as hand-class weights, e.g. "AA:1,AKs:0.42". Defaults are left to the solver config.
iterationsNoRequested solver iterations, 50 to 5000.
effective_stackYesEffective stack behind, in big blinds.
max_aggressionsNoRaises allowed per street, 1 to 4.

Output Schema

ParametersJSON Schema
NameRequiredDescription
potNoPot in big blinds.
boardNoBoard for the requested solve.
titleNoTitle given when the job was recorded.
reasonNoWhy the job does not start a solve.
statusNo"pending", "running", "done", or "failed".
dispatchNoAlways "not_configured".
queue_idNoId for get_queued_solve.
createdAtNoISO timestamp the job was recorded.
solution_idNoAlways null while dispatch is disabled.
effective_stackNoEffective stack in big blinds.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations state the write/side-effect profile (readOnly=false, destructive=false, idempotent=false), and the description adds genuinely non-obvious context: the recorded job stays pending and no solver dispatch or billing occurs. This is exactly the kind of operational caveat annotations cannot express; it stops short of describing retry/idempotency implications.

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?

Three sentences, front-loaded with purpose, then required inputs, then the key 'does not start a solve' caveat. Efficient, though the 'Required: ...' list marginally duplicates the schema's required array.

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 and annotations covering the safety profile, the description need not explain returns. It covers purpose, required inputs, and the critical pending/no-dispatch behavior, so an agent has what it needs; only the interaction with retries/idempotency is left implicit.

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% with units ('in big blinds') and constraints already documented per-property, so the schema carries the burden. The description's enumeration of the four required fields and '(bb)' units largely repeats what the schema provides, adding little beyond confirming the required set.

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 (Record) and resource (heads-up postflop solve request/enqueue solve), and the scope qualifier 'heads-up postflop' distinguishes it from the many read-side siblings like get_queued_solve, list_queued_solves, get_postflop_node.

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

Usage Guidelines3/5

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

It explains what happens after the call (job stays pending, no solve started), which informs usage, but it never names an alternative or states when to record a request versus inspecting existing ones. Usage is implied rather than explicitly routed.

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

explain_comboExplain a postflop comboA
Read-onlyIdempotent
Inspect

Preferred tool for exact NLHE postflop hand questions. Returns a canonical context, exact action mix, action EV/loss when available, made-hand and draw classification, blocker facts, and same-rank-class suit comparisons. The server computes evidence; the agent should phrase causality as interpretation.

ParametersJSON Schema
NameRequiredDescriptionDefault
packYesPack id from list_postflop_packs. Use a sizingTrees packId to pick the tree: the pack id for 75% pot on the flop, or "<pack>-flop33" for 33%.
pathNoExact childSegment path from get_postflop_node, e.g. ["Check", "Bet 5.5"]. Empty for the root.
boardYesBoard in spaced form, e.g. "6s 4h 2s"
comboYesRequired exact two-card combo, e.g. As5s
anteBbNoRequested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage.
formatNoRequested poker format. "cash" uses the cash trees. "mtt" is supported only for preflop chip-EV against game nlmtt8; ICM, PKO, and satellite remain unsupported.
objectiveNoRequested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage.
comparisonLimitNoMaximum same-rank-class suit comparisons (default 6, maximum 12)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultNoRecommendation, made-hand and draw classification, blockers, the exact action mix with EV, and same-rank-class suit comparisons. Null when the request is unsupported.
contextNoCanonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.
coverageNoWhether the request was answered exactly, aggregated, or refused as out of coverage.
warningsNoCaveats that must survive into any answer built on this result.
schemaVersionNoEnvelope version, currently "1.0".

TDQS

A3.7/5.0
Behavior4/5

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

The annotations already declare a safe, idempotent, read-only, closed-world read. Beyond that, the description adds real behavioral guidance: EV/loss is only returned 'when available,' and the explicit instruction that the server computes evidence while the agent should phrase causality as interpretation is a meaningful guardrail not captured by structured fields.

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?

Three tight sentences, front-loaded with the primary use case, followed by the return payload and a behavioral caveat. No filler, though the enumerated return list is somewhat dense.

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 restate return values, and the parameter-level guidance lives in a fully described schema. The added note on framing causality as interpretation rounds out an otherwise complete definition for this domain-specific analysis tool.

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%, so all eight parameters — including the pack/path/board/combo mechanics and the anteBb/format/objective coverage caveats — are already documented in the schema. The description adds no additional parameter-level detail, so the baseline 3 applies.

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

Purpose4/5

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

The description states a specific verb and resource ('explain' a 'postflop combo') and lists exactly what the tool returns (action mix, EV/loss, hand and draw classification, blocker facts, suit comparisons). It is clearly a per-combo solver explanation, but it never names a sibling (e.g. get_hand_results, get_postflop_node, compare_strategies) to differentiate itself.

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

Usage Guidelines3/5

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

It positions itself as the 'preferred tool for exact NLHE postflop hand questions,' which implies the usage context, and the schema notes tie parameters back to list_postflop_packs and get_postflop_node. However, there is no explicit when-not and no named alternative for adjacent tasks such as comparing strategies or fetching a whole node.

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

find_handsFind my handsA
Read-onlyIdempotent
Inspect

Find hands the account has uploaded. Returns hand_id, session_id, handAt, position, cards, game, board, potType, street lines, and netBb. Solver grade buckets are not filled. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortYesRow order: newest first, largest win first, or largest loss first (the default).biggest_loss
limitYesHands to return, 1 to 50.
filterNoHand-level filters, all optional.
game_typeNoOnly hands of this game type. Matches hole-card count.
session_idNoOnly hands from this upload session (see list_my_sessions).
table_sizeNoOnly hands dealt at tables of this many seats.
gto_vs_3bet_bucketNoSolver grade bucket for hero's action vs a 3-bet. Grades are not computed, so any value matches nothing rather than inventing a frequency.
gto_plo5_rfi_bucketNoSolver grade bucket for PLO5 raise-first-in. Grades are not computed, so any value matches nothing.

Output Schema

ParametersJSON Schema
NameRequiredDescription
gtoNoAlways "not graded": solver grades are not attached.
hintNoWhere to upload hands when the account has none.
handsNoMatching hands, sorted as requested.
totalNoMatching hands before the limit.
gtoNoteNoWhy a solver-grade filter matches nothing.
returnedNoHands in this response.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnlyHint, idempotentHint, non-destructive), so the bar is lower. The description still adds real behavioral value: solver grade buckets are not filled, and the explicit fallback when the account has no hands. It omits pagination/truncation behavior and the fact that sort defaults to biggest_loss.

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?

Three sentences, front-loaded with the core purpose before details, with no filler. The enumeration of return fields is long but useful; the grade-bucket sentence is partly redundant with the schema descriptions.

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, yet the key behavioral edge cases (empty account, unfilled grade buckets affecting the gto_* filters) are covered. An agent has enough to call it correctly and handle the zero-result 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?

Schema description coverage is 100%, so the schema already documents sort, limit, filter fields, and both gto bucket params. The description's note that grade buckets 'are not filled' restates the schema's own caveat rather than adding new meaning. Baseline 3 applies.

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

Purpose4/5

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

States a specific verb+resource and scopes it precisely ('hands the account has uploaded'), then enumerates the returned fields (hand_id, session_id, handAt, position, cards, game, board, potType, street lines, netBb). It does not explicitly contrast with the nearest sibling (list_my_sessions, get_hand_results), but the scope is unambiguous.

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 a concrete routing rule for the empty-result case: offer get_upload_link's hosted upload page rather than asking the user to paste histories into chat. That names an alternative tool and the condition that selects it, though it offers no guidance on when to prefer this over sibling retrieval tools in the normal case.

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

get_board_reportReport on board texturesA
Read-onlyIdempotent
Inspect

Preferred tool for board-texture heuristics. Aggregates action frequencies and range/action composition across solved boards in one postflop pack. Results explicitly report sample breadth and use equal weight per board.

ParametersJSON Schema
NameRequiredDescriptionDefault
packYesPack id from list_postflop_packs. Use a sizingTrees packId to pick the tree: the pack id for 75% pot on the flop, or "<pack>-flop33" for 33%.
pathNoExact childSegment path from get_postflop_node, e.g. ["Check", "Bet 5.5"]. Empty for the root.
anteBbNoRequested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage.
formatNoRequested poker format. "cash" uses the cash trees. "mtt" is supported only for preflop chip-EV against game nlmtt8; ICM, PKO, and satellite remain unsupported.
filtersNoTexture filters applied to the pack's solved boards. All optional; omit for every board.
objectiveNoRequested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage.
boardLimitNoMaximum matching boards to analyze (default and maximum 50)
representativeLimitNoMaximum representative boards returned (default 12, maximum 20)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultNoAction frequencies and range composition aggregated across solved boards, with equal weight per board, plus representative boards. Null when the request is unsupported.
contextNoCanonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.
coverageNoWhether the request was answered exactly, aggregated, or refused as out of coverage.
warningsNoCaveats that must survive into any answer built on this result.
schemaVersionNoEnvelope version, currently "1.0".

TDQS

A4/5.0
Behavior4/5

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

Annotations already declare read-only, idempotent, non-destructive behavior, so the bar is low. The description adds genuinely non-obvious methodology: results report sample breadth and weight each board equally, which matters for interpreting the aggregate. It does not mention rate limits or cost.

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?

Three short sentences, front-loaded with the usage claim followed by the mechanism and the statistical caveat. Every sentence carries information an agent would not get from the schema or annotations.

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?

An output schema exists, so return-shape explanation is not needed, and annotations carry the safety profile. With 100% schema coverage the remaining burden is light, and the description covers purpose, usage fit, and weighting methodology. It stops short of clarifying how it relates to the node-level siblings for related questions.

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%, so the schema already documents all 8 parameters including the nested filters object and the pack/path relationship. The description adds only the scoping phrase "one postflop pack" and no format or syntax 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.

Purpose4/5

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

States a specific action (aggregates action frequencies and range/action composition) on a specific resource (solved boards in one postflop pack), which distinguishes it from node-level siblings like get_postflop_node. It positions itself as the texture-heuristic tool but never names the sibling it displaces, so an agent still has to infer the boundary.

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?

"Preferred tool for board-texture heuristics" gives a clear use context: reach for this when aggregating across many boards rather than inspecting one node. The pack parameter also routes the agent to list_postflop_packs. There is no explicit when-not statement or named alternative.

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

get_configGet table configurationA
Read-onlyIdempotent
Inspect

Table for one preflop game and stack, in big blinds: seats, stacks, blinds (sb 0.5, bb 1), ante, antePostedBy, stackIncludesAnte, openSizes (first-in raise-to), evUnit, evBaseline. Convergence is not published. stackIncludesAnte is true: the named depth is the starting stack and the 1bb BB ante is posted from it. openSizes at 40bb is open 2.2x (listing 2.2bb; node decodes code 40034 to 2.19bb) and SB 2.8x (2.8bb). 10bb is all-in/fold versus 50bb stacks, so stacks is null there. evs on nodes are small blinds relative to fold. Example: get_config({ game: "nlmtt8", stack: 40 }).

ParametersJSON Schema
NameRequiredDescriptionDefault
gameYes"nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/Limp/AI/Open/3B tokens), "nlh8-hydra" = no-limit hold'em 8-max MTT chip-EV with a classic 0.1bb ante from every seat (10, 20, 30, 60bb; same tokens as nlmtt8), "plo" = pot-limit Omaha 6-max cash (4-card), "plo5" = pot-limit Omaha 5-card 6-max (100bb, 1.2bb ante), "plo9" = pot-limit Omaha 9-max cash, "plo6hu" = 6-card Omaha heads-up (BTN vs BB, 100bb). Cash trees are not tournament, ICM, PKO, or satellite solves. nlmtt8 is chip-EV only.
stackYesStack depth in big blinds, e.g. 40

Output Schema

ParametersJSON Schema
NameRequiredDescription
anteNoAnte in big blinds.
gameNoGame id.
seatsNoSeats in action order.
stackNoStack depth in big blinds.
unitsNoUnit labels for stack, stacks, blinds, ante, openSizes, and evs.
blindsNoBlinds in big blinds.
evUnitNoEV unit, "sb".
stacksNoStarting stacks per seat. Null where the depth is solved against a different stack (10bb all-in/fold versus 50bb).
openSizesNoFirst-in raise-to sizes, by seat, with label and sizeBb.
evBaselineNoWhat EV is measured against, "fold".
antePostedByNoSeat that posts the ante.
schemaVersionNoPayload version, 1.
stackIncludesAnteNoTrue when the named depth already contains the ante.

TDQS

A3.6/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, closed-world, non-destructive), and the description adds real behavioral context beyond them: convergence is not published, stackIncludesAnte semantics for the 1bb BB ante, stacks is null at 10bb (all-in/fold vs 50bb), and that node EVs are small blinds relative to fold. These are non-obvious edge cases an agent would otherwise get wrong, though formatting behavior and error cases are unaddressed.

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

Conciseness3/5

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

Information density is high and most sentences carry non-obvious domain facts, but there is no front-loaded topic sentence and the text is a run-on stream mixing return fields, ante accounting, open-size encoding, null semantics and units. Detail such as 'node decodes code 40034 to 2.19bb' is marginal and hurts readability without adding routing value.

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?

An output schema exists, so return values need not be explained, yet the description supplies the interpretive context an agent needs (units, ante treatment, null stacks at 10bb) for a two-parameter lookup tool. What remains missing is when to prefer this over listing games or fetching tree docs, which is a usage gap rather than a completeness one.

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 schema itself documents each game enum value exhaustively, so the description's enum discussion (nlmtt8, nlh8-hydra ante scheme) is largely redundant with structured data. It does add field-level semantics not in the schema (evUnit, evBaseline, openSizes as first-in raise-to), but not parameter-level meaning, so the baseline 3 applies.

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

Purpose4/5

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

The opening clause identifies the returned resource precisely ('Table for one preflop game and stack, in big blinds: seats, stacks, blinds, ante, antePostedBy, stackIncludesAnte, openSizes, evUnit, evBaseline'), so an agent can tell it returns table/spot configuration rather than strategy or results. It is not a clean verb+resource sentence and makes no attempt to distinguish itself from siblings like list_games or get_tree_docs, which keeps it out of 5 territory.

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

Usage Guidelines3/5

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

Usage is only implied: the trailing example get_config({ game: "nlmtt8", stack: 40 }) shows how to call it, and the field list implies you use it to understand a table before deeper queries. There is no explicit when-to-use, no when-not, and no named alternative among the ~28 siblings.

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

get_exploitabilityGet preflop exploitabilityA
Read-onlyIdempotent
Inspect

Preflop exploitability for a game. No preflop dataset publishes exploitability, convergence, or iteration counts. The answer is not available; this tool never fills in a number.

ParametersJSON Schema
NameRequiredDescriptionDefault
gameYesPreflop game id to report on, e.g. "nl" or "nlmtt8". Any known game answers "not available".

Output Schema

ParametersJSON Schema
NameRequiredDescription
gameNoGame id, echoed.
reasonNoWhy no number is returned.
statusNoAlways "not available".
datasetNoDataset the game maps to, or null when unknown.
availableNoAlways false.
iterationsNoAlways null.
convergenceNoAlways null.
exploitabilityNoAlways null: no figure is published or estimated.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description's job is to add behavior beyond that. It does: it explains why the answer is unavailable (no preflop dataset publishes exploitability, convergence, or iteration counts) and guarantees the tool will never fabricate a number. The only gap is not stating whether the response is an empty result or an explicit "not available" payload.

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?

Three short sentences, front-loaded with the resource and immediately followed by the critical caveat. Every sentence earns its place; nothing is repeated from the schema or annotations.

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 need not explain return values, and it covers the essential oddity of the tool thoroughly. It is only incomplete in not pointing the agent toward an alternative path for computing exploitability.

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 there is a single parameter, whose description already explains that any known game yields "not available". The description adds nothing further about the game id format or valid values. Baseline 3 is appropriate when the schema carries the parameter semantics.

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

Purpose4/5

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

The description names the resource (preflop exploitability for a given game) and, unusually, its defining behavior: it reports that no dataset publishes this metric rather than a value. An agent can immediately tell this apart from siblings like get_hand_results or compare_strategies. It is slightly weakened by being a noun phrase rather than stating a retrieval action, but the intent is unambiguous.

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

Usage Guidelines3/5

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

It implicitly tells the agent not to call this expecting a number ("The answer is not available; this tool never fills in a number"), which is meaningful usage guidance for a dead-end lookup. However, it names no alternative for actually obtaining exploitability (e.g., enqueue_solve), and gives no explicit when-to-use / when-not-to-use framing. Guidance is implied rather than stated.

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

get_hand_resultsGet my results curveA
Read-onlyIdempotent
Inspect

Per-hand cumulative results for a winnings curve. points is [{ hand, bb }], oldest to newest, downsampled. Pass session_id for one session. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

ParametersJSON Schema
NameRequiredDescriptionDefault
max_pointsYesPoints on the curve after downsampling, 2 to 200.
session_idNoOnly this upload session's hands. Omit for the whole account.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNoWhere to upload hands when the account has none.
netBbNoFinal cumulative result in big blinds.
pointsNoDownsampled curve, oldest to newest.
totalHandsNoHands behind the curve.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already declare the safe read-only/idempotent profile, so the bar is lower. The description still adds real value beyond them: the curve is downsampled, ordered oldest to newest, and formats points as [{ hand, bb }], plus empty-state guidance to route to the upload page.

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-loads the purpose, then output shape, then the one parameter, then the empty-state fallback. Dense but every sentence carries information; slightly compressed with the inline backtick notation.

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 doesn't need to explain returns, yet it usefully summarizes the curve format. Empty-account behavior is covered, so an agent has enough to call and recover from the zero-hands case.

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%, so both parameters are already documented. The description restates session_id scoping ('Pass session_id for one session') but adds no syntax or behavior beyond the schema; the points format described is output, not a parameter. Baseline 3 is appropriate.

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

Purpose4/5

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

The description names a specific verb+resource: a per-hand cumulative results curve of winnings. It is distinguishable from siblings like get_session_summary or get_tournament_results by the per-hand granularity, though it doesn't explicitly contrast itself with those tools.

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?

It gives clear context: pass session_id to scope to one session, and instructs the agent to fall back to the upload page from get_upload_link when the account has no hands. It stops short of explicitly naming alternative tools for aggregated stats.

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

get_nodeGet preflop decision nodeA
Read-onlyIdempotent
Inspect

Actions available at a decision node. history is an action path ending in the position about to act, e.g. "UTG_60%_HJ". sizeBb is the raise-to in big blinds and sizePctPot is the percent of the pot after calling (nlmtt8 40bb Open 40034 is 2.19bb; the pack label is 2.2x). evs are small blinds relative to fold. Compact mode returns action totals; add hand for its exact mixed strategy. full=true is full=1: all 169 hold'em hands with explicit 0, and no invented EVs.

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNoHold'em only. When true, each action includes all 169 hands with weight 0 where the bundle omitted the hand. EVs stay only where the bundle scored them.
gameYes"nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/Limp/AI/Open/3B tokens), "nlh8-hydra" = no-limit hold'em 8-max MTT chip-EV with a classic 0.1bb ante from every seat (10, 20, 30, 60bb; same tokens as nlmtt8), "plo" = pot-limit Omaha 6-max cash (4-card), "plo5" = pot-limit Omaha 5-card 6-max (100bb, 1.2bb ante), "plo9" = pot-limit Omaha 9-max cash, "plo6hu" = 6-card Omaha heads-up (BTN vs BB, 100bb). Cash trees are not tournament, ICM, PKO, or satellite solves. nlmtt8 is chip-EV only.
handNoOptional hand/class
stackYesStack depth in big blinds
detailNoResponse detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
historyYesAction path ending in a position
minFreqNoTrim per-action ranges

Output Schema

ParametersJSON Schema
NameRequiredDescription
gameNoPreflop game id, e.g. "nl" or "nlmtt8".
handNoThe requested hand, when one was asked for.
hintNoHow to narrow, page, or widen the same query.
spotNoAction path ending in an action, echoed from the request.
actorNoPosition to act at this node.
stackNoStack depth in big blinds.
unitsNoUnit labels: stack and sizeBb in bb, evs in sb.
evUnitNoEV unit, "sb".
actionsNoActions at the node.
historyNoAction path ending in the acting position.
versionNoDataset version where the bundle publishes one.
evBaselineNoWhat EV is measured against, "fold".
schemaVersionNoPayload version, 1.
continuingHandsNoHand classes that continue past this node.
continuingCombosNoCombos that continue past this node.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds real behavioral context: EV values are small blinds relative to fold, compact mode returns action totals, and full=true yields all 169 hands with explicit 0 and no invented EVs — meaningful disclosures about what is and isn't synthesized.

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 is front-loaded in the first clause, then it moves through parameter and mode semantics economically. The 'full=true is full=1' fragment is cryptic and some sentences are dense, but there is little waste.

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 described, yet the description still clarifies mode differences and EV units for a complex 7-parameter solver tool. Together with full schema coverage, an agent has enough 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 coverage is 100% (baseline 3), and the description goes further by explaining the `history` string format with a concrete example ('UTG_60%_HJ'), sizeBb as raise-to in big blinds with a worked number, and the rationale behind full=true's 0-weight hands.

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

Purpose4/5

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

States a specific verb and resource — 'Actions available at a decision node' — which clearly separates it from the sibling get_postflop_node via the 'preflop' scope in the title. It never names the alternative sibling explicitly, so an agent must infer preflop-vs-postflop routing rather than being told.

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

Usage Guidelines3/5

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

'add `hand` for its exact mixed strategy' and the detail schema's 'use "full" only when exact complete data is required' give implied usage conditions. However, there is no explicit when-to-use / when-not-to-use guidance or routing to siblings like get_postflop_node or get_range.

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

get_opponent_limp_rangeGet an opponent's limp rangeA
Read-onlyIdempotent
Inspect

Shown-hand first-in limp range: 169-class counts of hole cards villains showed after an open limp. Pass position for one seat. Sample is showdown-only. This is not a solver range.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitYesHole-card classes to return, most frequent first, 1 to 169.
positionNoOnly limps from these seats.
game_typeNoOnly hands of this game type.
session_idNoOnly hands from this upload session.
table_sizeNoOnly hands dealt at tables of this many seats.
opponent_idNoOnly this opponent's limps (see list_my_opponents). Omit for every tracked villain.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoThat the sample is showdown-only and the counts are observations.
sampleNoShown limped hands behind the counts.
classesNoObserved classes, most frequent first. Counts, not solver frequencies.
classesByPositionNoSeat label to that seat's observed classes.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower; the description nonetheless adds substantive caveats beyond them — the sample is showdown-only and shown-hand only, and it is not a solver-derived range. It does not discuss sample-size thresholds or filtering behavior, but the added context is meaningful.

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?

Three tight clauses, front-loaded with what the tool returns, then the invocation hint, then the two caveats. Telegraphic but every clause carries information; no filler.

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 need not explain return values, and it supplies the key interpretive caveats (showdown-only, not a solver range). For a 6-parameter filterable analytics tool whose schema is fully documented, this is close to complete, though a note on sparsity/sample confidence would help.

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%, so every one of the 6 parameters is already documented in the schema. The description only adds 'Pass position for one seat', which sits slightly awkwardly against the schema's array-of-seats semantics and provides marginal extra meaning. Baseline 3 is appropriate.

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 precise verb+resource (observed limp range) plus the exact output form (169-class hole-card counts) and the population (hole cards villains showed after an open limp). The closing 'This is not a solver range' explicitly separates it from solver-range siblings such as get_range and get_postflop_range.

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

Usage Guidelines3/5

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

Usage is implied rather than stated: the solver-range disclaimer and 'Sample is showdown-only' hint at when the data is appropriate, and 'Pass position for one seat' is a light invocation hint. However, no explicit when-to-use/when-not conditions or named alternative tools are given beyond the negation.

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

get_opponent_notesGet opponent notesA
Read-onlyIdempotent
Inspect

Leak notes computed from uploaded hands for one opponent, with the sample size on each line.

ParametersJSON Schema
NameRequiredDescriptionDefault
opponent_idYesOpponent id from list_my_opponents.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent instead of a payload when the request named something that does not exist. No figure is estimated in its place.
notesNoNotes, or a single line saying the sample is too small.
opponent_idNoOpponent id, echoed.
display_nameNoScreen name as written in the history.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description still adds real context beyond them: notes are derived from uploaded hands, and every line carries its own sample size, which tells the agent how to interpret the output.

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?

A single front-loaded sentence with no filler; the scope ('one opponent') and the output characteristic ('sample size on each line') both land immediately.

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 and annotations carrying the safety profile, the description only needs to frame the tool's purpose, which it does. The implicit dependency on prior hand uploads is hinted at but not spelled out, leaving a small gap.

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 there is only one parameter, whose schema description already routes to list_my_opponents. The description adds no further parameter detail, so the baseline 3 applies.

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

Purpose4/5

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

States a specific resource (leak notes) with its scope ('for one opponent') and origin ('computed from uploaded hands'), which is clear and distinct from the range/report siblings. It does not explicitly contrast itself with any sibling tool, so it stops short of a 5.

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

Usage Guidelines3/5

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

Usage is implied rather than stated: the phrase 'computed from uploaded hands' hints that hand histories must exist first, and the schema points to list_my_opponents for the id. There is no explicit when-to-use/when-not guidance or named alternative.

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

get_postflop_nodeGet postflop solver nodeA
Read-onlyIdempotent
Inspect

One postflop solver node: the acting player's strategy for every hand class, the legal next segments, board, reach and the reach-weighted action split. Walk deeper by appending a returned childSegment (an action like "Bet 5.5" or a runout like "deal:7c") to path.

ParametersJSON Schema
NameRequiredDescriptionDefault
packYesPack id from list_postflop_packs. Use a sizingTrees packId to pick the tree: the pack id for 75% pot on the flop, or "<pack>-flop33" for 33%.
pathNoSegments from the root, e.g. ["Check", "Bet 5.5"]. Empty for the root node.
boardYesBoard in spaced form, e.g. "3h 3d 2s"
comboNoOptional exact combo, e.g. AsKh (PLO5: five cards, as listed in the node's hands)
limitNoMaximum representative compact combos (default 40, maximum 200)
detailNoResponse detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNoHow to narrow, page, or widen the same query.
nodeNoFull detail: the stored node. Null at a chance point, where runouts hang directly under the path.
pathNoSegments walked from the root to this node.
boardNoBoard at this node.
comboNoThe requested combo, when one was asked for.
handsNoCompact rows in `columns` order, or the full per-combo strategy objects in full detail.
potBbNoPot at this node in big blinds.
reachNoFull detail: the acting player's per-combo reach.
actionsNoActions at the node with their reach-weighted frequency.
columnsNoColumn order for `hands`: combo, reach, frequencies, evBb, evLossBb, actionEvBb.
summaryNoWhat the compact range left out, so nothing looks complete when it is sampled.
actionFreqsNoFull detail: aggregate frequency per action.
actingPlayerNo0 for out of position, 1 for in position.
childSegmentsNoAppend one of these to `path` to walk deeper.

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds real behavioral context beyond that: the node is reachable/expandable via path+childSegment, and the default compact detail 'removes bulk maps' while 'full' is reserved for exact complete data — useful trade-off disclosure.

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?

Two dense sentences with no filler, front-loading what the node returns before the traversal instruction. It is efficient, though poker-domain jargon ('childSegment', 'reach-weighted action split') keeps it slightly heavy.

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 explain return values, and annotations plus 100% schema coverage carry most of the structured load. It covers content, traversal and detail trade-offs; the only real gap is not routing the agent away from the superficially similar get_node sibling.

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%, so all six parameters including pack, path, board, combo, limit and the detail enum are already documented in the schema. The description reinforces how path works (appending a childSegment) but adds little per-parameter meaning beyond what the schema provides; baseline 3 is appropriate.

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

Purpose4/5

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

States a specific verb+resource (get a postflop solver node) and enumerates exactly what one node contains: per-hand-class strategy, legal next segments, board, reach and reach-weighted action split. The 'postflop' qualifier separates it from generic siblings, but it never distinguishes itself from the sibling get_node, which is the one an agent could easily confuse it with.

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

Usage Guidelines3/5

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

The second sentence explains the traversal pattern — append a returned childSegment to `path` to go deeper — which is genuinely useful usage guidance. However, it gives no explicit when-to-use/when-not guidance against alternatives like get_node, get_postflop_range, or get_hand_results, leaving the agent to infer the boundary.

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

get_postflop_rangeGet postflop action rangeA
Read-onlyIdempotent
Inspect

The range a player takes one flop action with, from a solved pack: hand-class weights ("AA:1,AKs:0.42,...", same format as the preflop ranges) after every earlier flop action on the path. path ends in the action whose range you want, e.g. ["Check", "Bet 1.8", "Call 1.8"] for the check-call range. Bet-size tree. "33" = 33% pot on the flop, then 75% pot on the turn and river, plus all-in. "75" = 75% pot on every street, plus all-in. Compact and full detail apply to the other range tools; this returns the action range itself.

ParametersJSON Schema
NameRequiredDescriptionDefault
handNoOptional exact combo (AsKh) or hand class (AKs) for one frequency instead of reading the whole range.
packYesPack id from list_postflop_packs
pathYesFlop actions ending in the action whose range you want
treeYesBet-size tree. "33" = 33% pot on the flop, then 75% pot on the turn and river, plus all-in. "75" = 75% pot on every street, plus all-in. PLO5 packs are solved on "33" only.
boardYesFlop, e.g. "3h 3d 2s"
minFreqNoDrop classes at or below this weight. Default 0.

Output Schema

ParametersJSON Schema
NameRequiredDescription
handNoThe requested hand, when one was asked for.
packNoPack id the range was read from, after tree resolution.
pathNoFlop actions, ending in the action asked for.
treeNoBet-size tree, "33" or "75".
boardNoCanonical board as stored in the pack.
errorNoPresent instead of a payload when the request named something that does not exist. No figure is estimated in its place.
rangeNoHand-class weights as "AA:1,AKs:0.42,…", the preflop range format.
actionNoThe action whose range this is.
summaryNoWhat the compact range left out, so nothing looks complete when it is sampled.
weightsNoHand class to frequency. An omitted class has weight 0.

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds useful behavioral context – the hand-class weight return format and how the path accumulates prior actions – but says nothing about pagination, cost, or failure modes for an invalid path.

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

Conciseness3/5

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

It is reasonably front-loaded, but the tree explanation ('33' = 33% pot on the flop...) restates the schema's tree description almost verbatim, duplicating structured data rather than adding new information. A sentence could be trimmed without loss.

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 return shape needn't be described, and annotations carry the safety profile. Between the path example and tree semantics, the agent has enough to call a 6-param tool correctly; only explicit sibling routing 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 adds real value with a concrete path example (['Check','Bet 1.8','Call 1.8']) and distinguishes the tree enum behavior ('33' vs '75'), which helps the agent construct valid values beyond reading the schema.

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

Purpose4/5

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

States a specific verb and resource ('the range a player takes one flop action with, from a solved pack') and clarifies it returns the action range itself rather than the compact/full-detail ranges of the other range tools. It differentiates from siblings only loosely ('the other range tools'), so it falls just short of a 5.

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

Usage Guidelines3/5

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

The path-accumulation semantics ('after every earlier flop action on the path') and the worked example imply when to use it, but the description never names a concrete alternative tool or states an explicit when-not-to-use condition versus get_range or get_postflop_node. Usage is inferable rather than stated.

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

get_queued_solveGet a queued solveA
Read-onlyIdempotent
Inspect

Look up one queued solve for this account. status is pending, running, done, or failed. solution_id is null until a worker exists.

ParametersJSON Schema
NameRequiredDescriptionDefault
queue_idYesQueue id returned by enqueue_solve.

Output Schema

ParametersJSON Schema
NameRequiredDescription
potNoPot in big blinds.
boardNoBoard for the requested solve.
titleNoTitle given when the job was recorded.
reasonNoWhy the job does not start a solve.
statusNo"pending", "running", "done", or "failed".
dispatchNoAlways "not_configured".
queue_idNoId for get_queued_solve.
createdAtNoISO timestamp the job was recorded.
solution_idNoAlways null while dispatch is disabled.
effective_stackNoEffective stack in big blinds.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds genuine context beyond them: the valid status values and the fact that solution_id stays null until a worker exists. It does not state whether polling is expected or at what cadence.

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?

Three short sentences, front-loaded with the action and then the state/model semantics. Every sentence carries new information with no filler.

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 return shape needn't be re-explained, and annotations cover safety. The only gap is routing guidance relative to list_queued_solves, which the description leaves to inference.

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%, so queue_id is fully documented in the schema as 'Queue id returned by enqueue_solve'. The description's added detail (status, solution_id) concerns returned fields, not the parameter, so the baseline 3 is appropriate.

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

Purpose4/5

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

States a specific verb and resource ('Look up one queued solve') and the 'one' implicitly distinguishes it from the list_queued_solves sibling. It does not explicitly name that sibling, so an agent still has to infer the single-vs-list split.

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

Usage Guidelines3/5

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

Scoping is implied by 'for this account' and 'one queued solve', but there is no explicit when-to-use guidance or named alternative (e.g. list_queued_solves) to route the agent. Usage must be inferred from the singular framing.

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

get_rangeGet preflop rangeA
Read-onlyIdempotent
Inspect

The GTO range for one spot. spot is an action path of POSITION_ACTION pairs ending in the action whose range you want, e.g. NLHE cash "UTG_60%_HJ_Call", nlmtt8 "UTG_Open", or PLO "UTG_Open_HJ_3B". Add hand for one exact frequency and EV. Compact mode is default; PLO returns representative pure/mixed hands unless a hand is specified; plo5 returns the top hands by EV that take the action (limit up to 500 compact, 2000 full).

ParametersJSON Schema
NameRequiredDescriptionDefault
gameYes"nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/Limp/AI/Open/3B tokens), "nlh8-hydra" = no-limit hold'em 8-max MTT chip-EV with a classic 0.1bb ante from every seat (10, 20, 30, 60bb; same tokens as nlmtt8), "plo" = pot-limit Omaha 6-max cash (4-card), "plo5" = pot-limit Omaha 5-card 6-max (100bb, 1.2bb ante), "plo9" = pot-limit Omaha 9-max cash, "plo6hu" = 6-card Omaha heads-up (BTN vs BB, 100bb). Cash trees are not tournament, ICM, PKO, or satellite solves. nlmtt8 is chip-EV only.
handNoOptional hand/class, e.g. AKs or (KA)(KA)
spotYesAction path ending in an action
limitNoMaximum compact rows to return (default 120, maximum 500).
stackYesStack depth in big blinds, e.g. 100
detailNoResponse detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
minFreqNoDrop hands at or below this weight (PLO ranges are large)

Output Schema

ParametersJSON Schema
NameRequiredDescription
evNoFull detail: EV of the requested hand in small blinds.
evsNoHand class to EV, only where the solved bundle scored the hand.
evSbNoEV of the requested hand in small blinds.
freqNoFull detail: frequency of the requested hand.
gameNoPreflop game id, e.g. "nl" or "nlmtt8".
handNoThe requested hand, when one was asked for.
hintNoHow to narrow, page, or widen the same query.
kindNoplo5: the action family.
spotNoAction path ending in an action, echoed from the request.
actorNoPosition to act at this node.
handsNoHand classes in the range.
rangeNoCompact rows in `columns` order.
stackNoStack depth in big blinds.
actionNoplo5: the action the range belongs to.
combosNoCombos in the range.
columnsNoColumn order for `range`: hand, frequency, evSb.
historyNoAction path ending in the acting position.
summaryNoWhat the compact range left out, so nothing looks complete when it is sampled.
versionNoDataset version where the bundle publishes one.
weightsNoHand class to frequency. An omitted class has weight 0.
frequencyNoFrequency of the requested hand, 0 to 1.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare this a safe, idempotent read, so the bar is lower; the description still adds meaningful behavior: compact is the default response shape, PLO collapses to representative pure/mixed hands, and plo5 truncates to the top hands by EV with stated limits. It does not mention rate limits or pagination beyond the limit note, but the modality differences across game families are genuinely useful disclosure.

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 purpose in the first sentence, then examples and mode notes; nearly every clause carries information. It is dense and slightly run-on in the example-heavy middle, but no sentence is filler.

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?

An output schema exists, so return values need not be described; the description instead covers the inputs that matter (spot token grammar, game family quirks, detail modes, hand drill-down). The main residual gap is the absence of routing guidance to sibling range tools, which is a usage rather than a completeness issue.

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 baseline is 3, but the description compensates for the schema's thin "Action path ending in an action" by giving concrete spot strings per game family ("UTG_60%_HJ_Call", "UTG_Open", "UTG_Open_HJ_3B") and explaining what `hand` yields. That is real added meaning for the least self-evident parameter.

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

Purpose4/5

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

States a specific verb+resource ("The GTO range for one spot") and enumerates the supported game formats, so the agent knows exactly what comes back. It never names a sibling such as get_postflop_range or get_range_metadata to sharpen the boundary, but the title/description pairing makes the preflop scope unambiguous.

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

Usage Guidelines3/5

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

Gives real usage signals: add `hand` when you want a single frequency and EV, only use `detail: full` "when exact complete data is required," and PLO returns representative hands unless a hand is named. It stops short of comparing itself to alternatives (get_postflop_range, get_node, compare_strategies), so the agent must infer which tool to pick.

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

get_range_metadataGet range index metadataA
Read-onlyIdempotent
Inspect

Index metadata for one preflop game, stack, and path: bundle stats for hold'em/PLO bundles, or the matching node row for plo5 and plo6hu. Does not return a strategy and does not invent exploitability.

ParametersJSON Schema
NameRequiredDescriptionDefault
gameYesPreflop game id, e.g. "nl", "nl9", "nlmtt8", "nlh8-hydra", "plo", "plo9", "plo5", "plo6hu".
pathYesAction path, e.g. UTG_Open or LJ_Fold. Use (root) or empty for the plo5 root.
stackYesStack depth in big blinds, e.g. 100.

Output Schema

ParametersJSON Schema
NameRequiredDescription
gameNoGame id, echoed.
noteNoWhat the match means, or that nothing was estimated.
pathNoAction path, echoed.
rowsNoMatching index rows.
actorNoActing position read off the path.
errorNoPresent instead of a payload when the request named something that does not exist. No figure is estimated in its place.
matchNo"bundle", "node", or "none".
stackNoStack depth in big blinds, echoed.
datasetNoDataset the game maps to.
preflopExploitabilityNoAlways "not available".

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive, closed-world behavior, so the safety profile is covered. The description adds genuine extra context: the return payload branches by game type (bundle stats for hold'em/PLO vs. a node row for plo5/plo6hu) and it explicitly disclaims two things it does not do.

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?

Two tight sentences with the payload behavior front-loaded and the exclusions second; every clause carries information. Slightly dense with domain jargon ('bundle stats', 'plo6hu') but no filler.

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?

A read-only, single-shot lookup with full schema descriptions, rich annotations, and an output schema, so return-format explanation is not needed. The description covers the one non-obvious element (game-dependent payload) and the boundary conditions; only an explicit sibling pointer 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 coverage is 100% with per-parameter examples ('nl', 'plo5', 'UTG_Open', '100'), so the schema already carries the meaning. The description restates the three required inputs without adding format or validity detail beyond them, so the baseline 3 applies.

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

Purpose4/5

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

States a concrete verb and resource ('Index metadata for one preflop game, stack, and path') and further specifies the output shape per game family (bundle stats vs. node row). It also fences itself off from the more obvious sibling by declaring it 'does not return a strategy', which is what get_range presumably does, though it never names that alternative.

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 clear when-not guidance by excluding strategy and exploitability outputs, which tells the agent when to prefer get_range or get_exploitability instead. However, no alternative tool is named and there is no positive statement of the use case that selects this tool over list_games/get_node.

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

get_session_summarySummarize a sessionB
Read-onlyIdempotent
Inspect

Headline numbers and HUD rates for one uploaded session.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_idYesSession id from list_my_sessions.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNoSession id.
hudNoHUD rates over this session, as percentages.
heroNoHero name in the history.
errorNoPresent instead of a payload when the request named something that does not exist. No figure is estimated in its place.
handsNoHands in the session.
netBbNoSession result in big blinds.
endedAtNoLast hand timestamp.
game_typeNoGame type: "NLHE", "PLO", "PLO5", or "PLO6".
startedAtNoFirst hand timestamp.

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, non-destructive, and closed-world, so the safety profile is fully covered. The description adds only the scope constraint that it operates on a single already-uploaded session; it discloses nothing about aggregation method or cost.

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?

A single eight-word sentence with no filler and the resource front-loaded. It is efficient, though terse to the point of omitting any actionable usage context.

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 no explanation, and the one parameter is fully described in the schema while annotations carry the safety profile. The definition is adequate for correct invocation, with the main gap being the absence of usage guidance.

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 single session_id parameter is fully documented in the schema (UUID format, sourced from list_my_sessions). The description adds no syntax or format meaning beyond that, so the baseline of 3 applies.

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

Purpose4/5

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

The description names a specific resource (one uploaded session) and specifies the content returned (headline numbers and HUD rates), which distinguishes it from generic session listings. It does not explicitly contrast with siblings like list_my_sessions or get_board_report, but the scope is unambiguous.

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

Usage Guidelines2/5

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

There is no when-to-use guidance: no mention of prerequisites (session must be uploaded first), no statement of when this is preferable to get_board_report or other per-session tools, and no exclusions. The only usage hint lives in the schema's session_id description, not the tool description.

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

get_tournament_resultsGet my tournament resultsA
Read-onlyIdempotent
Inspect

MTT results imported from tournament summary files. Money is in cents. Hand histories are not a source of buy-ins or prizes. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitYesTournament summaries to include, 1 to 500.

Output Schema

ParametersJSON Schema
NameRequiredDescription
roiNoReturn on investment as a ratio, or null.
noteNoPresent when no tournament summaries have been uploaded.
itmPctNoShare of tournaments that cashed, 0 to 1, or null.
recentNoTournaments, newest first.
buyInCentsNoTotal buy-ins, or null when one buy-in is unknown.
tournamentsNoTournament summaries counted.
receivedCentsNoTotal prize money received.
netProfitCentsNoReceived minus buy-ins, or null when a buy-in is unknown.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the description correctly spends its words on added context: money is denominated in cents and hand histories are not a source of buy-ins or prizes. This is meaningful data-shape information beyond the annotations.

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?

Four short sentences, front-loaded with what the data is, then units and caveats, then the fallback workflow. No filler, though the upload-link sentence is long enough that it could be tightened.

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?

An output schema exists, so return-value explanation is unnecessary, and the description covers provenance, currency units, and a fallback path. It does not state what happens when there are zero tournaments (as opposed to zero hands), a minor gap for a single-parameter read tool.

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% for the single `limit` parameter (1–500, default 200), so the schema fully documents it. The description adds nothing about the limit or result windowing, which is the expected baseline-3 outcome 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.

Purpose4/5

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

The description identifies the resource and its provenance ("MTT results imported from tournament summary files"), which tells an agent this returns tournament-level results rather than hand results. It is clear but does not explicitly contrast with siblings like get_hand_results or get_session_summary.

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?

It gives a concrete conditional workflow: when the account has no hands, offer the hosted upload page from get_upload_link instead of asking for pasted histories. That is real usage guidance, though there is no explicit when-to-use framing versus other results tools.

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

get_tree_docsGet tree documentationA
Read-onlyIdempotent
Inspect

Tree documentation for one dataset: coverage note from the shipped README and per-stack bundle or node counts from the shipped index. Does not read or modify range bytes.

ParametersJSON Schema
NameRequiredDescriptionDefault
datasetYesDataset id from list_datasets, e.g. "nl/v2", "nl9", "nlmtt8", "plo", "plo9", "plo5", "plo6hu".

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent instead of a payload when the request named something that does not exist. No figure is estimated in its place.
sourceNoFile the coverage note came from.
stacksNoPer-stack counts.
datasetNoDataset id, echoed.
coverageNoCoverage row from the shipped README.
preflopExploitabilityNoAlways "not available".

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false and closed-world, so the safety profile is covered. The description adds real scope detail beyond that: it clarifies the payload comes only from the shipped README and shipped index, and explicitly that range bytes are neither read nor modified. That scoping is meaningful added context, though no auth, staleness or paging behavior is mentioned.

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 compact sentences, front-loaded with what the tool returns, followed by a scope-limiting exclusion. Every clause carries information and nothing is redundant.

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?

For a one-parameter, read-only tool with full annotations and an output schema, the description needn't explain return values, and it adequately covers content and scope. It is essentially complete, with only the absence of any when-to-use guidance keeping it from 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?

There is a single parameter (dataset) at 100% schema description coverage, with the schema supplying concrete id examples. The description contributes only "for one dataset", adding no format or constraint beyond what the schema already documents, so the baseline 3 applies.

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

Purpose4/5

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

The description states a specific verb+resource (documentation for one dataset's tree) and enumerates exactly what the payload contains: a coverage note from the shipped README and per-stack bundle/node counts from the shipped index. This is far more specific than a tautology. However, it never names a sibling it should be preferred over (e.g. get_range or get_range_metadata), so sibling differentiation is left implicit.

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

Usage Guidelines3/5

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

The clause "Does not read or modify range bytes" gives a negative boundary that implicitly routes an agent wanting actual range data to a sibling like get_range. But there is no positive statement of when to reach for this tool and no alternative is named, so guidance is merely implied.

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

list_datasetsList solved datasetsA
Read-onlyIdempotent
Inspect

List preflop datasets in the shipped tree documentation (stacks, positions, whether each bundle was analyzed). Preflop exploitability is not available.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
readmeNoHow to read one dataset's write-up.
sourceNoWhere the documentation came from, "data/tree-docs".
datasetsNoDocumented datasets.
generatedNoDate the documentation was generated.
preflopExploitabilityNoAlways "not available": no preflop dataset publishes it.

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already declare this a safe, read-only, idempotent, closed-world read, so the safety profile is covered. The description adds value beyond them by describing the content each entry carries and by flagging the key limitation (no preflop exploitability), which prevents the agent from misusing the results.

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 with the resource and scope front-loaded and the limitation trailing. Every clause carries information (what is listed, where it lives, what fields appear, what is unavailable) with no filler.

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?

An output schema exists so return values need not be spelled out, and annotations cover the safety profile; the description supplies the remaining needed context (scope, per-entry content, one absence). Only the differentiation from sibling listing tools is left implicit.

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?

The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a no-parameter tool applies. No parameter semantics are missing or contradicted.

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

Purpose4/5

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

States a specific verb (List) and resource (preflop datasets) and adds scope: they live in the shipped tree documentation, and it enumerates what each entry conveys (stacks, positions, analyzed status). It does not name or distinguish itself from similar siblings such as list_postflop_packs or get_tree_docs, so an agent must infer the boundary.

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

Usage Guidelines2/5

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

There is no explicit when-to-use guidance and no alternatives named among a large family of list_* siblings. The closing caveat 'Preflop exploitability is not available' hints at what the tool cannot do, but it is not framed as routing guidance, leaving usage to inference.

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

list_gamesList covered gamesA
Read-onlyIdempotent
Inspect

Discover covered stack depths and positions. Call this before low-level preflop queries. "nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/Limp/AI/Open/3B tokens), "nlh8-hydra" = no-limit hold'em 8-max MTT chip-EV with a classic 0.1bb ante from every seat (10, 20, 30, 60bb; same tokens as nlmtt8), "plo" = pot-limit Omaha 6-max cash (4-card), "plo5" = pot-limit Omaha 5-card 6-max (100bb, 1.2bb ante), "plo9" = pot-limit Omaha 9-max cash, "plo6hu" = 6-card Omaha heads-up (BTN vs BB, 100bb). Cash trees are not tournament, ICM, PKO, or satellite solves. nlmtt8 is chip-EV only.

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNoResponse detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.

Output Schema

ParametersJSON Schema
NameRequiredDescription
_coverageNoFormats and objectives this server does and does not answer.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description still adds real behavioral context beyond them: which solves are out of scope ('Cash trees are not tournament, ICM, PKO, or satellite solves') and what each code actually returns (169-grid hands, per-hand EV in small blinds, chip-EV vs. classic-ante variants).

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?

The purpose and the preflop-query directive are front-loaded before the reference block. The long code enumeration is dense but each entry carries distinct information an agent cannot get elsewhere; the only blemish is the stray escaped newline ("\n" = ...) that breaks the 'nl' entry's formatting.

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?

An output schema exists, so return-value explanation is not required, and the description fully documents the game-code domain plus scope caveats a caller needs. It is essentially complete for a zero-required-parameter discovery tool, missing only a note on how the detail flag changes the payload (already handled by the schema).

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 'detail' parameter has its enum values documented in the schema, so the schema carries the parameter burden. The description says nothing about the 'detail' option, so baseline 3 is appropriate.

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

Purpose4/5

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

The description states a specific verb and resource ('Discover covered stack depths and positions') and then enumerates the exact game identifiers it returns, so an agent knows precisely what this produces. It does not explicitly differentiate itself from near-siblings like list_datasets or list_spots, but the enumerated domain makes the distinction inferable.

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?

It gives an explicit usage directive: 'Call this before low-level preflop queries,' which tells the agent when to reach for it and its ordering relative to other tools. It stops short of naming the alternative tools to use once the code is known, so it is clear context rather than full when/when-not routing.

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

list_library_solutionsList my saved solutionsA
Read-onlyIdempotent
Inspect

Finished postflop solutions saved for this account. None are marked done while dispatch is disabled.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitYesSolutions to return, 1 to 50.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoWhy no solution is marked done.
solutionsNoEmpty while solver dispatch is disabled.

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so safety and determinism are covered without the description. The description adds one genuine behavioral caveat – 'None are marked done while dispatch is disabled' – which tells the agent results may lack a completed status depending on system state, though the phrasing is cryptic and the return format/pagination is left to the output schema.

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?

Two short sentences with no filler, and the resource scope is front-loaded ahead of the state caveat. The second sentence is terse to the point of ambiguity but does convey information rather than padding.

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?

For a read-only list tool with full annotations, complete parameter schema and an output schema, the description supplies the essential scope plus a state caveat. Nothing critical is missing, though the dispatch caveat is underexplained.

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 'limit' parameter is fully documented with range and default in the schema. The description adds no additional meaning about the limit, so the baseline 3 applies.

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

Purpose4/5

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

The description names a specific resource with a qualifier: 'Finished postflop solutions saved for this account.' The word 'finished' implicitly distinguishes it from list_queued_solves and get_queued_solve, so an agent can separate the completed-solution listing from the pending one. It is clear but does not explicitly name the sibling it excludes.

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

Usage Guidelines3/5

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

Usage is implied by the phrase 'finished postflop solutions' – an agent can infer this is the tool for browsing already-computed results rather than queued work. However, there is no explicit when-to-use statement and no named alternative (e.g., list_queued_solves) to route to for unfinished solves.

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

list_my_opponentsList my opponentsA
Read-onlyIdempotent
Inspect

Tracked opponents from uploaded hands. Each row has handCount, handsVsHero, and heroBb100Vs. Pass name to find one villain.

ParametersJSON Schema
NameRequiredDescriptionDefault
heroNoOnly hands where this hero name was seated.
nameNoCase-insensitive substring of the opponent's screen name.
sortYesRow order: most hands, most recent, or by hero's bb/100 against them (toughest = worst for hero).hands
limitYesOpponents to return, 1 to 500.
game_typeNoOnly hands of this game type, e.g. "NLHE" or "PLO".
min_handsYesDrop opponents seen in fewer hands than this.

Output Schema

ParametersJSON Schema
NameRequiredDescription
opponentsNoOpponents, sorted as requested.

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile is fully covered. The description adds the shape of each returned row (handCount, handsVsHero, heroBb100Vs), which is useful behavioral context, but says nothing about defaults, caps, or empty-result behavior.

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?

Three short sentences, front-loaded with the data source before the row shape and the filter hint; nothing is wasted. Slight deduction because the row field names are dropped without context, leaving the reader to interpret heroBb100Vs on their own.

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 need not explain returns, and the schema fully covers all six parameters plus required/minimum constraints. For a read-only list tool this is close to complete; the missing piece is any hint about the typical workflow connecting this to the per-opponent siblings.

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 every parameter is documented in-schema, including the sort enum semantics and the 1-500 limit range, so the baseline is 3. The description only echoes the name filter ('find one villain') and does not add meaning beyond the schema, e.g. how it interacts with hero or min_hands.

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

Purpose4/5

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

States a specific resource and scope: tracked opponents derived from uploaded hands, which an agent can distinguish from session/hand-level siblings. It does not explicitly name a sibling, so it stops short of a 5, but the verb+resource pairing is clear.

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

Usage Guidelines3/5

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

The only guidance is 'Pass name to find one villain,' which implies a lookup use case but gives no when-to-use versus when-not-to-use, and no routing to alternatives like get_opponent_notes for notes on a specific villain. Usage is implied rather than stated.

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

list_my_sessionsList my sessionsA
Read-onlyIdempotent
Inspect

Recent uploaded sessions, newest first: id, hero, game type, dates, hands, and net result. game_type matches hole-card count. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitYesSessions to return, 1 to 50.
game_typeNoOnly sessions containing this game type.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNoWhere to upload hands when the account has none.
sessionsNoSessions, newest first.

TDQS

A4/5.0
Behavior4/5

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

Annotations already establish read-only, idempotent, non-destructive behavior, so the description is free to add other context — and it does: newest-first ordering and the empty-state fallback flow. It does not mention pagination or result-size behavior, a minor gap for a listing tool.

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?

Two sentences, front-loaded with the core purpose and return fields, then the fallback instruction. Efficient and free of filler, though the second sentence packs two distinct ideas into one line.

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?

An output schema exists, so field-level return explanation is optional, yet the description still names key fields and the sort order. Combined with the empty-account fallback, an agent has enough to call this correctly, with only pagination behavior unaddressed.

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 real meaning beyond the schema by explaining that 'game_type matches hole-card count', which clarifies the NLHE/PLO/PLO5/PLO6 enum semantics. The limit parameter is left entirely to the schema.

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

Purpose4/5

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

Specific verb+resource ('Recent uploaded sessions') with a clear scope signal ('newest first') and an enumeration of returned fields, which separates it from detail-oriented siblings like get_session_summary. It stops short of explicitly naming the sibling it differs from, so it is clear but not fully self-differentiating.

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 conditional routing for the empty-account case: fall back to get_upload_link rather than asking the user to paste histories. That is a concrete when-to-use rule, but there is no guidance on when to prefer this list view over get_session_summary or find_hands for detail.

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

list_postflop_packsList postflop packsA
Read-onlyIdempotent
Inspect

Every solved postflop pack: preflop line, positions (OOP vs IP), stack, pot, the bet-size trees it is solved under, and the solved boards. Boards use the spaced form ("3h 3d 2s"). NLHE packs list sizingTrees: "75" (75% pot every street, the pack id itself) and "33" (33% pot on the flop, then 75%, under the <pack>-flop33 id); every postflop tool accepts either tree's packId. PLO5 packs (ids starting plo5-) solve one 33% flop tree, flop decisions only. Compact output lists board names per pack. Pass pack (the 75% id or the -flop33 id) for that tree's per-board detail and per-flop exploitability where the index publishes a number. Missing exploitability is omitted, never estimated. Pass variant to list only NLHE or PLO5 packs. Call this before get_postflop_node.

ParametersJSON Schema
NameRequiredDescriptionDefault
packNoOne pack id (75% id or the -flop33 id): per-board detail and that tree's exploitability
detailNoResponse detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
variantNoOnly packs of this game: nlhe (hold'em) or plo5 (five-card Omaha)

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNoHow to narrow, page, or widen the same query.
packsNoPacks matching `variant` and `pack`.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial domain behavior on top: pack-id conventions for the 75% vs '-flop33' trees, the PLO5 single-tree restriction, and the policy that missing exploitability is omitted rather than estimated. It also discloses that 'compact' removes bulk maps, which materially affects what an agent receives.

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?

The opening sentence is well front-loaded with the full content of a pack, and nearly every clause carries information. However, the remainder is a dense run-on that mixes parameter semantics and output-mode behavior into one block, which would benefit from structure.

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; the description nonetheless clarifies the compact/full distinction and exploitability omission. For a filtered-list tool with 100% schema coverage and clear annotations, 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.

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 goes beyond the schema by explaining what the `pack` ids actually mean (75% id vs `<pack>-flop33`), that every postflop tool accepts either tree's packId, and what detail levels retain or drop, adding real domain semantics the schema cannot express.

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 ('Every solved postflop pack') and enumerates exactly what each entry contains (preflop line, positions, stack, pot, sizing trees, solved boards). It is clearly distinguishable from sibling list/get tools and explicitly positions itself relative to get_postflop_node.

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 strong usage direction: 'Call this before get_postflop_node' establishes the workflow, and it explains how to use `variant` and `pack` to narrow the listing. It does not state when this tool should be skipped in favor of a sibling list tool (e.g., list_datasets), so it stops short of explicit when-not guidance.

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

list_queued_solvesList my queued solvesA
Read-onlyIdempotent
Inspect

List this account's solver-queue jobs, newest first. Jobs are not dispatched.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitYesJobs to return, 1 to 50.

Output Schema

ParametersJSON Schema
NameRequiredDescription
solvesNoQueued jobs. None are dispatched.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive, and closed-world, so safety is covered. The description adds two things annotations cannot convey: result ordering (newest first) and that queued jobs are not dispatched, which tells the agent this is passive inspection rather than a trigger.

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 short sentences with no waste. The resource and scope lead, and the non-dispatch caveat follows immediately where it is most useful.

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?

An output schema exists, so return shape need not be described, and annotations cover the safety profile. The description supplies scope and ordering; the only minor gap is no mention of how the queue relates to enqueue_solve or of pagination beyond the limit parameter.

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 'limit' parameter is fully documented in the schema (range 1-50, default 20). The description adds no syntax or default information 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.

Purpose4/5

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

Specific verb+resource ('List this account's solver-queue jobs') plus ordering ('newest first'). It does not name the adjacent siblings get_queued_solve (singular fetch) or enqueue_solve, so an agent must infer the boundary itself, but the scope is unambiguous.

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

Usage Guidelines3/5

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

Usage is only implied by the verb and the scoping phrase 'this account's'; there is no explicit when-to-use statement and no pointer to get_queued_solve for single-job retrieval or enqueue_solve for adding jobs. The closest thing to guidance is the behavioral note that jobs are not dispatched.

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

list_spotsSearch preflop spotsA
Read-onlyIdempotent
Inspect

Search valid decision nodes for a stack depth, tagged by depth (1 = RFI, 2 = vs open, 3 = 3-bet pots, …). Compact mode is paginated; use depth, contains, and offset to narrow results without loading thousands of paths. plo9 has no spot index: walk it with get_node from history "UTG".

ParametersJSON Schema
NameRequiredDescriptionDefault
gameYes"nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/Limp/AI/Open/3B tokens), "nlh8-hydra" = no-limit hold'em 8-max MTT chip-EV with a classic 0.1bb ante from every seat (10, 20, 30, 60bb; same tokens as nlmtt8), "plo" = pot-limit Omaha 6-max cash (4-card), "plo5" = pot-limit Omaha 5-card 6-max (100bb, 1.2bb ante), "plo9" = pot-limit Omaha 9-max cash, "plo6hu" = 6-card Omaha heads-up (BTN vs BB, 100bb). Cash trees are not tournament, ICM, PKO, or satellite solves. nlmtt8 is chip-EV only.
depthNoOptional decision depth filter
limitNoMaximum compact rows to return (default 120, maximum 500).
stackYesStack depth in big blinds
detailNoResponse detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
offsetNoCompact pagination offset
containsNoOptional case-insensitive history substring filter

Output Schema

ParametersJSON Schema
NameRequiredDescription
gameNoGame id.
hintNoHow to narrow, page, or widen the same query.
spotsNoThis page of decision nodes.
stackNoStack depth in big blinds.
totalNoSpots in the dataset for this stack.
offsetNoOffset this page started at.
matchedNoSpots left after the depth and contains filters.
returnedNoSpots in this page.
nextOffsetNoOffset for the next page, or null at the end.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive and the closed world, so safety is covered. The description adds real behavioral context: compact mode is paginated, results can be narrowed to avoid huge payloads, and plo9 lacks a spot index entirely — a genuine capability limitation not visible in the schema.

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 is front-loaded and every sentence carries information; nothing is redundant with the schema. It is slightly clipped in places (the trailing plo9 sentence lacks a period), but the terse style suits an agent-facing definition.

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 no explanation, and the game enum is fully documented in the schema. The description covers pagination, depth codes, and the plo9 exception, leaving only minor gaps such as default-vs-full detail behavior, which the schema already states.

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 goes beyond it by decoding the depth values (1 = RFI, 2 = vs open, 3 = 3-bet pots), which the schema only labels as an opaque "decision depth filter," and ties contains/offset to the compact pagination workflow.

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 ("Search valid decision nodes") scoped to a stack depth, and differentiates itself from the sibling get_node by contrast. An agent can tell this is the preflop spot index rather than a postflop node or range tool.

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 concrete usage guidance (use depth, contains, and offset to narrow results without loading thousands of paths) and an explicit when-not case: plo9 has no spot index, so use get_node instead. The alternative and the condition that selects it are both named.

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

upload_hand_historyUpload a hand historyAInspect

Secondary upload path for a small paste. Prefer get_upload_link and the hosted /upload page. Runs the same ingestion pipeline and returns hands parsed, tournaments parsed, and errors. Does not grade solver frequencies.

ParametersJSON Schema
NameRequiredDescriptionDefault
textYesRaw hand history or tournament summary text.
filenameNoName to record for the paste. Defaults to "paste.txt".

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorsNoParse errors, if any.
filenameNoFilename recorded for the paste.
persistedNoAlways false: nothing is written to durable storage.
sessionIdNoSession id for the stored hands, or null when nothing parsed.
handsParsedNoHands parsed.
persistenceNoWhere the hands live, "process_memory".
tournamentsParsedNoTournament summaries parsed.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare the mutation profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false), so the bar is lower. The description adds real context beyond them: it shares the same ingestion pipeline as the hosted path and reports hands parsed, tournaments parsed, and errors. It omits that repeated uploads are non-idempotent, which is the one meaningful behavioral 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?

Four short sentences with no filler, and the identity plus the routing advice are front-loaded. The trailing scope exclusion earns its place, though the returns sentence partly duplicates the output schema.

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?

An output schema exists, so return values need not be explained, and the description still covers purpose, routing, and scope limits. The remaining gap is the non-idempotent nature of re-uploading the same paste, which the description never warns about.

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%, so both parameters (text, filename) are already fully documented. The description only implies a size expectation via 'small paste' and adds no format or content detail beyond the schema, so the baseline 3 is correct.

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 (upload a hand history paste) and immediately positions itself as a secondary path versus the primary sibling get_upload_link. An agent can tell it apart from the other upload 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.

Usage Guidelines5/5

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

Explicitly names the preferred alternative (get_upload_link and the hosted /upload page) and the condition that selects this tool instead (a small paste). It also states a scope exclusion — it does not grade solver frequencies — 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.

Tool Schema Changelog

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

  1. 29 tool updates
    • Changedcompare_strategies15 fields changed
      • addedInput schema / properties / baseline / description
        Added value: +"The context deltas are measured from. One side of the comparison. Preflop contexts use game, stack, history and optional hand; postflop contexts use pack, board, path and optional combo."
      • addedInput schema / properties / baseline / properties / board / description
        Added value: +"Postflop only. Board in spaced form, e.g. \"3h 3d 2s\"."
      • addedInput schema / properties / baseline / properties / combo / description
        Added value: +"Postflop only. Exact two-card combo, e.g. As5s. Provide it in both contexts or neither."
      • addedInput schema / properties / baseline / properties / game / description
        Added value: +"Preflop only. Both sides must name the same game."
      • addedInput schema / properties / baseline / properties / hand / description
        Added value: +"Preflop only. One hand or class, e.g. AKs. Provide it in both contexts or neither; PLO comparisons require it."
      • addedInput schema / properties / baseline / properties / history / description
        Added value: +"Preflop only. Action path ending in the position about to act, e.g. \"UTG_60%_HJ\"."
      • addedInput schema / properties / baseline / properties / stack / description
        Added value: +"Preflop only. Stack depth in big blinds."
      • addedInput schema / properties / comparison / description
        Added value: +"The context deltas are measured to. One side of the comparison. Preflop contexts use game, stack, history and optional hand; postflop contexts use pack, board, path and optional combo."
      • addedInput schema / properties / comparison / properties / board / description
        Added value: +"Postflop only. Board in spaced form, e.g. \"3h 3d 2s\"."
      • addedInput schema / properties / comparison / properties / combo / description
        Added value: +"Postflop only. Exact two-card combo, e.g. As5s. Provide it in both contexts or neither."
      • addedInput schema / properties / comparison / properties / game / description
        Added value: +"Preflop only. Both sides must name the same game."
      • addedInput schema / properties / comparison / properties / hand / description
        Added value: +"Preflop only. One hand or class, e.g. AKs. Provide it in both contexts or neither; PLO comparisons require it."
      • addedInput schema / properties / comparison / properties / history / description
        Added value: +"Preflop only. Action path ending in the position about to act, e.g. \"UTG_60%_HJ\"."
      • addedInput schema / properties / comparison / properties / stack / description
        Added value: +"Preflop only. Stack depth in big blinds."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Coverage-first envelope: coverage and context describe the answer, result carries it.",
        +  "properties": {
        +    "context": {
        +      "description": "Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "coverage": {
        +      "description": "Whether the request was answered exactly, aggregated, or refused as out of coverage.",
        +      "properties": {
        +        "analyzedBoards": {
        +          "description": "Boards actually read at the requested path.",
        +          "type": "integer"
        +        },
        +        "available": {
        +          "description": "What is published instead.",
        +          "type": "string"
        +        },
        +        "dataClass": {
        +          "description": "\"solver\", \"solver_aggregate\", or \"solver_comparison\".",
        +          "type": "string"
        +        },
        +        "generatedAt": {
        +          "description": "When the pack was generated.",
        +          "type": "string"
        +        },
        +        "hasEv": {
        +          "description": "Whether the pack ships per-combo EV.",
        +          "type": "boolean"
        +        },
        +        "matchingBoards": {
        +          "description": "Boards matching the texture filters.",
        +          "type": "integer"
        +        },
        +        "objective": {
        +          "description": "\"solver_ev\", \"cash_game_ev\", or \"chip_ev\".",
        +          "type": "string"
        +        },
        +        "omittedByLimit": {
        +          "description": "Matching boards dropped by boardLimit.",
        +          "type": "integer"
        +        },
        +        "reason": {
        +          "description": "Why the request is out of coverage.",
        +          "type": "string"
        +        },
        +        "requested": {
        +          "description": "The format, objective, ante, or pack that was asked for.",
        +          "type": "object"
        +        },
        +        "solveQuality": {
        +          "description": "Published exploitability and iteration counts. Omitted, never estimated, when the pack does not publish them.",
        +          "type": "object"
        +        },
        +        "source": {
        +          "description": "Pack, board, path, generation time, and solve quality.",
        +          "type": "object"
        +        },
        +        "status": {
        +          "description": "\"exact\", \"aggregated_report\", or \"unsupported\". Treat \"unsupported\" as a hard stop.",
        +          "type": "string"
        +        },
        +        "unavailableAtPath": {
        +          "description": "Selected boards with no node at the path.",
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "result": {
        +      "description": "Both snapshots, the per-action frequency and EV deltas, and the largest combo changes for postflop comparisons. Null when the request is unsupported.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "schemaVersion": {
        +      "description": "Envelope version, currently \"1.0\".",
        +      "type": "string"
        +    },
        +    "warnings": {
        +      "description": "Caveats that must survive into any answer built on this result.",
        +      "items": {
        +        "description": "One caveat about how the result may be used.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedenqueue_solve12 fields changed
      • addedInput schema / properties / add_allin / description
        Added value: +"Add an all-in branch alongside the bet sizes."
      • addedInput schema / properties / bet_sizes / description
        Added value: +"Bet sizes as fractions of the pot, e.g. [0.33, 0.75]."
      • addedInput schema / properties / board / description
        Added value: +"Board to solve, e.g. \"3h 3d 2s\"."
      • addedInput schema / properties / effective_stack / description
        Added value: +"Effective stack behind, in big blinds."
      • addedInput schema / properties / ip_range / description
        Added value: +"In-position range in the same weights format."
      • addedInput schema / properties / iterations / description
        Added value: +"Requested solver iterations, 50 to 5000."
      • addedInput schema / properties / max_aggressions / description
        Added value: +"Raises allowed per street, 1 to 4."
      • addedInput schema / properties / oop_range / description
        Added value: +"Out-of-position range as hand-class weights, e.g. \"AA:1,AKs:0.42\". Defaults are left to the solver config."
      • addedInput schema / properties / pot / description
        Added value: +"Starting pot in big blinds."
      • addedInput schema / properties / tags / description
        Added value: +"Free-form tags stored with the job."
      • addedInput schema / properties / title / description
        Added value: +"Label for the job, 1 to 120 characters."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "One recorded solve request. Dispatch is not configured, so a job stays pending and never gets a solution id.",
        +  "properties": {
        +    "board": {
        +      "description": "Board for the requested solve.",
        +      "type": "string"
        +    },
        +    "createdAt": {
        +      "description": "ISO timestamp the job was recorded.",
        +      "type": "string"
        +    },
        +    "dispatch": {
        +      "description": "Always \"not_configured\".",
        +      "type": "string"
        +    },
        +    "effective_stack": {
        +      "description": "Effective stack in big blinds.",
        +      "type": "number"
        +    },
        +    "pot": {
        +      "description": "Pot in big blinds.",
        +      "type": "number"
        +    },
        +    "queue_id": {
        +      "description": "Id for get_queued_solve.",
        +      "type": "integer"
        +    },
        +    "reason": {
        +      "description": "Why the job does not start a solve.",
        +      "type": "string"
        +    },
        +    "solution_id": {
        +      "description": "Always null while dispatch is disabled.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "description": "\"pending\", \"running\", \"done\", or \"failed\".",
        +      "type": "string"
        +    },
        +    "title": {
        +      "description": "Title given when the job was recorded.",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedexplain_combo1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Coverage-first envelope: coverage and context describe the answer, result carries it.",
        +  "properties": {
        +    "context": {
        +      "description": "Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "coverage": {
        +      "description": "Whether the request was answered exactly, aggregated, or refused as out of coverage.",
        +      "properties": {
        +        "analyzedBoards": {
        +          "description": "Boards actually read at the requested path.",
        +          "type": "integer"
        +        },
        +        "available": {
        +          "description": "What is published instead.",
        +          "type": "string"
        +        },
        +        "dataClass": {
        +          "description": "\"solver\", \"solver_aggregate\", or \"solver_comparison\".",
        +          "type": "string"
        +        },
        +        "generatedAt": {
        +          "description": "When the pack was generated.",
        +          "type": "string"
        +        },
        +        "hasEv": {
        +          "description": "Whether the pack ships per-combo EV.",
        +          "type": "boolean"
        +        },
        +        "matchingBoards": {
        +          "description": "Boards matching the texture filters.",
        +          "type": "integer"
        +        },
        +        "objective": {
        +          "description": "\"solver_ev\", \"cash_game_ev\", or \"chip_ev\".",
        +          "type": "string"
        +        },
        +        "omittedByLimit": {
        +          "description": "Matching boards dropped by boardLimit.",
        +          "type": "integer"
        +        },
        +        "reason": {
        +          "description": "Why the request is out of coverage.",
        +          "type": "string"
        +        },
        +        "requested": {
        +          "description": "The format, objective, ante, or pack that was asked for.",
        +          "type": "object"
        +        },
        +        "solveQuality": {
        +          "description": "Published exploitability and iteration counts. Omitted, never estimated, when the pack does not publish them.",
        +          "type": "object"
        +        },
        +        "source": {
        +          "description": "Pack, board, path, generation time, and solve quality.",
        +          "type": "object"
        +        },
        +        "status": {
        +          "description": "\"exact\", \"aggregated_report\", or \"unsupported\". Treat \"unsupported\" as a hard stop.",
        +          "type": "string"
        +        },
        +        "unavailableAtPath": {
        +          "description": "Selected boards with no node at the path.",
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "result": {
        +      "description": "Recommendation, made-hand and draw classification, blockers, the exact action mix with EV, and same-rank-class suit comparisons. Null when the request is unsupported.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "schemaVersion": {
        +      "description": "Envelope version, currently \"1.0\".",
        +      "type": "string"
        +    },
        +    "warnings": {
        +      "description": "Caveats that must survive into any answer built on this result.",
        +      "items": {
        +        "description": "One caveat about how the result may be used.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedfind_hands10 fields changed
      • changedInput schema / properties / filter / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "facedLimp": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "facedThreeBet": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "flopBetPctPot": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "max": {
        -                "anyOf": [
        -                  {
        -                    "description": "Exclusive upper bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "min": {
        -                "anyOf": [
        -                  {
        -                    "description": "Inclusive lower bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "flopFacedBetPctPot": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "max": {
        -                "anyOf": [
        -                  {
        -                    "description": "Exclusive upper bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "min": {
        -                "anyOf": [
        -                  {
        -                    "description": "Inclusive lower bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "flopFirstAction": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "check",
        -                "bet",
        -                "call",
        -                "fold",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "flopFirstResponseToBet": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "check",
        -                "bet",
        -                "call",
        -                "fold",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "foldedToThreeBet": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "isIpVsPfr": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "isPfr": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "limped": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "pfr": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "position": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "UTG",
        -                "UTG1",
        -                "UTG2",
        -                "MP",
        -                "LJ",
        -                "HJ",
        -                "CO",
        -                "BTN",
        -                "SB",
        -                "BB"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "rfi": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "rfiOpp": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "riverBetPctPot": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "max": {
        -                "anyOf": [
        -                  {
        -                    "description": "Exclusive upper bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "min": {
        -                "anyOf": [
        -                  {
        -                    "description": "Inclusive lower bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "riverFacedBetPctPot": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "max": {
        -                "anyOf": [
        -                  {
        -                    "description": "Exclusive upper bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "min": {
        -                "anyOf": [
        -                  {
        -                    "description": "Inclusive lower bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "riverFirstAction": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "check",
        -                "bet",
        -                "call",
        -                "fold",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "riverFirstResponseToBet": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "check",
        -                "bet",
        -                "call",
        -                "fold",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "sawFlop": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "sawShowdown": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "threeBet": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "turnBetPctPot": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "max": {
        -                "anyOf": [
        -                  {
        -                    "description": "Exclusive upper bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "min": {
        -                "anyOf": [
        -                  {
        -                    "description": "Inclusive lower bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "turnFacedBetPctPot": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "max": {
        -                "anyOf": [
        -                  {
        -                    "description": "Exclusive upper bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "min": {
        -                "anyOf": [
        -                  {
        -                    "description": "Inclusive lower bound, % of pot.",
        -                    "minimum": 0,
        -                    "type": "number"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "turnFirstAction": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "check",
        -                "bet",
        -                "call",
        -                "fold",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "turnFirstResponseToBet": {
        -        "anyOf": [
        -          {
        -            "items": {
        -              "enum": [
        -                "check",
        -                "bet",
        -                "call",
        -                "fold",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "vpip": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "vsThreeBetAction": {
        -        "anyOf": [
        -          {
        -            "description": "Opener's action vs a 3-bet: fold, call, or raise (4-bet).",
        -            "items": {
        -              "enum": [
        -                "fold",
        -                "call",
        -                "raise"
        -              ],
        -              "type": "string"
        -            },
        -            "type": "array"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "wasSrp": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "wasThreeBetPot": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "wonAtShowdown": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "description": "Hand-level filters. Every field is optional; null means the filter is not applied.",
        +    "properties": {
        +      "facedLimp": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero acted after an opponent's open limp."
        +      },
        +      "facedThreeBet": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's open was 3-bet."
        +      },
        +      "flopBetPctPot": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "max": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Exclusive upper bound, % of pot."
        +              },
        +              "min": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Inclusive lower bound, % of pot."
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Size of hero's flop bet, as % of pot."
        +      },
        +      "flopFacedBetPctPot": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "max": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Exclusive upper bound, % of pot."
        +              },
        +              "min": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Inclusive lower bound, % of pot."
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Size of the flop bet hero faced, as % of pot."
        +      },
        +      "flopFirstAction": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "check",
        +                "bet",
        +                "call",
        +                "fold",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's first action on the flop."
        +      },
        +      "flopFirstResponseToBet": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "check",
        +                "bet",
        +                "call",
        +                "fold",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's first action facing a flop bet."
        +      },
        +      "foldedToThreeBet": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero folded to a 3-bet."
        +      },
        +      "isIpVsPfr": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero was in position against the preflop raiser."
        +      },
        +      "isPfr": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero was the preflop raiser."
        +      },
        +      "limped": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero open-limped."
        +      },
        +      "pfr": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero raised preflop."
        +      },
        +      "position": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "UTG",
        +                "UTG1",
        +                "UTG2",
        +                "MP",
        +                "LJ",
        +                "HJ",
        +                "CO",
        +                "BTN",
        +                "SB",
        +                "BB"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Keep hands where hero sat in one of these seats."
        +      },
        +      "rfi": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero raised first in."
        +      },
        +      "rfiOpp": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero had a raise-first-in opportunity (folded to hero)."
        +      },
        +      "riverBetPctPot": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "max": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Exclusive upper bound, % of pot."
        +              },
        +              "min": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Inclusive lower bound, % of pot."
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Size of hero's river bet, as % of pot."
        +      },
        +      "riverFacedBetPctPot": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "max": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Exclusive upper bound, % of pot."
        +              },
        +              "min": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Inclusive lower bound, % of pot."
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Size of the river bet hero faced, as % of pot."
        +      },
        +      "riverFirstAction": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "check",
        +                "bet",
        +                "call",
        +                "fold",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's first action on the river."
        +      },
        +      "riverFirstResponseToBet": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "check",
        +                "bet",
        +                "call",
        +                "fold",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's first action facing a river bet."
        +      },
        +      "sawFlop": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero saw a flop."
        +      },
        +      "sawShowdown": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hand reached showdown."
        +      },
        +      "threeBet": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero 3-bet."
        +      },
        +      "turnBetPctPot": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "max": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Exclusive upper bound, % of pot."
        +              },
        +              "min": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Inclusive lower bound, % of pot."
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Size of hero's turn bet, as % of pot."
        +      },
        +      "turnFacedBetPctPot": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "max": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Exclusive upper bound, % of pot."
        +              },
        +              "min": {
        +                "anyOf": [
        +                  {
        +                    "minimum": 0,
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ],
        +                "description": "Inclusive lower bound, % of pot."
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Size of the turn bet hero faced, as % of pot."
        +      },
        +      "turnFirstAction": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "check",
        +                "bet",
        +                "call",
        +                "fold",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's first action on the turn."
        +      },
        +      "turnFirstResponseToBet": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "check",
        +                "bet",
        +                "call",
        +                "fold",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero's first action facing a turn bet."
        +      },
        +      "vpip": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero put money in voluntarily."
        +      },
        +      "vsThreeBetAction": {
        +        "anyOf": [
        +          {
        +            "items": {
        +              "enum": [
        +                "fold",
        +                "call",
        +                "raise"
        +              ],
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Opener's action vs a 3-bet: fold, call, or raise (4-bet)."
        +      },
        +      "wasSrp": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hand was a single-raised pot."
        +      },
        +      "wasThreeBetPot": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hand was a 3-bet pot."
        +      },
        +      "wonAtShowdown": {
        +        "anyOf": [
        +          {
        +            "type": "boolean"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Hero won at showdown."
        +      }
        +    },
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • addedInput schema / properties / filter / description
        Added value: +"Hand-level filters, all optional."
      • addedInput schema / properties / game_type / description
        Added value: +"Only hands of this game type. Matches hole-card count."
      • addedInput schema / properties / gto_plo5_rfi_bucket / description
        Added value: +"Solver grade bucket for PLO5 raise-first-in. Grades are not computed, so any value matches nothing."
      • addedInput schema / properties / gto_vs_3bet_bucket / description
        Added value: +"Solver grade bucket for hero's action vs a 3-bet. Grades are not computed, so any value matches nothing rather than inventing a frequency."
      • addedInput schema / properties / limit / description
        Added value: +"Hands to return, 1 to 50."
      • addedInput schema / properties / session_id / description
        Added value: +"Only hands from this upload session (see list_my_sessions)."
      • addedInput schema / properties / sort / description
        Added value: +"Row order: newest first, largest win first, or largest loss first (the default)."
      • addedInput schema / properties / table_size / description
        Added value: +"Only hands dealt at tables of this many seats."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Hands this account has uploaded.",
        +  "properties": {
        +    "gto": {
        +      "description": "Always \"not graded\": solver grades are not attached.",
        +      "type": "string"
        +    },
        +    "gtoNote": {
        +      "description": "Why a solver-grade filter matches nothing.",
        +      "type": "string"
        +    },
        +    "hands": {
        +      "description": "Matching hands, sorted as requested.",
        +      "items": {
        +        "description": "One uploaded hand.",
        +        "properties": {
        +          "board": {
        +            "description": "Board as dealt.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "cards": {
        +            "description": "Hero's hole cards.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "flop": {
        +            "description": "Flop action lines.",
        +            "items": {
        +              "description": "One flop action line.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "game": {
        +            "description": "Game type: \"NLHE\", \"PLO\", \"PLO5\", or \"PLO6\".",
        +            "type": "string"
        +          },
        +          "gto_plo5_rfi_bucket": {
        +            "description": "Solver grade bucket. Not filled: grades are not computed.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "gto_status": {
        +            "description": "Always \"not_graded\": no solver frequency is attached to uploaded hands.",
        +            "type": "string"
        +          },
        +          "gto_vs_3bet_bucket": {
        +            "description": "Solver grade bucket. Not filled: grades are not computed.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "handAt": {
        +            "description": "Hand timestamp as written in the history.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "hand_id": {
        +            "description": "Stable id for this hand.",
        +            "type": "string"
        +          },
        +          "netBb": {
        +            "description": "Hero's result in big blinds.",
        +            "type": "number"
        +          },
        +          "position": {
        +            "description": "Hero's seat, e.g. BTN.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "potType": {
        +            "description": "Preflop pot type, e.g. \"srp\" or \"3bet\".",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "preflop": {
        +            "description": "Preflop action lines.",
        +            "items": {
        +              "description": "One preflop action line.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "river": {
        +            "description": "River action lines.",
        +            "items": {
        +              "description": "One river action line.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "session_id": {
        +            "description": "Upload session the hand came from.",
        +            "type": "string"
        +          },
        +          "source_hand_id": {
        +            "description": "Hand id printed by the original site.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "table_size": {
        +            "description": "Seats at the table.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "timezone": {
        +            "description": "Timezone label from the history.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "turn": {
        +            "description": "Turn action lines.",
        +            "items": {
        +              "description": "One turn action line.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "vsThreeBetAction": {
        +            "description": "Hero's action facing a 3-bet: \"fold\", \"call\", or \"raise\".",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "hint": {
        +      "description": "Where to upload hands when the account has none.",
        +      "type": "string"
        +    },
        +    "returned": {
        +      "description": "Hands in this response.",
        +      "type": "integer"
        +    },
        +    "total": {
        +      "description": "Matching hands before the limit.",
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_board_report7 fields changed
      • addedInput schema / properties / filters / description
        Added value: +"Texture filters applied to the pack's solved boards. All optional; omit for every board."
      • addedInput schema / properties / filters / properties / connectivity / description
        Added value: +"How many board cards sit inside one five-rank straight window."
      • addedInput schema / properties / filters / properties / highCard / description
        Added value: +"Exact highest board rank."
      • addedInput schema / properties / filters / properties / highCardClass / description
        Added value: +"Highest board rank bucketed: ace, ten through king, seven through nine, or lower."
      • addedInput schema / properties / filters / properties / pairedness / description
        Added value: +"Rank repetition on the board."
      • addedInput schema / properties / filters / properties / suitTexture / description
        Added value: +"Most cards of one suit on the board. A three-card monotone flop is monotone."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Coverage-first envelope: coverage and context describe the answer, result carries it.",
        +  "properties": {
        +    "context": {
        +      "description": "Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "coverage": {
        +      "description": "Whether the request was answered exactly, aggregated, or refused as out of coverage.",
        +      "properties": {
        +        "analyzedBoards": {
        +          "description": "Boards actually read at the requested path.",
        +          "type": "integer"
        +        },
        +        "available": {
        +          "description": "What is published instead.",
        +          "type": "string"
        +        },
        +        "dataClass": {
        +          "description": "\"solver\", \"solver_aggregate\", or \"solver_comparison\".",
        +          "type": "string"
        +        },
        +        "generatedAt": {
        +          "description": "When the pack was generated.",
        +          "type": "string"
        +        },
        +        "hasEv": {
        +          "description": "Whether the pack ships per-combo EV.",
        +          "type": "boolean"
        +        },
        +        "matchingBoards": {
        +          "description": "Boards matching the texture filters.",
        +          "type": "integer"
        +        },
        +        "objective": {
        +          "description": "\"solver_ev\", \"cash_game_ev\", or \"chip_ev\".",
        +          "type": "string"
        +        },
        +        "omittedByLimit": {
        +          "description": "Matching boards dropped by boardLimit.",
        +          "type": "integer"
        +        },
        +        "reason": {
        +          "description": "Why the request is out of coverage.",
        +          "type": "string"
        +        },
        +        "requested": {
        +          "description": "The format, objective, ante, or pack that was asked for.",
        +          "type": "object"
        +        },
        +        "solveQuality": {
        +          "description": "Published exploitability and iteration counts. Omitted, never estimated, when the pack does not publish them.",
        +          "type": "object"
        +        },
        +        "source": {
        +          "description": "Pack, board, path, generation time, and solve quality.",
        +          "type": "object"
        +        },
        +        "status": {
        +          "description": "\"exact\", \"aggregated_report\", or \"unsupported\". Treat \"unsupported\" as a hard stop.",
        +          "type": "string"
        +        },
        +        "unavailableAtPath": {
        +          "description": "Selected boards with no node at the path.",
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "result": {
        +      "description": "Action frequencies and range composition aggregated across solved boards, with equal weight per board, plus representative boards. Null when the request is unsupported.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "schemaVersion": {
        +      "description": "Envelope version, currently \"1.0\".",
        +      "type": "string"
        +    },
        +    "warnings": {
        +      "description": "Caveats that must survive into any answer built on this result.",
        +      "items": {
        +        "description": "One caveat about how the result may be used.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_config1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Table setup for one preflop game and stack, in big blinds. Convergence is not published.",
        +  "properties": {
        +    "ante": {
        +      "description": "Ante in big blinds.",
        +      "type": "number"
        +    },
        +    "antePostedBy": {
        +      "description": "Seat that posts the ante.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "blinds": {
        +      "description": "Blinds in big blinds.",
        +      "properties": {
        +        "bb": {
        +          "description": "Big blind, 1.",
        +          "type": "number"
        +        },
        +        "sb": {
        +          "description": "Small blind, 0.5.",
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "evBaseline": {
        +      "description": "What EV is measured against, \"fold\".",
        +      "type": "string"
        +    },
        +    "evUnit": {
        +      "description": "EV unit, \"sb\".",
        +      "type": "string"
        +    },
        +    "game": {
        +      "description": "Game id.",
        +      "type": "string"
        +    },
        +    "openSizes": {
        +      "description": "First-in raise-to sizes, by seat, with label and sizeBb.",
        +      "type": "object"
        +    },
        +    "schemaVersion": {
        +      "description": "Payload version, 1.",
        +      "type": "number"
        +    },
        +    "seats": {
        +      "description": "Seats in action order.",
        +      "items": {
        +        "description": "Seat label.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "stack": {
        +      "description": "Stack depth in big blinds.",
        +      "type": "number"
        +    },
        +    "stackIncludesAnte": {
        +      "description": "True when the named depth already contains the ante.",
        +      "type": "boolean"
        +    },
        +    "stacks": {
        +      "description": "Starting stacks per seat. Null where the depth is solved against a different stack (10bb all-in/fold versus 50bb).",
        +      "items": {
        +        "description": "Starting stack in big blinds.",
        +        "type": "number"
        +      },
        +      "type": [
        +        "array",
        +        "null"
        +      ]
        +    },
        +    "units": {
        +      "description": "Unit labels for stack, stacks, blinds, ante, openSizes, and evs.",
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_exploitability2 fields changed
      • addedInput schema / properties / game / description
        Added value: +"Preflop game id to report on, e.g. \"nl\" or \"nlmtt8\". Any known game answers \"not available\"."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Preflop exploitability for one game. No preflop dataset publishes one, so the answer is always unavailable and never a number.",
        +  "properties": {
        +    "available": {
        +      "description": "Always false.",
        +      "type": "boolean"
        +    },
        +    "convergence": {
        +      "description": "Always null.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "dataset": {
        +      "description": "Dataset the game maps to, or null when unknown.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "exploitability": {
        +      "description": "Always null: no figure is published or estimated.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "game": {
        +      "description": "Game id, echoed.",
        +      "type": "string"
        +    },
        +    "iterations": {
        +      "description": "Always null.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "reason": {
        +      "description": "Why no number is returned.",
        +      "type": "string"
        +    },
        +    "status": {
        +      "description": "Always \"not available\".",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_hand_results3 fields changed
      • addedInput schema / properties / max_points / description
        Added value: +"Points on the curve after downsampling, 2 to 200."
      • addedInput schema / properties / session_id / description
        Added value: +"Only this upload session's hands. Omit for the whole account."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Cumulative result per hand, for a winnings curve.",
        +  "properties": {
        +    "hint": {
        +      "description": "Where to upload hands when the account has none.",
        +      "type": "string"
        +    },
        +    "netBb": {
        +      "description": "Final cumulative result in big blinds.",
        +      "type": "number"
        +    },
        +    "points": {
        +      "description": "Downsampled curve, oldest to newest.",
        +      "items": {
        +        "description": "One point on the curve.",
        +        "properties": {
        +          "bb": {
        +            "description": "Cumulative result in big blinds.",
        +            "type": "number"
        +          },
        +          "hand": {
        +            "description": "Hand number, oldest first.",
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "totalHands": {
        +      "description": "Hands behind the curve.",
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_node1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Every action at one preflop decision node.",
        +  "properties": {
        +    "actions": {
        +      "description": "Actions at the node.",
        +      "items": {
        +        "description": "One action available at a preflop node.",
        +        "properties": {
        +          "action": {
        +            "description": "Action token, e.g. \"Fold\", \"Open\", \"3B\".",
        +            "type": "string"
        +          },
        +          "combos": {
        +            "description": "Combos that take this action.",
        +            "type": "number"
        +          },
        +          "evSb": {
        +            "description": "EV in small blinds for the requested hand, if scored.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "evs": {
        +            "additionalProperties": {
        +              "description": "EV in small blinds relative to folding.",
        +              "type": "number"
        +            },
        +            "description": "Hand class to EV, only where the solved bundle scored the hand.",
        +            "type": "object"
        +          },
        +          "frequency": {
        +            "description": "Frequency for the requested hand, or the action total.",
        +            "type": "number"
        +          },
        +          "kind": {
        +            "description": "Action family, e.g. \"fold\", \"call\", \"raise\".",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "sizeBb": {
        +            "description": "Raise-to size in big blinds, for raising actions.",
        +            "type": "number"
        +          },
        +          "sizePctPot": {
        +            "description": "Raise size as a percent of the pot after calling.",
        +            "type": "number"
        +          },
        +          "weights": {
        +            "additionalProperties": {
        +              "description": "Action frequency from 0 to 1.",
        +              "type": "number"
        +            },
        +            "description": "Hand class to frequency. An omitted class has weight 0.",
        +            "type": "object"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "actor": {
        +      "description": "Position to act at this node.",
        +      "type": "string"
        +    },
        +    "continuingCombos": {
        +      "description": "Combos that continue past this node.",
        +      "type": "number"
        +    },
        +    "continuingHands": {
        +      "description": "Hand classes that continue past this node.",
        +      "type": "number"
        +    },
        +    "evBaseline": {
        +      "description": "What EV is measured against, \"fold\".",
        +      "type": "string"
        +    },
        +    "evUnit": {
        +      "description": "EV unit, \"sb\".",
        +      "type": "string"
        +    },
        +    "game": {
        +      "description": "Preflop game id, e.g. \"nl\" or \"nlmtt8\".",
        +      "type": "string"
        +    },
        +    "hand": {
        +      "description": "The requested hand, when one was asked for.",
        +      "type": "string"
        +    },
        +    "hint": {
        +      "description": "How to narrow, page, or widen the same query.",
        +      "type": "string"
        +    },
        +    "history": {
        +      "description": "Action path ending in the acting position.",
        +      "type": "string"
        +    },
        +    "schemaVersion": {
        +      "description": "Payload version, 1.",
        +      "type": "number"
        +    },
        +    "spot": {
        +      "description": "Action path ending in an action, echoed from the request.",
        +      "type": "string"
        +    },
        +    "stack": {
        +      "description": "Stack depth in big blinds.",
        +      "type": "number"
        +    },
        +    "units": {
        +      "description": "Unit labels: stack and sizeBb in bb, evs in sb.",
        +      "type": "object"
        +    },
        +    "version": {
        +      "description": "Dataset version where the bundle publishes one.",
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_opponent_limp_range7 fields changed
      • addedInput schema / properties / game_type / description
        Added value: +"Only hands of this game type."
      • addedInput schema / properties / limit / description
        Added value: +"Hole-card classes to return, most frequent first, 1 to 169."
      • addedInput schema / properties / opponent_id / description
        Added value: +"Only this opponent's limps (see list_my_opponents). Omit for every tracked villain."
      • addedInput schema / properties / position / description
        Added value: +"Only limps from these seats."
      • addedInput schema / properties / session_id / description
        Added value: +"Only hands from this upload session."
      • addedInput schema / properties / table_size / description
        Added value: +"Only hands dealt at tables of this many seats."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Shown-hand first-in limp range from uploaded hands. Observed counts, not a solver range.",
        +  "properties": {
        +    "classes": {
        +      "description": "Observed classes, most frequent first. Counts, not solver frequencies.",
        +      "items": {
        +        "description": "One observed hole-card class.",
        +        "properties": {
        +          "count": {
        +            "description": "Times the class was shown.",
        +            "type": "integer"
        +          },
        +          "hand": {
        +            "description": "169-grid class, e.g. AKs.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "classesByPosition": {
        +      "additionalProperties": {
        +        "description": "Observed classes, most frequent first. Counts, not solver frequencies.",
        +        "items": {
        +          "description": "One observed hole-card class.",
        +          "properties": {
        +            "count": {
        +              "description": "Times the class was shown.",
        +              "type": "integer"
        +            },
        +            "hand": {
        +              "description": "169-grid class, e.g. AKs.",
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "description": "Seat label to that seat's observed classes.",
        +      "type": "object"
        +    },
        +    "note": {
        +      "description": "That the sample is showdown-only and the counts are observations.",
        +      "type": "string"
        +    },
        +    "sample": {
        +      "description": "Shown limped hands behind the counts.",
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_opponent_notes2 fields changed
      • addedInput schema / properties / opponent_id / description
        Added value: +"Opponent id from list_my_opponents."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Leak notes computed from uploaded hands for one opponent.",
        +  "properties": {
        +    "display_name": {
        +      "description": "Screen name as written in the history.",
        +      "type": "string"
        +    },
        +    "error": {
        +      "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.",
        +      "type": "string"
        +    },
        +    "notes": {
        +      "description": "Notes, or a single line saying the sample is too small.",
        +      "items": {
        +        "description": "One note, with the sample size it rests on.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "opponent_id": {
        +      "description": "Opponent id, echoed.",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_postflop_node1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "One postflop solver node: the acting player's strategy and the legal next segments.",
        +  "properties": {
        +    "actingPlayer": {
        +      "description": "0 for out of position, 1 for in position.",
        +      "type": [
        +        "integer",
        +        "null"
        +      ]
        +    },
        +    "actionFreqs": {
        +      "description": "Full detail: aggregate frequency per action.",
        +      "items": {
        +        "description": "Reach-weighted frequency for the action at this index.",
        +        "type": "number"
        +      },
        +      "type": "array"
        +    },
        +    "actions": {
        +      "description": "Actions at the node with their reach-weighted frequency.",
        +      "items": {
        +        "description": "One action available at a postflop node.",
        +        "properties": {
        +          "action": {
        +            "description": "Action segment including its size, e.g. \"Bet 5.5\".",
        +            "type": "string"
        +          },
        +          "actionType": {
        +            "description": "Action label without the size.",
        +            "type": "string"
        +          },
        +          "addBb": {
        +            "description": "Chips this action adds, in big blinds.",
        +            "type": "number"
        +          },
        +          "comparisonKey": {
        +            "description": "Size-normalised action key used to line two nodes up, e.g. \"Bet 75% pot\".",
        +            "type": "string"
        +          },
        +          "evBb": {
        +            "description": "Action EV in big blinds where the pack publishes it.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "evLossBb": {
        +            "description": "EV given up against the best action, in big blinds.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "frequency": {
        +            "description": "Reach-weighted frequency from 0 to 1.",
        +            "type": "number"
        +          },
        +          "label": {
        +            "description": "Action label, e.g. \"Check\", \"Bet\", \"Call\".",
        +            "type": "string"
        +          },
        +          "sizePotPct": {
        +            "description": "Bet size as a percent of the pot, bets only.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "board": {
        +      "anyOf": [
        +        {
        +          "description": "Board in spaced form.",
        +          "type": "string"
        +        },
        +        {
        +          "description": "Cards visible at this node.",
        +          "items": {
        +            "description": "One card.",
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      ],
        +      "description": "Board at this node."
        +    },
        +    "childSegments": {
        +      "description": "Append one of these to `path` to walk deeper.",
        +      "items": {
        +        "description": "An action like \"Bet 5.5\" or a runout like \"deal:7c\".",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "columns": {
        +      "description": "Column order for `hands`: combo, reach, frequencies, evBb, evLossBb, actionEvBb.",
        +      "items": {
        +        "description": "Column name.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "combo": {
        +      "description": "The requested combo, when one was asked for.",
        +      "type": "string"
        +    },
        +    "hands": {
        +      "description": "Compact rows in `columns` order, or the full per-combo strategy objects in full detail.",
        +      "items": {
        +        "anyOf": [
        +          {
        +            "description": "One compact row.",
        +            "type": "array"
        +          },
        +          {
        +            "description": "One combo's stored strategy.",
        +            "type": "object"
        +          }
        +        ]
        +      },
        +      "type": "array"
        +    },
        +    "hint": {
        +      "description": "How to narrow, page, or widen the same query.",
        +      "type": "string"
        +    },
        +    "node": {
        +      "description": "Full detail: the stored node. Null at a chance point, where runouts hang directly under the path.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "path": {
        +      "description": "Segments walked from the root to this node.",
        +      "items": {
        +        "description": "One segment from the root.",
        +        "type": "string"
        +      },
        +      "type": [
        +        "array",
        +        "null"
        +      ]
        +    },
        +    "potBb": {
        +      "description": "Pot at this node in big blinds.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "reach": {
        +      "description": "Full detail: the acting player's per-combo reach.",
        +      "items": {
        +        "description": "A combo and its reach weight.",
        +        "type": "array"
        +      },
        +      "type": "array"
        +    },
        +    "summary": {
        +      "description": "What the compact range left out, so nothing looks complete when it is sampled.",
        +      "properties": {
        +        "classes": {
        +          "description": "Postflop: hand classes with reach at the node.",
        +          "type": "integer"
        +        },
        +        "matchingHands": {
        +          "description": "plo5: classes that take the action before the cut.",
        +          "type": "integer"
        +        },
        +        "minFreq": {
        +          "description": "plo5: the frequency floor applied.",
        +          "type": "number"
        +        },
        +        "mixedHands": {
        +          "description": "Classes strictly between 0.005 and 0.995.",
        +          "type": "integer"
        +        },
        +        "mixedInReturned": {
        +          "description": "plo5: mixed classes among the returned rows.",
        +          "type": "integer"
        +        },
        +        "nonzeroHands": {
        +          "description": "Hand classes with a frequency above 0.",
        +          "type": "integer"
        +        },
        +        "omitted": {
        +          "description": "Rows dropped by the compact cut.",
        +          "type": "integer"
        +        },
        +        "pureHands": {
        +          "description": "Classes at frequency 0.995 or higher.",
        +          "type": "integer"
        +        },
        +        "pureInReturned": {
        +          "description": "plo5: pure classes among the returned rows.",
        +          "type": "integer"
        +        },
        +        "returned": {
        +          "description": "Rows in this response.",
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_postflop_range4 fields changed
      • addedInput schema / properties / hand / description
        Added value: +"Optional exact combo (AsKh) or hand class (AKs) for one frequency instead of reading the whole range."
      • addedInput schema / properties / minFreq / description
        Added value: +"Drop classes at or below this weight. Default 0."
      • addedInput schema / properties / tree / description
        Added value: +"Bet-size tree. \"33\" = 33% pot on the flop, then 75% pot on the turn and river, plus all-in. \"75\" = 75% pot on every street, plus all-in. PLO5 packs are solved on \"33\" only."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "The range a player takes one flop action with, as hand-class weights.",
        +  "properties": {
        +    "action": {
        +      "description": "The action whose range this is.",
        +      "type": "string"
        +    },
        +    "board": {
        +      "description": "Canonical board as stored in the pack.",
        +      "type": "string"
        +    },
        +    "error": {
        +      "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.",
        +      "type": "string"
        +    },
        +    "hand": {
        +      "description": "The requested hand, when one was asked for.",
        +      "properties": {
        +        "frequency": {
        +          "description": "Reach-weighted frequency from 0 to 1.",
        +          "type": "number"
        +        },
        +        "hand": {
        +          "description": "Hand or class the frequency belongs to.",
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "pack": {
        +      "description": "Pack id the range was read from, after tree resolution.",
        +      "type": "string"
        +    },
        +    "path": {
        +      "description": "Flop actions, ending in the action asked for.",
        +      "items": {
        +        "description": "One flop action.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "range": {
        +      "description": "Hand-class weights as \"AA:1,AKs:0.42,…\", the preflop range format.",
        +      "type": "string"
        +    },
        +    "summary": {
        +      "description": "What the compact range left out, so nothing looks complete when it is sampled.",
        +      "properties": {
        +        "classes": {
        +          "description": "Postflop: hand classes with reach at the node.",
        +          "type": "integer"
        +        },
        +        "matchingHands": {
        +          "description": "plo5: classes that take the action before the cut.",
        +          "type": "integer"
        +        },
        +        "minFreq": {
        +          "description": "plo5: the frequency floor applied.",
        +          "type": "number"
        +        },
        +        "mixedHands": {
        +          "description": "Classes strictly between 0.005 and 0.995.",
        +          "type": "integer"
        +        },
        +        "mixedInReturned": {
        +          "description": "plo5: mixed classes among the returned rows.",
        +          "type": "integer"
        +        },
        +        "nonzeroHands": {
        +          "description": "Hand classes with a frequency above 0.",
        +          "type": "integer"
        +        },
        +        "omitted": {
        +          "description": "Rows dropped by the compact cut.",
        +          "type": "integer"
        +        },
        +        "pureHands": {
        +          "description": "Classes at frequency 0.995 or higher.",
        +          "type": "integer"
        +        },
        +        "pureInReturned": {
        +          "description": "plo5: pure classes among the returned rows.",
        +          "type": "integer"
        +        },
        +        "returned": {
        +          "description": "Rows in this response.",
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "tree": {
        +      "description": "Bet-size tree, \"33\" or \"75\".",
        +      "type": "string"
        +    },
        +    "weights": {
        +      "additionalProperties": {
        +        "description": "Action frequency from 0 to 1.",
        +        "type": "number"
        +      },
        +      "description": "Hand class to frequency. An omitted class has weight 0.",
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_queued_solve2 fields changed
      • addedInput schema / properties / queue_id / description
        Added value: +"Queue id returned by enqueue_solve."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "One recorded solve request. Dispatch is not configured, so a job stays pending and never gets a solution id.",
        +  "properties": {
        +    "board": {
        +      "description": "Board for the requested solve.",
        +      "type": "string"
        +    },
        +    "createdAt": {
        +      "description": "ISO timestamp the job was recorded.",
        +      "type": "string"
        +    },
        +    "dispatch": {
        +      "description": "Always \"not_configured\".",
        +      "type": "string"
        +    },
        +    "effective_stack": {
        +      "description": "Effective stack in big blinds.",
        +      "type": "number"
        +    },
        +    "pot": {
        +      "description": "Pot in big blinds.",
        +      "type": "number"
        +    },
        +    "queue_id": {
        +      "description": "Id for get_queued_solve.",
        +      "type": "integer"
        +    },
        +    "reason": {
        +      "description": "Why the job does not start a solve.",
        +      "type": "string"
        +    },
        +    "solution_id": {
        +      "description": "Always null while dispatch is disabled.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "description": "\"pending\", \"running\", \"done\", or \"failed\".",
        +      "type": "string"
        +    },
        +    "title": {
        +      "description": "Title given when the job was recorded.",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_range1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "One action's range: hand-class frequencies, and EV where the bundle scored it.",
        +  "properties": {
        +    "action": {
        +      "description": "plo5: the action the range belongs to.",
        +      "type": "string"
        +    },
        +    "actor": {
        +      "description": "Position to act at this node.",
        +      "type": "string"
        +    },
        +    "columns": {
        +      "description": "Column order for `range`: hand, frequency, evSb.",
        +      "items": {
        +        "description": "Column name.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "combos": {
        +      "description": "Combos in the range.",
        +      "type": "number"
        +    },
        +    "ev": {
        +      "description": "Full detail: EV of the requested hand in small blinds.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "evSb": {
        +      "description": "EV of the requested hand in small blinds.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "evs": {
        +      "additionalProperties": {
        +        "description": "EV in small blinds relative to folding.",
        +        "type": "number"
        +      },
        +      "description": "Hand class to EV, only where the solved bundle scored the hand.",
        +      "type": "object"
        +    },
        +    "freq": {
        +      "description": "Full detail: frequency of the requested hand.",
        +      "type": "number"
        +    },
        +    "frequency": {
        +      "description": "Frequency of the requested hand, 0 to 1.",
        +      "type": "number"
        +    },
        +    "game": {
        +      "description": "Preflop game id, e.g. \"nl\" or \"nlmtt8\".",
        +      "type": "string"
        +    },
        +    "hand": {
        +      "description": "The requested hand, when one was asked for.",
        +      "type": "string"
        +    },
        +    "hands": {
        +      "description": "Hand classes in the range.",
        +      "type": "number"
        +    },
        +    "hint": {
        +      "description": "How to narrow, page, or widen the same query.",
        +      "type": "string"
        +    },
        +    "history": {
        +      "description": "Action path ending in the acting position.",
        +      "type": "string"
        +    },
        +    "kind": {
        +      "description": "plo5: the action family.",
        +      "type": "string"
        +    },
        +    "range": {
        +      "description": "Compact rows in `columns` order.",
        +      "items": {
        +        "description": "One row: hand, frequency, EV in small blinds or null.",
        +        "type": "array"
        +      },
        +      "type": "array"
        +    },
        +    "spot": {
        +      "description": "Action path ending in an action, echoed from the request.",
        +      "type": "string"
        +    },
        +    "stack": {
        +      "description": "Stack depth in big blinds.",
        +      "type": "number"
        +    },
        +    "summary": {
        +      "description": "What the compact range left out, so nothing looks complete when it is sampled.",
        +      "properties": {
        +        "classes": {
        +          "description": "Postflop: hand classes with reach at the node.",
        +          "type": "integer"
        +        },
        +        "matchingHands": {
        +          "description": "plo5: classes that take the action before the cut.",
        +          "type": "integer"
        +        },
        +        "minFreq": {
        +          "description": "plo5: the frequency floor applied.",
        +          "type": "number"
        +        },
        +        "mixedHands": {
        +          "description": "Classes strictly between 0.005 and 0.995.",
        +          "type": "integer"
        +        },
        +        "mixedInReturned": {
        +          "description": "plo5: mixed classes among the returned rows.",
        +          "type": "integer"
        +        },
        +        "nonzeroHands": {
        +          "description": "Hand classes with a frequency above 0.",
        +          "type": "integer"
        +        },
        +        "omitted": {
        +          "description": "Rows dropped by the compact cut.",
        +          "type": "integer"
        +        },
        +        "pureHands": {
        +          "description": "Classes at frequency 0.995 or higher.",
        +          "type": "integer"
        +        },
        +        "pureInReturned": {
        +          "description": "plo5: pure classes among the returned rows.",
        +          "type": "integer"
        +        },
        +        "returned": {
        +          "description": "Rows in this response.",
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "version": {
        +      "description": "Dataset version where the bundle publishes one.",
        +      "type": "number"
        +    },
        +    "weights": {
        +      "additionalProperties": {
        +        "description": "Action frequency from 0 to 1.",
        +        "type": "number"
        +      },
        +      "description": "Hand class to frequency. An omitted class has weight 0.",
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_range_metadata3 fields changed
      • addedInput schema / properties / game / description
        Added value: +"Preflop game id, e.g. \"nl\", \"nl9\", \"nlmtt8\", \"nlh8-hydra\", \"plo\", \"plo9\", \"plo5\", \"plo6hu\"."
      • addedInput schema / properties / stack / description
        Added value: +"Stack depth in big blinds, e.g. 100."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Index metadata for one preflop game, stack, and path. Never a strategy, and never an invented exploitability.",
        +  "properties": {
        +    "actor": {
        +      "description": "Acting position read off the path.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "dataset": {
        +      "description": "Dataset the game maps to.",
        +      "type": "string"
        +    },
        +    "error": {
        +      "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.",
        +      "type": "string"
        +    },
        +    "game": {
        +      "description": "Game id, echoed.",
        +      "type": "string"
        +    },
        +    "match": {
        +      "description": "\"bundle\", \"node\", or \"none\".",
        +      "type": "string"
        +    },
        +    "note": {
        +      "description": "What the match means, or that nothing was estimated.",
        +      "type": "string"
        +    },
        +    "path": {
        +      "description": "Action path, echoed.",
        +      "type": "string"
        +    },
        +    "preflopExploitability": {
        +      "description": "Always \"not available\".",
        +      "type": "string"
        +    },
        +    "rows": {
        +      "description": "Matching index rows.",
        +      "items": {
        +        "description": "One index row.",
        +        "properties": {
        +          "analyzed": {
        +            "description": "Whether the row was analyzed.",
        +            "type": "boolean"
        +          },
        +          "decisionNodes": {
        +            "description": "Decision nodes.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "edges": {
        +            "description": "Edges.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "format": {
        +            "description": "Format label.",
        +            "type": "string"
        +          },
        +          "freqSumChecks": {
        +            "description": "Frequency-sum checks run.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "freqSumOff": {
        +            "description": "Checks that came out off.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "gzBytes": {
        +            "description": "Compressed size in bytes.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "hasRaiseMeta": {
        +            "description": "Whether raise metadata is stored.",
        +            "type": "boolean"
        +          },
        +          "key": {
        +            "description": "Row key.",
        +            "type": "string"
        +          },
        +          "manifestEdgeCount": {
        +            "description": "Edge count from the manifest.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "maxActions": {
        +            "description": "Most actions on any node.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "position": {
        +            "description": "Acting position.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "stack": {
        +      "description": "Stack depth in big blinds, echoed.",
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_session_summary2 fields changed
      • addedInput schema / properties / session_id / description
        Added value: +"Session id from list_my_sessions."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Headline numbers and HUD rates for one uploaded session.",
        +  "properties": {
        +    "endedAt": {
        +      "description": "Last hand timestamp.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "error": {
        +      "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.",
        +      "type": "string"
        +    },
        +    "game_type": {
        +      "description": "Game type: \"NLHE\", \"PLO\", \"PLO5\", or \"PLO6\".",
        +      "type": "string"
        +    },
        +    "hands": {
        +      "description": "Hands in the session.",
        +      "type": "integer"
        +    },
        +    "hero": {
        +      "description": "Hero name in the history.",
        +      "type": "string"
        +    },
        +    "hud": {
        +      "description": "HUD rates over this session, as percentages.",
        +      "properties": {
        +        "limp": {
        +          "description": "Open limp, percent.",
        +          "type": "number"
        +        },
        +        "pfr": {
        +          "description": "Preflop raise, percent.",
        +          "type": "number"
        +        },
        +        "sample": {
        +          "description": "Hands the rates are computed over.",
        +          "type": "integer"
        +        },
        +        "threeBet": {
        +          "description": "3-bet, percent.",
        +          "type": "number"
        +        },
        +        "vpip": {
        +          "description": "Voluntarily put money in pot, percent.",
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "id": {
        +      "description": "Session id.",
        +      "type": "string"
        +    },
        +    "netBb": {
        +      "description": "Session result in big blinds.",
        +      "type": "number"
        +    },
        +    "startedAt": {
        +      "description": "First hand timestamp.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_tournament_results2 fields changed
      • addedInput schema / properties / limit / description
        Added value: +"Tournament summaries to include, 1 to 500."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "MTT results from uploaded tournament summaries. Money is in cents.",
        +  "properties": {
        +    "buyInCents": {
        +      "description": "Total buy-ins, or null when one buy-in is unknown.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "itmPct": {
        +      "description": "Share of tournaments that cashed, 0 to 1, or null.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "netProfitCents": {
        +      "description": "Received minus buy-ins, or null when a buy-in is unknown.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "note": {
        +      "description": "Present when no tournament summaries have been uploaded.",
        +      "type": "string"
        +    },
        +    "receivedCents": {
        +      "description": "Total prize money received.",
        +      "type": "number"
        +    },
        +    "recent": {
        +      "description": "Tournaments, newest first.",
        +      "items": {
        +        "description": "One tournament.",
        +        "properties": {
        +          "buyInCents": {
        +            "description": "Buy-in in cents.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "fieldSize": {
        +            "description": "Entrants.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "finish": {
        +            "description": "Finishing place.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "game": {
        +            "description": "Game label from the summary.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "id": {
        +            "description": "Row id.",
        +            "type": "string"
        +          },
        +          "receivedCents": {
        +            "description": "Prize received in cents.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "sourceId": {
        +            "description": "Tournament id from the summary file.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "roi": {
        +      "description": "Return on investment as a ratio, or null.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "tournaments": {
        +      "description": "Tournament summaries counted.",
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_tree_docs1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Tree documentation and per-stack counts for one dataset.",
        +  "properties": {
        +    "coverage": {
        +      "description": "Coverage row from the shipped README.",
        +      "type": "string"
        +    },
        +    "dataset": {
        +      "description": "Dataset id, echoed.",
        +      "type": "string"
        +    },
        +    "error": {
        +      "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.",
        +      "type": "string"
        +    },
        +    "preflopExploitability": {
        +      "description": "Always \"not available\".",
        +      "type": "string"
        +    },
        +    "source": {
        +      "description": "File the coverage note came from.",
        +      "type": "string"
        +    },
        +    "stacks": {
        +      "description": "Per-stack counts.",
        +      "items": {
        +        "description": "One stack depth of the dataset.",
        +        "properties": {
        +          "analyzed": {
        +            "description": "Analyzed rows at this depth.",
        +            "type": "integer"
        +          },
        +          "bundles": {
        +            "description": "Bundles at this depth, for per-bundle datasets.",
        +            "items": {
        +              "description": "One bundle.",
        +              "properties": {
        +                "analyzed": {
        +                  "description": "Whether the bundle was analyzed.",
        +                  "type": "boolean"
        +                },
        +                "decisionNodes": {
        +                  "description": "Decision nodes in the bundle.",
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "edges": {
        +                  "description": "Edges in the bundle.",
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "gzBytes": {
        +                  "description": "Compressed size in bytes.",
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "key": {
        +                  "description": "Bundle key.",
        +                  "type": "string"
        +                },
        +                "position": {
        +                  "description": "Acting position the bundle covers.",
        +                  "type": "string"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "decisionNodes": {
        +            "description": "Decision nodes across the bundles.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "edges": {
        +            "description": "Edges across the bundles.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "formats": {
        +            "description": "Formats at this depth.",
        +            "items": {
        +              "description": "Format label.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "hasRaiseMeta": {
        +            "description": "Whether raise metadata is stored.",
        +            "type": "boolean"
        +          },
        +          "note": {
        +            "description": "How to read the rows at this depth.",
        +            "type": "string"
        +          },
        +          "positions": {
        +            "description": "Positions at this depth.",
        +            "items": {
        +              "description": "Seat label.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "rows": {
        +            "description": "Index rows at this depth.",
        +            "type": "integer"
        +          },
        +          "sampleKeys": {
        +            "description": "Sample keys, for per-node datasets.",
        +            "items": {
        +              "description": "A node key.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "stackBb": {
        +            "description": "Stack depth in big blinds.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedget_upload_link1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Hosted upload page for hand histories.",
        +  "properties": {
        +    "expiresAt": {
        +      "description": "When the signed token expires, or null when unsigned.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "primary": {
        +      "description": "Always true: this is the primary upload path.",
        +      "type": "boolean"
        +    },
        +    "resource": {
        +      "description": "MCP resource URI that returns the same payload.",
        +      "type": "string"
        +    },
        +    "tokenAttached": {
        +      "description": "Whether the URL carries a signed token for this account.",
        +      "type": "boolean"
        +    },
        +    "url": {
        +      "description": "URL to hand to the user, signed when signing is configured.",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_datasets1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Preflop datasets in the shipped tree documentation.",
        +  "properties": {
        +    "datasets": {
        +      "description": "Documented datasets.",
        +      "items": {
        +        "description": "One dataset.",
        +        "properties": {
        +          "analyzed": {
        +            "description": "Rows whose bundle was analyzed.",
        +            "type": "integer"
        +          },
        +          "formats": {
        +            "description": "Formats in the index.",
        +            "items": {
        +              "description": "Format label.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "id": {
        +            "description": "Dataset id to pass to get_tree_docs, e.g. \"nl/v2\".",
        +            "type": "string"
        +          },
        +          "perNode": {
        +            "description": "True when index rows are per node rather than per bundle.",
        +            "type": "boolean"
        +          },
        +          "positions": {
        +            "description": "Positions with index rows.",
        +            "items": {
        +              "description": "Seat label.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "rows": {
        +            "description": "Index rows for the dataset.",
        +            "type": "integer"
        +          },
        +          "stacks": {
        +            "description": "Covered stack depths.",
        +            "items": {
        +              "description": "Stack depth in big blinds.",
        +              "type": "number"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "generated": {
        +      "description": "Date the documentation was generated.",
        +      "type": "string"
        +    },
        +    "preflopExploitability": {
        +      "description": "Always \"not available\": no preflop dataset publishes it.",
        +      "type": "string"
        +    },
        +    "readme": {
        +      "description": "How to read one dataset's write-up.",
        +      "type": "string"
        +    },
        +    "source": {
        +      "description": "Where the documentation came from, \"data/tree-docs\".",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_games1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": {
        +    "description": "One game id to its covered stacks and positions. Full detail adds the bundle manifest fields.",
        +    "properties": {
        +      "bundleCount": {
        +        "description": "Bundles in the dataset.",
        +        "type": "integer"
        +      },
        +      "error": {
        +        "description": "Upstream status code when a game did not answer.",
        +        "type": "number"
        +      },
        +      "game": {
        +        "description": "Game id.",
        +        "type": "string"
        +      },
        +      "generatedAt": {
        +        "description": "When the dataset was generated.",
        +        "type": "string"
        +      },
        +      "positions": {
        +        "description": "Covered positions.",
        +        "items": {
        +          "description": "Seat label.",
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "stacks": {
        +        "description": "Covered stack depths.",
        +        "items": {
        +          "description": "Stack depth in big blinds.",
        +          "type": "number"
        +        },
        +        "type": "array"
        +      },
        +      "version": {
        +        "description": "Dataset version.",
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "description": "Coverage for every preflop game, plus what this server does not solve.",
        +  "properties": {
        +    "_coverage": {
        +      "description": "Formats and objectives this server does and does not answer.",
        +      "properties": {
        +        "format": {
        +          "description": "Supported formats: cash and mtt_chip_ev.",
        +          "items": {
        +            "description": "A supported format.",
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "supportedObjectives": {
        +          "description": "Objectives that return data.",
        +          "items": {
        +            "description": "A supported objective.",
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "supportedTournament": {
        +          "description": "The one certified tournament tree.",
        +          "properties": {
        +            "anteBb": {
        +              "description": "BB ante in big blinds, 1.",
        +              "type": "number"
        +            },
        +            "format": {
        +              "description": "Always \"mtt\".",
        +              "type": "string"
        +            },
        +            "game": {
        +              "description": "Game id, \"nlmtt8\".",
        +              "type": "string"
        +            },
        +            "objective": {
        +              "description": "Always \"chip_ev\".",
        +              "type": "string"
        +            },
        +            "tableSize": {
        +              "description": "Seats, 8.",
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "unsupported": {
        +          "description": "ICM, PKO, satellites, 9-max MTT, tournament and multiway postflop.",
        +          "items": {
        +            "description": "A request type with no published data.",
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_library_solutions2 fields changed
      • addedInput schema / properties / limit / description
        Added value: +"Solutions to return, 1 to 50."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Finished postflop solutions saved for this account.",
        +  "properties": {
        +    "note": {
        +      "description": "Why no solution is marked done.",
        +      "type": "string"
        +    },
        +    "solutions": {
        +      "description": "Empty while solver dispatch is disabled.",
        +      "items": {
        +        "description": "One finished solution.",
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_my_opponents7 fields changed
      • addedInput schema / properties / game_type / description
        Added value: +"Only hands of this game type, e.g. \"NLHE\" or \"PLO\"."
      • addedInput schema / properties / hero / description
        Added value: +"Only hands where this hero name was seated."
      • addedInput schema / properties / limit / description
        Added value: +"Opponents to return, 1 to 500."
      • addedInput schema / properties / min_hands / description
        Added value: +"Drop opponents seen in fewer hands than this."
      • addedInput schema / properties / name / description
        Added value: +"Case-insensitive substring of the opponent's screen name."
      • addedInput schema / properties / sort / description
        Added value: +"Row order: most hands, most recent, or by hero's bb/100 against them (toughest = worst for hero)."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Opponents tracked across this account's uploaded hands.",
        +  "properties": {
        +    "opponents": {
        +      "description": "Opponents, sorted as requested.",
        +      "items": {
        +        "description": "One opponent.",
        +        "properties": {
        +          "cbetFaced": {
        +            "description": "Flop c-bets the opponent faced.",
        +            "type": "integer"
        +          },
        +          "cbetFold": {
        +            "description": "Those c-bets the opponent folded to.",
        +            "type": "integer"
        +          },
        +          "displayName": {
        +            "description": "Screen name as written in the history.",
        +            "type": "string"
        +          },
        +          "gameTypes": {
        +            "description": "Game types seen.",
        +            "items": {
        +              "description": "Game type.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "handCount": {
        +            "description": "Hands the opponent appears in.",
        +            "type": "integer"
        +          },
        +          "handsVsHero": {
        +            "description": "Hands played against hero.",
        +            "type": "integer"
        +          },
        +          "heroBb100Vs": {
        +            "description": "Hero's bb/100 in hands against this opponent.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "heroes": {
        +            "description": "Hero accounts that faced this opponent.",
        +            "items": {
        +              "description": "Hero name.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "id": {
        +            "description": "Opponent id for get_opponent_notes.",
        +            "type": "string"
        +          },
        +          "lastSeen": {
        +            "description": "Most recent hand timestamp.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "net": {
        +            "description": "Hero's net big blinds in those hands.",
        +            "type": "number"
        +          },
        +          "notes": {
        +            "description": "Leak notes.",
        +            "items": {
        +              "description": "One leak note with its sample size.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "notesCount": {
        +            "description": "Leak notes available.",
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_my_sessions3 fields changed
      • addedInput schema / properties / game_type / description
        Added value: +"Only sessions containing this game type."
      • addedInput schema / properties / limit / description
        Added value: +"Sessions to return, 1 to 50."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Recent uploaded sessions, newest first.",
        +  "properties": {
        +    "hint": {
        +      "description": "Where to upload hands when the account has none.",
        +      "type": "string"
        +    },
        +    "sessions": {
        +      "description": "Sessions, newest first.",
        +      "items": {
        +        "description": "One upload session.",
        +        "properties": {
        +          "endedAt": {
        +            "description": "Last hand timestamp.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "filename": {
        +            "description": "Uploaded filename.",
        +            "type": "string"
        +          },
        +          "game_type": {
        +            "description": "Dominant game type in the session.",
        +            "type": "string"
        +          },
        +          "game_types": {
        +            "description": "Every game type in the session.",
        +            "items": {
        +              "description": "Game type.",
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "hands": {
        +            "description": "Hands in the session.",
        +            "type": "integer"
        +          },
        +          "hero": {
        +            "description": "Hero name in the history.",
        +            "type": "string"
        +          },
        +          "id": {
        +            "description": "Session id.",
        +            "type": "string"
        +          },
        +          "netBb": {
        +            "description": "Session result in big blinds.",
        +            "type": "number"
        +          },
        +          "startedAt": {
        +            "description": "First hand timestamp.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_postflop_packs1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Solved postflop packs and their boards.",
        +  "properties": {
        +    "hint": {
        +      "description": "How to narrow, page, or widen the same query.",
        +      "type": "string"
        +    },
        +    "packs": {
        +      "description": "Packs matching `variant` and `pack`.",
        +      "items": {
        +        "description": "One solved pack.",
        +        "properties": {
        +          "actionEvCoverage": {
        +            "description": "How action EV is reconstructed, and for how many boards.",
        +            "type": "object"
        +          },
        +          "boardCount": {
        +            "description": "Solved boards in the pack.",
        +            "type": "integer"
        +          },
        +          "boards": {
        +            "description": "Board names in the pack list, or per-board detail when one `pack` was requested.",
        +            "items": {
        +              "anyOf": [
        +                {
        +                  "description": "Board in spaced form, e.g. \"3h 3d 2s\".",
        +                  "type": "string"
        +                },
        +                {
        +                  "description": "One solved board.",
        +                  "properties": {
        +                    "actionEv": {
        +                      "description": "Whether per-action EV can be reconstructed here.",
        +                      "type": "object"
        +                    },
        +                    "board": {
        +                      "description": "Board in spaced form.",
        +                      "type": "string"
        +                    },
        +                    "exploitabilityPct": {
        +                      "description": "Published exploitability as a percent of the pot. Omitted when the index has no number.",
        +                      "type": "number"
        +                    },
        +                    "exploitabilityTree": {
        +                      "description": "Which tree the exploitability belongs to.",
        +                      "type": "string"
        +                    },
        +                    "iterations": {
        +                      "description": "Published solver iterations.",
        +                      "type": "integer"
        +                    },
        +                    "queryable": {
        +                      "description": "Whether nodes can be walked.",
        +                      "type": "boolean"
        +                    },
        +                    "river": {
        +                      "description": "Whether the river is solved.",
        +                      "type": "boolean"
        +                    },
        +                    "trees": {
        +                      "description": "Trees this board is solved under.",
        +                      "items": {
        +                        "description": "\"75\" or \"33\".",
        +                        "type": "string"
        +                      },
        +                      "type": "array"
        +                    }
        +                  },
        +                  "type": "object"
        +                }
        +              ]
        +            },
        +            "type": "array"
        +          },
        +          "effStackBb": {
        +            "description": "Effective stack behind, in big blinds.",
        +            "type": "number"
        +          },
        +          "exploitability": {
        +            "description": "\"published\" or \"not available\" for this tree. Never estimated.",
        +            "type": "string"
        +          },
        +          "generatedAt": {
        +            "description": "When the pack was generated.",
        +            "type": "string"
        +          },
        +          "hasEv": {
        +            "description": "Whether combos carry EV.",
        +            "type": "boolean"
        +          },
        +          "id": {
        +            "description": "Pack id to pass as `pack`.",
        +            "type": "string"
        +          },
        +          "ipPos": {
        +            "description": "In-position seat.",
        +            "type": "string"
        +          },
        +          "oopPos": {
        +            "description": "Out-of-position seat.",
        +            "type": "string"
        +          },
        +          "potBb": {
        +            "description": "Starting pot in big blinds.",
        +            "type": "number"
        +          },
        +          "preflopLine": {
        +            "description": "Preflop line the pack starts from.",
        +            "type": "string"
        +          },
        +          "queryableBoards": {
        +            "description": "Boards whose nodes can be walked.",
        +            "type": "integer"
        +          },
        +          "sizingTrees": {
        +            "description": "Bet-size trees; either packId is accepted by every postflop tool.",
        +            "items": {
        +              "description": "One bet-size tree of this pack.",
        +              "properties": {
        +                "betSizing": {
        +                  "description": "What the tree bets on each street.",
        +                  "type": "string"
        +                },
        +                "boards": {
        +                  "description": "Boards solved under the tree.",
        +                  "type": "integer"
        +                },
        +                "missing": {
        +                  "description": "Boards the tree does not cover.",
        +                  "items": {
        +                    "description": "A board absent from this tree.",
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "packId": {
        +                  "description": "Pack id that addresses this tree.",
        +                  "type": "string"
        +                },
        +                "tree": {
        +                  "description": "\"75\" or \"33\".",
        +                  "type": "string"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "stackBb": {
        +            "description": "Starting stack in big blinds.",
        +            "type": "number"
        +          },
        +          "title": {
        +            "description": "Human title.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_queued_solves2 fields changed
      • addedInput schema / properties / limit / description
        Added value: +"Jobs to return, 1 to 50."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "This account's solver-queue jobs, newest first.",
        +  "properties": {
        +    "solves": {
        +      "description": "Queued jobs. None are dispatched.",
        +      "items": {
        +        "description": "One recorded solve request. Dispatch is not configured, so a job stays pending and never gets a solution id.",
        +        "properties": {
        +          "board": {
        +            "description": "Board for the requested solve.",
        +            "type": "string"
        +          },
        +          "createdAt": {
        +            "description": "ISO timestamp the job was recorded.",
        +            "type": "string"
        +          },
        +          "dispatch": {
        +            "description": "Always \"not_configured\".",
        +            "type": "string"
        +          },
        +          "effective_stack": {
        +            "description": "Effective stack in big blinds.",
        +            "type": "number"
        +          },
        +          "pot": {
        +            "description": "Pot in big blinds.",
        +            "type": "number"
        +          },
        +          "queue_id": {
        +            "description": "Id for get_queued_solve.",
        +            "type": "integer"
        +          },
        +          "reason": {
        +            "description": "Why the job does not start a solve.",
        +            "type": "string"
        +          },
        +          "solution_id": {
        +            "description": "Always null while dispatch is disabled.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "description": "\"pending\", \"running\", \"done\", or \"failed\".",
        +            "type": "string"
        +          },
        +          "title": {
        +            "description": "Title given when the job was recorded.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedlist_spots1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Valid decision nodes for one game and stack, paginated.",
        +  "properties": {
        +    "game": {
        +      "description": "Game id.",
        +      "type": "string"
        +    },
        +    "hint": {
        +      "description": "How to narrow, page, or widen the same query.",
        +      "type": "string"
        +    },
        +    "matched": {
        +      "description": "Spots left after the depth and contains filters.",
        +      "type": "integer"
        +    },
        +    "nextOffset": {
        +      "description": "Offset for the next page, or null at the end.",
        +      "type": [
        +        "integer",
        +        "null"
        +      ]
        +    },
        +    "offset": {
        +      "description": "Offset this page started at.",
        +      "type": "integer"
        +    },
        +    "returned": {
        +      "description": "Spots in this page.",
        +      "type": "integer"
        +    },
        +    "spots": {
        +      "description": "This page of decision nodes.",
        +      "items": {
        +        "description": "One decision node.",
        +        "properties": {
        +          "actor": {
        +            "description": "Position to act.",
        +            "type": "string"
        +          },
        +          "depth": {
        +            "description": "Decision depth: 1 = RFI, 2 = vs open, 3 = 3-bet pots.",
        +            "type": "integer"
        +          },
        +          "history": {
        +            "description": "Action path ending in the acting position.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "stack": {
        +      "description": "Stack depth in big blinds.",
        +      "type": "number"
        +    },
        +    "total": {
        +      "description": "Spots in the dataset for this stack.",
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
    • Changedupload_hand_history2 fields changed
      • addedInput schema / properties / filename / description
        Added value: +"Name to record for the paste. Defaults to \"paste.txt\"."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "description": "Result of ingesting one pasted hand history.",
        +  "properties": {
        +    "errors": {
        +      "description": "Parse errors, if any.",
        +      "items": {
        +        "description": "One parse error.",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "filename": {
        +      "description": "Filename recorded for the paste.",
        +      "type": "string"
        +    },
        +    "handsParsed": {
        +      "description": "Hands parsed.",
        +      "type": "integer"
        +    },
        +    "persisted": {
        +      "description": "Always false: nothing is written to durable storage.",
        +      "type": "boolean"
        +    },
        +    "persistence": {
        +      "description": "Where the hands live, \"process_memory\".",
        +      "type": "string"
        +    },
        +    "sessionId": {
        +      "description": "Session id for the stored hands, or null when nothing parsed.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "tournamentsParsed": {
        +      "description": "Tournament summaries parsed.",
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
  2. 29 tool updates
    • First observedcompare_strategies
    • First observedenqueue_solve
    • First observedexplain_combo
    • First observedfind_hands
    • First observedget_board_report
    • First observedget_config
    • First observedget_exploitability
    • First observedget_hand_results
    • First observedget_node
    • First observedget_opponent_limp_range
    • First observedget_opponent_notes
    • First observedget_postflop_node
    • First observedget_postflop_range
    • First observedget_queued_solve
    • First observedget_range
    • First observedget_range_metadata
    • First observedget_session_summary
    • First observedget_tournament_results
    • First observedget_tree_docs
    • First observedget_upload_link
    • First observedlist_datasets
    • First observedlist_games
    • First observedlist_library_solutions
    • First observedlist_my_opponents
    • First observedlist_my_sessions
    • First observedlist_postflop_packs
    • First observedlist_queued_solves
    • First observedlist_spots
    • First observedupload_hand_history

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with the TexasSolver poker solver to run game theory optimal (GTO) poker calculations, load preflop ranges, and build game trees with structured parameters for analyzing poker hands and strategies.
    -
  • A
    license
    A
    quality
    D
    maintenance
    Enables simulated multi-table No-Limit Texas Hold'em study and decision-support, allowing users to practice against bots and get equity/pot-odds/preflop-chart advice.
    12
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources