{"_id":"@baguette-studios/journeytest-core","_rev":"3-7fa457e84b0aa0268700506c0da11fa0","name":"@baguette-studios/journeytest-core","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@baguette-studios/journeytest-core","version":"0.1.0","keywords":["agent-browser","ai-testing","pi-agent","journey-testing","e2e"],"author":{"name":"Jules Astier"},"license":"MIT","_id":"@baguette-studios/journeytest-core@0.1.0","maintainers":[{"name":"baguette-studios","email":"astier.jules@gmail.com"}],"homepage":"https://github.com/julesastier/journeytest-core#readme","bugs":{"url":"https://github.com/julesastier/journeytest-core/issues"},"bin":{"journeytest":"dist/cli.js"},"dist":{"shasum":"5cb6ef5666c1540d91f0bec4c8a4e45339419c3d","tarball":"https://registry.npmjs.org/@baguette-studios/journeytest-core/-/journeytest-core-0.1.0.tgz","fileCount":240,"integrity":"sha512-Yp1Gh3VUaaO6d/RknogSD0bmuIfPhLObS0zp1qdH/4OOzNELPxcJjNKZFBZuPj+XLu5yyJgfvh6eW2aVwz8mbw==","signatures":[{"sig":"MEQCIA11+FLuwA4Al1cjlwn+n/dePtedHmBet1KRiOyoNahEAiBvSpstRvMd7TrhWBWtVdaiT4efR/41BayuloOmzN+y+w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1417643},"type":"module","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cli":{"types":"./dist/cli.d.ts","import":"./dist/cli.js"},"./factories":{"types":"./dist/factories/index.d.ts","import":"./dist/factories/index.js"}},"scripts":{"dev":"tsx src/cli.ts","test":"vitest run","build":"tsc -p tsconfig.json","clean":"rm -rf dist coverage","prepack":"npm run clean && npm run build","validate":"npm run typecheck && npm test","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","release:check":"npm run validate && npm pack --dry-run","prepublishOnly":"npm run validate"},"_npmUser":{"name":"baguette-studios","email":"astier.jules@gmail.com"},"repository":{"url":"git+https://github.com/julesastier/journeytest-core.git","type":"git"},"_npmVersion":"10.9.3","description":"AI-agent-directed user journey testing for web apps with Pi and agent-browser.","directories":{},"_nodeVersion":"22.19.0","dependencies":{"zod":"4.4.3","commander":"15.0.0","@earendil-works/pi-ai":"0.79.4","@earendil-works/pi-agent-core":"0.79.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"4.22.4","vitest":"4.1.9","typescript":"6.0.3","@types/node":"25.9.3"},"peerDependencies":{"convex":"^1.42.0","agent-browser":"^0.31.1"},"peerDependenciesMeta":{"convex":{"optional":true},"agent-browser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/journeytest-core_0.1.0_1782674249056_0.3774147242027306","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@baguette-studios/journeytest-core","version":"0.1.1","keywords":["agent-browser","ai-testing","pi-agent","journey-testing","e2e"],"author":{"name":"Jules Astier"},"license":"MIT","_id":"@baguette-studios/journeytest-core@0.1.1","maintainers":[{"name":"baguette-studios","email":"astier.jules@gmail.com"}],"homepage":"https://github.com/Jules-Astier/journeytest-core#readme","bugs":{"url":"https://github.com/Jules-Astier/journeytest-core/issues"},"bin":{"journeytest":"dist/cli.js"},"dist":{"shasum":"92b56204245995b12d1245a537c5f9ba4da45b57","tarball":"https://registry.npmjs.org/@baguette-studios/journeytest-core/-/journeytest-core-0.1.1.tgz","fileCount":250,"integrity":"sha512-fOuxgLdYHNkvw11z3WODPuV+SikCG/Nuxn18Q3cXCrgmnXWd8Z1xpkc7y8PYpAMmL6/HiQgVfSuXj0JZEs1Tbg==","signatures":[{"sig":"MEYCIQC//GZzEwbUFSyg2ezmDDPames6xFjFt2Kr1XiM2canIgIhAIrUBvmrrsq7okF82alMG+H2yzc5q5UQ8eyjz6V+y5K8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@baguette-studios%2fjourneytest-core@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1497330},"type":"module","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cli":{"types":"./dist/cli.d.ts","import":"./dist/cli.js"},"./factories":{"types":"./dist/factories/index.d.ts","import":"./dist/factories/index.js"}},"gitHead":"87d8d560e3882835eac97c0c7c7b1f904bed5a92","scripts":{"dev":"tsx src/cli.ts","test":"vitest run","build":"tsc -p tsconfig.json","clean":"rm -rf dist coverage","prepack":"npm run clean && npm run build","validate":"npm run typecheck && npm test","typecheck":"tsc -p tsconfig.json --noEmit","test:smoke":"node scripts/test-smoke.mjs --runs=5 --timeout=30000","test:watch":"vitest","test:verbose":"vitest run --reporter=verbose","release:check":"npm run validate && npm pack --dry-run","prepublishOnly":"npm run validate","test:smoke:quick":"node scripts/test-smoke.mjs --runs=1 --timeout=30000","test:agent-browser":"vitest run tests/agentBrowserUiChange.test.ts --reporter=verbose --testTimeout=10000"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:6118a7ef-26b0-4cd0-9ac5-c5cde4b090e8"}},"repository":{"url":"git+https://github.com/Jules-Astier/journeytest-core.git","type":"git"},"_npmVersion":"11.17.0","description":"AI-agent-directed user journey testing for web apps with Pi and agent-browser.","directories":{},"_nodeVersion":"24.17.0","dependencies":{"zod":"4.4.3","commander":"15.0.0","@earendil-works/pi-ai":"0.79.4","@earendil-works/pi-agent-core":"0.79.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"4.22.4","vitest":"4.1.9","typescript":"6.0.3","@types/node":"25.9.3"},"peerDependencies":{"convex":"^1.42.0","agent-browser":"^0.31.1"},"peerDependenciesMeta":{"convex":{"optional":true},"agent-browser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/journeytest-core_0.1.1_1782730199288_0.06074852942425846","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@baguette-studios/journeytest-core","version":"0.1.2","description":"AI-agent-directed user journey testing for web apps with Pi and agent-browser.","type":"module","license":"MIT","author":{"name":"Jules Astier"},"repository":{"type":"git","url":"git+https://github.com/Jules-Astier/journeytest-core.git"},"bugs":{"url":"https://github.com/Jules-Astier/journeytest-core/issues"},"homepage":"https://jules-astier.github.io/journeytest-core/","publishConfig":{"access":"public","provenance":true},"bin":{"journeytest":"dist/cli.js"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./cli":{"types":"./dist/cli.d.ts","import":"./dist/cli.js"},"./factories":{"types":"./dist/factories/index.d.ts","import":"./dist/factories/index.js"}},"scripts":{"build":"tsc -p tsconfig.json","clean":"rm -rf dist coverage","dev":"tsx src/cli.ts","test":"vitest run","test:verbose":"vitest run --reporter=verbose","test:smoke":"node scripts/test-smoke.mjs --runs=5 --timeout=30000","test:smoke:quick":"node scripts/test-smoke.mjs --runs=1 --timeout=30000","test:agent-browser":"vitest run tests/agentBrowserUiChange.test.ts --reporter=verbose --testTimeout=10000","test:watch":"vitest","typecheck":"tsc -p tsconfig.json --noEmit","docs:dev":"vitepress dev docs","docs:build":"vitepress build docs","docs:preview":"vitepress preview docs","validate":"npm run typecheck && npm test","release:check":"npm run validate && npm pack --dry-run","release":"semantic-release","release:dry-run":"semantic-release --dry-run --no-ci","prepublishOnly":"npm run validate","prepack":"npm run clean && npm run build"},"keywords":["agent-browser","ai-testing","pi-agent","journey-testing","e2e"],"dependencies":{"@earendil-works/pi-agent-core":"0.79.4","@earendil-works/pi-ai":"0.79.4","commander":"15.0.0","zod":"4.4.3"},"peerDependencies":{"agent-browser":"^0.31.1","convex":"^1.42.0"},"peerDependenciesMeta":{"agent-browser":{"optional":true},"convex":{"optional":true}},"devDependencies":{"@commitlint/cli":"^21.1.0","@commitlint/config-conventional":"^21.1.0","@semantic-release/changelog":"^6.0.3","@semantic-release/commit-analyzer":"^13.0.1","@semantic-release/exec":"^7.1.0","@semantic-release/git":"^10.0.1","@semantic-release/github":"^12.0.8","@semantic-release/npm":"^13.1.5","@semantic-release/release-notes-generator":"^14.1.1","@types/node":"25.9.3","conventional-changelog-conventionalcommits":"^10.2.0","semantic-release":"^25.0.5","tsx":"4.22.4","typescript":"6.0.3","vitepress":"^1.6.4","vitest":"4.1.9"},"engines":{"node":">=24"},"gitHead":"9139d581fc6a882257ea4c46bdf16d59547c0ae5","_id":"@baguette-studios/journeytest-core@0.1.2","_nodeVersion":"24.17.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-b9RGP+7sLj0u9fwW+ANsVvOXJJ6GeYz6kxYM9HldcJHK0QDdXqDf6bc4PTNOsGEZtNhH/C7Um50jFqRYh1CuIg==","shasum":"dea9692b75883c8ff06282555a4d706d522a27f5","tarball":"https://registry.npmjs.org/@baguette-studios/journeytest-core/-/journeytest-core-0.1.2.tgz","fileCount":251,"unpackedSize":1491164,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@baguette-studios%2fjourneytest-core@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICK46wW7dfbtqkkDhD5LCvQj3zU5krcaFnjXcrh0fqO6AiEAqIMZ/sueaIM5wHKruWMcK8bulc49+SX4EyrPeScHcE8="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:6118a7ef-26b0-4cd0-9ac5-c5cde4b090e8"}},"directories":{},"maintainers":[{"name":"baguette-studios","email":"astier.jules@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/journeytest-core_0.1.2_1782754011714_0.38108491897444075"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-28T19:17:28.927Z","modified":"2026-06-29T17:26:52.148Z","0.1.0":"2026-06-28T19:17:29.204Z","0.1.1":"2026-06-29T10:49:59.445Z","0.1.2":"2026-06-29T17:26:51.873Z"},"bugs":{"url":"https://github.com/Jules-Astier/journeytest-core/issues"},"author":{"name":"Jules Astier"},"license":"MIT","homepage":"https://jules-astier.github.io/journeytest-core/","keywords":["agent-browser","ai-testing","pi-agent","journey-testing","e2e"],"repository":{"type":"git","url":"git+https://github.com/Jules-Astier/journeytest-core.git"},"description":"AI-agent-directed user journey testing for web apps with Pi and agent-browser.","maintainers":[{"name":"baguette-studios","email":"astier.jules@gmail.com"}],"readme":"# @baguette-studios/journeytest-core\n\nAI-agent-directed user journey testing for web apps.\n\n`@baguette-studios/journeytest-core` standardizes:\n\n- tester profiles\n- user journeys\n- explicit pass, fail, and blocker criteria\n- agent-owned verdicts\n- video, timeline, JSON, screenshot, dashboard, and Markdown report artifacts\n\nThe first director implementation uses Pi Agent SDK. The first browser implementation uses the `agent-browser` CLI.\n\n## Documentation\n\nDurable project documentation lives in the OKF-style bundle under [`docs/`](docs/index.md)\nand is published with VitePress to GitHub Pages:\n\nhttps://jules-astier.github.io/journeytest-core/\n\nUpdate the relevant docs whenever public behavior, schemas, generated artifacts,\nextension points, examples, or workflows change.\n\nRun the docs site locally with:\n\n```bash\nnpm run docs:dev\n```\n\n## Install\n\n```bash\nnpm install @baguette-studios/journeytest-core\nnpm install agent-browser\n```\n\nJourneyTest runs on Node.js 24 or newer. The default browser driver shells out\nto the `agent-browser` CLI, so install `agent-browser` in the project that runs\njourneys or make the `agent-browser` executable available on `PATH`.\n\n## Agent Skills\n\nJourneyTest includes the `journeytest-author` agent skill for writing and\nreviewing tester profiles, journey JSON, and data lifecycle setup.\n\nInstall it from this GitHub repository with Vercel's `skills` CLI:\n\n```bash\nnpx skills add Jules-Astier/journeytest-core --skill journeytest-author\n```\n\n`skills add` installs project-local skills by default. To target Codex\nexplicitly, run:\n\n```bash\nnpx skills add Jules-Astier/journeytest-core \\\n  --skill journeytest-author \\\n  --agent codex\n```\n\nPreview the skills exposed by the repository without installing anything:\n\n```bash\nnpx skills add Jules-Astier/journeytest-core --list\n```\n\nIf `@baguette-studios/journeytest-core` is already installed in a project, you\ncan also sync the bundled skill files from `node_modules`:\n\n```bash\nnpx skills experimental_sync --agent codex\n```\n\nThe `experimental_sync` command is currently experimental in the `skills` CLI,\nbut it works because JourneyTest publishes its `skills/` directory. It creates\nor updates project-local agent skill directories such as `.agents/skills/` and\nwrites `skills-lock.json`.\n\nJourneyTest does not run an interactive `postinstall` prompt. npm install\nscripts run in CI and other non-interactive environments, can be disabled by\npackage managers, and cannot reliably choose which local agent directory should\nreceive the skill. Use the explicit commands above instead, or add `--global`\nwhen you intentionally want a user-wide skill install.\n\nFor local development:\n\n```bash\nnpm install\nnpm run build\n```\n\n## Release Automation\n\nPushes to `main` run the CI/CD workflow. The `validate` job checks Conventional\nCommit messages, runs type checks and tests, and verifies package contents with\n`npm pack --dry-run`.\n\nIf validation passes, semantic-release reads commits since the last `v*` tag,\ncalculates the next SemVer version, generates `CHANGELOG.md` and GitHub release\nnotes, commits release metadata, tags the release, publishes to npm, and creates\nthe GitHub release.\n\nRelease bump rules:\n\n- `feat`: minor release\n- `fix` or `perf`: patch release\n- `type!` or `BREAKING CHANGE:` footer: major release\n- `docs`, `refactor`, `test`, `build`, `ci`, `chore`, and `revert`: release\n  note entries when included with a release, but no release by themselves unless\n  breaking\n\nConfigure npm Trusted Publishing for `Jules-Astier/journeytest-core` and\n`.github/workflows/ci.yml`, or add a GitHub Actions repository secret named\n`NPM_TOKEN` with npm publish permission. The package sets\n`publishConfig.provenance` so npm publishes with provenance where supported.\n\nThis repository currently needs one bootstrap tag before the first automated\nrelease run:\n\n```bash\ngit tag v0.1.1 6cbb66d\ngit push origin v0.1.1\n```\n\nAfter that, semantic-release owns release commits, changelog updates, tags, and\nnpm publishing.\n\n## Validate Examples\n\n```bash\nnpx journeytest validate --journeys examples/journeys --profiles examples/profiles\n```\n\n## Author Journey JSON\n\nThese helper commands are deterministic local utilities. They do not call a model.\n\nCreate a starter authoring tree:\n\n```bash\nnpx journeytest init --dir journeytest\n```\n\nThis writes:\n\n```text\njourneytest/\n  profiles/admin.json\n  journeys/admin-invite-user.json\n```\n\nGenerate one profile or journey at a time:\n\n```bash\nnpx journeytest new profile admin --out journeytest/profiles/admin.json\n\nnpx journeytest new journey admin-invite-user \\\n  --profile admin \\\n  --app-name \"Acme Admin\" \\\n  --base-url http://127.0.0.1:3000 \\\n  --out journeytest/journeys/admin-invite-user.json\n```\n\nDraft a richer journey from structured local inputs without calling a model:\n\n```bash\nnpx journeytest draft journey checkout-refund \\\n  --title \"Checkout refund request\" \\\n  --profile support \\\n  --app-name \"Support Console\" \\\n  --base-url http://127.0.0.1:5173 \\\n  --objective \"Submit a refund request for a disposable order.\" \\\n  --precondition \"The tester is authenticated as support.\" \\\n  --task \"Find the disposable order.\" \\\n  --task-outcome \"The order detail page is visible.\" \\\n  --task \"Submit a refund request.\" \\\n  --pass \"The app confirms that the refund request was submitted.\" \\\n  --fail \"The app reports success but the order shows no refund request.\" \\\n  --blocker \"Stop if the order is not disposable test data.\" \\\n  --data orderId=ord_test_123 \\\n  --out journeytest/journeys/checkout-refund.json\n```\n\nYou can also supply `--input draft.json` with the same fields in JSON and override individual values with flags.\n\nPrint JSON Schema for editor integration or review:\n\n```bash\nnpx journeytest schema journey > journey.schema.json\nnpx journeytest schema profile > profile.schema.json\nnpx journeytest schema --out journeytest.schemas.json\n```\n\nLint journeys for schema validity and authoring quality:\n\n```bash\nnpx journeytest lint --journeys journeytest/journeys --profiles journeytest/profiles\n```\n\n`lint` catches missing blocker criteria, weak or generic fail criteria, critical pass criteria without required evidence, and destructive journeys that lack explicit blocker or cleanup guidance.\n\n## Run A Journey\n\n```bash\nnpx journeytest run examples/journeys/admin-invite-user.json \\\n  --profile examples/profiles/admin.json \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --out runs\n```\n\n## Model Authentication\n\nPi OAuth providers such as `anthropic`, `openai-codex`, and `github-copilot` need an OAuth `auth.json` file. JourneyTest resolves that file in this order:\n\n1. `--auth <path>`\n2. `JOURNEYTEST_AUTH_PATH`\n3. Existing `./auth.json` in the current working directory, for backward compatibility\n4. User config auth file\n\nThe default user config path is:\n\n- macOS: `~/Library/Application Support/JourneyTest/auth.json`\n- Linux: `${XDG_CONFIG_HOME:-~/.config}/journeytest/auth.json`\n- Windows: `%APPDATA%\\JourneyTest\\auth.json`\n\nThe upstream Pi login CLI writes `auth.json` into its current directory. On macOS, create the default JourneyTest auth file with:\n\n```bash\nmkdir -p \"$HOME/Library/Application Support/JourneyTest\"\n(cd \"$HOME/Library/Application Support/JourneyTest\" && npx @earendil-works/pi-ai login anthropic)\n```\n\nFor a project-local legacy file, run `npx @earendil-works/pi-ai login anthropic` from the project root. `auth.json` is ignored by Git, but a user config location is preferred for new setup. To use another file:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --auth ~/.config/journeytest/auth.json\n```\n\nor:\n\n```bash\nJOURNEYTEST_AUTH_PATH=~/.config/journeytest/auth.json npx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514\n```\n\nInspect the auth file JourneyTest will use without printing secrets:\n\n```bash\nnpx journeytest auth\nnpx journeytest auth --json\n```\n\nJourneyTest does not maintain its own fixed provider/model list. For the Pi\ndirector and bookmark curator, `--provider` and `--model` are passed through to\nthe installed Pi package. Any provider/model pair supported by that Pi version\ncan be used. OAuth-backed providers must have credentials in the resolved\n`auth.json`; API-key-backed providers can use the environment variables or auth\nmechanisms expected by Pi.\n\n## Browser State Setup\n\nUse `--state <path>` when the tested app needs pre-authenticated browser cookies or storage:\n\n```bash\nagent-browser open http://127.0.0.1:3000\n# Log in manually or with agent-browser commands, then save state:\nagent-browser state save ./auth-state.json\n\nnpx journeytest run examples/journeys/admin-invite-user.json \\\n  --profile examples/profiles/admin.json \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --state ./auth-state.json \\\n  --out runs\n```\n\nBrowser state files contain cookies, localStorage, and sessionStorage. Keep them out of Git; `auth-state*.json`, `browser-state*.json`, `storage-state*.json`, and `*.storage-state.json` are ignored by default. For long-lived shared state, prefer a path outside the repo and pass it with `--state`.\n\n## Browser Environment\n\nSet browser environment overrides per run:\n\n```bash\nnpx journeytest run examples/journeys/admin-invite-user.json \\\n  --profile examples/profiles/admin.json \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --viewport 1440x900@2 \\\n  --out runs\n```\n\nor use a curated device preset:\n\n```bash\nnpx journeytest run examples/journeys/admin-invite-user.json \\\n  --profile examples/profiles/admin.json \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --device iphone-14 \\\n  --out runs\n```\n\nJourneys can also declare `browserEnvironment` defaults in JSON. CLI flags override journey defaults. Current built-in presets are `iphone-14`, `pixel-7`, and `ipad-pro-11`.\n\n## Secret Handling\n\nJourneyTest redacts common secret-shaped values before writing text artifacts and event/result JSON: API keys, OAuth/access/refresh tokens, bearer/basic authorization headers, cookies, browser storage state, password/secret-looking keys, and values supplied by lifecycle providers through `redactValues`. This applies to `events.ndjson`, `run.json`, Markdown/dashboard rendering, browser snapshots, visible-DOM summaries, UI-change timeline JSON, console evidence, network request logs, HAR files, and lifecycle artifacts.\n\nScreenshots and video are visual evidence and cannot be text-redacted. Avoid displaying raw secrets in the app under test, and use dedicated test accounts and short-lived browser state.\n\n## Run A Directory Of Journeys\n\n`run` also accepts a directory and recursively discovers `*.json` journey files, similar to pytest collection:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --out runs\n```\n\nFilter suites with tags, journey ids, deterministic shards, or rerun-failed selection:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --tag smoke \\\n  --exclude-tag destructive \\\n  --journey-id admin-invite-user \\\n  --shard 1/3 \\\n  --out runs\n```\n\nRerun only unhealthy journeys from a previous suite directory, `history.json`, or `run.json`:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --rerun-failed runs/<previous-timestamp>-run \\\n  --out runs\n```\n\nBy default, journeys run sequentially. Run multiple journeys at once with `--parallel-agents`:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --parallel-agents 3 \\\n  --out runs\n```\n\nWith the default `agent-browser` driver, parallel journeys share one headless browser session and each journey gets its own labeled tab. This keeps parallel runs from launching one Chrome-for-Testing app per agent. Browser commands are safely serialized around tab switching, while Pi directors can still run concurrently.\n\nTabs in a shared browser session share cookies, storage, cache, and history. `agent-browser` also supports one active video recording per session, so JourneyTest serializes shared-tab video recording per journey and writes one `video.webm` for each journey run. For full browser-session isolation, or fully concurrent per-journey video recording, use:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --parallel-agents 3 \\\n  --parallel-browser-mode isolated-sessions \\\n  --out runs\n```\n\nIn isolated-session mode, each journey gets its own Pi director, browser driver, run directory, and browser session. If you do not pass `--session`, JourneyTest uses the generated run id as the session name. If you pass `--session` with `--parallel-agents > 1`, the value is treated as a session prefix and each journey receives a unique derived browser session name.\n\nJourneyTest records one journey-scoped `video.webm` by default. Dashboard bookmarks still seek to the relevant action timestamps in that video. Use `--no-video` to skip video entirely.\n\nUse `--retries <count>` to retry failing journeys. The final `run.json` keeps per-attempt metadata and marks journeys as flaky when they pass only after one or more failed attempts.\n\nEach journey director run has a wall-clock timeout. The default is 30 minutes per attempt; tune it with `--journey-timeout-ms <ms>`, or pass `--journey-timeout-ms 0` to disable it for an intentionally open-ended diagnostic run.\n\nFor a single journey, the CLI prints that run's `dashboard.html` path and `file://` URL. For multiple journeys, it prints every run dashboard plus a generated suite dashboard:\n\n```text\nDashboard: /path/to/runs/<timestamp>-admin-invite-user/dashboard.html\nDashboard URL: file:///path/to/runs/<timestamp>-admin-invite-user/dashboard.html\nRun dashboard: /path/to/runs/<timestamp>-run/dashboard.html\nRun dashboard URL: file:///path/to/runs/<timestamp>-run/dashboard.html\n```\n\nFor directory runs, all journey artifacts are grouped under that same run folder:\n\n```text\nruns/<timestamp>-run/\n  dashboard.html\n  history.json\n  <timestamp>-journey-a/\n  <timestamp>-journey-b/\n```\n\nCompare a suite run against a previous suite directory, or a single previous `run.json`, with `--compare-to`:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --compare-to runs/<previous-timestamp>-run \\\n  --out runs\n```\n\nThe suite dashboard shows current and previous run/verdict status side by side, highlights newly failed, newly passed, still failing, and flaky/changed journeys, and writes a compact `history.json` summary for trend tooling.\n\nThe run writes:\n\n```text\nruns/<timestamp>-<journey-id>/\n  dashboard.html\n  events.ndjson\n  report.md\n  run.json\n  video.webm\n  screenshots/\n  snapshots/\n  console/\n  network/\n  ui-changes/\n```\n\nOpen `dashboard.html` in a browser to review the run video, timestamped bookmarks, agent verdict text, criteria, findings, screenshots, snapshots, UI-change timelines, raw JSON, and generated collateral links.\n\nWhen click coordinates are available from the browser driver, the dashboard shows a brief marker over the video at the clicked point while playback reaches that action or when you click the corresponding chapter.\n\nBy default, JourneyTest records short UI-change timelines around click, fill, type, and key-press actions when the browser driver supports it. These artifacts capture visible user-relevant changes such as button label changes, status/alert/live-region updates, dialogs, route changes, focus changes, and form progress. Change timelines are written under `ui-changes/`, with supporting before/change/after screenshots in `screenshots/`, before/after accessibility snapshots in `snapshots/`, and bounded before/after visible-DOM summaries when supported by the browser driver. Journeys can require this evidence with `requiredEvidence: [\"uiChangeTimeline\"]`, and verdicts can attach the artifact path as `evidence.uiChangeTimeline`.\n\nTune this capture with `--ui-change-timeout-ms`, `--ui-change-quiet-ms`, `--ui-change-max-changes`, `--ui-change-max-screenshots`, `--no-ui-change-screenshots`, `--no-ui-change-snapshots`, and `--no-ui-change-dom-snapshots`. Disable the observation window entirely with `--no-ui-change-recording`.\n\nThe browser tool surface also supports targeted container scrolling, hover, drag-and-drop, and file upload when the active driver supports them. For scrolling, pass a target container selector/ref to scroll within a modal or panel instead of the page.\n\n## Video Chapters\n\nRecorded videos get timestamped bookmarks from UI actions only, such as clicks, fills, typing, pressing keys, drags, uploads, and hovers. Snapshot captures, screenshots, tool start/end events, and assistant-message events are not turned into bookmarks. Bookmark timestamps refer to elapsed time within the journey recording.\n\nBy default, the CLI runs a post-run Pi bookmark curator using the same `--provider` and `--model`. The curator receives the action timeline plus nearby assistant text and can remove noisy action bookmarks or relabel them as concise chapter-style labels such as `Submit invite form`.\n\nDisable that extra model call with:\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --no-curate-bookmarks\n```\n\nUse a custom bookmark-curation system prompt with `--bookmark-system-prompt ./prompt.txt`.\n\n## Data Lifecycle\n\nJourneys can declare database setup, preflight checks, post-run checks, and cleanup separately from the loose `data` bag. JourneyTest orchestrates the lifecycle and writes durable artifacts:\n\n```text\nruns/<timestamp>-<journey-id>/\n  setup.json\n  preflight.json\n  postconditions.json\n  cleanup.json\n```\n\nDefine named environments in a lifecycle config file and pass it to `run`. Environments can use Convex functions, local scripts, or app-owned HTTP endpoints:\n\n```json\n{\n  \"appLifecycle\": {\n    \"ports\": {\n      \"frontend\": {},\n      \"backend\": {}\n    },\n    \"app\": {\n      \"baseUrl\": \"http://$hosts.frontend:$ports.frontend\",\n      \"allowedOrigins\": [\n        \"http://$hosts.frontend:$ports.frontend\",\n        \"http://$hosts.backend:$ports.backend\"\n      ]\n    },\n    \"start\": {\n      \"command\": \"node\",\n      \"commandArgs\": [\"scripts/journeytest-services.mjs\", \"start\"],\n      \"env\": {\n        \"FRONTEND_PORT\": \"$ports.frontend\",\n        \"BACKEND_PORT\": \"$ports.backend\"\n      },\n      \"passContext\": \"json-stdin\",\n      \"cwd\": \"../my-app\",\n      \"timeoutMs\": 60000\n    },\n    \"cleanup\": {\n      \"command\": \"node\",\n      \"commandArgs\": [\"scripts/journeytest-services.mjs\", \"cleanup\"],\n      \"passContext\": \"json-stdin\",\n      \"cwd\": \"../my-app\"\n    }\n  },\n  \"dataEnvironments\": {\n    \"local-convex\": {\n      \"provider\": \"convex\",\n      \"transport\": \"http\",\n      \"urlEnv\": \"CONVEX_URL\",\n      \"capabilities\": {\n        \"publicFunctions\": true,\n        \"internalFunctions\": false\n      }\n    },\n    \"local-script\": {\n      \"provider\": \"script\",\n      \"command\": \"node\",\n      \"commandArgs\": [\"scripts/journeytest-lifecycle.mjs\"],\n      \"passArgs\": \"json-argv\",\n      \"cwd\": \"../my-app\"\n    },\n    \"local-http\": {\n      \"provider\": \"http\",\n      \"url\": \"http://127.0.0.1:3000/__journeytest/lifecycle\",\n      \"authHeader\": \"X-JourneyTest-Token\",\n      \"authTokenEnv\": \"JOURNEYTEST_LIFECYCLE_TOKEN\"\n    }\n  }\n}\n```\n\n```bash\nnpx journeytest run examples/journeys \\\n  --profiles examples/profiles \\\n  --provider anthropic \\\n  --model claude-sonnet-4-20250514 \\\n  --data-lifecycle journeytest.lifecycle.json \\\n  --out runs\n```\n\nThe CLI default data lifecycle provider auto-routes each environment by its `provider` field. Use `--data-lifecycle-provider convex`, `script`, or `http` only when you intentionally want to force one provider factory.\n\n`appLifecycle` is for the app-under-test services: Docker compose stacks, frontend/backend dev servers, workers, or similar. JourneyTest allocates unused ports for each name in `ports`, expands `$ports.<name>` and `$hosts.<name>` in `app`, `commandArgs`, and `env`, then runs `start` before suite data lifecycle and journeys. If `app.baseUrl` is set, selected journeys run against that resolved URL instead of the URL authored in each journey file.\n\nStart and cleanup scripts receive a JSON context by argv, stdin, or not at all:\n\n```json\n{\n  \"phase\": \"start\",\n  \"suiteRunId\": \"2026-06-28T210000-run\",\n  \"runDir\": \"runs/2026-06-28T210000-run/_app-lifecycle\",\n  \"ports\": { \"frontend\": 51749, \"backend\": 51750 },\n  \"hosts\": { \"frontend\": \"127.0.0.1\", \"backend\": \"127.0.0.1\" },\n  \"app\": { \"baseUrl\": \"http://127.0.0.1:51749\" }\n}\n```\n\nThe start script should launch or reuse services, wait until they are healthy, then exit. The cleanup script runs after suite cleanup, and JourneyTest also attempts it on `SIGINT` or `SIGTERM`. Script stdout, stderr, exit code, parsed JSON output, and cleanup results are written under `_app-lifecycle/`.\n\nEach journey can reference an environment and app-owned lifecycle operations:\n\n```json\n{\n  \"dataLifecycle\": {\n    \"environment\": \"local-convex\",\n    \"setup\": {\n      \"id\": \"setup-s2\",\n      \"kind\": \"mutation\",\n      \"function\": \"testLifecycle:setupS2\",\n      \"manifestPath\": \"$.journeys.s2\"\n    },\n    \"preflight\": [\n      {\n        \"id\": \"s2-ready\",\n        \"kind\": \"query\",\n        \"function\": \"testLifecycle:assertS2Ready\"\n      }\n    ],\n    \"postconditions\": [\n      {\n        \"id\": \"s2-submitted\",\n        \"kind\": \"query\",\n        \"function\": \"testLifecycle:assertS2Submitted\"\n      }\n    ],\n    \"cleanup\": {\n      \"id\": \"cleanup-s2\",\n      \"kind\": \"mutation\",\n      \"function\": \"testLifecycle:cleanupJourney\",\n      \"args\": { \"namespace\": \"$context.namespace\" }\n    }\n  }\n}\n```\n\nThe same `dataLifecycle` operation shape works for every provider. `args` supports `$context.scope`, `$context.runId`, `$context.suiteRunId`, `$context.journeyRunId`, `$context.journeyId`, `$context.testerProfileId`, `$context.namespace`, `$context.environment`, `$manifest`, `$manifest.field`, `$suiteManifest`, `$suiteManifest.field`, and `$env.NAME`.\n\nFor `script` environments, `function` is the operation name passed to the configured command. By default JourneyTest runs:\n\n```text\n<command> <commandArgs...> <function> '<resolved args JSON>'\n```\n\nIf `command` is omitted, `function` is executed as the command and the resolved args JSON is passed as the first argv value. Set `passArgs` to `json-stdin` to write JSON to stdin or `none` to pass no operation args. Script stdout, stderr, and exit code are captured in lifecycle artifacts. The last JSON line printed to stdout is used as the operation result, which can include `checks`.\n\nFor `http` environments, `function` is an endpoint path under `url` unless it is absolute. JourneyTest posts the resolved args JSON to that endpoint and uses the JSON response as the operation result. If `authTokenEnv` is set, JourneyTest sends `Authorization: Bearer <token>` by default; use `authHeader` and `authScheme` to customize it. Auth token values are redacted from lifecycle artifacts, including echoed response fields and error text.\n\nUse `--keep-data` to skip cleanup while debugging. Convex HTTP transport requires the app project to expose test-gated public functions. Convex CLI transport uses `npx convex run` from `projectDir` and can target internal functions when the environment declares that capability.\n\n## Journey Video\n\nWhen video recording is enabled, JourneyTest starts recording after the browser driver starts and stops recording before the driver closes. The run writes one journey-scoped `video.webm`, and action bookmarks seek to timestamps within that recording.\n\n## Verdict Ownership\n\nThe framework owns schema validation, browser action execution, artifact capture, and report writing.\n\nThe agent owns the test verdict. A journey must include explicit `passCriteria`, `failCriteria`, and optional `blockerCriteria`. The Pi director requires the agent to call `journey_finish` with a structured verdict, which the framework validates and records.\n","readmeFilename":"README.md"}