Get started

Your first run

Recording

npx saffron run                         # everything under features/
npx saffron run features/login.feature  # one file
npx saffron run --filter @smoke         # by tag
npx saffron run --filter @TC-1,@TC-2    # any of several tags (or repeat --filter)
npx saffron run --headed                # watch the browser

If your project already has caches, steps whose exact text matches an existing recording are seeded: the leading run of known steps replays zero-AI and the agent records only the novel ones (⚡ 4/6 steps seeded). The more scenarios you record, the cheaper each new one gets, write shared steps with identical wording (and the page in the step text, e.g. "…on the guest information page") to maximize hits. Quoted values may differ (I enter "admin"… seeds from I enter "bob"…), data-table steps seed whenever their table keys match, and novel steps can sit anywhere in the scenario: seeded steps before, between, and after them all replay free.

No cache exists yet, so the agent executes each scenario in a real browser. Expect real token spend per scenario (typically $0.15–$2.00 depending on length and seeding: the report shows exact numbers, including cache traffic: prompt-cache reads/writes are the dominant cost of agent sessions, and the CLI and report break them out so the small "in+out tokens" figure is never mistaken for the bill). Scenarios finish yellow with a cache proposal each, or red if an assertion genuinely doesn't hold.

Try it on the example suite

If saffron init installed the Saucedemo examples, this is the whole first run, credentials included (they are the public demo ones):

cp .env.example .env                 # SAUCE_USER / SAUCE_PASSWORD, resolved at replay only
npx playwright install chromium
npx saffron run --filter @smoke      # records "Successful login" and "Add a product to the cart"

Both scenarios come back yellow with verified ✓ proposals (the agent recorded them, then a zero-AI proof replay confirmed the recordings). Measured on the real site: 35 AI calls and about $3 of AI usage for the two, most of it prompt-cache traffic, which the report breaks out honestly. Open the narratives, then:

npx saffron accept --all
npx saffron run --filter @smoke      # green, 0 AI calls, 0 tokens

Now run everything: npx saffron run (a few dollars more: the remaining scenarios seed most of their steps from what is already recorded). The login-errors Scenario Outline records once and replays both example rows; "Recover from a locked-out login" invokes the login StepSet in the middle of the scenario; the checkout invokes a second set mid-scenario that carries a data table, recorded as <table:firstName> references. Every set comes from shared.steps.saffron, so later callers record mostly seeded. Delete a cache and run again to watch a re-record; edit a table value and watch it replay free.

Review and accept proposals

npx saffron diff                         # what the proposals would change, action by action
npx saffron accept                       # no args: list pending proposals with narratives
npx saffron accept --all                 # promote every VERIFIED proposal; UNVERIFIED ones are skipped
npx saffron accept --all --include-unverified   # promote UNVERIFIED ones too (deliberately)
npx saffron accept <file...>             # promote one or more (an UNVERIFIED file is accepted with a warning)
npx saffron reject <file...>             # discard: the agent retries next run

Each proposal is stamped by a zero-AI proof replay that ran before it was filed: verified ✓ means the recording already replayed deterministically once; UNVERIFIED ✗ means it did not (the listing shows the reason). accept --all skips UNVERIFIED proposals so a bad recording never lands by bulk-accepting; accept it by file if you have read it and still want it, or better, re-record it (§12). A proposal is also stamped UNVERIFIED when the recording cannot be right on its face, for example a fill recorded with an empty value on a step that passes a value. If a recording fails its proof replay, Saffron automatically runs one refinement pass, the agent is told "the app works, your recording doesn't replay", before stamping. Opt out with --no-verify or "verifyProposals": false if a scenario has non-idempotent side effects (verification re-executes it).

Read the narrative and the recorded steps before accepting, the proposal is the contract every future replay will execute. Then commit .saffron/cache/ to git like any other reviewed artifact.

Every run after that: free

npx saffron run             # cached scenarios replay: 0 AI calls, 0 tokens, ~1-3s each
npx saffron run --no-agent  # guarantee zero AI: failures go red instead of healing
npx saffron report          # open the latest HTML report

Every run also appends to .saffron/history.jsonl, so reports show deltas vs the previous run and 20-run sparklines, and the CLI warns about chronic scenarios (healing repeatedly = re-record it, don't keep paying) and surfaces recurring failure themes.