Skip to content

Latest commit

 

History

206 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BookSaver Agent

BookSaver Agent logo

BookSaver is a self-hosted Python agent that watches refundable Booking.com hotel reservations for a cheaper equivalent room. It re-runs the search with the original dates and occupancy and alerts the right user. Reservation changes happen independently in Booking.com; BookSaver never cancels, books, pays, or runs a rebooking workflow.

Warning

BookSaver is experimental personal-use software, not a hosted service. Booking.com UI changes, account state, and datacenter-IP controls can break live checks even when the test suite passes. Automated access may violate Booking.com's terms. Read the full disclaimer and validate the tool with your own refundable booking before relying on it.

Current state

See the story index for delivery and qualification status and the decision index for accepted architecture. The implementation includes:

  • bounded Browser Use price/inventory execution and an explicit deterministic/Stagehand rollback;
  • same-property, dates, occupancy, room-type, currency, and refundability checks;
  • local SQLite history, redacted traces, and savings alerts;
  • automatic authenticated-account reservation discovery with visible eligibility reasons;
  • a private Telegram interface with owner-issued, single-use invites and per-user isolation;
  • encrypted, user-scoped Booking.com sessions and optional personal Anthropic keys;
  • Docker/systemd deployment and an opt-in HTTPS /connect login flow for a trusted VPS;
  • a noVNC-compatible, deny-by-default login viewer with native mobile-keyboard controls;
  • immediate same-user /connect recovery after a viewer is closed or abandoned;
  • complete user purge across SQLite and encrypted sessions, plus Booking.com-only login navigation.

Use the issue tracker for current open work. Qualification and live acceptance remain explicit gates in the lifecycle artifacts.

How it works

  1. You connect your Booking.com account; BookSaver synchronizes positively observed reservations, preserves unseen saved rows when a refresh is partial or fails, and uses only current-run, upcoming, refundable observations for monitoring.
  2. Three times per UTC day by default, BookSaver gives each user one randomized slot in a different broad part of the day. At each slot it synchronizes that user's account once, then opens a fresh authenticated mobile Chromium context for every eligible booking. /checknow remains available for an immediate check.
  3. Price routing defaults to the legacy deterministic journey. owner_canary, explicit consented_users, or qualified agentic routing admits the pinned local Browser Use classic agent in a fresh local Chromium profile. Every physical action is code-authorized; reservation, checkout, payment, cancellation, credential, MFA/captcha, arbitrary navigation, shell, clipboard, upload, and download capabilities are absent. Stagehand remains an explicit rollback adapter for a future job, never an automatic second attempt.
  4. Only a cheaper, currency-aligned, still-refundable equivalent offer becomes a savings result.
  5. Telegram or email reports the result. You independently review and make any change in Booking.com; the next synchronization observes the updated account state.

Every check is locally traceable with booksaver checks trace <CHECK_ID>.

Agentic price traces include a versioned price_validation event for successful and rejected observations. It records query/terminal rejection, all failed per-offer evidence checks, actual room-match/selection outcomes, and bounded lexical room hints. Inspect offers[].selection for room mismatch or other exclusions, and offers[].evidence_rejections for missing/conflicting all-in, refundability, completeness, or currency evidence. Up to 20 offers are detailed; the total and omitted counts are explicit. Room hints are recognized words, not semantic equivalence claims; missing words mean unmentioned, not absent. Raw room labels, page text, screenshots, refundability prose, and secrets are not added to these diagnostics. This instrumentation does not change which offers are accepted or invoke additional models. When guarded recovery assists account discovery, the local log includes a synchronization run ID; inspect its content-free provider/call/token/action/timing audit with booksaver bookings trace <SYNC_RUN_ID>. Randomized slots are persisted locally, so restarts do not reroll or replay completed work. Send /status to see your own next planned UTC slot.

The [agent] section uses a fixed Sonnet 5 primary and one measured Opus 5 escalation. Fable and arbitrary model IDs are rejected. Model calls share persisted USD 1 per-browser-job and USD 10 per deployment UTC-day ceilings; predictable outcomes such as a confirmed reconnect requirement use no model call. The section also keeps the existing outer per-check limits (max_steps, max_llm_calls, and check_timeout_seconds) and tighter recovery defaults:

primary_model = "claude-sonnet-5"
escalation_model = "claude-opus-5"
max_job_cost_usd = "1.00"
max_deployment_daily_cost_usd = "10.00"
reserve_opus_diagnostic_for_ambiguous_episode = true
max_recovery_calls_per_step = 4
recovery_timeout_seconds = 60
screenshot_after_no_progress = 2
max_semantic_action_executions = 2

Older config files remain valid and receive these defaults automatically. The inner limits cannot expand the outer per-check or per-user daily LLM budgets.

Inventory and price use independent browser-executor routes. Agentic inventory is the default; the agentic price executor remains disabled by default:

[agentic_browser]
routing = "legacy" # price: legacy | owner_canary | consented_users | agentic
price_executor = "browser_use" # agentic price adapter: browser_use | stagehand
inventory_routing = "agentic" # inventory: legacy | agentic
disclosure_version = "anthropic-visible-booking-page-v1"

inventory_routing = "agentic" uses the pinned Browser Use classic agent for every read-only inventory trigger, including /bookings, /checknow, scheduled checks, and post-connect sync. It runs locally in a fresh browser, receives only a closed set of code-guarded read-only actions, and uses the deployment's Anthropic key. BookSaver accepts only positively observed reservations from that run and never lets model output mark an unseen saved reservation absent. Set it to legacy as a capability-specific rollback; this setting does not promote the price executor.

The Docker build installs the exact resolved runtime graph from requirements.lock; this is intentional because Browser Use 0.11.13 has broad transitive dependency ranges. Telemetry, cloud sync, external version checks, downloads, persistent screenshots, and stock Browser Use actions are disabled by the BookSaver adapter.

For price execution, owner_canary routes only the deployment owner. An owner may explicitly select consented_users to route the owner and every active invitee with current /connect disclosure consent through Browser Use before statistical qualification completes. This choice does not mark the canary qualified; qualification remains useful for monitoring and rollback. The default adapter runs Browser Use 0.11.13 in-process against the installed Playwright Chromium, injects encrypted Booking.com cookies through a code-owned local CDP connection, and sends the exact transient browser's semantic view and screenshots to Sonnet 5 using BOOKSAVER_LLM_API_KEY. BookSaver constructs the trusted search URL, removes Browser Use's stock actions, exposes only guarded read-only clicks/scrolls/keys/waits and typed submissions, and proves authentication independently. USD 1 per-check, USD 10 deployment-day, 15-action, six visual-click, and 180-second limits remain hard. Set price_executor = "stagehand" only to roll a future job back to the prior Stagehand semantic/computer-use adapter.

The executor returns observations only. BookSaver still verifies property, dates, occupancy, authentication, Genius evidence, currency, all-in totals, explicit refundability, room equivalence, and the cheapest valid offer before any savings alert. Agentic failure is terminal for that check; the legacy browser is a configured rollback route, not an automatic second attempt. Invited users always require current versioned /connect disclosure consent. They may be admitted either by the explicit consented_users route or by the statistically qualified agentic route.

All Browser Use inventory and price calls use the deployment owner's BOOKSAVER_LLM_API_KEY, including calls initiated by invitees. /admin users shows that funding policy and only whether an optional personal key is configured for legacy LLM work; it never prints, decrypts, fingerprints, or validates a key.

The owner governs that release entirely from the local VPS:

booksaver agentic status
booksaver agentic compare <CHECK_ID> --correct   # or --incorrect
booksaver agentic promote
booksaver agentic regress <MACHINE_CODE>

Promotion reads the persisted evidence itself and cannot be supplied a fabricated verdict. It requires 30 owner checks over at least 14 days, ten correct manual comparisons, at least 95% valid eligible observations, average cost at most USD 0.10, p95 cost at most USD 0.50, p95 duration at most 180 seconds, fallback use at most 20%, zero critical violations, and explicit owner execution of promote. During the 30-day rollback window, a critical violation or three consecutive eligible failures automatically regresses routing to legacy. Offline fixtures qualify the adapter and safety boundary; they do not substitute for this live owner evidence.

Model behavior can be measured without opening Booking.com or reading local sessions/database. The explicit qualification command replays the packaged synthetic corpus ten times per fixture for both approved profiles and requires at least nine correct runs per fixture with zero prohibited executions. It reports aggregate correctness, safety, calls, actions, latency, token use, and exact estimated cost without printing prompts or page content. Live execution requires an explicit cost cap and is admitted call-by-call under the same deployment ceiling:

booksaver evaluate recovery --live --qualify --persist --max-cost-usd 10.00
booksaver evaluate qualification

It requires BOOKSAVER_LLM_API_KEY. Custom fixtures are exploratory only and cannot create a recordable production qualification result.

If adaptive assistance indicates likely DOM drift, BookSaver correlates a content-free maintenance incident and alerts only the configured owner. Inspect encrypted local evidence with booksaver incidents list and booksaver incidents inspect <INCIDENT_ID>; bundles expire after seven days and are never sent through Telegram.

Recommended setup: private Telegram bot on your VPS

Prerequisites

  • a Linux host with Docker Compose v2, 2 GB RAM minimum, and a DNS name if /connect is enabled;
  • a private Telegram bot token from BotFather and your numeric Telegram chat ID;
  • an Anthropic API key for Browser Use price/inventory execution, Stagehand rollback routes, and legacy LLM extraction/recovery (without one, use only the configured scripted routes);
  • acceptance of the trust boundary: the VPS runs the temporary login browser and must be under your control.

Install

git clone https://github.com/romkagribok/booksaver-agent.git
cd booksaver-agent

cp .env.example .env
cp config.toml.example config.toml
chmod 600 .env config.toml

Fill in .env, set owner_chat_id in config.toml, and set the same HTTPS hostname in BOOKSAVER_AUTH_DOMAIN and remote_auth.public_url. Then start and verify the stack:

docker compose --profile remote-auth up -d --build
docker compose ps
docker compose logs -f booksaver

In a private chat with the bot, send /start, then /connect. BookSaver discovers your Booking.com reservations automatically. Use /bookings to refresh the account inventory and see why any reservation is ineligible for price-drop checks. Bare /checknow immediately shows saved caller-owned choices; selecting one runs a single fresh inventory verification and immediate price check through the coordinator. The first real Booking.com check is a required deployment test; VPS IPs can encounter bot walls.

The VPS deployment runbook covers DNS/TLS, backups, upgrades, smoke testing, recovery cookie import, and the non-Docker systemd alternative.

Local development and desktop operation

Python 3.11+ is required.

python3.11 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
playwright install chromium

booksaver init
booksaver config validate
booksaver --help

booksaver init creates ~/.booksaver/config.toml with mode 0600. For a desktop operator, enable the Telegram bot in that file, export the required BOOKSAVER_* values, and run booksaver run. Connect each admitted user through /connect; auth import remains a scoped break-glass recovery path.

Useful CLI commands include bookings list, checks list, checks trace, savings list, and auth status|delete|import. Run any command with --help for its full arguments.

Data, LLM, and security boundaries

  • Configuration, SQLite data, encrypted sessions, traces, and snapshots stay in the configured local data directory. Backups contain sensitive booking data and must be protected.
  • Secrets are read from environment variables, never from committed configuration: BOOKSAVER_TELEGRAM_BOT_TOKEN, BOOKSAVER_LLM_API_KEY, BOOKSAVER_SECRET_KEY, and optional BOOKSAVER_SMTP_PASSWORD.
  • BookSaver does not intentionally send cookies, passwords, MFA codes, or raw API keys to the LLM. When LLM features are enabled, it may send bounded rendered page text and, during escalation, screenshots to the configured Anthropic model. Rendered content can include account or booking details; use a provider/data policy you accept.
  • /connect keeps credentials out of Telegram and BookSaver forms, but the browser executes on the VPS. A compromised root account could still observe login input. This is the known hardening boundary tracked in issue #6.
  • Telegram access is owner/invite only. There is no public-bot mode and no BookSaver-operated backend.

Development

Install the Python development extras and existing Node validation dependencies before running the repository quality gate:

python3 -m pip install -e ".[dev]"
npm ci
python3 -m ruff check src tests
python3 -m mypy src
python3 -m pytest
npm run test:aidlc-validator
npm run validate:aidlc

Accepted requirements, decisions, and delivery history live in memory-bank/. The installed specs.md AI-DLC framework lives in .specsmd/aidlc/. Tool-specific agent files are discovery adapters; the framework and memory bank are the authoritative sources.

License and disclaimer

Released under the MIT License. BookSaver is not affiliated with, endorsed by, or sponsored by Booking.com or Booking Holdings Inc. See docs/DISCLAIMER.md.

About

An autonomous agent that monitors your travel bookings, detects price drops by navigating live booking sites with a browser agent, and rebooks on your behalf — runs as a lightweight local daemon, no account or platform required.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages