{
  "contract_version": "1",
  "provenance": {
    "kind": "source-contract",
    "production_verified": false
  },
  "protocol_versions": {
    "legacy_guest_api": 1,
    "interactive_guest_api": 2,
    "native_abi": 3,
    "extension_manifest_schema": 1,
    "forecast_provider_api": 1
  },
  "imports": [
    {
      "name": "tradingai.has_capability",
      "signature": "(i32) -> i32",
      "behavior_source_text": "Returns 1 only when the host granted that capability. V1 exposes index 7 as `tradingRead`."
    },
    {
      "name": "tradingai.log",
      "signature": "(i32, i32) -> ()",
      "behavior_source_text": "Best-effort UTF-8 diagnostic, limited to 64 KiB. The current host does not persist logs."
    },
    {
      "name": "tradingai.market_get_candles",
      "signature": "(i32, i32, i32, i32, i32, i32) -> i32",
      "behavior_source_text": "Reads a host-staged OHLCV envelope under `tradingRead`; at most 256 bars and 128 KiB JSON. Requires native ABI v3 with candle support."
    },
    {
      "name": "tradingai.market_get_quote",
      "signature": "(i32, i32, i32, i32) -> i32",
      "behavior_source_text": "Copies a quote JSON snapshot prepared by the host for the current callback. It performs no guest network request and requires `tradingRead`. The output is limited to 16 KiB and symbols to 256 bytes."
    },
    {
      "name": "tradingai.view_set_json",
      "signature": "(i32, i32) -> i32",
      "behavior_source_text": "Publishes one JSON display per callback, at most 64 KiB. Zero means success; negative values are errors. Requires `tradingRead`; rendering requires signed `guestOutput: true` and native ABI v3 feature bit 2."
    },
    {
      "name": "tradingai.event_get_json",
      "signature": "(i32, i32) -> i32",
      "behavior_source_text": "Copies the host-staged interactive event into guest memory, up to 4 MiB. The staged event is cleared after the callback. Requires native ABI v3 feature bit 3."
    },
    {
      "name": "tradingai.output_set_json",
      "signature": "(i32, i32) -> i32",
      "behavior_source_text": "Publishes one interactive output envelope per callback, up to 2 MiB and 32 commands. The host validates the whole envelope and capability mapping before accepting it. Requires native ABI v3 feature bit 4."
    }
  ],
  "allowed_capabilities": [
    "tradingRead",
    "chartWrite",
    "alertsWrite",
    "languageModel",
    "network",
    "secrets",
    "fileSystemRead",
    "openExternal"
  ],
  "interactive_api_v2": {
    "event_types": [
      "activate",
      "action",
      "result",
      "market",
      "alert",
      "tick",
      "workspace",
      "deactivate"
    ],
    "event_example": {
      "api_version": 2,
      "type": "activate",
      "context": {
        "workspace": "opaque-namespace",
        "generation": "opaque-installation-and-workspace-generation",
        "locale": "zh",
        "now": "UTC ISO8601"
      },
      "data": {}
    },
    "context_example": {
      "workspace": "opaque-namespace",
      "generation": "opaque-installation-and-workspace-generation",
      "locale": "zh",
      "now": "UTC ISO8601"
    },
    "output_example": {
      "api_version": 2,
      "views": {
        "intraday-alerts.overview": {
          "type": "column",
          "children": []
        }
      },
      "commands": [
        {
          "id": "request-1",
          "method": "storage.read",
          "params": {}
        }
      ]
    },
    "commands": [
      {
        "method": "storage.read",
        "params_source_text": "{}",
        "result_source_text": "{value: <JSON value or null>, resume_required: <bool>}`; key `ext.<extensionId>.workspace.v1",
        "documented_capability_source_text": null,
        "required_capabilities": [],
        "conditional_capabilities": []
      },
      {
        "method": "storage.write",
        "params_source_text": "{value: <JSON value>, acknowledge_resume_required?: <bool>}",
        "result_source_text": "`{saved:true}`; authoritative workspace transaction",
        "documented_capability_source_text": null,
        "required_capabilities": [],
        "conditional_capabilities": []
      },
      {
        "method": "charts.list",
        "params_source_text": "{}",
        "result_source_text": "{charts:[{chart_id,symbol,timeframe,source_id?,reference_price?}]}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "charts.open",
        "params_source_text": "{chart_id?,symbol,timeframe,source_id?}",
        "result_source_text": "{chart_id,symbol,timeframe,source_id?}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "chartWrite"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "market.read",
        "params_source_text": "{chart_id?,symbol,timeframe,source_id?}",
        "result_source_text": "evidence object; completed bars and optional forming reference distinct",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "market.subscribe",
        "params_source_text": "{subscription_id,chart_id?,symbol,timeframe,source_id?}",
        "result_source_text": "`{subscribed:true}`; later `market` events",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "market.unsubscribe",
        "params_source_text": "{subscription_id}",
        "result_source_text": "{unsubscribed:true}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "alerts.create",
        "params_source_text": "{client_request_id,contribution_id,chart_id,symbol,timeframe,kind,price,second_price?,expires_at,title,message}",
        "result_source_text": "{id}`; confirmed/persisted and provenance stamped; kinds `rangeEntry`,`crossUp`,`crossDown",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "alertsWrite"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "alerts.list",
        "params_source_text": "{}",
        "result_source_text": "`{alerts:[{id,enabled,consumed,expired,definition_verified,triggered_at?,triggered_price?,message?,kind?,price?,second_price?}]}`; only owned rules",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "alerts.adopt",
        "params_source_text": "{plan_id,ids:[...]}",
        "result_source_text": "`{adopted_ids,rejected_ids}`; proves legacy ownership using the first-read workspace snapshot and exact native rule definition before adopting; guest-supplied ids alone confer no authority",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "alertsWrite"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "alerts.enable",
        "params_source_text": "{ids:[...],enabled}",
        "result_source_text": "{updated:true}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "alertsWrite"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "alerts.remove",
        "params_source_text": "{ids:[...]}",
        "result_source_text": "{removed:true}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "alertsWrite"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "notifications.publish",
        "params_source_text": "{id,title,body,symbol?,timeframe?,payload?}",
        "result_source_text": "`{published:true}`; local channels only",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "alertsWrite"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "models.settings",
        "params_source_text": "{provider:\"typesafe\"}",
        "result_source_text": "{enabled,model,has_api_key}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "languageModel"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "models.configure",
        "params_source_text": "{provider:\"typesafe\",enabled?,model?,clear_api_key?}",
        "result_source_text": "settings; host owns secret entry dialog",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "languageModel"
        ],
        "conditional_capabilities": [
          {
            "capability": "secrets",
            "when_source_text": "command.kind == InteractiveWasmCommandKind.modelsConfigure && !capabilities.contains(ExtensionCapability.secrets)"
          }
        ]
      },
      {
        "method": "models.test",
        "params_source_text": "{provider:\"typesafe\"}",
        "result_source_text": "{connected:true}",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "languageModel"
        ],
        "conditional_capabilities": [
          {
            "capability": "network",
            "when_source_text": "command.kind == InteractiveWasmCommandKind.modelsTest || command.kind == InteractiveWasmCommandKind.modelsDecide"
          }
        ]
      },
      {
        "method": "models.decide",
        "params_source_text": "{provider:\"typesafe\",state:<object>,questions:<object>}",
        "result_source_text": "official typed decision response JSON",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "languageModel"
        ],
        "conditional_capabilities": [
          {
            "capability": "network",
            "when_source_text": "command.kind == InteractiveWasmCommandKind.modelsTest || command.kind == InteractiveWasmCommandKind.modelsDecide"
          }
        ]
      },
      {
        "method": "models.recipe",
        "params_source_text": "{recipe:<Recipe JSON>,parameters:<string map>}",
        "result_source_text": "correlated completed output object; temporary untrusted recipe, forced read-only session with only its schema-validated result collector",
        "documented_capability_source_text": null,
        "required_capabilities": [
          "languageModel"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "feed.request",
        "params_source_text": "{kind:\"rss\"|\"json\"|\"trading_economics\"|\"mcp\",source_id,endpoint,operation?,request_id?,arguments?}",
        "result_source_text": "`{status,content_type?,headers:{retry_after?},body}`; the host owns transport headers and MCP session state. MCP operations are `initialize`, `notifications/initialized`, `tools/list`, `resources/list`, or `tools/call`; `request_id` is required for MCP requests except notifications.",
        "documented_capability_source_text": "`network`; `secrets` is additionally required for authenticated transports or stored credentials",
        "required_capabilities": [
          "network"
        ],
        "conditional_capabilities": [
          {
            "capability": "secrets",
            "when_source_text": "command.kind == InteractiveWasmCommandKind.feedRequest && (command.params['kind'] == 'trading_economics' || command.params['kind'] == 'mcp') && !capabilities.contains(ExtensionCapability.secrets)"
          }
        ]
      },
      {
        "method": "feed.credentials",
        "params_source_text": "{action:\"status\"|\"configure\"|\"clear\",source_id,kind,endpoint}",
        "result_source_text": "Returns `has_credential` with `configured` or `cleared` when applicable. Cancellation preserves the existing state. Secret values never cross the broker.",
        "documented_capability_source_text": "secrets",
        "required_capabilities": [
          "secrets"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "news.legacy",
        "params_source_text": "{}",
        "result_source_text": "`{version:1,revision?,marketIntelFeed,manualDataset}`. The host returns the v1 feed/settings/news/calendar projection for one-time guest migration, plus an optional manual dataset. Only `tradingai.market_intel` may call this migration method. Credential migration is idempotent and provider-scoped; legacy keys are not changed or deleted.",
        "documented_capability_source_text": "tradingRead",
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": [],
        "only_extension_id": "tradingai.market_intel"
      },
      {
        "method": "news.read",
        "params_source_text": "{symbol?,limit?}",
        "result_source_text": "`{news:[...]}` from the authoritative news workspace projection after migration, or the legacy projection before migration. Manually imported news uses `source_id:\"manual\"`, a known timestamp, no URL, and empty topics.",
        "documented_capability_source_text": "tradingRead",
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "calendar.read",
        "params_source_text": "{from?,to?,country?,limit?}",
        "result_source_text": "`{events:[...]}` from the same authoritative projection and migration boundary as `news.read`.",
        "documented_capability_source_text": "tradingRead",
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "ui.confirm",
        "params_source_text": "{title,message}",
        "result_source_text": "`{confirmed}` from a host-owned confirmation dialog.",
        "documented_capability_source_text": "none",
        "required_capabilities": [],
        "conditional_capabilities": []
      },
      {
        "method": "ui.import",
        "params_source_text": "{kind:\"market_intel_json\"}",
        "result_source_text": "`{cancelled,data?}` from the host file picker; input is limited to 1 MiB. This grant does not expose guest filesystem paths or general file access.",
        "documented_capability_source_text": "fileSystemRead",
        "required_capabilities": [
          "fileSystemRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "ui.openExternal",
        "params_source_text": "{url}",
        "result_source_text": "`{opened}`; the host accepts HTTPS URLs only.",
        "documented_capability_source_text": "openExternal",
        "required_capabilities": [
          "openExternal"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "context.read",
        "params_source_text": "{}",
        "result_source_text": "`{symbol?,timeframes:[],watchlist:[],foreground,now}` for the current host context.",
        "documented_capability_source_text": "tradingRead",
        "required_capabilities": [
          "tradingRead"
        ],
        "conditional_capabilities": []
      },
      {
        "method": "context.publish",
        "params_source_text": "{enabled,surface_id,title,status:\"loading\"|\"ready\"|\"empty\"|\"error\",captured_at?,context?}",
        "result_source_text": "`{published}`; the host validates surface ownership and candidate selection and enforces the Workbench snapshot size limit.",
        "documented_capability_source_text": "none",
        "required_capabilities": [],
        "conditional_capabilities": []
      },
      {
        "method": "assistant.prompt",
        "params_source_text": "{prompt,surface_id:\"news.overview\"}",
        "result_source_text": "`{accepted}` through the read-only Goose dispatch path.",
        "documented_capability_source_text": "languageModel",
        "required_capabilities": [
          "languageModel"
        ],
        "conditional_capabilities": []
      }
    ]
  }
}
