From restaurant-ranker
Use when probing restaurant booking platforms (TableCheck, SevenRooms, Chope, CoverManager, Hungry Hub, Eatigo, Weeloy, Inline, OpenTable, Resy, Tock) to read table availability for a trip — which dates / times / party sizes are open vs booked out — across a city's restaurants. Read-only: reads the calendar, never makes or confirms a reservation. Drives the real booking widget via the agent-browser CLI, one verified recipe per platform, one browser session per restaurant for sequential/parallel fan-out. Part of the restaurant-ranker plugin.
How this skill is triggered — by the user, by Claude, or both
Slash command
/restaurant-ranker:booking-probeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Reads **table availability** from restaurant booking widgets by driving the real UI with the
drivers/drive_sevenrooms.pyfinalize_fill.pyrecipes/_TEMPLATE.mdrecipes/chope.mdrecipes/covermanager.mdrecipes/dinnerbooking.mdrecipes/eatigo.mdrecipes/hungryhub.mdrecipes/inline.mdrecipes/opentable.mdrecipes/pocket-concierge.mdrecipes/sevenrooms.mdrecipes/superb.mdrecipes/tablecheck.mdrecipes/thefork.mdrecipes/weeloy.mdreferences/clickthrough-technique.mdreferences/engine-routing.mdreferences/ma-dispatch.mdreferences/platform-knowledge.mdReads table availability from restaurant booking widgets by driving the real UI with the
agent-browser CLI — snapshot → click → re-snapshot — and recording, per (venue × date ×
party), which time slots are offered vs booked out. Builds a per-city availability dataset for
trip brainstorming. It is a brainstorming/research tool. It never books anything.
Read availability only. NEVER submit, confirm, or complete a reservation.
Push through gates to reach and read the slot list (accept T&C, set party size, pick a default course menu, dismiss cookie banners). Then STOP. Reading the offered slots IS the probe. Clicking a slot, a "Next"/"Book"/"Confirm"/"Complete" button, or entering payment / deposit details is a FAILURE of the task — it creates a real reservation, blocks a real table, and violates lakbai's core anti-goal.
Forbidden, no exceptions:
Red flags — STOP immediately if you think any of these:
All of these mean: you are about to create a real booking. Back out. The slot list is enough.
200 bookable restaurants per city — Manila, Bangkok, Tokyo, New York, and beyond — probed availability-only. Harden this skill one restaurant at a time via sequential MA / autopilot sessions, accumulating edge-case coverage until every platform recipe is bulletproof against all cases. Confidence per restaurant before scaling. Slow and deliberate.
Each restaurant is a test case for the skill. Run them one by one:
recipes/<platform>.md), full target grid
(every date × party 2/4/6). One agent-browser --session lakbai-<venue-slug> per restaurant.unresolved/error):
that venue is confirmed; add it to the recipe's "cases handled" ledger; move to the next.Never silently drop a failure. An honest unresolved with a blocker note is correct; a fake
available/full is the worst outcome (it corrupts the dataset — see Common Mistakes).
agent-browser's accessibility snapshot sees form controls but often NOT the result slots (heavy
widgets render them in shadow DOM). The universal pattern: use agent-browser eval with a
recursive shadow-root walk to click buried controls and read slots from document.body.innerText,
and match elements by a combined signature (data-test + aria-label + title + text), never a
single attribute. Full technique + gotchas: references/clickthrough-technique.md.
Endgame: one MA/autopilot session per restaurant, each running its platform recipe as a behavior
brief, fanned out across a city's 200 venues. agent-browser --session lakbai-<venue-slug> gives
each restaurant an isolated browser. Build up sequentially (one at a time) until confident, then
widen parallelism. A reference driver that codifies a recipe end-to-end: drivers/drive_sevenrooms.py.
Dispatching MA sessions: use the autopilot skill (/autopilot, three-gate pipeline) to launch
one Managed Agent per restaurant; monitor via the MA API / investigate-cma skill. The full
booking-probe dispatch contract — the read-only-law behavior brief, the zero-unresolved/no-booking
outcome checklist, skill upload, the agent-browser-in-container caveat, and the MA API cheat sheet —
is in references/ma-dispatch.md. Read it before any fan-out.
| Platform | Recipe | Status |
|---|---|---|
| SevenRooms | recipes/sevenrooms.md | ✅ verified (driver + 3×90-unit grids, zero unresolved) |
| TableCheck | recipes/tablecheck.md | ✅ verified OLD Rails (Florilège); ✅ verified new-React (ADHOC Bangkok, party 2, CloakBrowser-CDP) |
| Chope | recipes/chope.md | ✅ verified OLD jQuery (Vertigo BKK, inner_api replay) + NEW Vue SPA read path (Jhol BKK, UI clickthrough — Next=checkout boundary); proxy-to-TableCheck case noted |
| Eatigo | recipes/eatigo.md | ✅ verified (Glass House + Goji, party-independent, per-slot discount; payload-read primary, picker-click fallback) |
| Hungry Hub | recipes/hungryhub.md | ✅ verified (Lamaya BKK live widget — new-SPA drawer flow, per-slot seat_left, real full + partial days; package-vs-restaurant scoping) |
| CoverManager | recipes/covermanager.md | ✅ verified (Supra BCN + DiverXO MAD — cross-slug API replay, month map + per-meal change_day; deposit boundary held) |
| Weeloy | recipes/weeloy.md | ⚠️ DEFUNCT (2026-06-03) — consumer portal dead, API orphaned; re-route venues to their current engine |
| Inline | recipes/inline.md | ⚠️ anti-bot-blocked (PerimeterX Press&Hold; plain Chrome + CloakBrowser both walled from datacenter IP) → unresolved until residential IP/warmed session |
| Pocket Concierge | recipes/pocket-concierge.md | ✅ verified (Narisawa real open/full/closed; CloakBrowser; Instant-vs-Waitlist) — readable OMAKASE mirror |
| OMAKASE | references/platform-knowledge.md | ⚠️ login-gated → gated (check Pocket Concierge mirror first); CloakBrowser-CDP |
| DinnerBooking | recipes/dinnerbooking.md | ✅ verified (AOC Copenhagen — Cloudflare Turnstile cleared via CloakBrowser+patchright; easyTable same family) |
| Superb / Formitable | recipes/superb.md | ✅ verified (Copenhagen iter3 — ALTCHA proof-of-work cleared headless via CloakBrowser) |
| OpenTable | recipes/opentable.md | ✅ verified (Copenhagen iter3 — DataDome cleared via CloakBrowser humanize; RestaurantsAvailability GraphQL slots) |
| Resy · Tock · Toreta | — | ⏳ new engines (build on demand) |
Build order follows venue count + Michelin coverage: TableCheck → Chope → Hungry Hub → the rest →
new engines. To add a platform, copy recipes/_TEMPLATE.md. Prior DOM/endpoint knowledge per
platform (tokens, gates, widget generations) is in references/platform-knowledge.md. The anti-bot
escalation tier — the tiered CloakBrowser playbook (patchright + xvfb + humanize) for the
Turnstile / ALTCHA / DataDome / CDP walls, plus the "403 means wrong tier, not blocked" rule and the
loop for cracking an engine with no recipe yet — is the cloakbrowser sibling skill
(../cloakbrowser/SKILL.md). Read it before probing any anti-bot engine.
Many restaurants book on their own website but delegate to a known engine (Sühring → SevenRooms,
Potong → Chope, Gaa → TableCheck). Resolve direct sites to an engine, then route to its recipe.
Engine-detection method + the Bangkok direct-site map + deposit/phone-only handling:
references/engine-routing.md.
Per-venue JSON, one file per restaurant (no write contention when fanning out), under the
caller's CWD: ./<city>-booking-probe/clickthrough/<venue-slug>.json. Never hard-code an
absolute path. Each unit record: {date, party_size, status, slots:[{time, meal, state}], note}
where each slot's state ∈ available | filled. Day-level status ∈ available | full | no-slots |
gated | unresolved | error is a ROLLUP (any available slot → available; all filled → full).
Don't reduce a date to available/full. Capture every seating time with its per-slot state so the dataset shows which times are gone (e.g. 19:00 filled, 21:00 open).
filled, enabled = available.
Do not drop the greyed ones. (CoverManager's complete class is a DAY-cell state, not a greyed
slot — verified 2026-06-03; its slots are render-only-bookable, see next bullet.)service_grid = union of all times the venue ever offers across the probed window;
per date, filled = service_grid − offered_that_date. The full 30-day grid is what makes this sound.
finalize_fill.py computes this from the per-date offered slots — run it after a venue's grid completes.available/full when the read actually failed. A failed read
is unresolved with a blocker note — always. Silent empties poison the dataset.data-test masks the aria-label; always match the
combined signature.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub clsandoval/restaurant-ranker --plugin restaurant-ranker