Documentation

Table Reservation GOAT CLI

table-reservation-goat-pp-cli

Install

npx -y @mvanhorn/printing-press-library install table-reservation-goat

Installs the CLI binary and the agent skill for Claude Code, Codex, Cursor, Gemini CLI, Copilot, and more. Add --cli-only or --skill-only for one half. Requires Node.

Documentation

One reservation CLI for OpenTable, Tock, and Resy — search each network at once, watch for cancellations, book, and track changes from a local store agents can query.

OpenTable, Tock, and Resy split the US fine-dining world between them and share zero data. This CLI unifies them: goat searches all three at once, watch polls each network for cancellations, earliest composes availability across all three, and drift surfaces what changed at a venue since your last look. Auth is auth login --chrome (for OT + Tock cookies) plus auth login --resy --email <you@example.com> (for the Resy API token) — no partner keys.

Created by @pejmanjohn (Pejman Pour-Moezzi). Contributors: @ganes-j (Jesse Ganes).

Authentication

Two distinct credentials, both managed by auth login:

  • OpenTable + Tock are cookie-session networks. Anonymous reads (search, restaurant detail, availability) work out of the box via Surf with a Chrome TLS fingerprint that clears Akamai (OpenTable) and Cloudflare (Tock). For richer data — anything that requires being signed in — run auth login --chrome once to import your already-logged-in cookies from your local Chrome profile.
  • Resy uses a long-lived API token. Run auth login --resy --email <you@example.com> once; you'll be prompted for your password with echo disabled, the CLI exchanges it for a JWT, and only the token persists in ~/.config/table-reservation-goat-pp-cli/session.json. The password is never stored. The shared public ResyAPI key (the same value every browser uses on resy.com) is hardcoded — there is nothing to register.

auth status shows the per-network state for all three. auth logout without arguments clears everything; auth logout --network resy clears just one network so the other two stay signed in.

Quick Start

# import Chrome cookies for OpenTable + Tock
table-reservation-goat-pp-cli auth login --chrome

# exchange email + password for a Resy API token (interactive password prompt)
table-reservation-goat-pp-cli auth login --resy --email you@example.com

# populate the local SQLite store from each network (restaurants, availability)
table-reservation-goat-pp-cli sync --full

# headline command — single ranked list across all three networks
table-reservation-goat-pp-cli goat 'omakase manhattan' --party 2 --when 'fri 7-9pm' --agent

# set up a cancellation watch and let the printer poll each network adaptively
table-reservation-goat-pp-cli watch add 'alinea' --party 2 --window 'sat 7-9pm' --notify local

# Resy watch — addressed by numeric venue id from `goat <name> --network resy`
table-reservation-goat-pp-cli watch add 'resy:1387' --party 2 --window 'fri 7-9pm' --notify local

# soonest open slot per venue. Bare slugs auto-resolve on OpenTable + Tock;
# Resy venues must be addressed explicitly by numeric id from `goat --network resy`
# because Resy uses numeric venue IDs that don't share slug-space with OT/Tock names.
table-reservation-goat-pp-cli earliest 'le-bernardin,atomix,smyth,alinea,resy:1387' --party 2 --within 14d --agent

# book on Resy (numeric venue id from search)
TRG_ALLOW_BOOK=1 table-reservation-goat-pp-cli book resy:1387 --date 2026-05-15 --time 19:30 --party 2 --agent

# cancel a Resy reservation (resy_token from book output)
table-reservation-goat-pp-cli cancel resy:<resy-token> --agent

Unique Features

These capabilities aren't available in any other tool for this API.

Cross-network ground truth

  • goat — One query across OpenTable, Tock, and Resy simultaneously, ranked by relevance, earliest availability, and price band.

    When a user asks an agent to find a table, this is the single command that searches both reservation networks and returns structured ranked results — agents do not need to know which network covers which restaurant.

    table-reservation-goat-pp-cli goat 'tasting menu chicago' --party 2 --when 'this weekend' --agent --select results.name,results.network,results.earliest_slot,results.price_band
    
  • earliest — Across a list of restaurants from either network, return the earliest open slot per venue within a time horizon.

    When a user gives an agent a shortlist of venues and wants the soonest opportunity, this is the right shape — one structured response with one row per venue across all three networks.

    table-reservation-goat-pp-cli earliest 'alinea,le-bernardin,smyth,atomix' --party 4 --within 21d --agent --select earliest.venue,earliest.network,earliest.slot_at,earliest.attributes
    

Local state that compounds

  • watch — Persistent local watcher that polls each network for openings on your target venues and party size, with notifications and optional auto-book.

    Resy's Notify covers Resy only; tockstalk covers Tock only; restaurant-mcp's snipe covers Resy+OT only. None covers each network; none persists state. Use this when an agent or user needs a hot reservation that isn't currently available.

    table-reservation-goat-pp-cli watch add 'le-bernardin' --party 2 --window 'Fri 7-9pm' --notify slack
    
  • drift — Show what changed at a specific venue since the last sync — new experiences, slot price moves, hours changes.

    Hot-target deep-watch: when an agent or user is hunting one venue, drift surfaces every meaningful change since the last look.

    table-reservation-goat-pp-cli drift alinea --since '2026-04-01' --agent
    
  • book — Place a reservation on OpenTable or Tock (v0.2). Free reservations only; payment-required venues return a typed payment_required error pointing at v0.3. Two safety layers: PRINTING_PRESS_VERIFY=1 short-circuits to dry-run regardless (verifier mock-mode floor), and live commit fires only when TRG_ALLOW_BOOK=1 is set. Without the env var, returns a dry-run envelope with a hint. Idempotency pre-flight via ListUpcomingReservations + normalized matching prevents double-book on retry; filesystem advisory lock keyed on (network, slug, date, time, party) prevents concurrent double-book across processes.

    TRG_ALLOW_BOOK=1 table-reservation-goat-pp-cli book opentable:water-grill-bellevue --date 2026-05-13 --time 19:00 --party 2 --agent
    

    Tock book uses chromedp-attach (drives a real Chrome session) since Tock's book flow uses traditional form-submit + Braintree CSRF. Card-required venues (most non-prepay Tock restaurants) prompt for CVC on stderr; the value flows through to the browser at confirm time. Free venues skip the CVC prompt. Requires Chrome running with --remote-debugging-port=9222, OR the CLI spawns a stealth headless Chrome as fallback. CVC can also be set via TRG_TOCK_CVC env var for non-interactive usage (MCP tool calls).

  • cancel — Cancel a reservation. NOT gated by TRG_ALLOW_BOOK (recovery action) but still respects the PRINTING_PRESS_VERIFY floor. Compound argument shape:

    • OpenTable: cancel opentable:<restaurantId>:<confirmationNumber>:<securityToken>
    • Tock: cancel tock:<venueSlug>:<purchaseId>

    All compound parts are returned by the corresponding book command's JSON output.

    table-reservation-goat-pp-cli cancel opentable:1255093:114309:01Ozsdas9H1Yx --agent
    

Usage

Run table-reservation-goat-pp-cli --help for the full command reference and flag list.

Commands

availability

Check open reservation slots across OpenTable, Tock, and Resy

  • table-reservation-goat-pp-cli availability check - Check open slots for a restaurant on a specific date and party size
  • table-reservation-goat-pp-cli availability multi-day - Multi-day availability for a single restaurant — Mon-Sun matrix

restaurants

Search and inspect restaurants across OpenTable, Tock, and Resy

  • table-reservation-goat-pp-cli restaurants get - Get a restaurant's full detail — hours, address, cuisine, price band, photos, accolades
  • table-reservation-goat-pp-cli restaurants list - List restaurants across OpenTable, Tock, and Resy; filter by location, cuisine, price band, accolades, and party size

watch

Persistent local cancellation watcher across all three networks

  • table-reservation-goat-pp-cli watch add - Register a watch for a venue, party size, and time window
  • table-reservation-goat-pp-cli watch list - List active watches
  • table-reservation-goat-pp-cli watch cancel - Cancel a watch by id
  • table-reservation-goat-pp-cli watch tick - Run one polling tick across all active watches (for cron / agents)

Output Formats

# Human-readable table (default in terminal, JSON when piped)
table-reservation-goat-pp-cli restaurants list

# JSON for scripting and agents
table-reservation-goat-pp-cli restaurants list --json

# Filter to specific fields
table-reservation-goat-pp-cli restaurants list --json --select id,name,neighborhood

# Dry run — show the request without sending
table-reservation-goat-pp-cli restaurants list --dry-run

# Agent mode — JSON + compact + no prompts in one flag
table-reservation-goat-pp-cli restaurants list --agent

Agent Usage

This CLI is designed for AI agent consumption:

  • Non-interactive - never prompts, every input is a flag
  • Pipeable - --json output to stdout, errors to stderr
  • Filterable - --select id,name returns only fields you need
  • Previewable - --dry-run shows the request without sending
  • Explicit retries - add --idempotent to create retries and --ignore-missing to delete retries when a no-op success is acceptable
  • Confirmable - --yes for explicit confirmation of destructive actions
  • Piped input - write commands can accept structured input when their help lists --stdin
  • Offline-friendly - sync/search commands can use the local SQLite store when available
  • Agent-safe by default - no colors or formatting unless --human-friendly is set

Exit codes: 0 success, 2 usage error, 3 not found, 5 API error, 7 rate limited, 10 config error.

Health Check

table-reservation-goat-pp-cli doctor

Verifies configuration and connectivity to the API.

Configuration

Config file: ~/.config/table-reservation-goat-pp-cli/config.toml

Static request headers can be configured under headers; per-command header overrides take precedence.

Power-user knobs (env vars)

OpenTable's WAF can rate-limit aggressive scans. The CLI ships with a disk cache, singleflight dedupe, and an AdaptiveLimiter so typical use never hits the limit. These env vars override the defaults:

Env varDefaultEffect
TRG_OT_CACHE_TTL3mHow long a cached availability response stays fresh. Range [1m, 24h]; out-of-range falls back to default with a stderr warning.
TRG_OT_THROTTLE_RATE0.5Initial calls/second for the OT AdaptiveLimiter. Lower values pace harder (0.1 = 10s spacing); higher values are appropriate when routing through a personal proxy. Range [0.01, 5.0].
TRG_OT_NO_CACHEunsetSet to 1 to bypass the cache by default. The --no-cache flag on earliest and watch tick does the same per-call.
TRG_ALLOW_BOOKunsetLive commit gate for book. Without it, book returns a dry-run envelope. cancel is NOT gated by this — it's a recovery action.
PRINTING_PRESS_VERIFYunsetVerifier-mode floor. When =1, both book and cancel short-circuit to dry-run regardless of TRG_ALLOW_BOOK. Set automatically by printing-press verify mock-mode subprocesses.
TRG_TOCK_CVCunsetWhen set, used as the CVC for Tock card-required bookings instead of prompting on stderr. Useful for MCP tool calls and other non-interactive contexts.
TABLE_RESERVATION_GOAT_TOCK_CHROME_DEBUG_URLhttp://localhost:9222Override for the Chrome DevTools endpoint used by the Tock chromedp-attach book flow.
HTTPS_PROXY / HTTP_PROXYunsetStandard Go-honored proxy URLs. Useful for routing OT traffic through a personal proxy or Tor SOCKS5 (socks5://localhost:9050).

Troubleshooting

Not found errors (exit code 3)

  • Check the resource ID is correct
  • Run the list command to see available items

API-specific

  • PersistedQueryNotFound 400 from OpenTable on first run — the persisted-query hash drifted; run table-reservation-goat-pp-cli doctor --refresh-hashes to bootstrap the current hash from a fresh homepage fetch
  • Cloudflare challenge from exploretock.com — Surf transport with Chrome TLS clears this automatically; if you see a 403, run table-reservation-goat-pp-cli doctor to verify the Surf fingerprint is loaded
  • Authentication required on a venue or detail call that needs sign-in — run table-reservation-goat-pp-cli auth login --chrome to import cookies, then auth status to confirm each network are signed in
  • Empty availability results for a venue you know has openings — check --party and --time (Tock returns empty when no slot matches the seating area filter); also try goat <venue> --debug to see the per-network response
  • Watch never fires even though slots opened on the website — verify watch list --json shows your watch state: active and last_polled_at recent; if the limiter is throttled the typed RateLimitError will be in the recent log — increase --cadence to back off

Sources & Inspiration

This CLI was built by studying these projects and resources:

Generated by CLI Printing Press

For agents: pass /documentation/table-reservation-goat/agents.md to install this CLI from a prompt.