Create a brand-new Twenty account using a disposable email, verify via the magic-link email, pick the 7-day free trial without a credit card, and land on the workspace bootstrap.
twenty.com with a workspace subdomain (not app.twenty.com) AND we're past the /plan-required page (no card collected via Stripe).Workspace subdomain per account: Twenty redirects each new account to a unique subdomain like agentmail-xxxx.twenty.com after verify-email. The crawler must capture this workspaceOrigin post-signup and use it for all subsequent navigation. Hard-coded app.twenty.com URLs fail.
Plan paywall vs free path: the modal looks like a single Pro Plan offer but has TWO toggle pills: "30 days trial With Credit Card" (→ Stripe Checkout) and "7 days trial Without Credit Card" (→ workspace setup). Pick the latter — case-insensitive regex matching surfaces both, must disambiguate.
Thread Twenty's 5-screen onboarding: workspace name → user profile → email-sync (skipped via hotkey) → team invite (finished empty) → land on workspace home with demo data.
/objects/companieshttps://<sub>.twenty.com/objects/companies?viewId=... (no /create/*, /sync/*, or /invite-team prefix) AND the workspace sidebar is rendered (Companies, People, Opportunities, Tasks, Notes are visible).The 5-screen onboarding chain: /plan-required → /create/workspace → /create/profile → /sync/emails → /invite-team → /objects/companies. Each requires a distinct interaction, and force-navigating to /objects/* mid-chain triggers a redirect back to the unfinished step.
SyncEmails has no detectable Skip button: Twenty renders "Continue without sync" as a <ClickToActionLink> (custom component, not a <button> with role). readButtons doesn't find it. But Twenty wires useHotkeysOnFocusedElement(Key.Enter, continueWithoutSync) — pressing Enter triggers the skip path.
Interstitial loop primitive: the crawler should iterate "wait for new page → detect known interstitial pattern → try Skip/Continue → fall back to keyboard hotkey" until a stable end state is reached.
From the workspace Companies view (pre-seeded with 5 demo records: Airbnb, Anthropic, Stripe, Figma, Notion), add a new Company via the inline "+ Add New" link below the table.
Crawler Demo Corp ...). List footer count increments from 5 to 6."+ New Company" header button is a dropdown trap: the obvious top-right button labeled "New Company..." opens a dropdown menu (not directly an inline add). Multiple matching buttons exist on the page, making case-insensitive regex selection unreliable.
The reliable trigger is "+ Add New": rendered as a <span> below the last row, not a <button>. readButtons misses it. The crawler uses a CDP Runtime.evaluate to query for elements with that exact text and click them directly. Once clicked, an inline editable row appears with the Name cell focused — typing immediately fills it.
Navigate to the People view (pre-seeded with 5 demo contacts), add a new Person via the same inline "+ Add New" pattern. Exercises a different object type with the same record-table UI machinery.
CrawlerFirst...) AND the URL stays at /objects/people.Same machinery, different object: Twenty's record-table is fully generic — the same "+ Add New" pattern works for Companies, People, Opportunities, Tasks, Notes, and any custom objects (the demo workspace also had Rockets, Pets, Pet Care Agreements, Star History). The crawler can reuse the exact same step sequence per object type.
Navigate to the Opportunities view — Twenty's deal/pipeline object — and add a new Opportunity record. Confirms the inline create pattern transfers cleanly across all primary CRM nouns.
Crawler Deal ... AND the URL stays at /objects/opportunities.Opportunities have stages (pipeline view) but the default list view is identical to Companies/People. Twenty users typically switch to a Kanban-shaped view for deal management — that's a separate flow we didn't exercise. The list-view CRUD path is fully covered by this test.