{"id":"9928b336-deb1-4e3e-bb26-53400a9780d4","entityType":"agent","slug":"clawhub-chrischall-tock-fpx","name":"tock-fpx","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-tock-fpx","canonicalPath":"/agent/clawhub-chrischall-tock-fpx","generatedAt":"2026-10-11T16:03:01.150Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:52:03.591Z","emptyReason":null},"description":"Query Tock (exploretock.com — restaurant discovery, availability, and the signed-in user's reservations) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the tock-mcp server — list metros, search a metro's restaurants, get a venue's bookable calendar, and list reservations, all through a signed-in browser tab. Use when you want Tock data without the MCP, in a script, or on a machine where the MCP isn't installed.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:tock-fpx","sourceUrl":"https://clawhub.ai/chrischall/tock-fpx","homepage":"https://clawhub.ai/chrischall/skills/tock-fpx","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/tock-fpx","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/tock-fpx","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"tock-fpx technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:52:03.591Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:52:03.591Z","emptyReason":null},"stars":null,"forks":null,"downloads":1054,"packageName":null,"latestVersion":"1.1.8","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:52:03.520Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T13:52:03.591Z","lastCrawledAt":"2026-10-11T13:52:03.520Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T13:52:03.520Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.8","createdAt":"2026-10-09T23:29:58.854Z","changelog":"- Removed the file skill-card.md. - No functional or user-facing changes; documentation and usage remain unchanged.","fileCount":5,"zipByteSize":9605},{"version":"1.1.7","createdAt":"2026-10-07T13:40:03.719Z","changelog":"- Removed the skill-card.md file. - No user-facing changes to functionality or documentation.","fileCount":5,"zipByteSize":9649},{"version":"1.1.6","createdAt":"2026-10-05T02:54:31.621Z","changelog":"- Removed the redundant skill-card.md file. - No changes to core functionality or documentation.","fileCount":5,"zipByteSize":9535},{"version":"1.1.5","createdAt":"2026-10-03T01:46:58.272Z","changelog":"tock-fpx 1.1.5 - Removed the unused skill-card.md file. - Updated references/extract-redux-slice.mjs (details not specified in diff). - No changes to user-facing documentation or functionality.","fileCount":5,"zipByteSize":9546},{"version":"1.1.4","createdAt":"2026-09-28T14:00:41.019Z","changelog":"- Updated documentation to reference the new ContextMint Bridge browser extension, replacing the previous Transporter extension. - Clarified installation and usage instructions for ContextMint Bridge, including public source and release information. - Removed mention and file for skill-card.md.","fileCount":5,"zipByteSize":9478},{"version":"1.1.3","createdAt":"2026-09-25T15:52:44.251Z","changelog":"- Removed the file skill-card.md. - No functional or behavioral changes to the skill itself.","fileCount":5,"zipByteSize":9304},{"version":"1.1.2","createdAt":"2026-09-23T21:40:56.000Z","changelog":"- Removed the file skill-card.md. - No user-facing features or documentation changes.","fileCount":5,"zipByteSize":9425},{"version":"1.1.1","createdAt":"2026-09-23T15:39:25.713Z","changelog":"- Removed the redundant skill-card.md file. - No changes to functionality or usage.","fileCount":5,"zipByteSize":9639}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:tock-fpx","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:tock-fpx` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/chrischall/tock-fpx before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T16:03:01.147Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-tock-fpx/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:52:03.591Z","emptyReason":null},"readme":"Skill: tock-fpx\n\nOwner: chrischall\n\nSummary: Query Tock (exploretock.com — restaurant discovery, availability, and the signed-in user's reservations) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the tock-mcp server — list metros, search a metro's restaurants, get a venue's bookable calendar, and list reservations, all through a signed-in browser tab. Use when you want Tock data without the MCP, in a script, or on a machine where the MCP isn't installed.\n\nTags: latest:1.1.8\n\nVersion history:\n\nv1.1.8 | 2026-10-09T23:29:58.854Z | auto\n\n- Removed the file skill-card.md.\n- No functional or user-facing changes; documentation and usage remain unchanged.\n\nv1.1.7 | 2026-10-07T13:40:03.719Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing changes to functionality or documentation.\n\nv1.1.6 | 2026-10-05T02:54:31.621Z | auto\n\n- Removed the redundant skill-card.md file.\n- No changes to core functionality or documentation.\n\nv1.1.5 | 2026-10-03T01:46:58.272Z | auto\n\ntock-fpx 1.1.5\n\n- Removed the unused skill-card.md file.\n- Updated references/extract-redux-slice.mjs (details not specified in diff).\n- No changes to user-facing documentation or functionality.\n\nv1.1.4 | 2026-09-28T14:00:41.019Z | auto\n\n- Updated documentation to reference the new ContextMint Bridge browser extension, replacing the previous Transporter extension.\n- Clarified installation and usage instructions for ContextMint Bridge, including public source and release information.\n- Removed mention and file for skill-card.md.\n\nv1.1.3 | 2026-09-25T15:52:44.251Z | auto\n\n- Removed the file skill-card.md.\n- No functional or behavioral changes to the skill itself.\n\nv1.1.2 | 2026-09-23T21:40:56.000Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing features or documentation changes.\n\nv1.1.1 | 2026-09-23T15:39:25.713Z | auto\n\n- Removed the redundant skill-card.md file.\n- No changes to functionality or usage.\n\nv1.1.0 | 2026-09-20T02:52:29.022Z | auto\n\n- Removed the file: skill-card.md.\n- No functional or user-facing changes; maintenance cleanup only.\n\nv1.0.0 | 2026-09-19T11:18:57.011Z | auto\n\n- Initial release of the tock-fpx skill (v1.0.0)\n- Query Tock (exploretock.com) data via the fpx CLI without running the tock-mcp server.\n- Supports listing metros, searching city restaurants, viewing venue calendars, and listing reservations through a signed-in browser tab.\n- Read-only access; booking and canceling reservations are not supported.\n- Requires the Transporter browser extension and setup of an fpx profile.\n- Removed the skill-card.md file.\n\nv0.5.4 | 2026-09-15T18:48:11.310Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation in SKILL.md.\n\nv0.5.3 | 2026-09-14T14:11:04.940Z | auto\n\n- Removed the sample file skill-card.md from the project.\n- No functional or user-facing changes.\n\nv0.5.2 | 2026-09-10T17:51:31.269Z | auto\n\n- Removed the file skill-card.md.\n- No functional changes to user-facing commands or documentation.\n\nv0.5.1 | 2026-09-09T21:16:57.907Z | auto\n\n- Removes the skill-card.md file.\n- No changes to functionality or documentation (SKILL.md remains the same).\n\nv0.5.0 | 2026-09-04T22:22:56.401Z | auto\n\n- Removed the redundant skill card file (skill-card.md) for a leaner package.\n- No user-facing feature or behavior changes; all core functionality and documentation remain unchanged.\n\nv0.4.0 | 2026-08-29T13:54:12.052Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing changes to functionality or documentation.\n\nv0.3.1 | 2026-08-28T21:07:41.840Z | auto\n\n- Added initial public documentation in SKILL.md, detailing how to use the `tock-fpx` skill to access Tock restaurant data via the fpx CLI and Transporter extension.\n- Outlined requirements, setup steps, supported data queries (metros, search, venue calendar, reservations), and read-only limitations.\n- Described how to extract data from Tock's SSR pages and authenticated GraphQL endpoints.\n- Documented exit codes, troubleshooting steps, and limitations for booking and cancellation actions.\n- Provided usage notes for both casual and technical users.\n\nArchive index:\n\nArchive v1.1.8: 5 files, 9605 bytes\n\nFiles: references/extract-redux-slice.mjs (4654b), references/requests.md (7205b), skill-card.md (2103b), SKILL.md (6035b), _meta.json (127b)\n\nFile v1.1.8:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari isn't available yet, so use Chrome for now), with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published `.sha256` file.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.8:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1791588598854\n}\n\nFile v1.1.8:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.8:skill-card.md\n\n## Description:\n\nHelps agents query Tock restaurants, availability, and a signed-in user's reservations through the fpx CLI and a paired browser tab without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to find Tock metros and restaurants, inspect venue availability, and look up the signed-in user's reservations from a shell. It provides read-only lookups, not booking or cancellation.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Reservation results can expose names, email addresses, and itinerary details.\n\nMitigation: Treat reservation and account details as private; avoid shared temporary files and redact terminal output before sharing it.\n\nRisk: Browser extension pairing grants the CLI access to a Tock tab, including signed-in reservation data.\n\nMitigation: Pair only a trusted fpx installation and browser extension, and use a signed-in tab only when retrieving reservations.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Tock request examples](references/requests.md)\n- [Tock response extraction helper](references/extract-redux-slice.mjs)\n- [ContextMint Bridge source](https://github.com/nullnet-app/contextmint-bridge)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON query examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only; reservation lookups require a signed-in Tock tab.]\n\n## Skill Version(s):\n\n1.1.8 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.7: 5 files, 9649 bytes\n\nFiles: references/extract-redux-slice.mjs (4654b), references/requests.md (7205b), skill-card.md (2139b), SKILL.md (6035b), _meta.json (127b)\n\nFile v1.1.7:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari isn't available yet, so use Chrome for now), with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published `.sha256` file.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.7:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1791380403719\n}\n\nFile v1.1.7:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.7:skill-card.md\n\n## Description:\n\nQueries Tock for restaurant discovery, venue availability, and the signed-in user's reservations through the fpx CLI and a browser tab without running the tock-mcp server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other Tock users use this skill to find restaurants, inspect bookable dates and times, and view their own reservations from a shell without an MCP server. The skill does not book or cancel reservations.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Reservation responses can expose names, email addresses, reservation IDs, venues, and dates.\n\nMitigation: Treat reservation results as private; avoid saving them in shared temporary directories and remove saved responses when finished.\n\nRisk: Queries run through fpx and the ContextMint Bridge extension using a browser session with access to exploretock.com.\n\nMitigation: Install and pair the extension only if you are comfortable with read-only requests to exploretock.com from that session.\n\n## Reference(s):\n\n- [Tock fpx request recipes](references/requests.md)\n- [Redux slice extraction helper](references/extract-redux-slice.mjs)\n- [ContextMint Bridge source and installation](https://github.com/nullnet-app/contextmint-bridge)\n- [Tock](https://www.exploretock.com)\n- [tock-fpx release](https://clawhub.ai/chrischall/skills/tock-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Shell commands, Code, Guidance]\n\n**Output Format:** [Markdown with shell commands and structured JSON query results]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only; reservation results may contain personal information.]\n\n## Skill Version(s):\n\n1.1.7 (source: server-resolved release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.6: 5 files, 9535 bytes\n\nFiles: references/extract-redux-slice.mjs (4654b), references/requests.md (7205b), skill-card.md (1884b), SKILL.md (6035b), _meta.json (127b)\n\nFile v1.1.6:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari isn't available yet, so use Chrome for now), with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published `.sha256` file.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.6:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.6\",\n  \"publishedAt\": 1791168871621\n}\n\nFile v1.1.6:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.6:skill-card.md\n\n## Description:\n\nHelps agents query Tock restaurants, availability, and signed-in reservations from a browser-backed shell without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to find restaurants and available reservations on Tock, or retrieve their own reservation history through a browser session. Booking and cancellation remain on Tock's website.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Browser-backed access to a signed-in Tock session can expose account identity and reservation history.\n\nMitigation: Grant browser access only if comfortable with the extension and avoid sharing reservation responses.\n\nRisk: Example commands can leave personal reservation data in temporary files or logs.\n\nMitigation: Avoid running sensitive examples on shared machines or saving their responses to uncontrolled logs.\n\n## Reference(s):\n\n- [Tock request examples](references/requests.md)\n- [Redux slice extraction helper](references/extract-redux-slice.mjs)\n- [ContextMint Bridge extension](https://github.com/nullnet-app/contextmint-bridge)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON query examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only queries; signed-in results can include personal reservation details.]\n\n## Skill Version(s):\n\n1.1.6 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.5: 5 files, 9546 bytes\n\nFiles: references/extract-redux-slice.mjs (4654b), references/requests.md (7205b), skill-card.md (1908b), SKILL.md (6035b), _meta.json (127b)\n\nFile v1.1.5:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari isn't available yet, so use Chrome for now), with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published `.sha256` file.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.5:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.5\",\n  \"publishedAt\": 1790992018272\n}\n\nFile v1.1.5:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.5:skill-card.md\n\n## Description:\n\nQueries Tock restaurant listings, availability, and signed-in reservation history from the shell through a paired browser session.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other Tock users can discover restaurants, inspect bookable dates, and view their own reservations without running a separate MCP server. The skill does not book or cancel reservations.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The paired browser extension can access exploretock.com through the user's browser session.\n\nMitigation: Install and pair it only if comfortable granting that site access, and review the extension before use.\n\nRisk: Reservation and profile results, including temporary files, may expose names, email addresses, and reservation history.\n\nMitigation: Treat outputs as sensitive, limit sharing, and remove temporary files when no longer needed.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Tock request recipes](references/requests.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Shell commands, JSON]\n\n**Output Format:** [Text or JSON with shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only results; signed-in reservation and profile responses may contain personal information.]\n\n## Skill Version(s):\n\n1.1.5 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.4: 5 files, 9478 bytes\n\nFiles: references/extract-redux-slice.mjs (4569b), references/requests.md (7205b), skill-card.md (1903b), SKILL.md (6035b), _meta.json (127b)\n\nFile v1.1.4:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari isn't available yet, so use Chrome for now), with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published `.sha256` file.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.4\",\n  \"publishedAt\": 1790604041019\n}\n\nFile v1.1.4:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.4:skill-card.md\n\n## Description:\n\nQuery Tock metros, restaurants, venue availability, and your reservations from a shell through a browser session without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to find Tock restaurants and availability or read an authorized account's reservations through the fpx CLI. Booking and cancellation remain on Tock's website.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The CLI and browser extension can access the signed-in Tock session.\n\nMitigation: Install only if comfortable granting this access; use account-specific commands only for accounts you own or are authorized to access.\n\nRisk: Saved reservation responses may contain names, email addresses, and booking details.\n\nMitigation: Avoid retaining or sharing response files; delete temporary files after use.\n\n## Reference(s):\n\n- [Tock requests for fpx](references/requests.md)\n- [ContextMint Bridge source](https://github.com/nullnet-app/contextmint-bridge)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance, Text]\n\n**Output Format:** [Markdown with shell commands and query examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only Tock queries; reservations and account identity require an authorized signed-in browser session.]\n\n## Skill Version(s):\n\n1.1.4 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.3: 5 files, 9304 bytes\n\nFiles: references/extract-redux-slice.mjs (4569b), references/requests.md (7205b), skill-card.md (1939b), SKILL.md (5615b), _meta.json (127b)\n\nFile v1.1.3:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.3\",\n  \"publishedAt\": 1790351564251\n}\n\nFile v1.1.3:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.3:skill-card.md\n\n## Description:\n\nGuides agents in querying Tock restaurant listings, availability, and signed-in reservations through the fpx CLI and a paired browser tab without running the Tock MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to browse Tock metros and venues, check bookable availability, and retrieve their own reservations through a paired browser session. Booking and cancellation remain on the Tock website.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Pairing fpx with a signed-in Tock tab grants access to personal reservation details.\n\nMitigation: Pair only on a trusted device and use the signed-in session only when reservation access is needed.\n\nRisk: Reservation and identity data may remain in terminal output or saved temporary files.\n\nMitigation: Avoid shared machines, limit exposure of terminal output, and delete saved response files when finished.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Tock](https://www.exploretock.com)\n- [Tock request recipes](references/requests.md)\n- [Redux slice extraction helper](references/extract-redux-slice.mjs)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON data, Guidance]\n\n**Output Format:** [Markdown instructions and CLI JSON output]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only; reservation queries require a signed-in Tock browser tab.]\n\n## Skill Version(s):\n\n1.1.3 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.2: 5 files, 9425 bytes\n\nFiles: references/extract-redux-slice.mjs (4569b), references/requests.md (7205b), skill-card.md (2228b), SKILL.md (5615b), _meta.json (127b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1790199656000\n}\n\nFile v1.1.2:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.2:skill-card.md\n\n## Description:\n\ntock-fpx helps agents query Tock restaurant discovery, venue availability, and a signed-in user's reservations from shell commands through the fpx CLI and the user's browser tab.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agent operators use this skill to retrieve Tock metros, restaurants, venue calendars, availability, and reservation history without running the Tock MCP server. The skill is read-only and relies on an fpx/Transporter browser session for access.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill uses fpx and the Transporter extension with access to an exploretock.com browser tab.\n\nMitigation: Install and run it only if that browser-session access is acceptable; keep Chrome site access scoped to exploretock.com and use a signed-in tab only for reservation queries.\n\nRisk: Reservation and profile outputs, including temporary JSON files, may contain names, email addresses, venue details, and booking times.\n\nMitigation: Treat those outputs as sensitive, avoid sharing them unnecessarily, and remove temporary files after use.\n\n## Reference(s):\n\n- [tock-fpx ClawHub skill page](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Skill instructions](artifact/SKILL.md)\n- [Tock request recipes](artifact/references/requests.md)\n- [Redux slice extractor](artifact/references/extract-redux-slice.mjs)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, markdown, code, shell commands, configuration]\n\n**Output Format:** [Markdown instructions with shell commands, JSON examples, and JavaScript helper code]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only workflows; reservation outputs can include personal data from the signed-in Tock account.]\n\n## Skill Version(s):\n\n1.1.2 (source: ClawHub server evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.1: 5 files, 9639 bytes\n\nFiles: references/extract-redux-slice.mjs (4569b), references/requests.md (7205b), skill-card.md (2749b), SKILL.md (5615b), _meta.json (127b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1790177965713\n}\n\nFile v1.1.1:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.1:skill-card.md\n\n## Description:\n\nQuery Tock restaurant discovery, venue availability, and signed-in reservation data from a shell with the fpx CLI through the user's own browser session.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to retrieve Tock metro, restaurant, venue calendar, availability, and reservation information with shell commands instead of running the Tock MCP server. It is intended for read-only lookup workflows; booking and cancellation should be done directly on Tock.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Reservation and account lookup can expose personal data from the user's signed-in Tock browser session, including names, email addresses, venues, reservation times, and locally saved response files.\n\nMitigation: Use the skill only for read-only lookup, keep saved responses local and short-lived, and avoid sharing command output that contains personal reservation or account details.\n\nRisk: The skill depends on a paired fpx/Transporter browser bridge with site access to exploretock.com.\n\nMitigation: Pair only with a trusted browser profile, keep the Transporter site access scoped to exploretock.com, and use fpx health checks when the bridge or challenge-cleared tab state is unclear.\n\nRisk: Booking and cancellation are outside the supported read-only flow, and reservation state can require confirmation after an action taken elsewhere.\n\nMitigation: Perform booking or cancellation directly on Tock, and treat a reservation as confirmed only after a confirmation ID, URL, or email is captured and a later reservation-history lookup verifies it.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Tock requests for fpx](references/requests.md)\n- [Redux slice extraction script](references/extract-redux-slice.mjs)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with shell commands, JavaScript helper usage, jq filters, and JSON request examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces read-only lookup instructions and command recipes; browser pairing and signed-in state determine which Tock data can be accessed.]\n\n## Skill Version(s):\n\n1.1.1 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.0: 5 files, 9667 bytes\n\nFiles: references/extract-redux-slice.mjs (4569b), references/requests.md (7205b), skill-card.md (2835b), SKILL.md (5615b), _meta.json (127b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`/api/graphql/<OperationName>`) — used only for\n   the signed-in patron's reservations, which are lazy-loaded client-side and\n   never appear in the SSR store. Clean JSON in and out — pipe straight to\n   `jq`:\n\n   ```sh\n   fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'\n   ```\n\nReady-to-run paths/bodies for both shapes, plus the exact GraphQL document and\njq recipes, are in `references/requests.md`.\n\n## The one rule: resolve the metro before searching\n\nTock's `/city/{slug}` search takes a **metro slug** (from `/city`'s `app`\nslice, e.g. `\"chicago\"`), never a free-text city name. A venue's own page path\nis its `domainName` slug (from a search result, or the\n`exploretock.com/{slug}` URL directly) — no numeric-id resolution needed\nbeyond that.\n\n## Exit codes (fetch verbs)\n\n- `0` — success. For GraphQL, a `0` HTTP status can still carry an `errors`\n  array in the body — check `jq '.errors // empty'`.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p tock`, confirm an exploretock.com tab is open.\n- `3` — bot wall: the tab hasn't cleared the Cloudflare challenge → open/\n  refresh a `www.exploretock.com` tab and retry.\n- `4` — upstream non-2xx from Tock (e.g. a bad slug → 404).\n\nA non-JSON 2xx body on the GraphQL path is almost always a bot-challenge or\nsign-in interstitial slipping through, not real data — don't blindly\n`JSON.parse` it.\n\n## Why no booking/cancel\n\nTock's booking/checkout/cancel flow is a stateful **protobuf** transaction\n(`/api/ticket/*`) authenticated by app-injected `X-Tock-Authorization` /\n`X-Tock-Session` / `X-Tock-Fingerprint` request headers set by Tock's own JS\ninterceptor — not cookies. A bridge fetch (fpx included) only carries the\ntab's cookies, so replaying the protobuf calls 404s\n(`\"Unknown business identifier\"`). Reconstructing those headers would mean\nharvesting the user's live session secrets or forging an anti-bot device\nfingerprint — both out of scope. This skill (like the MCP) stays read-only;\nbook/cancel on exploretock.com itself. Full detail: `docs/TOCK-API.md` in the\ntock-mcp repo.\n\nIf a booking was made outside this skill (on the site, by hand or by UI\nautomation), treat it as **confirmed** only when a confirmation ID/URL/email\nwas captured **and** it shows up in a `PatronReservationHistory` re-query\nafterward; otherwise report it as \"attempted, unverified.\" The post-booking\nmodal is not proof (a stale-cart confirm is a silent no-op that still renders\nit), and the reservations backend lags the Reservations tab by minutes — an\nimmediate empty re-read proves nothing.\n\n## Notes\n\n- `fpx health -p tock` shows bridge connection state when a call fails.\n- Reservations/profile calls need a **signed-in** tab; browsing does not.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.0\",\n  \"publishedAt\": 1789872749022\n}\n\nFile v1.1.0:references/requests.md\n\n# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerPerson.maxCents/100)\\t\\(.partySize | join(\",\"))\"' /tmp/tock-cal.json\n```\n\n`calendar.offerings` shape (§ TOCK-API.md \"Pages we fetch\"):\n\n```\nofferings: {\n  experience: [ { id, name, slug, shortCode, description, type,\n    currencyCode, partySize:[…], pricePerPerson:{minCents,maxCents},\n    ticketPriceInformation:{amountCents,priceType}, state,\n    communicationPolicy:{canTransfer,cancellationPolicyText},\n    eventDetails:{location:{address,city,state,zipCode,lat,lng,name}} } ],\n  openDate: [\"2026-07-03\", …],\n  openTime: [\"17:00\",\"17:15\", …]\n}\n```\n\n`priceType` of `PREPAID`/`DEPOSIT` means the experience needs a card at\ncheckout on exploretock.com — this skill cannot book it (see SKILL.md).\n\n## 4. Date-centered availability — `GET /{slug}/search?date=YYYY-MM-DD&size=N`\n\nSame `calendar` slice as §3, centered on `date`/`size` (party size). Tock\nreturns the *whole* open-date/open-time union regardless — the UI filters\nclient-side, so there's no per-date-only payload.\n\n```sh\nfpx get 'https://www.exploretock.com/alinea/search?date=2026-08-01&size=2' -p tock \\\n  | node extract-redux-slice.mjs calendar \\\n  | jq '{openDates: .offerings.openDate, openTimes: .offerings.openTime, experiences: [.offerings.experience[] | select(.partySize == null or (.partySize | index(2)))]}'\n```\n\n## 5. Signed-in patron's reservations — `POST /api/graphql/PatronReservationHistory`\n\nRequires a **signed-in** tab. `selection` is a string enum:\n`UPCOMING` | `PAST` | `CANCELED`.\n\n```sh\ncat > /tmp/tock-reservations.json <<'JSON'\n{\n  \"operationName\": \"PatronReservationHistory\",\n  \"variables\": { \"offset\": 0, \"limit\": 30, \"selection\": \"UPCOMING\" },\n  \"query\": \"\\n    query PatronReservationHistory($offset: Int!, $limit: Int!, $selection: String!) {\\n  purchases(offset: $offset, limit: $limit, selection: $selection) {\\n    id\\n    ...ConsumerPurchaseSummary\\n  }\\n}\\n\\n    fragment ConsumerPurchaseSummary on ConsumerPurchaseSummary {\\n  business {\\n    domainName\\n    id\\n    profileImages {\\n      altText\\n      backingUrl\\n      dominantColor\\n      id\\n      imageUrl\\n    }\\n    name\\n  }\\n  cancelledOrRefunded\\n  city\\n  country\\n  dinerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  eligibleForFeedback\\n  visitFiveStarRating\\n  firstTransferredTo {\\n    id\\n  }\\n  id\\n  ownerPatron {\\n    email\\n    firstName\\n    lastName\\n    id\\n  }\\n  ticketCount\\n  ticketDateTime\\n  ticketType {\\n    deliveryServiceProvider\\n    descriptiveVariety\\n    id\\n    name\\n    reserveShippingTime\\n    singleUnitQuantity\\n    variety\\n  }\\n}\\n\"\n}\nJSON\n\nfpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n  @/tmp/tock-reservations.json -p tock > /tmp/tock-reservations-response.json\n\njq -r '.data.purchases[] | \"\\(.ticketDateTime)\\t\\(.business.name)\\t\\(.ticketCount)ppl\\t\\(.ticketType.name)\\(if .cancelledOrRefunded then \" [CANCELLED]\" else \"\" end)\"' /tmp/tock-reservations-response.json\n```\n\nCheck GraphQL-level errors first: `jq '.errors // empty' /tmp/tock-reservations-response.json` — an\nauth-flavored message (matches `/auth|sign|login|unauthorized|permission/i`) means the tab\nisn't signed in; re-open exploretock.com and log in, then retry.\n\n## 6. Account identity (no standalone query)\n\nTock has no profile GraphQL query — the account holder's identity rides on\neach purchase as `ownerPatron` (fall back to `dinerPatron`). Reuse §5's call\nwith `\"selection\": \"UPCOMING\"` (or `\"PAST\"` if there are no upcoming\nreservations) and project the first entry:\n\n```sh\njq -r '.data.purchases[0] | (.ownerPatron // .dinerPatron) | \"\\(.firstName) \\(.lastName) <\\(.email)>\"' /tmp/tock-reservations-response.json\n```\n\nIf there are zero purchases in both selections, Tock exposes no identity at\nall for that account (this mirrors `tock_get_profile`'s behavior in the MCP).\n\n---\n\n## Booking / cancel — not supported\n\nSee `SKILL.md` § \"Why no booking/cancel\". The full reverse-engineered\nprotobuf protocol (lock → price → confirm → cancel) and the exact\n`X-Tock-*` header gate that blocks it are documented in the tock-mcp repo's\n`docs/TOCK-API.md` for the record — nothing here implements it.\n\nFile v1.1.0:skill-card.md\n\n## Description:\n\nQuery Tock restaurant discovery, availability, venue details, and the signed-in user's reservations from a shell with the fpx CLI through the user's browser session.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and technical users use this skill to query Tock data from shell workflows without running the tock-mcp server. It supports read-only restaurant discovery, metro and venue lookup, availability inspection, and user-directed reservation or account-identity reads through an existing browser session.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Signed-in reservation and account-identity commands can expose personal names, email addresses, and reservation details from the user's Tock account.\n\nMitigation: Run those commands only when the user explicitly wants that information retrieved, and avoid storing or sharing the returned personal data unnecessarily.\n\nRisk: The skill depends on a paired fpx/Transporter bridge and an exploretock.com browser tab, so results can fail or be incomplete when the tab is not signed in, not challenge-cleared, or not connected.\n\nMitigation: Check bridge health and login state before relying on results, and treat failed or empty signed-in reads as inconclusive unless the command output confirms the condition.\n\nRisk: Booking and cancellation are out of scope, and external booking attempts can be difficult to verify immediately from Tock's delayed reservation backend.\n\nMitigation: Use the skill only for read-only queries, and treat bookings as confirmed only after a confirmation ID, URL, or email is captured and a later reservation-history query verifies the reservation.\n\n## Reference(s):\n\n- [Tock requests for fpx](references/requests.md)\n- [extract-redux-slice.mjs](references/extract-redux-slice.mjs)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Publisher profile](https://clawhub.ai/user/chrischall)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Code, Configuration instructions, Guidance]\n\n**Output Format:** [Markdown with inline shell commands, jq filters, JSON request bodies, and JavaScript helper code]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only workflow guidance; signed-in reservation and account-identity queries may return personal data from the user's Tock account.]\n\n## Skill Version(s):\n\n1.1.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.0: 5 files, 9412 bytes\n\nFiles: references/extract-redux-slice.mjs (4569b), references/requests.md (7205b), skill-card.md (2191b), SKILL.md (5615b), _meta.json (127b)\n\nFile v1.0.0:SKILL.md\n\n---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'\n   ```\n\n2. **Authenticated GraphQL** (`","readmeExcerpt":"Skill: tock-fpx Owner: chrischall Summary: Query Tock (exploretock.com — restaurant discovery, availability, and the signed-in user's reservations) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the tock-mcp server — list metros, search a metro's restaurants, get a venue's bookable calendar, and list reservations, all through a signed-in browser tab. Use when you want Tock data without the MCP, in","codeSnippets":[],"executableExamples":[{"language":"sh","snippet":"npm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge"},{"language":"sh","snippet":"fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n     | jq '.metros // . | length'"},{"language":"sh","snippet":"fpx post-json 'https://www.exploretock.com/api/graphql/PatronReservationHistory?opname=PatronReservationHistory' \\\n     @body.json -p tock | jq '.data.purchases'"},{"language":"sh","snippet":"fpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'"},{"language":"sh","snippet":"fpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '"},{"language":"sh","snippet":"fpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: tock-fpx\ndescription: >-\n  Query Tock (exploretock.com — restaurant discovery, availability, and the\n  signed-in user's reservations) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the tock-mcp server — list metros,\n  search a metro's restaurants, get a venue's bookable calendar, and list\n  reservations, all through a signed-in browser tab. Use when you want Tock\n  data without the MCP, in a script, or on a machine where the MCP isn't\n  installed.\n---\n\n# Tock via fpx (no MCP)\n\n`www.exploretock.com` sits behind a Cloudflare managed challenge — a plain\n`curl`/Node request 403s every path (`cf-mitigated: challenge`, a \"Just a\nmoment...\" interstitial), including `/city` and `/{slug}`. There is no\nserver-side login form and no consumer token exchange. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same fetch\nsucceeds. Browsing (metros, search, venue detail, availability) needs no Tock\nlogin at all — just an open, challenge-cleared tab; only the reservations\nlist needs the tab **signed in**.\n\nThis is the same data the `tock_*` MCP tools return, reached with one-shot CLI\ncalls instead of a running server. It is **read-only** — see \"Why no\nbooking/cancel\" below.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli              # provides `fpx`\nfpx profile add tock --domain exploretock.com\nfpx pair -p tock                             # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari isn't available yet, so use Chrome for now), with an open\n`www.exploretock.com` tab (signed in, for the reservations tool only), and its\nChrome **Site access** allowing `exploretock.com`. Pairing persists — after the\nfirst approval every later `fpx` call reuses it. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published `.sha256` file.\n\n## Two call shapes\n\nTock has two different backends behind the same bridge:\n\n1. **SSR pages** (`/city`, `/city/{slug}`, `/{slug}`, `/{slug}/search`) — an\n   ordinary GET returns full HTML with the entire dataset embedded as a JS\n   object-literal assignment: `window.$REDUX_STATE = {\"app\":{...},\n   \"consumerPage\":{...}, \"calendar\":{...}, ...}`. It is **not** JSON — absent\n   fields are the bare identifier `undefined`, so `jq` can't parse the raw\n   response. Use the bundled `references/extract-redux-slice.mjs` (a faithful\n   port of the MCP's own `src/redux-state.ts`) to pull one named slice out as\n   real JSON, then pipe that to `jq`:\n\n   ```sh\n   fpx get 'https://www.exploretock.com/city' -p tock \\\n     | node references/extract-redux-slice.mjs app \\\n   "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"tock-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1791588598854\n}"},{"path":"references/requests.md","content":"# Tock requests for fpx\n\nAll paths are relative to `https://www.exploretock.com` (subdomain `www`).\nField names, slice keys, and the GraphQL document below are transcribed\nverbatim from the tock-mcp repo (`docs/TOCK-API.md`, `src/parse.ts`,\n`src/graphql-ops.ts`) — not guessed.\n\nEvery SSR-page recipe follows the same shape:\n\n```sh\nfpx get '<url>' -p tock | node extract-redux-slice.mjs <sliceKey> | jq '<filter>'\n```\n\n(`extract-redux-slice.mjs` lives alongside this file — see `SKILL.md` for why\nit's needed instead of piping straight to `jq`.)\n\n---\n\n## 1. List metros — `GET /city`\n\nSlice: `app`. The metro directory is the largest array whose items carry\n`slug` + `name` + numeric `businessCount`. Many entries have\n`businessCount: 0` (inactive) — filter those out for real venues.\n\n```sh\nfpx get 'https://www.exploretock.com/city' -p tock \\\n  | node extract-redux-slice.mjs app \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"slug\") and has(\"businessCount\")))]\n      | max_by(length)[]\n      | select(.businessCount > 0)\n      | \"\\(.slug)\\t\\(.businessCount)\\t\\(.name)\"\n    '\n```\n\nFields per metro: `name`, `slug`, `state`, `country`, `businessCount`,\n`isActive`, `isFeatured`, `timezone`, `currencyCode`, `lat`, `lng`, `id`.\n\n## 2. Search a metro's restaurants — `GET /city/{slug}[?query=]`\n\nSlice: `consumerPage`. Business listings are nested widget-tree arrays whose\nitems carry `domainName` + `name`; `?query=` filters server-side.\n\n```sh\nfpx get 'https://www.exploretock.com/city/chicago?query=tasting' -p tock \\\n  | node extract-redux-slice.mjs consumerPage \\\n  | jq -r '\n      [.. | arrays | select(length > 0 and (.[0] | type == \"object\") and (.[0] | has(\"domainName\") and has(\"name\")))]\n      | add\n      | unique_by(.domainName)[]\n      | \"\\(.domainName)\\t\\(.priceRange // \"\")\\t\\(.name) — \\(.neighborhood // .city // \"\")\"\n    '\n```\n\nFields per business: `domainName` (→ the venue's own page slug),\n`name`, `description`, `cuisines`, `priceRange` (e.g. `\"$$$$\"`),\n`businessType`, `city`, `state`, `country`, `neighborhood`, `webUrl`,\n`timeZone`, `currencyCode`, `locale`,\n`location {address city state country zipCode lat lng id}`,\n`profileImageUrl`, `heroImageUrl`, `isTockUnlisted`.\n\nA bare `/search?query=X` redirects to a detected metro — always call with an\nexplicit metro slug instead.\n\n## 3. Venue detail — `GET /{slug}`\n\nTwo slices in one fetch: `app` (the venue's own business record — the item\nwhose `domainName === slug`) and `calendar` (its bookable offerings).\n\n```sh\nfpx get 'https://www.exploretock.com/alinea' -p tock > /tmp/tock-venue.html\n\nnode extract-redux-slice.mjs app     < /tmp/tock-venue.html > /tmp/tock-app.json\nnode extract-redux-slice.mjs calendar < /tmp/tock-venue.html > /tmp/tock-cal.json\n\njq -r '.. | objects | select(.domainName == \"alinea\") | \"\\(.name) — \\(.cuisines) \\(.priceRange)\"' /tmp/tock-app.json\n\njq -r '.offerings.experience[] | \"\\(.id)\\t\\(.name)\\t\\(.pricePerPerson.minCents/100)-\\(.pricePerP"},{"path":"skill-card.md","content":"## Description:\n\nHelps agents query Tock restaurants, availability, and a signed-in user's reservations through the fpx CLI and a paired browser tab without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to find Tock metros and restaurants, inspect venue availability, and look up the signed-in user's reservations from a shell. It provides read-only lookups, not booking or cancellation.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Reservation results can expose names, email addresses, and itinerary details.\n\nMitigation: Treat reservation and account details as private; avoid shared temporary files and redact terminal output before sharing it.\n\nRisk: Browser extension pairing grants the CLI access to a Tock tab, including signed-in reservation data.\n\nMitigation: Pair only a trusted fpx installation and browser extension, and use a signed-in tab only when retrieving reservations.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/tock-fpx)\n- [Tock request examples](references/requests.md)\n- [Tock response extraction helper](references/extract-redux-slice.mjs)\n- [ContextMint Bridge source](https://github.com/nullnet-app/contextmint-bridge)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON query examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only; reservation lookups require a signed-in Tock tab.]\n\n## Skill Version(s):\n\n1.1.8 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1373,"uniquenessScore":43,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T13:52:03.591Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T13:52:03.591Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:03:01.150Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}