Demos & Environments
A Journey replays the same way every time, so it can be shown as well as checked: live in a visible browser, as a recording, or as a narrated video and step-by-step guide. A demo that no longer replays fails, like a test.
Demo mode: watch or record a run
Every run is headless by default, check and CI included. Demo mode is opt-in:
# A visible Chromium, each browser operation slowed by 250 ms (override with --slow-mo <ms>)
jevitate explore --strategy adversarial --url http://localhost:3000/settings --fake-ai --headed
# Headless, recorded: the videos are listed in the result (videoPaths) and the summary (VIDEO lines)
jevitate explore --strategy adversarial --url http://localhost:3000/settings --fake-ai --record-video
jevitate journey run checkout --record-video --screenshots | Flag | What it does | Commands |
|---|---|---|
--headed (or JEVITATE_HEADED=1) | A visible Chromium window | explore (every strategy), journey run, journey demo, demo, demo approve, verify-fix, regression capture, regression run |
--slow-mo <ms> | Delays each browser operation; 250 by default with --headed | the same |
--record-video [dir] | A video of each browser context, headless too; listed as videoPaths | explore, journey run, verify-fix |
--no-overlay | With --headed: hide the on-page overlay (step, intent, target highlight, outcome banner) | explore |
--screenshots [mode|dir] | Masked screenshots plus an index.md contact sheet (below) | explore, journey run, journey annotate, journey demo, verify-fix |
--evidence-video | Per defect: a captioned repro clip and before/at screenshots (evidence) | explore |
- The overlay is invisible to jevitate's own perception: it never changes what a run sees or decides.
-
--headedneeds a display. On Linux withoutDISPLAYorWAYLAND_DISPLAY(a CI container, WSL2 without WSLg) it is refused before any browser launches (exit 64), with a pointer to--record-video. -
Never headed:
mission run(what MCPqueue_explorationfeeds),load runandsource run. Achecksuite item opts in with its ownheaded,slowMo,recordVideoandoverlayoptions.
Environments: --env
A Journey is environment-free: recorded and authored Journeys keep app-relative paths, and the site
they were recorded on is only their default. Name the places your app runs in the committed
.jevitate/environments.json (jevitate init writes an example once and never
overwrites it):
{
"local": { "baseUrl": "http://localhost:3000" },
"staging": {
"baseUrl": "https://staging.example.com",
"allow": ["https://auth.example.com"],
"fixtures": "fixtures/staging.json",
"hooks": { "before": "./scripts/seed-staging.sh" }
},
"prod": { "baseUrl": "https://app.example.com", "production": true }
} jevitate journey run checkout --env staging
jevitate journey run checkout --base-url https://pr-123.preview.example.com # an ad-hoc environment
jevitate journey annotate checkout --env staging --real
jevitate regression run cart-total --env local
jevitate load run checkout --env staging --authorized-origin https://staging.example.com baseUrlis an origin. The Journey's recorded same-origin URLs move onto it, with their path, query and fragment.-
The run's allowlist is the environment:
baseUrlplusallow. A step on any other origin, or an unknown--env, is refused (exit 64) before any browser opens. fixturesandhooksapply when--fixtures,--beforeand--afterare not given. Hooks still need--allow-shell-hooks."production": truemarks a live environment.demorefuses it.--base-urlalone is an ad-hoc environment; with--envit replaces that environment'sbaseUrl.--env/--base-urlwork onjourney run,journey annotate,journey demo,regression runandload run, and asenv/baseUrlon acheckJourney item.- Without either flag, a Journey runs on its recorded site, exactly as before.
storageState, secret,
password, token, cookie, credential or
apiKey key anywhere in environments.json is refused. Sessions and secret
fields per environment live in ~/.jevitate/targets.json, keyed by origin, and runs start
from that session when you pass no --storage-state. A Journey's own vault secrets stay
bound to the origin they were recorded on.
{
"https://staging.example.com": {
"storageState": "sessions/staging.json",
"secretFields": ["label=Password=env:STAGING_PASSWORD"],
"personas": { "admin": { "storageState": "sessions/staging-admin.json" } }
}
} Journey intent: draft it, then approve it
Optional, additive fields tell a Journey's why, not only its what:
metadata.goal, persona, role, preconditions,
successCriteria, parameters, and per-step objective and
expectedResult. journey annotate drafts the missing ones by replaying the
Journey and reading the redacted page before and after each step:
jevitate journey annotate checkout --env staging --real # or --fake-ai for a deterministic smoke
# review or edit .jevitate/journeys/.drafts/checkout.annotations.json
jevitate journey annotate checkout --approve # the human gate: shows the diff, then writes - Drafts go to a sidecar, never into the Journey.
initkeepsjourneys/.drafts/out of git. --approvewrites only the intent fields. It never promotes the Journey or changes an action or an assertion.- A draft is bound to the Journey's content hash: if the Journey changed, approval is refused (
E_JOURNEY_ANNOTATIONS_STALE, exit 64). - Exit 0 drafted or applied · 2 the replay stopped early (a partial draft) · 64 bad input.
A narrated demo from a Journey: journey demo
jevitate journey demo checkout --env staging --video demos/checkout.webm --guide docs/checkout.md
jevitate journey demo checkout --headed --pace 2500 # present it live -
The overlay shows the Journey's goal as a title card, then each step's objective as the caption
(else its label), with the target highlighted and a
--pacepause (default 1500 ms), then an outcome card. Annotate first so every step has an objective. --video <file.webm>writes the recording and a.vttbeside it: one WebVTT cue per step. Convert to MP4 with ffmpeg if you need it.--guide <file.md>writes a Markdown guide: goal, preconditions, and per step its objective, expected result and a screenshot (overlay hidden).- With neither flag, both go to a fresh folder in the logs directory. Headless by default, for CI.
-
The replay is a
journey run(same params, session, environment, fixtures, site policy, fail-closed policy), so paid or destructive steps are refused as usual and a demo never self-heals.
| Exit | When |
|---|---|
0 | Replayed, and every requested output was written |
1 | Stale: the Journey no longer replays; nothing written |
2 | The replay completed but an output could not be produced |
64 | Bad arguments (--video not .webm, --guide not .md), an unknown Journey, --headed without a display |
From one sentence: demo "<aspect>"
jevitate demo "Save your display name" --env staging \
--success "textIncludes:testId=status|Saved" --real
# review the Journey, its annotations and the DRAFT video/guide, then:
jevitate demo approve demo-save-your-display-name - Explore and author. A goal-directed exploration toward the aspect writes a Journey.
--successis the independent check that proves it was shown: Jev drives, code decides. - Clean path. Detours and dead ends are dropped, the same delta debugging as
regression capture; a step goes only if the Journey still replays to its check without it. - Annotate. Each step's objective and expected result are drafted, as
journey annotatedoes. - Draft demo. Video,
.vttand guide, watermarked DRAFT, to--out <dir>or the logs directory.
Nothing is written unless every stage succeeds, and nothing is promoted until
demo approve <id>: it renders the final demo on the same environment, applies
the annotations and promotes the Journey. After that it is an ordinary Journey: re-render it with
journey demo --env <any>, or check it in CI with journey run.
demo create <aspect> is the long form.
demo runs only against a named environment
(--env is required). One flagged "production": true is refused before
anything runs (E_DEMO_PRODUCTION_ENV, exit 64), both when drafting and when approving.
Paid, destructive and session-ending controls stay refused unless that origin's
safety in ~/.jevitate/targets.json allows them.
Exit 0 drafted or approved · 1 the check was not reached or the path did not replay (nothing written or promoted) · 64 no --env / --success, a production environment, an existing id, or no draft to approve.
Screenshots and contact sheets
jevitate journey run checkout --screenshots # one per distinct screen + index.md
jevitate journey run checkout --screenshots steps # one per step
jevitate verify-fix --result <run>.result.json --fingerprint <fp> --screenshots screens:shots/ screens (the default) takes one screenshot per distinct screen, deduplicated by the
page-state fingerprint coverage uses (a typed value is not a new screen); steps takes
one per step. screens:<dir>, steps:<dir> or
<dir> pick the folder. Each image is the viewport after the step acted, overlay
hidden, and index.md lists each one with its step, route and what happened. The result
lists screenshotPaths, screenshotIndex and, for a refused capture,
screenshotsSkipped. A check item takes screenshots too.
Secrets are masked in the pixels
Every registered secret (--secret, secret fields, a Journey's secret parameters) shown
on the page, in text, a field's value or an attribute, is painted over by a display-only layer; the
page's own DOM is never changed. The mask is proven before and after every screenshot and at every
step of a clip. Fail closed: a screenshot that cannot be proven is not written, and
a clip whose mask failed at any step is deleted; the reason is recorded. Not covered: a secret
drawn on a canvas, inside a closed shadow root, or under a top-layer modal (that last case is
detected and refused). Captions, subtitles and guides are redacted as text too.
Full reference: docs/cli.md.
Over MCP, the same commands are demo_journey, create_demo,
approve_demo and annotate_journey (MCP & CLI).