A local-only, browser-first desktop application for controlled research, personalisation, email outreach, website-form outreach, and browser-assisted channel actions (LinkedIn).
The browser is a first-class runtime, not a collection of ad-hoc Playwright scripts.
The MVP combines:
- a desktop application (Electron) that is the whole product — no server to deploy;
- the user's installed Google Chrome driven through dedicated, app-managed persistent profiles;
- deterministic browser automation through Playwright, driven by versioned adapter packs;
- bounded AI-assisted target resolution and research;
- a resumable, SQLite-backed workflow/state-machine engine;
- email and browser channel adapters;
- research with evidence and verified quotes;
- human approval, assisted execution and human takeover;
- complete action/event logging.
The MVP does not depend on a custom Chromium fork.
- single user, installed locally, works locally — permanently (no SaaS direction);
- macOS first (Apple Silicon primary); Windows later is kept cheap by the stack choice but is not an MVP goal;
- installable as a signed, notarized
.appwithout Docker or other prerequisites except Google Chrome; - user brings their own AI provider API key;
- Gmail via the user's own Google OAuth client, plus generic IMAP/SMTP;
- generic website contact forms;
- LinkedIn as an isolated browser adapter,
assistedexecution mode by default; - default
approve_eachfor critical actions; approve_campaignavailable as an explicit mode with automated draft checks;- CAPTCHA, 2FA and account challenges always stop automation and require human intervention.
tabreach/
├── apps/
│ └── desktop/ # Electron main + preload + React renderer, packaging
├── packages/
│ ├── protocol/ # IPC envelopes, Zod schemas, shared types
│ ├── core/ # domain, SQLite, jobs/scheduler, workflows, policy, email, research, AI gateway
│ ├── browser-worker/ # Playwright, profiles, sessions, browser adapters, overlay, takeover
│ └── adapter-packs/ # versioned data definitions for browser adapters
├── fixtures/
│ └── sites/ # local fixture web apps for browser tests
├── docs/
│ ├── adr/
│ └── ...
├── CLAUDE.md
└── README.md
Claude Code must read, in order:
CLAUDE.mddocs/00-PRODUCT-VISION.mddocs/01-MVP-SCOPE.mddocs/03-SYSTEM-ARCHITECTURE.mddocs/22-IMPLEMENTATION-PLAN.md- the document for the subsystem being changed;
- relevant ADRs under
docs/adr/.
The revision rationale of 2026-09-28 is in docs/REVISION-NOTES-2026-09-28.md.
- Browser code never lives inside campaign/domain services; Playwright is imported only by
browser-worker. - Channel-specific behaviour must be behind channel adapters.
- Browser workflows are resumable state machines.
- LLM output is never treated as trusted executable instruction; semantic resolution picks from a closed candidate set.
- Critical external actions require policy evaluation and, by default, explicit human approval.
- Browser adapters act only in positively recognized page states.
- CAPTCHA/2FA/security challenges are never bypassed automatically.
- Secrets are never stored in Git, logs, screenshots or prompts.
- Every externally visible action produces an auditable action event and a side-effect ledger entry keyed by logical intent.
- Research claims keep source/evidence references with verified quotes.
- Failures preserve enough evidence to reproduce them without silently retrying forever.
- The app exposes no persistent network listeners; the only exception is a short-lived single-use OAuth loopback listener on
127.0.0.1. - No exactly-once promises: uncertain side effects are never automatically repeated.
By the end of Phase 0, a clean macOS checkout should be bootstrappable with:
pnpm install
pnpm devand a local unsigned .app build with:
pnpm packageExact commands may evolve, but onboarding must remain near-one-command and fully documented in docs/DEVELOPMENT.md.
Implemented phase by phase according to docs/22-IMPLEMENTATION-PLAN.md. As of 2026-09-30, Phases 0–7 and the 1.5, 3.5, 4.5, 5.5 and 6.5 audits are done:
- prospects, CSV import/export and the do-not-contact list;
- campaigns with versions, schedules in the recipient's time zone, contact policy and a keyboard approval queue;
- email through IMAP/SMTP or the Gmail API with the user's own OAuth client, without automatic duplicates, with replies and bounces stopping sequences;
- the AI gateway with the user's key (Anthropic, OpenRouter, OpenAI), research with verified quotes, reply labels and AI drafts with automated checks and
approve_campaign; - timelines of every contact, company and campaign;
- managed Chrome profiles, page recognition by adapter packs, challenges handed to the person, the in-page overlay, take/return control, Pause all and Emergency stop, the
about_to_commitcheckpoint for critical browser actions, and JavaScript-only sites rendered for research.; - website contact forms as a campaign channel: the form found and filled before approval, the approval showing exactly what goes in, sending through the checkpoint, the person pressing Send when a CAPTCHA, a consent or an unknown required field needs them, and AI recognizing unfamiliar fields from a closed list.;
- a LinkedIn adapter behind a switch that is off by default: invitations and messages from a signed-in browser profile, the person pressing Send unless auto is allowed per action class, the profile's identity checked before any click, the conversation read before every message, conservative per-account limits, and the share of unrecognized pages per pack version on the status screen. The pack was built on representative fixtures and still needs checking against real LinkedIn pages.
Next: Phase 8, hardening and release.