Sentience supports two ways to adopt verification:
Both paths share the same core idea:
Agent acts → Snapshot → Verification → Trace
Keep your planner/executor. Attach to a Playwright Page (or a CDP backend) and add verification after actions.
Use Sentience snapshots + actions directly (or wrap with AgentRuntime) to build a deterministic loop with assertions.
Sentience verification evaluates predicates against the latest snapshot. Whether you use the Debugger sidecar or the full SDK loop, you still call snapshot() (or dbg.snapshot()) to produce evidence for assertions.
If you set use_api: false, snapshots are processed locally and do not require a Sentience API key. You can add an API key later to enable server-side refinement (optional).
This is the “don’t replace my stack” path: your agent executes actions; Sentience verifies outcomes and emits traces/artifacts.
from sentience import SentienceDebugger
from sentience.tracing import Tracer, JsonlTraceSink
from sentience.verification import exists
# page is a Playwright Page from your existing framework
page = agent.get_page()
tracer = Tracer(run_id="run-123", sink=JsonlTraceSink("trace.jsonl"))
dbg = SentienceDebugger.attach(page, tracer=tracer)
await agent.step() # your loop
# local-only snapshot (no API key required)
await dbg.snapshot(use_api=False, goal="verify:after-step")
await dbg.check(exists("role=button text~'Checkout'"), label="checkout_visible", required=True).eventually()By default, Debugger will open a step automatically when you call check(). If you want cleaner traces, enforce explicit step boundaries.
dbg = SentienceDebugger(runtime=runtime, auto_step=False)
async with dbg.step("verify:checkout"):
await dbg.snapshot(use_api=False)
dbg.check(..., label="checkout_visible", required=True).once()This is the “start here” path: you use Sentience snapshots and action APIs directly.
from sentience import SentienceBrowser, snapshot, find, click, type_text, wait_for
with SentienceBrowser(api_key="sk_...") as browser:
browser.page.goto("https://example.com/login")
snap = snapshot(browser, {"use_api": False})
email = find(snap, "role=textbox text~'email'")
password = find(snap, "role=textbox text~'password'")
submit = find(snap, "role=button text~'sign in'")
type_text(browser, email.id, "user@example.com")
type_text(browser, password.id, "password123")
click(browser, submit.id)
ok = wait_for(browser, "role=heading text~'Dashboard'", timeout=5.0)
print("PASS" if ok.found else "FAIL")