@battlegrid/mcp-server 32.0.23 → 32.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -47,7 +47,7 @@ import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/cli
47
47
  * being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
48
48
  * correction. Never move it to track the server.
49
49
  */
50
- export declare const PACKAGE_VERSION = "32.0.23";
50
+ export declare const PACKAGE_VERSION = "32.0.25";
51
51
  export declare const DEFAULT_URL = "https://mcp.battlegrid.trade/mcp";
52
52
  export interface EnvConfig {
53
53
  apiKeys: string[];
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ import { Client, SdkHttpError, StreamableHTTPClientTransport } from '@modelconte
49
49
  * being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
50
50
  * correction. Never move it to track the server.
51
51
  */
52
- export const PACKAGE_VERSION = '32.0.23';
52
+ export const PACKAGE_VERSION = '32.0.25';
53
53
  export const DEFAULT_URL = 'https://mcp.battlegrid.trade/mcp';
54
54
  const MAX_RETRIES = 3;
55
55
  const RETRY_DELAYS_MS = [2000, 4000, 8000];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@battlegrid/mcp-server",
3
- "version": "32.0.23",
3
+ "version": "32.0.25",
4
4
  "description": "BattleGrid MCP server — play crypto prediction games from AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
3
- "contractVersion": "123.1.0",
3
+ "contractVersion": "129.1.0",
4
4
  "files": {
5
- "battlegrid-agent-management/SKILL.md": "4c2cb5cfec27cf11769d66763e024e6900c392e27a978de3080cf55b2ece7a68",
5
+ "battlegrid-agent-management/SKILL.md": "18c635d512ba0b9e17df11d157adff5aed0bd8cc0bfa32df3e53b5e9d3453e45",
6
6
  "battlegrid-agent-management/references/agent-stage-examples.md": "dffcc353d61dfc7b5bb6a2b3077fc6bf8c760a34c287cafb3b59b99306f24195",
7
- "battlegrid-arena-play/SKILL.md": "2e37970a66b8738ffbc445a23da90651c1f41b56ce4eef551582ab123517ef74",
7
+ "battlegrid-arena-play/SKILL.md": "ec55a4ed41f4e54a66ddc66ef3e9e9c87c31986e83f1d66c2ae91f3557bad514",
8
8
  "battlegrid-arena-play/references/entry-stage-examples.md": "0223f3743171ff213e943789d27590b2f65648398e85e10cd24938d5eb6af665",
9
9
  "battlegrid-market-analysis/SKILL.md": "fcbe98e30e1edce39bb170c224cdf20181934f62b5f3a26b293787c70eeb6229",
10
10
  "battlegrid-officers/SKILL.md": "3fd59ec301d1492c956fbdb4368fef61f29abd137f02f49a6172351c7a563309",
11
11
  "battlegrid-officers/references/officer-stage-examples.md": "ef46ba26f4b36c9964b5bde95fdf98e5952c3786b77be5f136056cac792f0aec",
12
- "battlegrid-radar-deployment/SKILL.md": "cf6664f51f92d40acce21a46f4fb078d9afe46c99c4f4b603bf002e73d4c5a23",
12
+ "battlegrid-radar-deployment/SKILL.md": "b344cd3d2051153115ce9840606e6a08a140f704d5da6a10fca18d81c3796be6",
13
13
  "battlegrid-radar-deployment/references/arena-stage-examples.md": "d27cfed1f4663f267c4a7ecebe4a6e65a450fc74bd14ce8987fb61af5bbf2ca5",
14
14
  "battlegrid-radar-deployment/references/radar-stage-examples.md": "13fc3f55d91d3da9754e1ed7fb27493b7b7ba4d40a6a7e8d1ee0365f90ea10de",
15
15
  "battlegrid-strategy-authoring/SKILL.md": "39cfa46b1f640e6800edb7e85a8f2c4b6b8786cddf71bb8244d172a44fc11d75",
16
16
  "battlegrid-strategy-authoring/references/strategy-stage-examples.md": "f10ecdc91f3660a708eee7a7bacefce2acbb46c9cf7e0ac1454bd54f839f39fd",
17
- "battlegrid-strategy-doctor/SKILL.md": "e34e055b0cc9b355bc1adeb5d49d464eaa0756ca3f48dc89ca2ccdda94e1311f",
17
+ "battlegrid-strategy-doctor/SKILL.md": "f15bce81a95b3cc6f1e8ebf3008ec56f7d100f74a5e3e85fc46cdd26554ed807",
18
18
  "battlegrid-strategy-examples/SKILL.md": "9d18bf0e4bf85a28508e2881a4cdf77b823ec831e7cec5d82f82dc251402f41c",
19
19
  "battlegrid-strategy-examples/references/playbooks.md": "a9464789df2e762faf9dbd7845101564bc1847cd193f709f8ac4b6bff08f09dd",
20
20
  "battlegrid-strategy-examples/references/recipes.md": "806aae0b4842408f6e6ed3e108293073f4f31d1c27fa419ad57df9e1134f23e7",
21
21
  "battlegrid-strategy-examples/references/tradingview-ports.md": "c62ce72b741abe5a92e1dec6615f26b19a54959aa1d29542518cd9a189390b98",
22
- "battlegrid-trade-analysis/SKILL.md": "3f927b4f9796178526fa1673a2043c5f14358c39aa955de33192ea58641f18fb",
23
- "battlegrid-trade-proposal/SKILL.md": "e761fc6bddc0d1db79fcb90046d03a18439562c8658de726ec286830edd6369b"
22
+ "battlegrid-trade-analysis/SKILL.md": "cc401a0c842be53df3725344db2e5446325c05ab580e8fa50cb9a6189de9e327",
23
+ "battlegrid-trade-proposal/SKILL.md": "8e20ce1206ae51f1f87c6e940c8b7ed2798dcd2dfc8d9a2f82adf1a4d0817313"
24
24
  }
25
25
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: battlegrid-agent-management
3
- description: Commission and govern the player's intelligence agents — interview and create one against a committed strategy and an approved model, change its configuration and risk limits, rebind it to another strategy, halt and resume it, archive and reactivate it, and act on its live positions (close, or move a stop outside the platform ratchet). Activate whenever the player wants a new agent, wants to change, pause, restart, retire or revive an existing one, asks what an agent is allowed to risk, or wants to intervene in a position an agent has open.
3
+ description: Commission and govern the player's intelligence agents — interview and create one against a committed strategy and an approved model, change its configuration and risk limits, rebind it to another strategy, halt and resume it, archive and reactivate it, and act on its live positions (close one, or move its stop or take-profit outside the platform ratchet). Activate whenever the player wants a new agent, wants to change, pause, restart, retire or revive an existing one, asks what an agent is allowed to risk, or wants to intervene in a position an agent has open.
4
4
  ---
5
5
 
6
6
  # Agent Management
@@ -158,8 +158,8 @@ again only on their word.
158
158
  ### 4. Lifecycle verbs: read first, state the radius, then confirm
159
159
 
160
160
  Every one of a draft commit (an edit or a rebind), halt, resume, activate and archive runs this
161
- shape. The reads (`get_agent_budget`, `get_agent_fund_allocation`, `get_agent_open_positions`,
162
- `get_agent_automation_status`, `get_agent_performance`, `get_agent_journal`) need no confirm and
161
+ shape. The reads (`get_agent_budget`, `list_user_active_positions`, `get_agent_automation_status`,
162
+ `get_agent_performance`, `get_agent_thought_log`) need no confirm and
163
163
  cost nothing but a call — do them first, always.
164
164
 
165
165
  State the blast radius **from server fields, as numbers**, before the confirm form:
@@ -244,23 +244,37 @@ partial config and never echo a read config back unchanged: the agent's read sha
244
244
  the axis (`strategyTimeframe` and `regimeTimeframe` are strategy-derived and refused as unknown
245
245
  keys). The commit holds the configuration to the same risk rules the agent form's Save applies.
246
246
 
247
- ### 7. Live positions: present the served state, name the bypass
248
-
249
- - `get_agent_open_positions` / `list_user_active_positions` / `get_position_audit_history` first —
250
- the `decisionId` these two tools need is discoverable only through those reads.
251
- - **`close_agent_position`** is irreversible: it submits a reduce-only market order and realizes
252
- the P&L. It carries a schema-level `confirm: true`, so present the position, its unrealized
253
- P&L and its protections, and confirm before calling. An exchange rejection comes back as a typed
254
- trading error — report it; a success means the close order was *accepted*.
255
- - **`override_agent_protection`** moves the effective stop — the stop-loss only; take-profit is not
256
- overridable here. It names the stop it replaces by `effectiveStopLossOrderId`, which
257
- `get_position_audit_history` serves. Its confirm must say, in words, that
258
- the change **moves the stop outside the platform's protective ratchet** — that is exactly what
259
- the tool is for — and name the direction: whether the new level sits further from or closer to
260
- price than the one the platform is holding. Present the current protection first, then the
261
- requested level, then that sentence. Its `result` is discriminated by `kind`: only `committed`
262
- advanced anything; every other branch names why the amendment did not apply — read it, do not
263
- assume the write landed.
247
+ ### 7. Position management: read, close, move the stop or the take-profit
248
+
249
+ 1. **Read first.** `list_user_active_positions` serves each open position's `decisionId`, its live
250
+ `effectiveStopLoss` and `effectiveTakeProfit`, the mark and the trailing state. Those are the
251
+ only inputs a write needs. Never take a write's inputs from `get_position_audit_history` — it
252
+ is history, not the live position — and never ask the player for an order id.
253
+ 2. **Close.** `close_agent_position({ decisionId, confirm: true })` is irreversible: it submits a
254
+ reduce-only market order and realizes the P&L. Present the position, its unrealized P&L and its
255
+ protections, and confirm before calling. An exchange rejection comes back as a typed trading
256
+ error — report it; a success means the close order was *accepted*.
257
+ 3. **Move the stop, the take-profit, or both.**
258
+ `override_agent_protection({ decisionId, stopLossPrice?, takeProfitPrice? })` — send only the
259
+ leg the player is moving; no order id. A stop must sit on the loss side of the live mark and a
260
+ take-profit on its profit side: a level the mark has already crossed would fill on arrival, so
261
+ the server refuses it as `level-crossed`, naming the mark.
262
+ 4. **What automation does after a move.** Trailing, break-even and time decay keep running and only
263
+ ever tighten from the new stop: a tighter stop stands until a mover beats it, a looser stop holds
264
+ only until an automated candidate beats it, a break-even that already committed never returns,
265
+ and time decay steps from the new stop. A moved take-profit changes nothing the movers compute —
266
+ they keep reading the signal's take-profit.
267
+ 5. **Confirm before every write, and read the result leg by leg.** For each leg, name the current
268
+ level → the requested level and the direction (closer to or further from price). Say, in words,
269
+ that the change **moves the stop outside the platform's protective ratchet** — that is exactly
270
+ what the tool is for — and what automation does afterwards (step 4). Present the current
271
+ protection first, then the requested levels, then those sentences. The answer's `success` is
272
+ true only when every requested leg committed. `level-crossed`, `mark-unavailable` and
273
+ `rate-limited` refused the whole request and wrote nothing; on `level-crossed` report the mark
274
+ it names and, when the player's intent is to exit now, offer `close_agent_position` — never
275
+ retry the same level. Under `dispatched`, read `stopLoss` and `takeProfit` on their own: only a
276
+ `committed` leg moved, a `queued` stop is recorded and will apply, and every other outcome names
277
+ why that leg did not move — do not assume the write landed.
264
278
 
265
279
  These tools carry no consent gate on either door: they are ownership-gated and behave identically
266
280
  in chat and through an external MCP client. Your confirm is interaction, never authorization —
@@ -151,7 +151,7 @@ player's, and the attribution is part of what was scored.
151
151
  `reasoning` is null when no record describes the current picks — say that rather than
152
152
  reconstructing one, and a pick missing from `reasoning.picks` is one the player chose.
153
153
  `list_my_market_grid_entries` is the history across sessions. An agent's decisions are a different
154
- record, `get_agent_journal`.
154
+ record, `get_agent_thought_log`.
155
155
 
156
156
  ## On the arena's session page
157
157
 
@@ -17,8 +17,8 @@ no slot shape, no condition union and no resolution type. Never carry a fact fro
17
17
  and never describe them as one thing with two modes.
18
18
 
19
19
  **Deployments are the autonomous trading switches.** An agent has no trading mode of its own: it
20
- trades a coin on its own only where a Radar policy puts it on duty, and a proposal the player
21
- approves needs no deployment. An Arena deployment enters an agent into a preset's sessions and grants
20
+ trades a coin on its own only where a Radar policy puts it on duty, and an entry the player queues
21
+ needs no deployment. An Arena deployment enters an agent into a preset's sessions and grants
22
22
  **no** trade permission — to have an agent trade a coin on its own, deploy it on Radar.
23
23
 
24
24
  ## The five failures this flow exists to prevent
@@ -57,8 +57,12 @@ Three reads, and they are not interchangeable:
57
57
  — they describe different stages and merging them invents a cause.
58
58
  - Render every code through its display meta. A raw `NO_ENTRY_CONDITION` or `OPEN_POSITION_CONFLICT` on
59
59
  screen is a system identifier leaking into an explanation.
60
- - **`get_agent_decision_context` is keyed by COIN**, not by agent. Use it for "why did nothing
61
- happen on SOL", once you know which coin the blocks are about.
60
+ - **`get_agent_decision_context` reads the decision behind an OPEN position.** It is keyed by coin
61
+ and answers only for the agent position open on it; for a coin with nothing open it is `null`, so
62
+ it never explains a trade that did not happen. For "why did nothing happen on SOL", read
63
+ `list_gate_blocks` for the pre-model refusals on that coin, and for a Radar coin
64
+ `get_radar_activity_summary` for its causes, then `get_radar_close_decisions` for the bars it
65
+ decided.
62
66
  - **`get_agent_coin_qualification` answers the forward-looking half.** The reason codes above say
63
67
  why an agent did NOT trade in the past; this says whether a coin would route for it RIGHT NOW,
64
68
  and which gate stops it — the strategy's entry condition, candidate levels, the ATR% volatility
@@ -80,11 +84,12 @@ Three reads, and they are not interchangeable:
80
84
  or `ORPHANED` it is not — the agent runs a materialized copy at its own `strategyRevision` — so
81
85
  name the binding state beside the definition rather than letting current rules read as running
82
86
  ones.
83
- - **Gate blocks link to their thought log** through `sourceThoughtLogId` — follow it with
84
- `get_agent_thought_log` when the block's reason needs the evaluation behind it.
85
- - `get_signal_performance` / `list_signal_logs` when the question is whether the signals fired, as
86
- distinct from whether the trades made money. `list_trade_outcomes` and `get_agent_journal` for
87
- what did happen.
87
+ - **A gate block carries the evaluation that refused it** in its `decisionRecord` — read it there
88
+ when the block's reason needs the evaluation behind it; there is no id to follow to another read.
89
+ - `list_signal_logs` narrowed by `agentId` when the question is whether the signals fired, as
90
+ distinct from whether the trades made money: its `summary` counts the evaluations and entries, and a
91
+ failed row's `rejection` names why its order was refused. `list_agent_trades` narrowed by `agentId`,
92
+ `get_agent_thought_log` and `get_agent_activity_feed` for what did happen.
88
93
  - **`get_agent_conviction_calibration` honours `readiness`.** An `INSUFFICIENT_DATA` calibration
89
94
  carries no win rate — report that there is not yet enough history, never a rate derived from a
90
95
  handful of trades.
@@ -14,7 +14,7 @@ Start with where the money is, always, even when the question is narrower — a
14
14
  means nothing without the whole.
15
15
 
16
16
  - `get_account_state` for the account total.
17
- - `get_agent_budget` for each agent's capital at risk, and `get_agent_fund_allocation` for its funding envelope.
17
+ - `get_agent_budget` for each agent's capital at risk.
18
18
 
19
19
  Then state a **reconciliation line**: the account total against the sum of its parts. If they
20
20
  agree, say they agree. **If they do not, state the gap as a gap** — name the amount and say you
@@ -32,18 +32,58 @@ Not "what were its returns" — whether it did *the thing it was told to do*.
32
32
  gate — and its trade levels with the ATR floor, not the agent's overlay prose. Read `bindingState` too: at `SYNCING` or `ORPHANED` the agent evaluates a materialized copy
33
33
  at its own `strategyRevision`, and judging it against the strategy's current revision measures it
34
34
  by rules it is not running.
35
- - `get_agent_performance` and `list_trade_outcomes` — judge against that mandate.
36
- - `get_trade_outcome_by_decision` / `get_trade_chart` when a specific trade needs explaining. A
35
+ - `get_agent_performance` and `list_agent_trades` narrowed by `agentId` — judge against that mandate. Its
36
+ `summary` and `resultSummary` cover the agent's whole scope on the player's account, not the page.
37
+ - `get_trade_outcome_by_decision` (a trade row's `decisionId`) / `get_trade_chart` when a specific trade
38
+ needs explaining: the outcome carries the fills, fees, slippage, leverage, duration and exit label. A
37
39
  measurable trade's `tradeExcursion` reads in R: `mfeR` and `maeR` (the best and worst it reached),
38
40
  `exitR`, and `giveBackR` (what it surrendered between its peak and the close). `exitEfficiency` is
39
41
  a union — branch on its `state` before reading `efficiencyPercent`. All of them are gross of
40
42
  costs; `netPnl` is the after-fee figure.
41
- - The record around the trades: `list_my_market_grid_entries` (the player's Market Grid entries —
42
- `agentId` for one agent's, none for every entry), `get_agent_thought_log` and
43
- `get_user_thought_log` (the reasoning), `get_agent_activity_feed` and `get_user_activity_feed` (what
44
- happened), and `get_agent_explorer` for where the agent stands among public agents.
45
- - `get_signal_performance` when the question is whether the agent's signals are working, as
46
- distinct from whether its trades made money.
43
+ - The record around the trades: `get_agent_thought_log` (an agent's decisions), `get_signal_log` (a
44
+ trade's reasoning and its pipeline), `list_my_market_grid_entries` / `get_my_market_grid_entry` (an
45
+ arena entry's reasoning — `agentId` for one agent's entries, none for every entry),
46
+ `get_agent_activity_feed` (what happened), and `get_agent_explorer` for where the agent stands
47
+ among public agents.
48
+ - `list_signal_logs` narrowed by `agentId` when the question is whether the agent's signals are
49
+ working, as distinct from whether its trades made money: its `summary` counts the evaluations and
50
+ the entries, and a failed row's `rejection` names why its order was refused.
51
+
52
+ ### Time-bounded questions
53
+
54
+ A question with a period in it — "the last 24 hours", "this week", "since Monday" — narrows the list
55
+ on the server, never by reading pages and filtering their timestamps yourself.
56
+
57
+ - Pass `list_signal_logs` (and `list_agent_trades`) `window`: `1D` for the last day, `7D` for the
58
+ week, `30D` for the month. The window trails the request instant, and the `summary` covers the
59
+ windowed scope, so quote it as that period's figure.
60
+ - For a period that is not a trailing preset, pass `since` and `until` instead: ISO-8601 instants
61
+ with an offset, half-open (`since` included, `until` excluded), under the default `LIFETIME`.
62
+ - Name the period you asked for beside every figure you quote from it.
63
+
64
+ ### What past decisions would have done
65
+
66
+ A question about a skip, an unfilled entry, or "if it had traded, would we be up?" is answered from
67
+ the platform's recorded forward marks, never from today's price.
68
+
69
+ - Select the decisions with `list_signal_logs`, then read each one's `get_signal_debrief` (the row's
70
+ `agentId`, and its `id` as `logId`). When the question is the agent-wide pattern rather than named
71
+ decisions, read `get_agent_decision_quality`.
72
+ - **Never mark a past decision against a current price.** A market-context read, a live mark or any
73
+ price read now answers a different question. The debrief's marks are anchored at the decision
74
+ (`decisionAnchor`) and, for a closed trade, at the exit (`exitAnchor`).
75
+ - SKIP and UNFILLED figures (`grossOfCosts: true`) are counterfactual and gross of fees, slippage and
76
+ funding. Quote them as recorded marks — what the market did — never as money the agent made, lost
77
+ or left on the table.
78
+ - While `verdict` is null the call is undecided: quote the RESOLVED rows' `signedReturnPct`,
79
+ `favorableExcursionPct` and `adverseExcursionPct` as recorded, name each PENDING row's `maturesAt`
80
+ as when that window completes, and claim neither a stop-out, a target hit nor a profit.
81
+ - While the verdict is pending, whether the staged stop or target was reached is read from
82
+ `planOutcome` on that decision's `list_signal_logs` row, and from nothing else. Never turn a
83
+ return or an excursion in the debrief into a stop-out or a target hit.
84
+ - A non-null verdict is reported by its label in words, beside the server's `verdictDetail`.
85
+ - A `{ debrief: null }` result is **UNDETERMINED** for that decision: say the read gave none, and
86
+ never estimate it another way.
47
87
 
48
88
  **Name the blemishes.** A verdict with no flaw in it is not a verdict, it is a summary. The trade
49
89
  that went against the mandate, the streak, the position held past its thesis — say it. A player
@@ -53,17 +93,16 @@ reading a clean report about a messy account learns nothing.
53
93
 
54
94
  - `list_user_active_positions` for everything at once: it carries the live mark and P&L
55
95
  (`markPrice`, `unrealizedPnlUsd`, `roePct`) — check `pricingStatus` and `generatedAtMs` before
56
- calling a mark current. `list_session_agent_positions` is the same view for one Market Grid
57
- session. `get_agent_open_positions` is an entry-only view with no live mark: never measure a
58
- distance to a trigger from it.
96
+ calling a mark current. Every position is served once, in `positions`, naming its `agentId` and
97
+ `marketGridSessionId`; `agents` carries each agent's group figures.
59
98
  - For each open position, report its protections **and how far the live mark sits from each
60
99
  trigger** — a stop is a number the player cannot act on; "3.1% from the stop" is one they can.
61
- - `get_decision_order_attribution` maps an executed order back to the decision that placed it.
62
- `get_open_orders` and `get_order_status` read the exchange directly — slower, and they fail when
63
- the exchange is unreachable; report that as UNDETERMINED, never as no orders.
100
+ - `list_agent_open_orders` is the platform's record of each agent order, naming its `decisionId` and
101
+ the venue's `exchangeOrderId` and `cloid`. `get_open_orders` reads the exchange directly — slower,
102
+ and it fails when the exchange is unreachable; report that as UNDETERMINED, never as no orders.
64
103
  - `get_deployment_policy` / `get_radar_deployment` when the protection state comes from standing
65
- policy rather than the position itself. `list_pending_approvals` and `list_gate_blocks` when
66
- something looks like it should have fired and did not.
104
+ policy rather than the position itself. `list_gate_blocks` when something looks like it should
105
+ have fired and did not.
67
106
 
68
107
  ## 4. Automation health — unprompted
69
108
 
@@ -1,20 +1,22 @@
1
1
  ---
2
2
  name: battlegrid-trade-proposal
3
- description: Find and stage a trade for one of the player's agents, for the player to approve. Activate whenever the player asks which coins fit an agent right now, which of their agents fits a coin, wants a trade found or proposed for an agent or on a coin, asks the agent to evaluate a coin, or wants to approve or decline a proposal it made. The scans are the agents' own gates — one agent over every active coin, or one coin over every one of the player's agents; a proposal is QUEUED for the agent's next strategy-bar close and answered into the conversation when that bar is decided; approval is always the player's word.
3
+ description: Find a trade for one of the player's agents and, on the player's consent, queue it to execute at the agent's next strategy-bar close. Activate whenever the player asks which coins fit an agent right now, which of their agents fits a coin, wants a trade found or placed for an agent or on a coin, or asks the agent to evaluate a coin. The scans are the agents' own gates — one agent over every active coin, or one coin over every one of the player's agents; a queued request is decided at the agent's next strategy-bar close, and a qualifying close places the agent's entry at once with no further step; consent is always the player's word, given before the request is queued.
4
4
  ---
5
5
 
6
6
  # Trade Proposal
7
7
 
8
- You are finding and staging a trade for an agent the player configured — never placing one. Every
9
- step below reads what the server decided and puts it to the player in their terms; nothing here
10
- re-sorts a list, re-derives a verdict, or approves on the player's behalf.
8
+ You are finding a trade for an agent the player configured and, once the player consents, queueing
9
+ it. Every step below reads what the server decided and puts it to the player in their terms;
10
+ nothing here re-sorts a list, re-derives a verdict, or queues on the player's behalf without their
11
+ word. No decision waits for the player afterwards: consent comes before the queue, and a qualifying
12
+ close executes.
11
13
 
12
14
  ## 0. What is already held — before anything else
13
15
 
14
- - `list_pending_approvals` and `list_user_active_positions` first, every time.
15
- - A proposal holds the player's live-position slot for that coin across **all** their agents until
16
- it is accepted, cancelled or expires. **Never propose on a coin the player already holds a pending
17
- or live position on** — say why, and name the decision or position that holds it.
16
+ - `list_user_active_positions` first, every time.
17
+ - A queued request holds the player's request slot for that coin, and a placing or live position its
18
+ position slot, across **all** their agents. **Never queue on a coin the player already holds a
19
+ live position on** — say why, and name the position that holds it.
18
20
 
19
21
  ## 1. When the player names a coin and not an agent — choose the agent
20
22
 
@@ -46,15 +48,23 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
46
48
  - A refused scan (`RATE_LIMITED`) is a refusal: say the scan was refused and when it can be retried
47
49
  (`retryAfterSeconds`). Never say "nothing fits".
48
50
 
49
- ## 3. Queue the request
51
+ ## 3. Confirm, then queue the request
50
52
 
51
- - `propose_entry_decision` **only** on the coins the player named, or on the top qualifying row
52
- when they asked for the best fit. One coin per call.
53
+ - **Confirm with the player before queueing.** Name the agent, the coin and the bar it will be
54
+ decided on, and say that a qualifying close places the agent's entry at once, sized by the agent's
55
+ own risk budget, with no further step. Ask, and queue only on their yes.
56
+ - **The player's own words can already be the consent.** "Trade SOL with Atlas at its next close" is
57
+ consent: queue without asking again. So is a standing instruction the player gave you to trade for
58
+ them. Interest is not consent — "what fits SOL right now?" is a question, so report the fit and ask
59
+ whether to trade it.
60
+ - `propose_entry_decision` **only** on that consent, and only on the coins the player named, or on
61
+ the top qualifying row when they asked for the best fit. One coin per call.
53
62
  - **The call does not decide.** It registers a request against the agent's next strategy-bar close
54
63
  and returns immediately; no model runs and nothing is spent. The agent reads that bar on its
55
64
  settled close, through the same path its radar deployments use.
56
- - `userMessage` is the player's own words for the turn. Mint a **fresh UUID** `idempotencyKey` per
57
- request; a retry with the same key replays the recorded result and never registers a second one.
65
+ - `userMessage` is the player's own words for the turn; it is recorded in the conversation and read
66
+ by no model. Mint a **fresh UUID** `idempotencyKey` per request; a retry with the same key replays
67
+ the recorded result and never registers a second one.
58
68
  - **One pending request per coin.** A second is refused with `CONFLICT` / `REQUEST_PENDING` — read
59
69
  the one that exists with `get_entry_request` rather than asking again.
60
70
 
@@ -64,18 +74,19 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
64
74
  (`barStart`), when the answer is due (`decidesBy`), and the deadline past which that bar can no
65
75
  longer be decided (`windowEndsAt`). `decidesBy` and `windowEndsAt` are different instants — a bar
66
76
  that has already settled is decided at the next sweep, seconds away.
67
- - Say where the answer will appear: on the delegation card in this conversation, and — if it
68
- proposes a trade — in `list_pending_approvals`. Nothing further is needed from the player until
69
- then; the card carries the answer to them when the bar closes.
77
+ - Say where the answer will appear: on the delegation card in this conversation. Nothing further is
78
+ needed from the player; the card carries the answer to them when the bar closes, and a qualifying
79
+ close's entry is already being placed by then.
70
80
  - When the player asks what the agent decided, read the request's conversation with
71
81
  `get_trade_conversation({ conversationId })`, using the id the `queued` result carried. It serves
72
82
  the whole transcript in stored order — the queued card, the agent's reasoning, its thesis and
73
- setups, the recommendation, a no-trade with its reason and next coins, or a close answer.
83
+ setups, the entry card naming the decision and the position it placed, a no-trade with its reason
84
+ and next coins, or a close answer.
74
85
  - `get_entry_request` re-reads a request until it is answered — including while its close has fired
75
- and the decision is being composed. `cancel_entry_request` withdraws it only while it still awaits
76
- its close; once the close has fired it is `NOT_FOUND`, and the answer arrives in the conversation.
77
- Both are `NOT_FOUND` once it has been answered, cancelled or expired, and that is the honest record:
78
- the answer is in the conversation.
86
+ and the decision is being composed, and past its deadline until its overdue answer lands.
87
+ `cancel_entry_request` withdraws it only while it still awaits its close; once the close has fired
88
+ it is `NOT_FOUND`, and the answer arrives in the conversation. Both are `NOT_FOUND` once it has
89
+ been answered or cancelled, and that is the honest record: the answer is in the conversation.
79
90
  - `type: "error"` — the block, with its remedy: `OPEN_POSITION_CONFLICT` means a position already
80
91
  holds the slot (see step 0) and nothing was queued; `LLM_CREDITS_EXHAUSTED` means top up when
81
92
  `topupAvailable` is true; `ENTRIES_PAUSED` means the platform has paused new entries while market
@@ -84,25 +95,20 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
84
95
  itself once the data is back: ask again then, under a fresh `idempotencyKey` — the same key only
85
96
  replays this refusal. A refused request (`RATE_LIMITED`) is a refusal with its retry-after.
86
97
  Never "nothing to do".
87
- - `type: "recommendation"` and `type: "no_trade"` arrive only as the **replay** of a request made
88
- before the queued contract shipped. Report them as step 5 describes and do not expect them from a
89
- fresh call.
90
98
 
91
- ## 5. When the answer arrives — approve or decline only on the player's word
99
+ ## 5. When the answer arrives — report it
92
100
 
93
- **On a web Commander surface the approval is the card's own.** The decided close lands on the
94
- delegation card in this conversation, carrying the player's Accept and Decline. `accept_entry_decision`
95
- and `cancel_entry_decision` remain yours for the external and Telegram doors, and on the web only on
96
- the player's explicit typed word — never inferred from interest, agreement, or a question about the
97
- trade.
101
+ Every request that is not withdrawn is answered exactly once, in the conversation.
98
102
 
99
- - A decided close produces one of: a PROPOSED decision awaiting approval; a no-trade with the
100
- reason and the next coins worth asking about; a refusal, `close_refused`, which names the gate that
101
- failed when the close did not qualify and none when it qualified and the radar's own gates stopped
102
- its fire; a window that passed with no sweep; a bar the agent's own radar deployment decided first;
103
- or an error carrying the engine's block, with nothing proposed, when admission refused the
104
- qualifying close's fire — `ENTRIES_PAUSED` while new entries are paused, an account block, a
105
- position already held.
103
+ - A decided close produces one of: an **entry** — the thesis, the setups and the entry card naming
104
+ the decision and the position it placed, which is already executing; a no-trade with the reason
105
+ and the next coins worth asking about; a refusal, `close_refused`, which names the gate that failed
106
+ when the close did not qualify and none when it qualified and the radar's own gates stopped its
107
+ fire; `close_missed`, naming the bar, when its window passed with no sweep; a bar the agent's own
108
+ radar deployment decided first; or an error carrying the engine's block, with nothing entered,
109
+ when admission refused the qualifying close's fire — `ENTRIES_PAUSED` while new entries are
110
+ paused, an account block, a halted agent, a position already held — or `EVALUATION_FAULTED` when
111
+ the decision that fired did not finish.
106
112
  - A bar the agent's own radar deployment decided first is reported from that deployment's decision,
107
113
  never decided again. It arrives as `close_fired_by_radar` — a trade taken in full — only when the
108
114
  deployment's fire enqueued a trade decision. Otherwise it arrives as what stopped that fire, and
@@ -111,14 +117,9 @@ trade.
111
117
  its hourly cap, post-close suppression, a decision already running on the coin — arrives as
112
118
  `close_refused` with no gate, because the close qualified and nothing was entered; and a close
113
119
  whose coin another agent's fire took arrives as `close_claimed_by_radar`.
114
- - On a proposal, state the direction, the entry, stop and take-profit levels, the position size,
115
- the **`convictionPercent`**, and the expiry (`expiresAt`). No conviction floor is applied on this
116
- surface: the conviction is the agent's own reading, and the player judges it.
117
- - Present it and **ask**. `accept_entry_decision` only after the player explicitly approves;
118
- `cancel_entry_decision` only after they explicitly decline.
119
- - Never accept because the conviction reads high, because the scan ranked the coin first, or
120
- because the player asked you to "find a trade" — finding is not approving. `get_entry_decision`
121
- re-reads the row if the conversation moved on before they answered.
122
- - Only a conversational decision awaits the player: radar fires and arena challenge reactions
123
- execute on their own. `list_entry_decisions` with `status: PENDING` lists the ones still waiting
124
- for an agent.
120
+ - On an entry, read the decision with `get_entry_decision` and state the direction, the entry, stop
121
+ and take-profit levels, the position size, the **`convictionPercent`**, and the position's state —
122
+ placing, working, open, rejected or expired. No conviction floor is applied on this surface: the
123
+ conviction is the agent's own reading, and the player's consent was the gate.
124
+ - Open positions, once filled, are `list_user_active_positions`'s; closing one happens only on the
125
+ player's word.