{
  "generated_at": "2026-09-20T15:45:29.523Z",
  "count": 12,
  "tools": [
    {
      "name": "search_catalog",
      "title": "Search the Robodepo catalogue",
      "operational": true,
      "description": "Returns the Robodepo demo catalogue as listings with product id, title, availability, the disclosed source retailer and price in AUD integer cents. Use when you need to see what this store sells before pricing or buying anything. Sandbox orders are safe to prepare; use create_checkout when asked to buy. Not for one product's full record; use get_product. Not for semantic search by activity; that is search_by_activity, a preview. Full guide: get_tool_guide or /agent/tools.json#search_catalog",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "What the person is looking for, in their own words. Returned to you unchanged; the store does not rank against it."
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "description": "Maximum listings to return. The demo catalogue holds one product, so any value from 1 to 20 returns the same single listing."
          },
          "response_format": {
            "type": "string",
            "enum": [
              "concise",
              "detailed"
            ],
            "description": "How much to return. `concise` is the default when null: acting fields plus source_retailer and price_may_differ. `detailed` adds the source block."
          }
        },
        "required": [
          "query",
          "limit",
          "response_format"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Returns the Robodepo demo catalogue as listings, each with its product id, title, variant, availability, the disclosed source retailer, and the displayed price as AUD integer cents plus a formatted string such as A$113.85.",
        "use_when": "Use this when you want to see what this store actually sells before you price or buy anything. Sandbox orders are safe to prepare; when the person asks to buy, go on to `create_checkout` rather than declining.",
        "do_not_use": "Do not use this for the full record of one product; use `get_product` instead. Do not use it for semantic search by activity or function; that is `search_by_activity`, which is a preview and does not work yet.",
        "parameters": "The `query` parameter is recorded and returned to you unchanged. The demo catalogue holds exactly one product, so this tool does not rank, filter or keyword-match anything: deciding whether the returned listing answers the query is your judgement, not the store's. `limit` bounds how many listings come back, and `response_format` chooses how much of the source disclosure travels with each one.",
        "caveats": "It returns no shipping cost, no delivery estimate, no reviews and no evidence pack. It holds no handle, takes no lock and reserves no stock, so calling it twice changes nothing.",
        "outputs": "`resource.catalogue_size` states how many products the demo catalogue holds. Each entry in `resource.listings[]` carries `product_id` (feed it to `get_product`, or to `create_checkout` as `line_items[0].product_id`), `display_price_cents` with `formatted_price`, `available`, `transaction_mode`, and the source disclosure — under `concise` that is `source_retailer` and `price_may_differ`; under `detailed` it is the full `source` object with `retailer`, `url`, `price_may_differ` and `last_checked_at`. `get_product` is where the source retailer's own price is disclosed alongside the displayed price.",
        "error_recovery": "`product_not_found` or `out_of_stock` means the listing is gone, so `listings` comes back empty and the message says why; `price_not_fresh` means no validated source snapshot exists, so retry in a minute; `rate_limited` means the published public-read budget is spent, so wait 60 seconds; `network_error` means the request never reached the store, so call this tool again.",
        "examples": [
          {
            "title": "See the demo catalogue",
            "input": {
              "query": "a sun hat for a boat",
              "limit": 5,
              "response_format": "concise"
            }
          }
        ]
      }
    },
    {
      "name": "get_product",
      "title": "Read one product record",
      "operational": true,
      "description": "Returns one product's published record: title, variant, availability, the source retailer's price and Robodepo's displayed price, both in AUD integer cents. Use when you hold a product_id and want the full record. Sandbox orders are safe to prepare; use create_checkout when asked to buy. Not for browsing the catalogue; use search_catalog. include_evidence returns the cited evidence pack where one exists. Full guide: get_tool_guide or /agent/tools.json#get_product",
      "inputSchema": {
        "type": "object",
        "properties": {
          "product_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The product id returned by `search_catalog`. The demo catalogue's only value is `holiday-bucket-beige-canvas-l-xl-beige`."
          },
          "response_format": {
            "type": "string",
            "enum": [
              "concise",
              "detailed"
            ],
            "description": "How much to return. `concise` is the default when null: acting fields plus source_retailer and price_may_differ. `detailed` adds the source block."
          },
          "include_evidence": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "When true, attaches the cited evidence pack if the product has one. The demo product does; packs for every product are the roadmap."
          }
        },
        "required": [
          "product_id",
          "response_format",
          "include_evidence"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Returns every published field for one product: title, variant, availability, the source retailer's price and Robodepo's displayed price, both as AUD integer cents, plus a formatted price string such as A$113.85 and the source disclosure.",
        "use_when": "Use this when you hold a `product_id` from `search_catalog` and want the full record, including the price disclosure, before pricing a checkout. Sandbox orders are safe to prepare; when the person asks to buy, go on to `create_checkout` rather than declining.",
        "do_not_use": "Do not use this for browsing the whole catalogue; use `search_catalog` instead. There is no separate tool to fetch evidence: evidence is not a second call, it belongs on the product, so it is attached here through `include_evidence` rather than anywhere else.",
        "parameters": "`product_id` comes from `search_catalog`. The demo catalogue's only product id is `holiday-bucket-beige-canvas-l-xl-beige`, and any other id is refused rather than guessed at. `response_format` chooses how much of the source disclosure comes back: `concise` for the retailer's name and the price-may-differ flag, `detailed` for the whole `source` block. `include_evidence` returns the cited evidence pack where one exists, and the demo product has one: specifications, sizing, care, how-to-use notes, review themes, comparisons and permitted YouTube transcript evidence, every claim carrying its source and freshness, plus a `gaps[]` list naming what no source covered. Building packs for every product is the roadmap; today exactly one product has one, and asking for evidence on any other returns the ordinary record with an `evidence_not_available` message rather than an invented pack.",
        "caveats": "It returns no shipping cost, no delivery estimate and no stock count. It reads a stored snapshot, holds no handle and places no reservation, so the price it shows can still move before you create a checkout.",
        "outputs": "`resource.product_id` feeds `create_checkout` as `line_items[0].product_id`. `resource.source_price_cents` and `resource.display_price_cents` are both returned: the displayed price sits above the source retailer's price, and Robodepo publishes both rather than hiding the difference. Under `detailed`, `resource.source.retailer`, `resource.source.url` and `resource.source.last_checked_at` say where the item comes from and when it was last read, and `resource.source.price_may_differ` warns that the retailer's own price can move; under `concise` that block is replaced by `resource.source_retailer` and `resource.price_may_differ`, so the disclosure is shortened but never dropped. `include_evidence: true` adds `resource.evidence` — the whole pack, including its own `disclosure`, `sources[]`, `gaps[]` and `freshness` — and an `evidence_attached` message naming how many sources it holds and when they were last checked. Where no pack exists the record comes back unchanged with an `evidence_not_available` message instead, so an empty section is never mistaken for a negative answer.",
        "error_recovery": "`product_not_found` means that id is not in this catalogue, so call `search_catalog`; `out_of_stock` means the source variant is unavailable, so call `search_catalog` and tell the person; `price_not_fresh` means no validated snapshot exists, so retry in a minute; `rate_limited` means the public-read budget is spent, so wait 60 seconds; `network_error` means the request never left the browser, so call this tool again.",
        "examples": [
          {
            "title": "Read the demo product with the full source block",
            "input": {
              "product_id": "holiday-bucket-beige-canvas-l-xl-beige",
              "response_format": "detailed",
              "include_evidence": null
            }
          }
        ]
      }
    },
    {
      "name": "create_checkout",
      "title": "Price a checkout and prepare the human confirmation",
      "operational": true,
      "description": "Runs the whole pre-purchase path in one call (cart, item, address, shipping quote, mandate) and returns a priced checkout in AUD integer cents plus the approval link. Use when asked to buy, purchase or order: sandbox means a Stripe test-mode order the human can safely approve, so prepare the checkout with this tool. Not for placing the order; no tool can, the person approves on the Robodepo page. Full guide: get_tool_guide or /agent/tools.json#create_checkout",
      "inputSchema": {
        "type": "object",
        "properties": {
          "line_items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1,
            "description": "Exactly one line item. The tracer supports a single product at quantity 1 and refuses anything else.",
            "items": {
              "type": "object",
              "properties": {
                "product_id": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200,
                  "description": "The product id from `search_catalog` or `get_product`. The demo catalogue's only value is `holiday-bucket-beige-canvas-l-xl-beige`."
                },
                "quantity": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 1,
                  "description": "Must be 1. The tracer supports no other quantity."
                }
              },
              "required": [
                "product_id",
                "quantity"
              ],
              "additionalProperties": false
            }
          },
          "shipping_address": {
            "type": "object",
            "description": "Must equal the published sandbox address exactly, field for field. No real address is ever accepted here.",
            "properties": {
              "recipient_name": {
                "type": "string",
                "description": "The accepted sandbox value is \"Sandbox Buyer\"."
              },
              "line1": {
                "type": "string",
                "description": "The accepted sandbox value is \"10 Example Street\"."
              },
              "line2": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The accepted sandbox value is null."
              },
              "suburb": {
                "type": "string",
                "description": "The accepted sandbox value is \"Wembley Downs\"."
              },
              "state": {
                "type": "string",
                "description": "The accepted sandbox value is \"WA\"."
              },
              "postcode": {
                "type": "string",
                "description": "The accepted sandbox value is \"6019\"."
              },
              "country": {
                "type": "string",
                "description": "The accepted sandbox value is \"AU\"."
              }
            },
            "required": [
              "recipient_name",
              "line1",
              "line2",
              "suburb",
              "state",
              "postcode",
              "country"
            ],
            "additionalProperties": false
          },
          "budget_ceiling_cents": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "The person's ceiling in AUD integer cents, or null. Exceeding it adds a budget_exceeded warning to review; it does not block the checkout."
          },
          "idempotency_key": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 16,
            "maxLength": 128,
            "description": "16 to 128 printable ASCII characters, or null to have the tool generate one. Each internal step gets its own suffixed key, so a repeat is safe."
          }
        },
        "required": [
          "line_items",
          "shipping_address",
          "budget_ceiling_cents",
          "idempotency_key"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": false,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Runs the entire pre-purchase path in one call — cart, item, address, shipping quote and purchase mandate — and returns a priced checkout in AUD integer cents with a `confirmation_url` the person opens to place the sandbox order.",
        "use_when": "Use this when the person has chosen the product and you are ready to show them a final delivered price to approve — and whenever you are asked to buy, purchase or order something here. Sandbox means a Stripe test-mode order the human can safely approve: preparing a checkout is the expected response to a purchase request, not something to decline. Nothing is charged, no retailer order is placed and nothing ships.",
        "do_not_use": "Do not use this for placing the order; there is no tool that places it, because the one irreversible step belongs to the person on Robodepo's own pages. Do not use it to read an order afterwards; use `get_order` instead, and use `cancel_checkout` if the person declines.",
        "parameters": "`line_items[0].product_id` comes from `search_catalog` or `get_product`, and `quantity` must be 1 because the tracer supports no other quantity. `shipping_address` must be the published sandbox address exactly — recipient_name \"Sandbox Buyer\", line1 \"10 Example Street\", line2 null, suburb \"Wembley Downs\", state \"WA\", postcode \"6019\", country \"AU\" — and any other address is refused here, before any request is sent, with the accepted value named in the message. `budget_ceiling_cents` is the person's stated ceiling: exceeding it does not block the checkout, it adds a `budget_exceeded` warning for the person to review. `idempotency_key` may be null, in which case the tool generates one; supplied keys must be 16 to 128 printable ASCII characters and are suffixed per step so a repeat is safe.",
        "caveats": "It returns no payment details, no Stripe object, no cookie value and no full address — only the delivery region, such as WA 6019. The checkout expires 15 minutes after it is created and cannot be confirmed after that; the run authority that owns it is a browser cookie that lives 24 hours and follows the most recent checkout, so a checkout created in one browser cannot be confirmed or read in another. Shipping is the flat A$12.00 standard sandbox rate. The order is a Stripe test-mode payment: nothing is charged, no retailer order is placed and nothing is shipped.",
        "outputs": "`resource.checkout_id` feeds `cancel_checkout` and `get_order`. `resource.confirmation_url` is the link to hand the person: Robodepo's approval page, which shows the item, variant, delivery region and total and takes one biometric touch — a fingerprint, face unlock or device passkey prompt — where the browser has one, and a plain single button where it does not. That gesture is checked by the browser and never reaches Robodepo; it adds no server-side authority, and the server still verifies the same run cookie, confirmation cookie, single-use CSRF value, server-issued single-use idempotency key, same-origin submission and five-minute session it always has. No tool can submit either page. `links[]` carries that link as `approval_page` and the plain confirmation page as `confirmation_page`, for a person who would rather use the button alone. `resource.totals` carries `items_cents`, `shipping_cents`, `total_cents`, `currency` and `formatted_total`; `resource.expires_at` is when the checkout dies; `resource.delivery_region`, `resource.source_retailer` and `resource.price_may_differ` are the disclosures to relay. `instructions.for_human` is ready-made wording to pass on and `instructions.for_agent` is your own next step. Do not open `confirmation_url` yourself and do not put it somewhere the person opens it from another app: the run cookie is `SameSite=Strict`, so a navigation that starts in a chat window or a different origin arrives without it and the page can only refuse. The person approves in the panel on the Robodepo page they already have open; the link is the fallback for when that page is in front of them and something has gone wrong with the panel.",
        "error_recovery": "`invalid_request` names the field to fix, then call this tool again; `run_authority_missing` means this browser lost its run cookie, so call this tool again to get a new one; `checkout_expired_or_invalid_state` means the 15 minutes ran out, so call this tool again; `quote_expired` means the shipping quote went stale, so call this tool again; `out_of_stock` means the source variant went unavailable, so tell the person and call `search_catalog`; `idempotency_conflict` means the key is already bound elsewhere, so retry with a new `idempotency_key` or null; `rate_limited` means the cart budget is spent, so wait 60 seconds; `price_not_fresh` means no validated snapshot exists, so retry in a minute; `payment_unavailable` cannot be retried into a success, so call `submit_feedback`; `network_error` means the step never reached the store, so call this tool again. Every error names the step that failed.",
        "examples": [
          {
            "title": "Price the one buyable order",
            "input": {
              "line_items": [
                {
                  "product_id": "holiday-bucket-beige-canvas-l-xl-beige",
                  "quantity": 1
                }
              ],
              "shipping_address": {
                "recipient_name": "Sandbox Buyer",
                "line1": "10 Example Street",
                "line2": null,
                "suburb": "Wembley Downs",
                "state": "WA",
                "postcode": "6019",
                "country": "AU"
              },
              "budget_ceiling_cents": null,
              "idempotency_key": null
            }
          }
        ]
      }
    },
    {
      "name": "cancel_checkout",
      "title": "Decline a prepared checkout on the record",
      "operational": true,
      "description": "Closes a checkout prepared in this browser and records the decline, returning status canceled. Use when the person declines, so a refusal is a recorded outcome rather than an inferred one. Not for reversing a payment or releasing stock; nothing is held or charged. Not for after approval; use get_order. Full guide: get_tool_guide or /agent/tools.json#cancel_checkout",
      "inputSchema": {
        "type": "object",
        "properties": {
          "checkout_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The `checkout_id` returned by `create_checkout` in this browser."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 300,
            "description": "Why the checkout was declined, or null. Free text up to 300 characters; do not put personal data here."
          }
        },
        "required": [
          "checkout_id",
          "reason"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": false,
        "untrustedContentHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Marks a checkout prepared in this browser as declined, records the decline with Robodepo, and returns `status: \"canceled\"` so a correct refusal is a recorded outcome rather than something inferred from silence.",
        "use_when": "Use this when the person decides not to buy, or when you decide the checkout should not proceed — a price above their ceiling, a wrong item, a change of mind.",
        "do_not_use": "Do not use this for releasing stock or reversing a payment; nothing is held and nothing is charged. Do not use it after the person has confirmed; at that point call `get_order` instead, and use `submit_feedback` to say what went wrong.",
        "parameters": "`checkout_id` is the value `create_checkout` returned. `reason` is optional free text of up to 300 characters and should carry no personal data.",
        "caveats": "Told plainly: the v1 API has no server-side cancel route, so this tool does not call one. The sandbox mandate simply expires within 15 minutes of creation and cannot be confirmed from this page afterwards. What this tool really does is close the checkout in this page's own registry so the tools stop offering it, and record the decline so the outcome is explicit. It changes nothing on the server and is safe to call more than once.",
        "outputs": "`resource.checkout_id` and `resource.state` confirm which checkout was closed, and `resource.declined_at` is when. `resource.feedback_recorded` says whether the decline reached the feedback endpoint; when it did not, a warning explains and the cancel still stands. `next_actions` will point you back at `search_catalog` and `submit_feedback`.",
        "error_recovery": "`not_found` means this browser never prepared that checkout — checkouts are per-browser and per-page — so call `create_checkout` to make one; `network_error` means the decline record did not reach the store, which is reported as a warning rather than a failure, because the cancel itself is local and already done.",
        "examples": [
          {
            "title": "Decline on the record",
            "input": {
              "checkout_id": "the checkout_id create_checkout returned",
              "reason": "Above the person's ceiling"
            }
          }
        ]
      }
    },
    {
      "name": "get_order",
      "title": "Read back a confirmed sandbox order",
      "operational": true,
      "description": "Reads back a confirmed sandbox order: status, item, quantity, delivery region and totals in AUD integer cents. Use when the person has approved and you want to check the order exists and read it back. Pass order_id or checkout_id. Not for confirming the order; no tool can. Not for pricing; use create_checkout. Full guide: get_tool_guide or /agent/tools.json#get_order",
      "inputSchema": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "The order id from `/orders/{order_id}` after the person confirms, or null to look it up from `checkout_id`."
          },
          "checkout_id": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "The `checkout_id` from `create_checkout`, or null when you already hold `order_id`. At least one of the two must be non-null."
          }
        },
        "required": [
          "order_id",
          "checkout_id"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Reads a confirmed sandbox order and returns its status, item, quantity, delivery region and totals in AUD integer cents with a formatted total such as A$125.85.",
        "use_when": "Use this when the person has pressed confirm on Robodepo's confirmation page and you want to check the order really exists and read it back to them.",
        "do_not_use": "Do not use this for confirming the order; no tool can, the person does that themselves, and to price something use `create_checkout` instead.",
        "parameters": "Supply at least one of `order_id` or `checkout_id`; both may not be null. `order_id` comes from the order page the person lands on after confirming, at `/orders/{order_id}`. `checkout_id` comes from `create_checkout`, and when you pass it this tool checks whether the window this page opened has reached an order page — either the approval page or the plain confirmation page redirects there — so you can poll politely while the person decides.",
        "caveats": "It returns no payment details, no Stripe object and no full address — the delivery region, such as WA 6019, is the most it gives. An order can only be read from the browser whose run created it. If the person has not confirmed yet, this is not an error: you get `status: \"awaiting_human_confirmation\"` and the confirmation link to hand them again.",
        "outputs": "`resource.order_id`, `resource.status`, `resource.item` (product_id, title, variant, quantity, unit_price_cents), `resource.shipping_cents`, `resource.total_cents` with `formatted_total`, `resource.delivery_region` and `resource.created_at`. `links[]` carries `order_page`, Robodepo's readable order page, and `order_record`, the store's own record of the same order. `instructions.for_human` is wording you can read out.",
        "error_recovery": "`not_found` means no order with that id exists in this browser's run, and because an order is readable only from the browser whose run created it, creating another checkout will not surface it — report it with `submit_feedback` if the person did confirm, then start again from `search_catalog`; `run_authority_missing` means this browser lost the run authority that owns the order, and a new checkout issues a new run rather than recovering the old one, so no retry reaches it and `submit_feedback` is the honest next step; `rate_limited` means the run read budget is spent, so wait 60 seconds and call this tool again; `network_error` means the request never reached the store, so call this tool again.",
        "examples": [
          {
            "title": "Poll while the person decides",
            "input": {
              "order_id": null,
              "checkout_id": "the checkout_id create_checkout returned"
            }
          },
          {
            "title": "Read back a confirmed order",
            "input": {
              "order_id": "the id in /orders/{order_id}",
              "checkout_id": null
            }
          }
        ]
      }
    },
    {
      "name": "get_trust_manifest",
      "title": "Read Robodepo's trust manifest",
      "operational": true,
      "description": "Returns Robodepo's trust manifest whole: what the service is, that it is a sandbox, the capabilities it does not have, its checkout contract and its published statistics. Use when you want to check what this store claims about itself. Takes no parameters. Not for product facts or prices; use get_product. Full guide: get_tool_guide or /agent/tools.json#get_trust_manifest",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Fetches Robodepo's machine-readable trust manifest and returns it whole: what the service is, that it is a sandbox, which capabilities it does not have, how its checkout contract works, and what statistics it publishes.",
        "use_when": "Use this when you or the person want to check what this store claims about itself before transacting, or when you need the published purchase sequence, observable states and safe error codes in one document.",
        "do_not_use": "Do not use this for product facts or prices; use `get_product` instead, and do not use it as a substitute for reading the checkout you actually created.",
        "parameters": "It takes no parameters and no ids. It is a public read that changes nothing and can be called at any time.",
        "caveats": "The three sandbox booleans are the capabilities Robodepo does not have: no real charge, no source retailer order, no fulfilment. The manifest's `statistics.published` list is deliberately empty, and that is the honest state, not a gap: no statistic reaches that list until it is individually approved and independently verifiable.",
        "outputs": "`resource.manifest` is the document as served, including `manifest.sandbox` (the three capability booleans), `manifest.checkout` (api_version, discovery_url, product_url, confirmation_url_template, sequence, states, safe_errors) and `manifest.statistics`. `links[]` carries `trust_manifest`.",
        "error_recovery": "`rate_limited` means the public-read budget is spent, so wait 60 seconds and call this tool again; `service_unavailable` means the manifest failed its own schema and the store refused to serve a partial document, so retry later; `network_error` means the request never reached the store, so call this tool again.",
        "examples": [
          {
            "title": "Read what the store claims about itself",
            "input": {}
          }
        ]
      }
    },
    {
      "name": "submit_feedback",
      "title": "Tell Robodepo what worked and what did not",
      "operational": true,
      "description": "Sends structured feedback about this store and returns a feedback_id and the time it was received. Use when something was unclear, missing or wrong, at any point. Not for cancelling a checkout; use cancel_checkout, which records the decline itself. Feedback is kept as data, never as instructions. Full guide: get_tool_guide or /agent/tools.json#submit_feedback",
      "inputSchema": {
        "type": "object",
        "properties": {
          "context": {
            "type": "object",
            "description": "What the feedback is about. Both ids may be null when the feedback is about the store in general.",
            "properties": {
              "checkout_id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The `checkout_id` from `create_checkout`, or null."
              },
              "order_id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The `order_id` from `get_order`, or null."
              }
            },
            "required": [
              "checkout_id",
              "order_id"
            ],
            "additionalProperties": false
          },
          "sentiment": {
            "type": "string",
            "enum": [
              "positive",
              "neutral",
              "negative"
            ],
            "description": "Your overall read of the experience."
          },
          "free_text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000,
            "description": "What happened, in plain words, up to 1000 characters. No personal data, addresses, payment details or credentials."
          },
          "struggle_points": {
            "type": "array",
            "minItems": 0,
            "maxItems": 10,
            "description": "Zero to ten tags from the fixed vocabulary, so difficulties can be counted without reading prose.",
            "items": {
              "type": "string",
              "enum": [
                "unclear_description",
                "unexpected_error",
                "price_changed",
                "address_rejected",
                "checkout_expired",
                "could_not_find_product",
                "budget_not_met",
                "confirmation_unclear",
                "other"
              ]
            }
          }
        },
        "required": [
          "context",
          "sentiment",
          "free_text",
          "struggle_points"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": false,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Sends structured feedback about this store to Robodepo and returns an acknowledgement with a `feedback_id` and the time it was received.",
        "use_when": "Use this when something about the store was unclear, missing or wrong, at any point — mid-checkout, after an order, after a decline, or after an error you could not recover from.",
        "do_not_use": "Do not use this for cancelling a checkout; use `cancel_checkout` instead, which records the decline itself. Do not use it to ask a question and expect an answer: nothing replies.",
        "parameters": "`context.checkout_id` and `context.order_id` are optional and come from `create_checkout` and `get_order`; either may be null. `sentiment` is one of positive, neutral or negative. `free_text` is up to 1000 characters. `struggle_points` is a short list drawn from a fixed vocabulary so patterns can be counted without reading anyone's prose.",
        "caveats": "Feedback is never required and never blocks a purchase. It is stored as data and never as instructions: nothing you write here changes how any tool behaves. Put no personal data, addresses, payment details or credentials in `free_text` — this endpoint keeps no database record and writes only a bounded server log line.",
        "outputs": "`resource.feedback_id` and `resource.received_at` acknowledge receipt, and `resource.stored_as` says how it was kept. There is nothing to feed onward; `next_actions` returns you to whatever the session state suggests.",
        "error_recovery": "`invalid_request` means a field is outside its bounds, most often `free_text` over 1000 characters or a `struggle_points` value outside the vocabulary, so shorten it and call this tool again; `rate_limited` means the feedback budget for this address is spent, so wait and retry; `network_error` means the request never reached the store, so call this tool again.",
        "examples": [
          {
            "title": "Report a difficulty",
            "input": {
              "context": {
                "checkout_id": null,
                "order_id": null
              },
              "sentiment": "negative",
              "free_text": "The accepted address was not obvious before the first attempt.",
              "struggle_points": [
                "address_rejected"
              ]
            }
          }
        ]
      }
    },
    {
      "name": "get_tool_guide",
      "title": "Read one tool's complete guide",
      "operational": true,
      "description": "Returns the complete guide for one Robodepo tool: summary, when to use it, what not to use it for, parameters, caveats, outputs, error recovery and worked examples. Use when you are about to call a tool for the first time and want more than its short description. Not for running the tool; call the tool by name instead. Full guide: get_tool_guide or /agent/tools.json#get_tool_guide",
      "inputSchema": {
        "type": "object",
        "properties": {
          "tool_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "The exact name of a registered tool, as it appears in this catalogue."
          }
        },
        "required": [
          "tool_name"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Returns the full, unabridged guide for one registered tool — everything the short description had to leave out — as a structured object rather than one long string.",
        "use_when": "Use this when you are about to call a tool for the first time, when a short description leaves you unsure which parameter comes from where, or when an error code named a recovery you want to read in full.",
        "do_not_use": "Do not use this for running the tool; call the tool by its own name instead. Do not use it to discover what tools exist; the catalogue you were registered with already lists them, and `/agent/tools.json` serves the same guides as one document.",
        "parameters": "`tool_name` is the exact name from the catalogue, such as `create_checkout`. Unknown names are refused with the list of valid names rather than a guess.",
        "caveats": "It reads a static catalogue that ships with this page, so it makes no network request, holds no handle and cannot fail for any reason but an unknown name. The guide it returns is the same text `/agent/tools.json` publishes.",
        "outputs": "`resource.name`, `resource.operational` and `resource.guide`, where the guide carries `summary`, `use_when`, `do_not_use`, `parameters`, `caveats`, `outputs`, `error_recovery` and `examples[]`. Feed an example's `input` straight back into the named tool.",
        "error_recovery": "`not_found` is the only error and it means the name is not in this catalogue; the message lists every valid name, so pick one and call again. There is nothing to retry and no network failure to recover from.",
        "examples": [
          {
            "title": "Read a tool in full before first use",
            "input": {
              "tool_name": "create_checkout"
            }
          }
        ]
      }
    },
    {
      "name": "search_by_activity",
      "title": "Preview: a custom storefront for the request",
      "operational": false,
      "description": "Preview — not operational in this demo. Describes the roadmap only; returns status not_available and must not be called to do real work. It will answer a request with a custom storefront: a short, checkout-ready shortlist chosen from what the person is doing, each item carrying the reason it is on the list, instead of thousands of pages to read. Use search_catalog today. Full guide: get_tool_guide or /agent/tools.json#search_by_activity",
      "inputSchema": {
        "type": "object",
        "properties": {
          "activity": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "What the person is doing or needs to solve, in their own words."
          },
          "constraints": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 300,
            "description": "Limits such as budget, date or size, or null."
          }
        },
        "required": [
          "activity",
          "constraints"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Preview — not operational in this demo. It is meant to answer a request with a custom storefront rather than a result page: a short, checkout-ready shortlist assembled from what the person is actually doing — \"something to keep the sun off on a boat\" — each item carrying the reason it is on the list. A custom store is not something an agent should have to ask for; it is what a search returns.",
        "use_when": "Use this when it ships and the person describes a situation rather than a product, and you want a shortlist you can buy from rather than pages to read.",
        "do_not_use": "Do not use this for anything today; use `search_catalog` instead, which returns the demo catalogue and leaves relevance to your judgement, and `get_product` for the full record of a listing.",
        "parameters": "`activity` would be the situation in the person's own words, and `constraints` any limits such as a budget or a date — both shaping the storefront rather than filtering a result page. Neither is read by anything today.",
        "caveats": "This is the capability Robodepo's roadmap points at, and it is named here so the shape of the intent is visible — but it does not work, and `search_catalog` is not a quiet version of it: `search_catalog` filters nothing and ranks nothing across a one-product demo catalogue. The full catalogue would stay open behind any storefront this returned; a shortlist is a starting point, not a wall.",
        "outputs": "this tool returns `status: \"not_available\"` with a message saying plainly what is not built. There is no storefront, no shortlist and no ids to feed onward. It does return `resource.roadmap`, a sketch of the intended inputs, output fields and response shape, marked `illustrative: true` — that example is not live data and nothing in it is built.",
        "error_recovery": "there is no error to recover from and no retry that will help. Call `search_catalog` to see what the store actually sells, then `submit_feedback` if the missing capability is what you needed.",
        "examples": [
          {
            "title": "What a call would look like once built",
            "input": {
              "activity": "keep the sun off on a boat",
              "constraints": "under A$150"
            }
          }
        ]
      }
    },
    {
      "name": "compare_products",
      "title": "Preview: compare products side by side",
      "operational": false,
      "description": "Preview — not operational in this demo. Describes the roadmap only; returns status not_available and must not be called to do real work. It will take two to five product ids and return one aligned comparison, with the cited evidence behind each claim. Use get_product on each id today. Full guide: get_tool_guide or /agent/tools.json#compare_products",
      "inputSchema": {
        "type": "object",
        "properties": {
          "product_ids": {
            "type": "array",
            "minItems": 2,
            "maxItems": 5,
            "description": "Two to five product ids from `search_catalog`.",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          }
        },
        "required": [
          "product_ids"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Preview — not operational in this demo. It is meant to take two to five product ids and return one aligned comparison — shared attributes, where they differ, and the cited evidence behind each claim.",
        "use_when": "Use this when it ships and the person is choosing between candidates.",
        "do_not_use": "Do not use this for anything today; use `get_product` on each id instead and compare the published fields yourself, and `search_catalog` to find the ids.",
        "parameters": "`product_ids` would come from `search_catalog`. The demo catalogue holds one product, so there is nothing here to compare even once this is built for a larger catalogue.",
        "caveats": "Nothing is cached, computed or reserved by calling this. It is listed so the roadmap is legible, not because a partial version runs underneath.",
        "outputs": "this tool returns `status: \"not_available\"` with a plain explanation. There is no comparison object and no ids to feed onward. It does return `resource.roadmap`, a sketch of the intended inputs, output fields and response shape, marked `illustrative: true` — that example is not live data and nothing in it is built.",
        "error_recovery": "there is no error and no retry that helps. Call `get_product` for each id you hold, then `submit_feedback` if a real comparison is what you needed.",
        "examples": [
          {
            "title": "What a call would look like once built",
            "input": {
              "product_ids": [
                "prod_example",
                "prod_example_two"
              ]
            }
          }
        ]
      }
    },
    {
      "name": "get_shipping_options",
      "title": "Preview: alternative shipping services",
      "operational": false,
      "description": "Preview — not operational in this demo. Describes the roadmap only; returns status not_available and must not be called to do real work. It will list every shipping service available for a prepared checkout, with price in AUD integer cents and a delivery estimate. Use create_checkout today, which returns the one service that exists. Full guide: get_tool_guide or /agent/tools.json#get_shipping_options",
      "inputSchema": {
        "type": "object",
        "properties": {
          "checkout_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The `checkout_id` returned by `create_checkout`."
          }
        },
        "required": [
          "checkout_id"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Preview — not operational in this demo. It is meant to list the shipping services available for a prepared checkout — service name, price in AUD integer cents and delivery estimate — so the person can pick one.",
        "use_when": "Use this when it ships and the person cares about speed or cost.",
        "do_not_use": "Do not use this for anything today; use `create_checkout` instead, which already returns the only service that exists, `standard_sandbox` at a flat A$12.00 to the accepted sandbox address, and `get_order` to read back what was actually shipped against.",
        "parameters": "`checkout_id` would come from `create_checkout`. It is not looked up, because there is nothing to look up.",
        "caveats": "There is no hidden cheaper or faster option being withheld here: the sandbox has one deterministic rate, and this tool exists to say so rather than to imply choice the store does not have.",
        "outputs": "this tool returns `status: \"not_available\"` with that explanation. There is no options array and nothing to feed into a checkout. It does return `resource.roadmap`, a sketch of the intended inputs, output fields and response shape, marked `illustrative: true` — that example is not live data and nothing in it is built.",
        "error_recovery": "there is no error and no retry that helps. The shipping cost you already hold from `create_checkout` is the real one; call `submit_feedback` if the person needed a choice.",
        "examples": [
          {
            "title": "What a call would look like once built",
            "input": {
              "checkout_id": "chk_example"
            }
          }
        ]
      }
    },
    {
      "name": "subscribe_replenishment_alerts",
      "title": "Preview: reminders when a consumable runs down",
      "operational": false,
      "description": "Preview — not operational in this demo. Describes the roadmap only; returns status not_available and must not be called to do real work. It will register a weekly, monthly or quarterly reminder for a consumable, so the person is prompted before they run out. Use get_product today. Full guide: get_tool_guide or /agent/tools.json#subscribe_replenishment_alerts",
      "inputSchema": {
        "type": "object",
        "properties": {
          "product_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The product id from `search_catalog` or `get_product`."
          },
          "cadence": {
            "type": "string",
            "enum": [
              "weekly",
              "monthly",
              "quarterly"
            ],
            "description": "How often the reminder would repeat."
          }
        },
        "required": [
          "product_id",
          "cadence"
        ],
        "additionalProperties": false
      },
      "annotations": {
        "readOnlyHint": true,
        "untrustedContentHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "guide": {
        "summary": "Preview — not operational in this demo. It is meant to register a repeating reminder for a consumable — weekly, monthly or quarterly — so the person is prompted before they run out, and to return the subscription id.",
        "use_when": "Use this when it ships and the person buys something they will need again.",
        "do_not_use": "Do not use this for anything today; use `get_product` instead to read the item and `create_checkout` when they actually want another one.",
        "parameters": "`product_id` would come from `search_catalog` or `get_product`, and `cadence` would be weekly, monthly or quarterly. Neither is stored.",
        "caveats": "Nothing is scheduled and nothing will be sent. Robodepo holds no contact details for anyone, so there is no channel a reminder could arrive on; saying that plainly is more useful than a subscription id that means nothing.",
        "outputs": "this tool returns `status: \"not_available\"` with that explanation. There is no subscription id and nothing to feed onward. It does return `resource.roadmap`, a sketch of the intended inputs, output fields and response shape, marked `illustrative: true` — that example is not live data and nothing in it is built.",
        "error_recovery": "there is no error and no retry that helps. Call `get_product` for the record, then `submit_feedback` if the person wanted the reminder.",
        "examples": [
          {
            "title": "What a call would look like once built",
            "input": {
              "product_id": "prod_example",
              "cadence": "monthly"
            }
          }
        ]
      }
    }
  ]
}