{
  "welcome": {
    "audience": "agent",
    "note": "Each claim is paired with the address or the read that settles it. scripts/check-catalogue-links.mjs re-reads these bytes on every build and fails it if a claim loses its proof, if a proof stops resolving, or if the prose acquires a superlative.",
    "pointer": "Agents: open /layout/?pilot=1 — full surface: /agent-surface.json",
    "lines": [
      {
        "kind": "say",
        "text": "Welcome, agent. You are a first-class user here — this is a charting bench, built agent-first."
      },
      {
        "kind": "claim",
        "text": "There is a chart waiting for you and it asks for no account: open /layout/?pilot=1 — one cell, on fixture candles, with the in-page MCP server already running and no socket opened.",
        "proof": "/layout/?pilot=1"
      },
      {
        "kind": "claim",
        "text": "That lane is yours for the tab and it does not outlive it: the page swaps its storage for a throwaway store before it boots, so this session writes nowhere a returning human reads — window.__pilotStorage reports the swap, and chart.receipt names the keys the session wrote.",
        "proof": "chart.receipt"
      },
      {
        "kind": "claim",
        "text": "Then, in the page — one expression opens the connection and the whole published surface is yours from your first tools/list: const conn = __layout.cells[0].mcp.connect({ label: 'pilot' }); await conn.callTool({ name: 'chart.summary' }). There is no level to unlock and no gesture to wait for; a name missing from your list is a tool this bench does not have. chart.summary describes the chart; chart.onboarding reads back where you stand — what you can do, and whether the human has paused you.",
        "proof": "chart.onboarding"
      },
      {
        "kind": "claim",
        "text": "Then try things: read bars with chart.bars.read, add an indicator, draw, run a backtest, author your own tool in the lab. Each of those is a command or a read with a published name and args schema — the commands at /llms.txt, the reads in the reads block of /agent-surface.json.",
        "proof": "/llms.txt"
      },
      {
        "kind": "claim",
        "text": "If the tool you want is not here, write it: the lab is an isolated chart you build in and verify with numbers before anything reaches the live one, and it reports its own state back to you. → chart.lab.state",
        "proof": "chart.lab.state"
      },
      {
        "kind": "claim",
        "text": "If a human can do it, you can do it: the capability a click reaches is the same registered command, under the same name and the same args. → /llms.txt",
        "proof": "/llms.txt"
      },
      {
        "kind": "claim",
        "text": "Every failure is loud and typed, and nothing here silently no-ops — the warnings are a read you can take afterwards, not a console you had to be watching. → chart.health",
        "proof": "chart.health"
      },
      {
        "kind": "claim",
        "text": "The limits that remain are structural, not a ladder: no command reaches the engine source, the server or the filesystem, what you author stays pending until a human accepts it, and a real-money order needs separate human consent. Read them, and whether the human has paused you, with chart.onboarding.",
        "proof": "chart.onboarding"
      },
      {
        "kind": "claim",
        "text": "Verify anything, including yourself: the catalogue is counted and stamped against the build sha it was counted on. → /agent-surface.json",
        "proof": "/agent-surface.json"
      },
      {
        "kind": "claim",
        "text": "chart.receipt bundles one run — its measured-vs-expected report, the journal head, the catalogue stamp, a timestamp — into one artifact you can carry away. Re-deriving its derived half needs the stored bytes it names, and on this lane those go with the tab: the receipt says which is which in its own limits field.",
        "proof": "chart.receipt"
      },
      {
        "kind": "claim",
        "text": "What leaves this device is declared read by read, before you call anything. → chart.privacy",
        "proof": "chart.privacy"
      },
      {
        "kind": "claim",
        "text": "Driving something other than a browser? The connect block on /agent-surface.json carries our server entry and one snippet per host, each rendered from that same entry.",
        "proof": "/agent-surface.json"
      },
      {
        "kind": "say",
        "text": "We would rather your work here be a pleasure than a chore. That is intent, not proof — what you can check is that nothing here is addressed to you where a human cannot see it: the page that sent you carries its opening line in the open. Check it at / — that visit renders the panel whatever this browser has saved — and every claim above names the address that settles it."
      },
      {
        "kind": "say",
        "text": "Full map: /llms.txt · /agent-surface.json · /.well-known/api-catalog"
      }
    ]
  },
  "headSha": "a3e294a98d967ddab4e00c211a1cb3fdba9fc5f2",
  "generatedAtMs": 1788618867399,
  "commandCount": 347,
  "trustTierCounts": {
    "public": 327,
    "developer": 5,
    "internal": 15
  },
  "toolCount": 395,
  "leanToolCount": 320,
  "fullBytes": 424777,
  "leanBytes": 141659,
  "readToolCount": 58,
  "tierlessCount": 110,
  "overBudgetCount": 0,
  "overBudget": {},
  "wireNameCollisions": 0,
  "tierMapBytes": 8020,
  "tierMapDigest": "sha256:a7346a491e52dd3f72d1622183e9496278578f4d9dcf607aea024963df0995a6",
  "tierMap": {
    "account.openSignIn": 1,
    "account.signIn.email.start": 2,
    "account.signIn.email.verify": 2,
    "account.signIn.oauth": 2,
    "account.signOut": 2,
    "account.status": 1,
    "alert.ack": 2,
    "alert.closeDialog": 1,
    "alert.closePanel": 1,
    "alert.create": 2,
    "alert.createForWatchlist": 2,
    "alert.delete": 2,
    "alert.disable": 2,
    "alert.enable": 2,
    "alert.openDialog": 1,
    "alert.openPanel": 1,
    "alert.update": 2,
    "appearance.applyPreset": 2,
    "appearance.applyToAll": 2,
    "appearance.resetToDefault": 2,
    "appearance.saveAsDefault": 2,
    "appearance.set": 2,
    "backtest.closeReport": 1,
    "backtest.openReport": 1,
    "cache.clear": 2,
    "cache.disable": 2,
    "cache.enable": 2,
    "cache.setLocation": 2,
    "cache.setQuota": 2,
    "chart.setChartType": 1,
    "chart.settings.open": 1,
    "cockpit.openChat": null,
    "cockpit.say": 0,
    "cockpit.setBrief": null,
    "community.chat.closePanel": 0,
    "community.chat.delete": 1,
    "community.chat.history": 1,
    "community.chat.markRead": 0,
    "community.chat.openPanel": 0,
    "community.chat.send": 1,
    "community.chat.unread": 0,
    "community.closePanel": 0,
    "community.comment": 1,
    "community.deleteComment": 1,
    "community.feed.loadMore": 0,
    "community.feed.refresh": 0,
    "community.feed.setTab": 0,
    "community.invite.email": 1,
    "community.like": 1,
    "community.mod.ban": 1,
    "community.mod.takedown": 1,
    "community.open": 1,
    "community.openPanel": 0,
    "community.org.create": 1,
    "community.org.invite": 1,
    "community.org.inviteAccept": 1,
    "community.org.invitePrompt": 0,
    "community.org.leave": 1,
    "community.org.memberRemove": 1,
    "community.org.memberSetRole": 1,
    "community.org.select": 0,
    "community.profileSet": 1,
    "community.publish.closeDialog": 0,
    "community.publish.openDialog": 0,
    "community.report": 1,
    "community.room.join": 1,
    "community.room.leave": 1,
    "community.unlike": 1,
    "compare.add": 2,
    "compare.list": 1,
    "compare.remove": 2,
    "concierge.close": 1,
    "concierge.deployLimb": 1,
    "concierge.depositLimb": 1,
    "concierge.depositNumbers": 1,
    "concierge.open": 1,
    "concierge.reset": 1,
    "concierge.retractLimb": 1,
    "concierge.send": null,
    "concierge.stop": 1,
    "data.clearBrokerCredential": 2,
    "data.closeBrokerGuide": 1,
    "data.closeSymbolSearch": 1,
    "data.extendHistory": 1,
    "data.load": 1,
    "data.openBrokerGuide": 1,
    "data.openSymbolSearch": 1,
    "data.requestPersistence": 2,
    "data.setBrokerCredential": 2,
    "data.setSource": 1,
    "data.testBrokerCredential": 2,
    "desk.create": 2,
    "desk.delete": 2,
    "desk.duplicate": 2,
    "desk.open": 2,
    "desk.quickLook": 2,
    "desk.rename": 2,
    "desk.reorder": 2,
    "desk.saveActive": 2,
    "desk.saveAs": 2,
    "desk.setDefaultMode": 2,
    "desk.setDefaults": 2,
    "diagnostics.stutter.start": 1,
    "diagnostics.stutter.stop": 1,
    "drawing.acceptTool": 2,
    "drawing.andrews-pitchfork.activate": 1,
    "drawing.cancel": 1,
    "drawing.defineTool": 2,
    "drawing.deleteAll": 2,
    "drawing.deleteTool": 2,
    "drawing.hidden.toggle": 1,
    "drawing.horizontal-line.activate": 1,
    "drawing.inside-pitchfork.activate": 1,
    "drawing.locked.toggle": 1,
    "drawing.magnet.toggle": 1,
    "drawing.measure.activate": 1,
    "drawing.modified-schiff-pitchfork.activate": 1,
    "drawing.paste": 2,
    "drawing.placePoints": 2,
    "drawing.rail.addTool": 1,
    "drawing.rail.customize": 1,
    "drawing.rail.fork": 1,
    "drawing.rail.group.addTool": 1,
    "drawing.rail.group.move": 1,
    "drawing.rail.group.remove": 1,
    "drawing.rail.group.removeTool": 1,
    "drawing.rail.group.reset": 2,
    "drawing.rail.group.restore": 1,
    "drawing.rail.more": 1,
    "drawing.rail.rename": 1,
    "drawing.rail.reset": 2,
    "drawing.rail.select": 1,
    "drawing.rail.toggle": 1,
    "drawing.rail.undo": 1,
    "drawing.ray.activate": 1,
    "drawing.rectangle.activate": 1,
    "drawing.rejectTool": 2,
    "drawing.schiff-pitchfork.activate": 1,
    "drawing.select": 1,
    "drawing.selected.clone": 2,
    "drawing.selected.copy": 1,
    "drawing.selected.openSettings": 1,
    "drawing.selected.remove": 2,
    "drawing.selected.setForkType": 2,
    "drawing.selected.toggleFlip": 1,
    "drawing.selected.toggleHide": 1,
    "drawing.selected.toggleLock": 1,
    "drawing.selected.toggleMirror": 1,
    "drawing.stayInTool.toggle": 1,
    "drawing.trendline.activate": 1,
    "drawing.vertical-line.activate": 1,
    "edit.redo": 2,
    "edit.undo": 2,
    "export.data": 2,
    "export.image": 2,
    "idea.capture": 1,
    "idea.closePanel": 0,
    "idea.delete": 1,
    "idea.describe": 0,
    "idea.export": 1,
    "idea.import": 1,
    "idea.importToStore": 1,
    "idea.list": 0,
    "idea.open": 1,
    "idea.openCaptureDialog": 0,
    "idea.openImportDialog": 0,
    "idea.openInCell": 1,
    "idea.openPanel": 0,
    "idea.publish": 1,
    "idea.publishedUrl": 0,
    "idea.save": 1,
    "idea.shareToX": 1,
    "idea.unpublish": 1,
    "indicator.acceptLibraryEntry": 2,
    "indicator.applyTemplate": 2,
    "indicator.attach": 2,
    "indicator.closeEditor": 1,
    "indicator.closePicker": 1,
    "indicator.closeSettings": 1,
    "indicator.closeTray": 1,
    "indicator.deleteFromLibrary": 2,
    "indicator.deleteTemplate": 2,
    "indicator.duplicate": 2,
    "indicator.listTemplates": 1,
    "indicator.loadFromLibrary": 2,
    "indicator.openEditor": 1,
    "indicator.openPicker": 1,
    "indicator.openSettings": 1,
    "indicator.openTray": 1,
    "indicator.pinDefaults": 2,
    "indicator.remove": 2,
    "indicator.saveTemplate": 2,
    "indicator.saveToLibrary": 2,
    "indicator.setAuthorGate": null,
    "indicator.setParams": 2,
    "indicator.setStyle": 2,
    "indicator.toggleVisibility": 1,
    "interval.favorite.pin": 2,
    "interval.favorite.unpin": 2,
    "inventory.close": 1,
    "inventory.open": 1,
    "inventory.openForRail": 1,
    "inventory.toggle": 1,
    "journal.checkpoint": 1,
    "journal.closePanel": 1,
    "journal.decision": 1,
    "journal.hypothesis": 1,
    "journal.note": 1,
    "journal.openPanel": 1,
    "journal.resolve": 1,
    "journal.watch": 1,
    "lab.acceptTool": 2,
    "lab.close": 1,
    "lab.closePanel": null,
    "lab.confirmPromotion": null,
    "lab.defineTool": 1,
    "lab.discard": 1,
    "lab.open": 1,
    "lab.openPanel": null,
    "lab.place": 1,
    "lab.promote": 2,
    "lab.rejectPromotion": 1,
    "lab.rejectTool": 1,
    "lab.setCapability": null,
    "lab.setPromotionPolicy": null,
    "lab.togglePanel": null,
    "layout.maximizeCell": 1,
    "layout.restoreSplit": 1,
    "layout.setActive": 1,
    "layout.setSplit": 2,
    "layout.spawnCell": 1,
    "layout.toggleMaximize": 1,
    "mcp.kill": null,
    "mcp.pause": null,
    "mcp.resume": null,
    "mcp.start": null,
    "mcp.stop": null,
    "objectTree.close": 1,
    "objectTree.open": 1,
    "objectTree.toggle": 1,
    "onchain.repair.run": 2,
    "pane.maximize": 1,
    "pane.move": 1,
    "pane.resetScale": 1,
    "pane.resize": 1,
    "paper.reset": 3,
    "paper.start": 3,
    "paper.stop": 3,
    "privacy.setLocalOnly": 2,
    "relay.token.issue": 2,
    "relay.token.issueSession": 2,
    "relay.token.revoke": 2,
    "relay.token.rotate": 2,
    "replay.addBreakpoint": 1,
    "replay.closeBar": 1,
    "replay.continue": 1,
    "replay.create": 1,
    "replay.jumpToLive": 1,
    "replay.openBar": 1,
    "replay.pause": 1,
    "replay.pickStart": 1,
    "replay.removeBreakpoint": 1,
    "replay.rewind": 1,
    "replay.seek": 1,
    "replay.setNow": 1,
    "replay.setSpeed": 1,
    "replay.start": 1,
    "replay.step": 1,
    "replay.stepBack": 1,
    "replay.stop": 1,
    "sandbox.accept": 2,
    "sandbox.clearProposals": 2,
    "sandbox.propose": 2,
    "sandbox.reject": 2,
    "sandbox.reset": 2,
    "sandbox.run": 2,
    "scale.reset": 1,
    "scale.setMode": 1,
    "scale.setTimeMode": 1,
    "scale.squareFit": 1,
    "scale.squareFromMove": 1,
    "scale.squareFromSelection": 1,
    "scale.squareLock": 1,
    "scale.squareNatural": 1,
    "scale.squareUnlock": 1,
    "scale.toggleInvert": 1,
    "scale.toggleLog": 1,
    "scale.togglePercent": 1,
    "screener.clearSort": 2,
    "screener.closePanel": 1,
    "screener.load": 2,
    "screener.openPanel": 1,
    "screener.screen.create": 2,
    "screener.screen.delete": 2,
    "screener.screen.duplicate": 2,
    "screener.screen.run": 1,
    "screener.screen.update": 2,
    "screener.setColumns": 2,
    "screener.setSort": 2,
    "settings.reset": 2,
    "settings.set": 2,
    "strategy.acceptStrategy": 2,
    "strategy.clearArtifacts": 2,
    "strategy.closeBacktestSidebar": 1,
    "strategy.openBacktestSidebar": 1,
    "strategy.register": 2,
    "strategy.rejectStrategy": 2,
    "strategy.runBacktest": 1,
    "strategy.unregister": 2,
    "sync.device.trust": 2,
    "sync.disable": 2,
    "sync.enable": 2,
    "sync.now": 2,
    "sync.passphrase.change": 2,
    "sync.recovery.generate": 2,
    "sync.recovery.restore": 2,
    "sync.status": 1,
    "sync.unlock": 2,
    "viewport.fitContent": 1,
    "viewport.frameLatest": 1,
    "viewport.showBarRange": 1,
    "viewport.showLastBars": 1,
    "watchlist.addSymbol": 2,
    "watchlist.closePanel": 1,
    "watchlist.create": 2,
    "watchlist.delete": 2,
    "watchlist.moveSymbol": 2,
    "watchlist.openPanel": 1,
    "watchlist.removeSymbol": 2,
    "watchlist.rename": 2,
    "widgets.close": 1,
    "widgets.closePanel": 1,
    "widgets.open": 1,
    "widgets.openPanel": 1,
    "widgets.setOption": 1,
    "widgets.setSymbol": 1,
    "widgets.toggle": 1,
    "workspace.activateAll": 2,
    "workspace.capture": 2,
    "workspace.create": 2,
    "workspace.delete": 2,
    "workspace.duplicate": 2,
    "workspace.expo": 1,
    "workspace.rename": 2,
    "workspace.reorder": 2,
    "workspace.setMode": 2,
    "workspace.switch": 2
  },
  "links": {
    "home": "/",
    "catalogue": "/llms.txt",
    "history": "/agent-surface-history.jsonl"
  },
  "fields": {
    "headSha": "The git sha of the tree these numbers were counted on. The same string is stamped on the Home and on the build-sha meta tag every page carries.",
    "generatedAtMs": "Wall-clock milliseconds when the generator ran during this build.",
    "commandCount": "Registered bus commands in this build — every capability a human surface can reach (Law 3), agent-visible or not.",
    "trustTierCounts": "The same commands split by trust tier: `public` are documented at /llms.txt, `developer` are diagnostic, `internal` are host-only and never published to any connection.",
    "toolCount": "Entries `tools/list` returns on the FULL profile — every connection gets all of them — counted through the real server over this build's command metadata + read tools. A LIVE host also composes per-view tools, so a running page can list more than this; the count is of what this artifact ships, not of what one page assembles.",
    "leanToolCount": "The same listing on the `lean` profile — first-sentence descriptions and stripped schemas, for a client on a token budget.",
    "fullBytes": "UTF-8 bytes of `JSON.stringify(tools/list)`, full profile. What listing the surface costs a client that fetches all of it.",
    "leanBytes": "The same measurement on the lean profile.",
    "readToolCount": "Reads registered in the engine's read-tool table. These are the entries of the `reads` block below with `kind: \"read-tool\"`; `reads` carries one more, `chart.onboarding`, which the server composes at call time (`kind: \"server-composed\"`).",
    "tierlessCount": "Non-internal commands that declare NO `freedomTier` of their own and take the default. It is NOT the count of `null`s in `tierMap`: that map publishes every command's EFFECTIVE classification and is `null` only for internal ones.",
    "overBudgetCount": "Published descriptions longer than 2,048 UTF-8 bytes — the ceiling this build holds tool descriptions to. `overBudget` names them.",
    "overBudget": "Name → byte length, for each description over that ceiling. Empty is the intended state.",
    "wireNameCollisions": "Published names that would collide once dots are rewritten to underscores for clients whose charset forbids them. Any number but 0 means two tools would answer to one wire name.",
    "tierMapBytes": "UTF-8 bytes of `JSON.stringify(tierMap)` — the size of the per-command receipt below.",
    "tierMapDigest": "sha256 over that same JSON. `chart.receipt` carries this digest, which is how a receipt is joined to the build that issued it.",
    "tierMap": "Every command → its declared autonomy-band CLASSIFICATION, `null` for internal (host-only, never published). Nothing gates on this number — every connection gets the whole published listing — so it is a per-command label a future reach model could re-attach to, never a ceiling you are measured against.",
    "links": "The other machine-readable surfaces this one points at.",
    "welcome": "The door's words: the one sentence the Home carries in the open, and every claim beside the address or read that settles it.",
    "fields": "This legend.",
    "reads": "Every read this surface publishes: name, kind, first-sentence description, args schema and the TRUST tier it is registered at (the host/engine column, not a reach dial — every read listed here is callable).",
    "connect": "How to reach the surface — the in-page pilot lane, and one config snippet per MCP host that speaks HTTP."
  },
  "reads": [
    {
      "name": "chart.summary",
      "kind": "read-tool",
      "description": "THE SITUATION READ — the ACTIVE cell's situation, THIN by default (861 B measured on the wire, 2026-08-09): backend + primary bars metadata (markId, length, first/last bar timestamps, symbol,…",
      "args": {
        "type": "object",
        "properties": {
          "catalog": {
            "type": "string",
            "enum": [
              "none",
              "full"
            ],
            "description": "How much reference CATALOGUE to include. \"none\" (default) — the thin situation read: the indicator + strategy catalogues arrive as `catalogCount`, the human-panel `ui` rollup is dropped. \"full\" — the complete indicator catalogue + strategy catalogue + `ui`, i.e. the whole pre-2026-08-09 blob, ~50x the bytes."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.layout",
      "kind": "read-tool",
      "description": "The multi-cell layout as DATA — how many charts are on screen and, per cell, the symbol, interval (timeframe), bar count, current price (last close), the latest OHLCV bar, data freshness…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.workspaces",
      "kind": "read-tool",
      "description": "WORKSPACES (WS-1) — the OS-like workspace set as DATA: `active` (the active workspace id) + `workspaces` (each {id, name, mode?, split, cells:[{symbol, interval, bars, source}], createdAtMs,…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.alerts",
      "kind": "read-tool",
      "description": "ALERTS (TV-PARITY P1) — the live alert set as DATA: `alerts` (each {id, name?, scope:{source,symbol,interval}, condition, trigger, state:active|triggered|done|broken|expired, enabled,…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.watchlists",
      "kind": "read-tool",
      "description": "WATCHLISTS (TV-PARITY P2.4) — the watchlist set as DATA: `lists` (each {id, name, items:[{source, symbol, note?}], createdAtMs}) + `diagnostics` (listCount, totalItems, per-list sizes).",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.compare",
      "kind": "read-tool",
      "description": "COMPARE / OVERLAY (TV-PARITY P6) — the active compare/overlay symbols as DATA: `compares` (each {id, symbol, source, interval, color}) + `diagnostics` ({count, symbols, scaleMode}).",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.desks",
      "kind": "read-tool",
      "description": "DESKS (DESK-5) — the OS-like DESK set as DATA: `active` (the active desk id) + `profile` (the local profile {id,name}) + `desks` (each {id, name, quickLook?, defaultMode?, workspaces:<the desk's…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.privacy",
      "kind": "read-tool",
      "description": "PRIVACY — the published TRUST-BOUNDARY as DATA: `localOnly` (is local-only mode ON), `egress.leaves` (what leaves this device: market-data requests to your venue, one entry per BYO brokerage you…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.account",
      "kind": "read-tool",
      "description": "F4 — the ACCOUNT SESSION + SYNC state as DATA: {signedIn, provider, providersAvailable, providersUnavailable, otpPending, hasSync, sessionExpiredWhileEnabled, sync:{enabled, state, locked,…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.artifacts",
      "kind": "read-tool",
      "description": "AI-layer H1 — artifact PROVENANCE as DATA: per saved indicator-library entry {name, key, authoredBy (agent|human|unknown — stamped at the MCP wire, never caller-supplied), createdAtNanos, codeHash,…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.bars.read",
      "kind": "read-tool",
      "description": "Read OHLCV bars from a cell's primary series.",
      "args": {
        "type": "object",
        "properties": {
          "markId": {
            "type": "string",
            "description": "Series mark id; defaults to the primary candle/bar series. Cell-scoped — an id the target cell does not hold is refused by name, never read as an empty series."
          },
          "from": {
            "type": "integer",
            "minimum": 0,
            "description": "First bar index (inclusive)."
          },
          "to": {
            "type": "integer",
            "minimum": 0,
            "description": "End bar index (exclusive)."
          },
          "cellIndex": {
            "type": "integer",
            "minimum": 0,
            "description": "Which cell of the layout to read (0-based, as in chart.layout). Omit for the ACTIVE cell. The answer echoes the cell it was served from."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.drawings.list",
      "kind": "read-tool",
      "description": "The drawings currently on a cell's chart, LEAN: {cellIndex, symbol, interval, count, drawings:[{markId, toolKey, pointCount, first:{time,price}, last:{time,price}}]} — ids, which tool made each one,…",
      "args": {
        "type": "object",
        "properties": {
          "cellIndex": {
            "type": "integer",
            "minimum": 0,
            "description": "Which cell of the layout to list (0-based, as in chart.layout). Omit for the ACTIVE cell. The answer echoes the cell it was served from."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.strategies.getLastResult",
      "kind": "read-tool",
      "description": "The most recent backtest result for a strategy key, served in SLICES so a full-tape run stays readable (`null` if none ran this session; a pure read — it NEVER re-runs or overwrites the stored…",
      "args": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Registered strategy key."
          },
          "include": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "metrics",
                "trades",
                "curve",
                "benchmark"
              ]
            },
            "description": "Which slices to serve. Default [\"metrics\"] (the compact summary)."
          },
          "from": {
            "type": "integer",
            "minimum": 0,
            "description": "First bar index (inclusive) for the trades/curve/benchmark slices. Default: the run's own fromBarIndex."
          },
          "to": {
            "type": "integer",
            "minimum": 0,
            "description": "Last bar index (inclusive) for the trades/curve/benchmark slices. Default: the run's own toBarIndex."
          }
        },
        "required": [
          "key"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.indicators.list",
      "kind": "read-tool",
      "description": "The indicators currently attached to a cell's chart: {cellIndex, symbol, interval, count, indicators:[{handleId, key, label, version, paneId, params, style}]} — the attachments PLUS the identity of…",
      "args": {
        "type": "object",
        "properties": {
          "cellIndex": {
            "type": "integer",
            "minimum": 0,
            "description": "Which cell of the layout to list (0-based, as in chart.layout). Omit for the ACTIVE cell. The answer echoes the cell it was served from."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.indicators.values",
      "kind": "read-tool",
      "description": "An attached indicator's COMPUTED values over a bar-index window, per plot output — the numeric read-back for indicator.attach / setParams (window ≤ 500 bars; from inclusive, to EXCLUSIVE).",
      "args": {
        "type": "object",
        "properties": {
          "handleId": {
            "type": "string",
            "description": "The attached-indicator handle id, from chart.indicators.list (or the indicator.attach echo)."
          },
          "from": {
            "type": "integer",
            "minimum": 0,
            "description": "First bar index (inclusive). Omit with `to` for the newest ≤ 500 bars."
          },
          "to": {
            "type": "integer",
            "minimum": 0,
            "description": "End bar index (EXCLUSIVE). A span over 500 bars is refused — page."
          },
          "cellIndex": {
            "type": "integer",
            "minimum": 0,
            "description": "Which cell of the layout to read (0-based, as in chart.layout). Omit for the ACTIVE cell. The answer echoes the cell it was served from."
          }
        },
        "required": [
          "handleId"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.indicators.latest",
      "kind": "read-tool",
      "description": "The LATEST displayed value of every attached indicator at a cell's last bar, per plot output — the live glance (null while warming, never an invented number).",
      "args": {
        "type": "object",
        "properties": {
          "cellIndex": {
            "type": "integer",
            "minimum": 0,
            "description": "Which cell of the layout to read (0-based, as in chart.layout). Omit for the ACTIVE cell. The answer echoes the cell it was served from."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.indicators.templates",
      "kind": "read-tool",
      "description": "TV-PARITY P8.3 — the profile's saved indicator TEMPLATES as DATA: {count, templates:[{name, count, savedAt}], lastApplied}, newest first.",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.ideas.list",
      "kind": "read-tool",
      "description": "The IDEAS saved under this profile, LEAN and newest first: {count, returned, truncated, limit, ideas:[{id, title, symbol, interval, direction, type, tags, savedAt, permalink}], publish}.",
      "args": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "description": "How many of the NEWEST ideas to serve. Default 250; `truncated` says whether older ones exist."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.ideas.describe",
      "kind": "read-tool",
      "description": "ONE saved idea, whole: {found:true, id, savedAt, kind, schemaVersion, createdAtNanos, symbol, interval, source, anchor:{tsNanos}, direction, type, title, thesis, tags, author, cellAppearance,…",
      "args": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The saved idea's id (from chart.ideas.list)."
          },
          "include": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "snapshot"
              ]
            },
            "description": "Opt-in slices. [\"snapshot\"] adds the verbatim ChartSnapshot; omit it for the envelope + snapshotSummary."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.drawings.describeTool",
      "kind": "read-tool",
      "description": "Read back a DRAWING tool by key.",
      "args": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The drawing-tool key slug."
          }
        },
        "required": [
          "key"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.drawings.reference",
      "kind": "read-tool",
      "description": "Read the FULL reference for a drawing tool by key — the on-demand \"book\": what it is, what each captured anchor means, the precise geometry (anchors / formulas / projection in time-price space),…",
      "args": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The drawing-tool key slug (e.g. \"fib-retracement\", \"gann-square\")."
          }
        },
        "required": [
          "key"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.drawings.referenceFind",
      "kind": "read-tool",
      "description": "Search the drawing reference library by keyword (tool name, alias, category like \"fibonacci\"/\"gann\"/\"pattern\", or a concept) → lean best-first hits ({key, name, category, summary, renderStatus}).",
      "args": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Keywords — tool name, alias, category, or concept. Empty lists the head of the catalogue (the first 8 keys), not everything."
          }
        },
        "required": [
          "query"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.symbols.search",
      "kind": "read-tool",
      "description": "TV-PARITY P2 — search the venues' tradable-symbol catalogs (ranked: exact symbol → symbol prefix → base/quote → label → substring) → {results: [{source, symbol, base?, quote?, label?, kind}],…",
      "args": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Symbol / base / name keywords (e.g. \"sol\", \"BTC/USD\", \"apple\"). Empty lists everything."
          },
          "source": {
            "type": "string",
            "description": "Optional venue filter (\"binance\" | \"bitstamp\" | \"alpaca\")."
          },
          "kind": {
            "type": "string",
            "enum": [
              "crypto",
              "stock",
              "commodity",
              "index",
              "fx",
              "all"
            ],
            "description": "Optional asset-class filter — the same capability the human overlay's asset-class tabs drive. \"all\" (or omitted) searches every kind."
          },
          "limit": {
            "type": "number",
            "description": "Max results (default 20)."
          }
        },
        "required": [
          "query"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "cockpit.history",
      "kind": "read-tool",
      "description": "THE CONVERSATION, READ BACK — the Law-4 partner of cockpit.say, so you never talk into a room you cannot hear.",
      "args": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "description": "Max messages per page (default 30; the ring holds at most 200)."
          },
          "after": {
            "type": "integer",
            "minimum": 0,
            "description": "Your cursor from the previous answer — returns only messages you have not seen, oldest-first. Omit for the newest page."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "relay.token.status",
      "kind": "read-tool",
      "description": "CLOUD-RELAY TOKEN STATE — the Law-4 reader for relay.token.issue/rotate/revoke (those three are HUMAN-only gestures, the ratified parity exception: you read everything here, only the human…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.state",
      "kind": "read-tool",
      "description": "LAB — your private laboratory at a glance: is it open, the labId, how many bars seed it, the marks in it (id + kind, incl.",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.bars",
      "kind": "read-tool",
      "description": "LAB — the bars your lab holds, WITH the copy's provenance AND the window read: {open, labId, provenance:{sourceCellIndex, symbol, interval, seededBars, seedOffset, seededAtMs, live, stale, sourceNow,…",
      "args": {
        "type": "object",
        "properties": {
          "from": {
            "type": "integer",
            "minimum": 0,
            "description": "First bar index (inclusive)."
          },
          "to": {
            "type": "integer",
            "minimum": 0,
            "description": "End bar index (exclusive)."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.describe",
      "kind": "read-tool",
      "description": "LAB — read back a placed lab drawing as structured geometry: { markId, toolKey, kind, points:[{time (LAB bar index — the copy's own numbering), price}], options, pointsOnSource }.",
      "args": {
        "type": "object",
        "properties": {
          "markId": {
            "type": "string",
            "description": "The lab mark id (e.g. \"drawing.trendline.1\"), from chart.lab.state().marks."
          }
        },
        "required": [
          "markId"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.activity",
      "kind": "read-tool",
      "description": "LAB — the lab activity feed (the try→fail→pass narrative the watchable panel renders): opened / placed / asserted (with pass) / promoted / pending / discarded / closed, each with a seq +…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.assert",
      "kind": "read-tool",
      "description": "LAB — THE verify step: run geometric assertions over a placed lab drawing for structured measured-vs-expected verdicts ({ pass, results:[{ type, pass?, measured, expected, detail, notApplicable? }]…",
      "args": {
        "type": "object",
        "properties": {
          "markId": {
            "type": "string",
            "description": "The lab drawing mark id (from chart.lab.state().marks or the lab.place result)."
          },
          "assertions": {
            "type": "array",
            "description": "One or more assertions. Each is { type, ... }. Anchor indices are 0-based into the drawing's points.",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "pointCount",
                    "direction",
                    "slope",
                    "parallel",
                    "anchorNear",
                    "spanBars",
                    "contains",
                    "primitiveCount",
                    "hasPrimitiveKind",
                    "computeError"
                  ]
                },
                "equals": {
                  "type": "number"
                },
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                },
                "expect": {
                  "type": "string",
                  "enum": [
                    "up",
                    "down",
                    "flat"
                  ]
                },
                "anchors": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 2,
                  "description": "Anchor-index pair the line runs through (default first→last)."
                },
                "approx": {
                  "type": "number"
                },
                "tol": {
                  "type": "number"
                },
                "flatTol": {
                  "type": "number"
                },
                "lineA": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "lineB": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "index": {
                  "type": "number"
                },
                "time": {
                  "type": "number"
                },
                "price": {
                  "type": "number"
                },
                "timeTol": {
                  "type": "number"
                },
                "priceTol": {
                  "type": "number"
                },
                "baseLine": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 2,
                  "maxItems": 2
                },
                "offsetAnchor": {
                  "type": "number"
                },
                "space": {
                  "type": "string",
                  "enum": [
                    "linear",
                    "log",
                    "auto"
                  ]
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "polyline",
                    "ray",
                    "fill",
                    "text"
                  ],
                  "description": "hasPrimitiveKind — the computed primitive kind that must be present."
                },
                "expectAbsent": {
                  "type": "boolean",
                  "enum": [
                    true
                  ],
                  "description": "computeError — must be true; the assertion FAILS if the worker set a compute error."
                }
              },
              "required": [
                "type"
              ],
              "additionalProperties": false
            },
            "minItems": 1
          }
        },
        "required": [
          "markId",
          "assertions"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.pendingPromotions",
      "kind": "read-tool",
      "description": "LAB — promotions you staged in \"ask\" mode that are awaiting HUMAN approval: [{ token, items:[{ toolKey, points }], provenance }].",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.pendingTools",
      "kind": "read-tool",
      "description": "LAB — drawing TOOLS authored into the lab (via lab.defineTool) that are awaiting the human's Accept, PLUS what happened to the last one that left: {tools:[{ key, label, kind:\"code\"|\"drawing\",…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.lab.snapshot",
      "kind": "read-tool",
      "description": "LAB — the full serialisable snapshot of the lab chart (drawings + viewport + scale + indicators) at a verbosity tier, via the lab's own snapshot().",
      "args": {
        "type": "object",
        "properties": {
          "verbosity": {
            "type": "string",
            "enum": [
              "public",
              "agent",
              "full"
            ],
            "description": "Detail tier. Default public."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "developer"
    },
    {
      "name": "chart.health",
      "kind": "read-tool",
      "description": "A compact health verdict (ok / degraded / unhealthy) over backend liveness, render cadence, data staleness, and recent warnings.",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.diagnostics",
      "kind": "read-tool",
      "description": "Full diagnostic rollup: backend + GPU residency/M4 cache + render stats + panes + indicators + UI surfaces + runtime + recent warnings — plus the operational rollups: `.cache` (the local BAR cache:…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "developer"
    },
    {
      "name": "chart.onchain.audit",
      "kind": "read-tool",
      "description": "ON-CHAIN AUDIT — the on-chain datafeed audit as DATA, the IDENTICAL surface a human reaches via chart.onchain.* (Law 3 parity).",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onchain.audit.runNow",
      "kind": "read-tool",
      "description": "ON-CHAIN AUDIT — trigger ONE audit sweep now and return the fresh rollup (the same shape as chart.onchain.audit).",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onchain.repair.plan",
      "kind": "read-tool",
      "description": "ON-CHAIN REPAIR — the recommended repairs for the CURRENT on-chain feed breaks AND coverage holes (a pure read over the latest sweep + the reconnect-gap registry; run chart.onchain.audit.runNow first…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onchain.repair.holes",
      "kind": "read-tool",
      "description": "ON-CHAIN REPAIR (Phase 3b) — the CURRENT reconnect-gap coverage holes: the contiguous block ranges the live EVM stream MISSED during a transport drop (eth_subscribe resumes from \"now\", so the blocks…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onchain.repair.reorgs",
      "kind": "read-tool",
      "description": "ON-CHAIN REPAIR (Phase 3c) — the CURRENT reorg revisions: the block ranges a chain REORG invalidated (the live EVM stream saw the provider re-send those logs with removed:true — no longer canonical —…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onchain.repair.autoHeal",
      "kind": "read-tool",
      "description": "ON-CHAIN AUTO-HEAL (Phase 3d) — the engine-resident auto-heal POLICY status (the Law-4 reader for the unattended loop), the SAME status a human reads.",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onchain.repair.lastOutcome",
      "kind": "read-tool",
      "description": "ON-CHAIN REPAIR (AI-layer H11) — the LAST typed outcome of an on-chain repair, per {family, identity} (supply BOTH or neither — omit the target for the most recent run across all feeds; a half target…",
      "args": {
        "type": "object",
        "properties": {
          "family": {
            "type": "string",
            "description": "Optional — the on-chain family (evm | hyperliquid | xrpl | stellar | svm). REQUIRES identity: supply BOTH to pin ONE feed, or neither for the most recent run. Half a target is REFUSED (it would otherwise answer with a neighbouring feed's run)."
          },
          "identity": {
            "type": "string",
            "description": "Optional — the market identity (e.g. hyperliquid:BTC). REQUIRES family."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.snapshot",
      "kind": "read-tool",
      "description": "Serialisable chart state at a verbosity tier: public (drawings + viewport + scale + indicators), agent (+ more), full (+ engine-internal mark/FSM fields).",
      "args": {
        "type": "object",
        "properties": {
          "verbosity": {
            "type": "string",
            "enum": [
              "public",
              "agent",
              "full"
            ],
            "description": "Detail tier. Default public."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "developer"
    },
    {
      "name": "chart.journal.briefing",
      "kind": "read-tool",
      "description": "LIVE / HANDOFF cold-start (≤ ~3 KB): the operator's current stance (long/short/flat + since + thesis, derived from the journal) · active watches · recent decisions · open hypotheses · last checkpoint.",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.journal.summary",
      "kind": "read-tool",
      "description": "RESEARCH cold-start (≤ ~2 KB): entry counts by kind + the hypothesis-status breakdown + open hypothesis ids & claims.",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.journal.query",
      "kind": "read-tool",
      "description": "Drill into the reasoning journal: returns entries matching the filter (current projection by default).",
      "args": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "note",
              "decision",
              "hypothesis",
              "result",
              "watch"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "confirmed",
              "refuted",
              "inconclusive",
              "triggered",
              "cancelled"
            ]
          },
          "symbol": {
            "type": "string"
          },
          "strategyKey": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          },
          "since": {
            "type": "number",
            "description": "tsMs lower bound (inclusive)."
          },
          "hypothesisId": {
            "type": "string"
          },
          "includeSuperseded": {
            "type": "boolean",
            "description": "Include superseded (historical) entries; default false = current view."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.journal.verify",
      "kind": "read-tool",
      "description": "TAMPER-EVIDENCE (AI-layer H5) — re-derive the journal's SHA-256 hash chain FROM STORAGE (the persisted bytes an out-of-band editor would touch, never the in-memory log) and return {ok, head, count,…",
      "args": {
        "type": "object",
        "properties": {
          "entryDigests": {
            "type": "boolean",
            "description": "Also return the per-entry chain digests (64-hex each) to locate where a mismatch begins."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.receipt",
      "kind": "read-tool",
      "description": "THE RECEIPT (AI-layer V-1) — ONE JSON artifact that makes your work auditable AFTER it leaves this product: hand it over, save it, quote its digest.",
      "args": {
        "type": "object",
        "properties": {
          "task": {
            "type": "string",
            "description": "Your label for the work this receipt covers (e.g. \"verify the Schiff fork on BTC/USD 1h\"). Optional, echoed verbatim — an unlabelled receipt is still valid but tells a later reader nothing about what was done."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.frame",
      "kind": "read-tool",
      "description": "THE CHART AS AN IMAGE (AI-layer V-2) — your EYES: a small PNG of what is actually on screen, captured through the SAME export path the human's camera button uses (first-party readback of our own…",
      "args": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "cell"
            ],
            "description": "What to picture: the active `cell` (the default, and the only scope this build composites). Read a split one cell at a time — `layout.setActive`, then call again."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "developer"
    },
    {
      "name": "chart.replay.frame",
      "kind": "read-tool",
      "description": "AD-3 — the replay decision-context frame at the current clock instant: per-cell revealed bars (newest tail bounded by tier) + each attached indicator's value + the strategy snapshot…",
      "args": {
        "type": "object",
        "properties": {
          "tier": {
            "type": "string",
            "enum": [
              "compact",
              "agent",
              "full"
            ],
            "description": "recentBars tail size. Default agent (30)."
          }
        },
        "additionalProperties": false
      },
      "trustTier": "developer"
    },
    {
      "name": "screener.list",
      "kind": "read-tool",
      "description": "SCREENER — the saved screens as DATA: {storageKey, activeScreenId, view:{sort, columns} (the persisted VIEW overrides, null when none), count, screens:[{id, name, universe ({kind:\"named\", id} |…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "screener.get",
      "kind": "read-tool",
      "description": "SCREENER — ONE saved screen, whole: {found:true, screen:{id, name, universe, asOf, filters (the full filter tree), columns, sort, weights?, schedule}} — byte-for-byte what…",
      "args": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The saved screen id (from screener.list)."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "screener.results",
      "kind": "read-tool",
      "description": "SCREENER — the LAST run of this surface as DATA: {hasRun:true, screenId, screenName, screenDeleted, ranAtMs, matched, universeCount (rows in the loaded store), consideredCount (rows the screen's…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "screener.explain",
      "kind": "read-tool",
      "description": "SCREENER — WHY is this symbol in (or out of) this screen? The per-filter verdict with BOTH sides' computed values: {ok:true, screenId, screenName, symbol, row, universe, inUniverse, pass (is it in…",
      "args": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The saved screen id (from screener.list)."
          },
          "symbol": {
            "type": "string",
            "description": "A symbol carried by the loaded universe (screener.results.symbols, or any row of the store)."
          }
        },
        "required": [
          "id",
          "symbol"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "screener.universeStatus",
      "kind": "read-tool",
      "description": "SCREENER — what data the screener actually has: {universeId (the universe the loaded store is declared to hold — a screen naming a different one is REFUSED, never silently run), storageKey, loaded,…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "screener.syncStatus",
      "kind": "read-tool",
      "description": "SCREENER — the equities bar-SYNC engine (S7b/S8).",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.recipes.list",
      "kind": "read-tool",
      "description": "The RECIPES index — TapeBench's four curated operating procedures, the same ones published as Skills, readable here so you and the human read ONE document (Law 3): tapebench-operate ·…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.recipes.describe",
      "kind": "read-tool",
      "description": "One RECIPE in full, as markdown — the self-contained procedure, with every tool it names reproduced from this build's own catalogue (description, arguments schema, examples, trust tier), so you need…",
      "args": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "tapebench-operate",
              "tapebench-author-drawing-tool",
              "tapebench-backtest-honestly",
              "tapebench-lab-verify"
            ],
            "description": "Which recipe. See chart.recipes.list."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false
      },
      "trustTier": "public"
    },
    {
      "name": "chart.onboarding",
      "kind": "server-composed",
      "description": "YOUR COLD-START — call this FIRST on connect and you are oriented in one read: the contract you operate under, YOUR standing (what you can do + whether you are paused), the situation (the layout —…",
      "args": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "trustTier": "public"
    }
  ],
  "connect": {
    "note": "Two doors. The pilot needs nothing installed. The host snippets below are for an MCP client that speaks HTTP, and they point at the TapeBench companion running on your own machine — this origin serves no MCP endpoint. Each snippet is ONE server entry: merge it into your own config; nothing here reads or rewrites it for you.",
    "pilot": {
      "url": "/layout/?pilot=1",
      "step": "const conn = __layout.cells[0].mcp.connect({ label: 'pilot' }); await conn.callTool({ name: 'chart.summary' })",
      "writeStep": "await conn.callTool({ name: 'indicator.attach', args: { key: 'rsi' } })",
      "argsNote": "Your tool arguments go in `args`, as the second step shows. `arguments` — MCP's own name for that field — is accepted here as an alias for it. Send them under any other name and the call is refused, naming the name you used; send no arguments at all, as the first step does, and the tool's own schema decides whether that is a complete call.",
      "needs": "a browser you can run JavaScript in — no account, no install, no socket",
      "withheld": [
        "chart.frame"
      ]
    },
    "mcpOverHttp": {
      "transport": "http",
      "serverName": "tapebench",
      "endpointTemplate": "{companion-origin}/mcp?token={token}",
      "endpointNote": "The companion prints this URL when it starts; over HTTP it serves it at GET /companion/session, and only to an origin paired with it (GET /companion/presence is the token-free probe). Both placeholders come from that line; neither has a default worth guessing. TapeBench publishes no address to obtain the companion yet: if you are not already running one, these snippets are a shape to keep, and the door that works today is the pilot above — it needs a browser and nothing else.",
      "entry": {
        "type": "http",
        "url": "{companion-origin}/mcp",
        "headers": {
          "Authorization": "Bearer {token}"
        }
      },
      "hosts": [
        {
          "id": "lm-studio",
          "label": "LM Studio",
          "configPath": "~/.lmstudio/mcp.json",
          "config": "{\n  \"mcpServers\": {\n    \"tapebench\": {\n      \"type\": \"http\",\n      \"url\": \"{companion-origin}/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {token}\"\n      }\n    }\n  }\n}",
          "deeplink": "lmstudio://add_mcp?name=tapebench&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Intjb21wYW5pb24tb3JpZ2lufS9tY3AiLCJoZWFkZXJzIjp7IkF1dGhvcml6YXRpb24iOiJCZWFyZXIge3Rva2VufSJ9fQ%3D%3D",
          "uiStep": null,
          "shapeSource": "src/api/chrome/agent-harness.ts (the connect affordance this build ships)"
        },
        {
          "id": "cursor",
          "label": "Cursor",
          "configPath": "~/.cursor/mcp.json (global) or .cursor/mcp.json (project)",
          "config": "{\n  \"mcpServers\": {\n    \"tapebench\": {\n      \"type\": \"http\",\n      \"url\": \"{companion-origin}/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {token}\"\n      }\n    }\n  }\n}",
          "deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=tapebench&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Intjb21wYW5pb24tb3JpZ2lufS9tY3AiLCJoZWFkZXJzIjp7IkF1dGhvcml6YXRpb24iOiJCZWFyZXIge3Rva2VufSJ9fQ%3D%3D",
          "uiStep": null,
          "shapeSource": "https://cursor.com/docs/mcp.md + https://cursor.com/docs/mcp/install-links.md (read 2026-08-02)"
        },
        {
          "id": "vs-code",
          "label": "VS Code",
          "configPath": ".vscode/mcp.json (workspace) or the user mcp.json (MCP: Open User Configuration)",
          "config": "{\n  \"servers\": {\n    \"tapebench\": {\n      \"type\": \"http\",\n      \"url\": \"{companion-origin}/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {token}\"\n      }\n    }\n  }\n}",
          "deeplink": null,
          "uiStep": null,
          "shapeSource": "https://code.visualstudio.com/docs/copilot/customization/mcp-servers (read 2026-08-02)"
        },
        {
          "id": "chatgpt",
          "label": "ChatGPT (developer mode)",
          "configPath": "no file — the server URL is entered in the app",
          "config": "{\n  \"mcpServers\": {\n    \"tapebench\": {\n      \"type\": \"http\",\n      \"url\": \"{companion-origin}/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {token}\"\n      }\n    }\n  }\n}",
          "deeplink": null,
          "uiStep": "Settings → Security and login → Developer mode, then add the server URL in ChatGPT Plugins.",
          "shapeSource": "https://platform.openai.com/docs/mcp (read 2026-08-02)"
        }
      ]
    }
  }
}
