Set up your project
Saffron lives inside the project you are testing. The fastest start:
npx saffron init
It scaffolds saffron.config.json, features/ and the .gitignore
entries (.env among them), and installs the Saffron agent skill into your project so AI
coding assistants write tests correctly (see §11, AI agents).
When run interactively it also offers to install the Saucedemo example
suite (--examples to say yes without the prompt, --no-examples to
skip it): a handful of short .saffron scenarios against the public demo shop
at https://www.saucedemo.com (login, a Scenario Outline, cart, checkout,
StepSets used both at the start and in the middle of a scenario), a
matching config (retries: 1) and a .env.example with the demo
credentials. A project that already has a saffron.config.json keeps it
as it is: init says when its baseURL is not the demo shop's, and to set
it or run with --base-url https://www.saucedemo.com. Nothing to host, nothing to
build; §4 walks through the first run with exactly these files.
your-project/
features/ your .saffron and .feature files
saffron.config.json configuration
.saffron/
cache/ committed replay caches → commit to git
proposals/ pending AI proposals → review, then gone
history.jsonl one line per run (trends) → commit recommended
reports/ latest.html / latest.json → gitignore
artifacts/ screenshots and traces, latest run → gitignore
ci/ CI runs viewed without importing → ignored by its own .gitignore
Minimal saffron.config.json:
{
"baseURL": "https://stage.your-app.com",
"features": "features"
}
Every option, with its default and what it does, is in §14
(Configuration reference). The two you are most likely to set first are
baseURL and features; everything else has a working default.
Add to .gitignore:
.saffron/reports/
.saffron/artifacts/
.saffron/ci/
.saffron/**/*.partial
.saffron/**/*.lock
.env
The .partial and .lock files are what a run killed while writing
leaves beside recordings and proposals; saffron init adds these lines.
.saffron/ci/ holds CI runs you viewed (§19); it writes its own
.gitignore, so a project set up before it existed needs no change.