Skip to main content

Overview

The Playbook System lets PassAgent execute password resets using human-readable instruction sets rather than brittle CSS selectors. Each playbook is a JSON file containing plain-English steps like “Click the Forgot Password link” that get compiled to BQL GraphQL mutations at runtime. This approach gives PassAgent three advantages:
  1. Readability — non-engineers can author and audit reset flows.
  2. Resilience — text-based element matching survives minor DOM changes.
  3. Speed — compiled BQL runs in a single Browserless request with no round-trips.
PassAgent ships with pre-built playbooks for GitHub, Discord, Netflix, Instagram, Facebook, Google, OpenAI, and X (Twitter). See data/reset-playbooks/ for the full set.

Architecture


Playbook Data Format

Every playbook is a versioned JSON file stored at data/reset-playbooks/{domainKey}.json.
{
  "version": 1,
  "domainKey": "github.com",
  "serviceName": "GitHub",
  "entryUrl": "https://github.com/password_reset",
  "steps": [
    {
      "instruction": "Navigate to the GitHub password reset page",
      "action": "goto",
      "target": "https://github.com/password_reset"
    },
    {
      "instruction": "Type the email address into the input field",
      "action": "type",
      "target": "__IDENTITY__"
    },
    {
      "instruction": "Click the Send password reset email button",
      "action": "click",
      "target": "Send password reset email"
    },
    {
      "instruction": "Wait for the confirmation message",
      "action": "wait",
      "target": "3000"
    }
  ],
  "successPatterns": [
    "check your email",
    "we sent",
    "password reset email",
    "reset link",
    "email with a link"
  ]
}

Field Reference

FieldTypeDescription
version1Schema version; must be 1 for validation to pass
domainKeystringeTLD+1 hostname used as the storage key (e.g. github.com)
serviceNamestringHuman-readable service name
entryUrlstringURL the playbook navigates to first
steps[]PlaybookStep[]Ordered instruction list (see Step Actions below)
successPatternsstring[]Lowercase text snippets checked against page body after execution
learnedFromAIboolean?Set to true when the playbook was auto-generated by PlaybookScout

Step Actions

Each step has an action field that determines how it compiles to BQL:
ActionCompiles ToDescription
gotogoto(url, waitUntil) + waitForTimeout(2000) + screenshotNavigate to a URL. Supports __IDENTITY__ placeholder.
clickevaluate(content: JS)Finds an element by visible text and clicks it. Searches buttons, links, [role=button], submit inputs, labels, and clickable divs.
typeevaluate(content: JS)Finds the best input field using a cascade of selectors (email, username, phone) and fills it using React-compatible nativeSetter.
waitwaitForTimeout(time)Pauses execution for the given number of milliseconds.

PlaybookStore

The PlaybookStore class in packages/reset-engine-core/src/playbook-store.ts is a file-based store that manages playbook JSON files on disk.
import { PlaybookStore } from "@passagent/reset-engine-core";

const store = new PlaybookStore("data/reset-playbooks");

// Load a playbook
const playbook = await store.get("github.com");

// List all available domains
const domains = await store.list();
// => ["accounts.google.com", "discord.com", "github.com", ...]

// Save a new or updated playbook
await store.put(newPlaybook);

// Remove a playbook
await store.delete("old-service.com");
The store sanitizes domain keys to filesystem-safe characters and validates that loaded playbooks have version: 1, a non-empty steps array, and a defined entryUrl.

PlaybookCompiler

The compiler in packages/reset-engine-core/src/playbook-compiler.ts transforms a playbook into a single BQL GraphQL mutation that Browserless executes atomically.

Compilation Pipeline

  1. Resource blocking — Rejects images, fonts, and media for faster page loads.
  2. Step compilation — Each step becomes one or more BQL operations with aliased names (step_0_nav, step_1_click, etc.).
  3. Post-action screenshots — Every goto and click step captures a screenshot for debugging.
  4. Final verification — After all steps, the compiler appends a 3-second settle wait, a final screenshot, and two evaluate calls that read document.body.innerText and window.location.href.
import { compilePlaybook } from "@passagent/reset-engine-core";

const { query, operationName } = compilePlaybook(
  playbook,
  "user@example.com"    // replaces __IDENTITY__ in steps
);
// query is a complete `mutation PlaybookReset { ... }` string

Click-by-Text Strategy

The click JS uses three-tier matching: exact match, starts-with, then includes — all case-insensitive against trimmed innerText. It searches button, a, [role=button], input[type=submit], label, div[tabindex], span[tabindex], and onclick elements.

Type Strategy

The type JS tries selectors in priority order: input[type=email], input[name*=email], input[autocomplete=email], input[name*=username], input[name*=login], input[type=text] (first visible empty), then input[type=tel]. Values are set using the React-compatible nativeSetter pattern that dispatches input and change events.

PlaybookScout AI Agent

When no playbook exists for a domain, the PlaybookScout agent auto-generates one. The scout:
  1. Navigates to the site’s login or password-reset URL via Browserless.
  2. Takes a screenshot and reads the DOM.
  3. Sends the screenshot and DOM context to Claude, asking it to produce a ResetPlaybook JSON.
  4. Validates the output and saves it to the PlaybookStore.
The scout report at data/playbook-scout-report.json tracks generation results. In the most recent run, the scout generated playbooks for 47 out of 57 sites (82% success rate). Failures were primarily CAPTCHA blocks (15 sites), page load timeouts (4), and missing reset forms (4). Average generation time was ~24 seconds with a single Claude call per site.

Success Detection

After BQL execution, the orchestrator checks whether the reset succeeded by comparing the final page text against the playbook’s successPatterns array.
import { compilePlaybookSuccessCheck } from "@passagent/reset-engine-core";

const { query } = compilePlaybookSuccessCheck([
  "check your email",
  "we sent",
  "reset link"
]);
// Evaluates JS on the page that returns { found: boolean, matched: string[] }
The success check runs as a separate BQL mutation that searches the page’s innerText for any of the provided patterns (case-insensitive).

Integration with the Orchestrator

The reset orchestrator (lib/agents/reset-orchestrator.ts) uses playbooks as the first phase of its three-phase fallback strategy:
  1. Playbook phase — Load from PlaybookStore, compile with PlaybookCompiler, execute via BQL.
  2. Universal agent phase — If no playbook exists, use the UniversalPasswordResetAgent with dynamic CSS selectors.
  3. Vision AI phase — If both above fail, launch a Playwright browser with Claude Vision for pixel-level navigation.
Playbooks provide the fastest and most reliable path because they execute in a single Browserless request with no LLM calls at runtime.