{
 "protocolVersion": "0.3.0",
 "name": "OpenKeyboards",
 "description": "Mechanical keyboards and switches from 30+ makers and stores, compared: layout, wireless, hot-swap, switch options and prices with buy links for every board; ThereminGoat's measured force curves (travel, tactile peak, bottom-out) for 2,300 switches.",
 "url": "https://openkeyboards.pages.dev/",
 "version": "2026-10-01",
 "capabilities": {
  "streaming": false,
  "pushNotifications": false,
  "stateTransitionHistory": false,
  "extensions": [
   {
    "uri": "https://fangorn.network/a2a/app/v1",
    "description": "The Fangorn app this agent fronts.",
    "required": false,
    "params": {
     "chainId": 421614,
     "appRegistry": "0x11d228c4774af3d9cae3b4b6874a12576a1a83ec",
     "dataRegistry": "0x775026e905d7b58b34d16bcbd385fa630ee36c26",
     "appId": "0xe08386b5205ebb447f93cc153a7afab95dd87793eac3a1bd4f4661d28a73230c",
     "fromBlock": "314677227",
     "namespaces": [
      "catalog"
     ],
     "views": [
      "https://openkeyboards.pages.dev/view"
     ]
    }
   }
  ]
 },
 "defaultInputModes": [
  "application/json"
 ],
 "defaultOutputModes": [
  "application/json"
 ],
 "skills": [
  {
   "id": "describe",
   "name": "Describe",
   "description": "What this app holds: its fields and how often each is present. Call it first.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "search",
   "name": "Search",
   "description": "Search by meaning: a question in plain words. Optional equality filters in `where`.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "search-keyboards-and-switches",
   "name": "Search keyboards and switches",
   "description": "Search by meaning, with keyboards and switches ranked separately: returns { keyboards: [...], switches: [...] }, the same split and order the page shows. Sold-out and unlisted items rank lower (in_stock on each hit). Hard requirements go in keyboards_where / switches_where as exact values, e.g. keyboards_where {size: \"75%\", under_usd: \"150\", wireless: \"yes\"}. `where` applies to both kinds; a field one kind lacks empties that kind. Ids work with get and rate.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "get",
   "name": "Get",
   "description": "One record in full, by the id search returns.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "count",
   "name": "Count",
   "description": "Count the distinct values of a field: the shape of the data before reading it.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "session",
   "name": "Session",
   "description": "What the person on this page saved and searched this session, and the taste (a vector over this app's records) their choices make.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "rate",
   "name": "Rate",
   "description": "Record that the person liked or disliked a record (or clear it), by the id search returns. Builds the taste discover ranks with.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "discover",
   "name": "Discover",
   "description": "Records for a taste: a kernel over what was liked (newest last) and disliked, not a text search. Pass likes and dislikes (ids from search), or omit them to use the taste on this page. Knobs are 0–1.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  },
  {
   "id": "discover-keyboards-and-switches",
   "name": "Discover keyboards and switches",
   "description": "Recommendations, as the page's For you shows them: { keyboards: {from, picks}, switches: {from, picks} }. Each kind is picked from the liked records of that kind only, and only from what is in stock. Omit likes/dislikes to use the person's 👍 👎 on this page, or pass ids from search. `from` 0 means nothing of that kind was liked yet. Ids work with get and rate.",
   "tags": [
    "keyboards",
    "mechanical-keyboards",
    "switches",
    "shopping",
    "webmcp"
   ]
  }
 ]
}