MCP & CLI
The same execution core has three faces: a CLI, a programmatic API, and an MCP facade. Only named, promoted Journeys cross the boundary.
The CLI
The binary is jevitate. Every command accepts --json for a machine-readable envelope.
# install
npm install -g @jevitate/cli
# set up
jevitate init
jevitate profile create work
# record by demonstration
jevitate record --url http://localhost:3000 --intent "Check out with a saved card"
# journeys
jevitate journey list
jevitate journey find "checkout"
jevitate journey run <id> --param email=you@example.com
# author from recorded takes
jevitate recording fit take.json
jevitate recording postdoc take.json --out journey.json
jevitate recording promote journey.json
# load / throughput
jevitate load run <journeyId> --concurrency 5 --iterations 10 --seed 1
# autonomous testing (goal / feature / exploratory / adversarial)
jevitate explore --url http://localhost:3000 --goal "..." --success urlIncludes:/inbox --real
jevitate explore --url http://localhost:3000 --strategy adversarial --real
jevitate explore --url http://localhost:3000 --feature checkout --route "/checkout/**"
# UX review — advisory, ranked, cited usability findings
jevitate ux ./checkout.recording.json --app-class consumer
jevitate explore --url http://localhost:3000 --strategy usability --goal "..." --app-class consumer --real
# Jev-driven authoring + regression capture
jevitate explore-author-journey --url http://localhost:3000 --goal "..." --success urlIncludes:/done --id checkout --name "Checkout"
jevitate regression capture --from ./failing.recording.json --id checkout-001
# distributed Journey sources
jevitate source add acme https://github.com/acme/jevitate-journeys.git --accept-tou
jevitate source list
jevitate journey publish checkout --to acme
# exploration mission targets (for queue_exploration)
jevitate mission target add staging --name "Staging" --authorized-origin https://staging.acme.test --base-url https://staging.acme.test/app
jevitate mission target promote staging
# MCP server (stdio)
jevitate mcp
# model-assisted authoring
jevitate generate <task>
jevitate setup <feature> Consume it from an agent
Jevitate is built to be driven by an AI agent or harness. Claude Code, Codex or Cursor can reach
it two ways: as this jevitate CLI, or as an MCP server over stdio. Both stay behind
the same allowlist and the same safety policy.
jevitate init ties it together. It collects any missing credentials and installs a
Jevitate skill set into the runtimes it detects: Claude Code, Codex or Cursor, plus a generic
AGENTS.md fallback when none is present. The skills give the agent the commands and
the safe way to run them.
# collect any missing keys, then install the skill set into detected agents
jevitate init
# install only the skills, or only the keys
jevitate init --skip-keys
jevitate init --skip-skills
# force-install to specific runtimes, or preview without writing
jevitate init --targets claude-code,codex,cursor
jevitate init --dry-run init collects any missing keys and installs
the skills. It does not register the MCP server into an agent's config for you, so add
jevitate mcp to your MCP client yourself.
Record by demonstration
jevitate record opens a real, headed browser on an authorized origin, lets you drive
the flow yourself, and captures it into a schema-valid Recording.
The authorized-target guard runs before any browser opens — an unauthorized
origin never launches Chromium. Press Enter when you're done to end the capture.
jevitate record \
--url http://localhost:3000 \
--intent "Check out with a saved card" \
--retro "The confirm button moved below the fold" \
--allow http://localhost:3000 --allow https://checkout.stripe.com --url <url>— the start URL you demonstrate from (must be an authorized origin).--intent <text>— your framing of the task, carried toRecording.intent.--retro <text>— an optional retrospective note, carried toRecording.retro.--allow <origin>— extra authorized origins (repeatable). Defaults to the target URL's own origin.--headless— run headless. The default is headed, since a record session is a live demonstration.--out <dir>— where the Recording is written (default~/.jevitate/recordings).
The Recording then feeds the parameterize → promote lifecycle on the Journeys page.
Distributed sources
A source is a remote git repo of shared Journeys. Adding one clones it and pins its
HEAD — it never trusts anything implicitly. Trust and Terms-of-Use acceptance are
separate, explicit acts, and the pin only advances when you run update.
# register a remote source (clone + pin its HEAD). --accept-tou
# acknowledges its declared Terms of Use so its Journeys can run
jevitate source add acme https://github.com/acme/jevitate-journeys.git --accept-tou
jevitate source list # registered sources + which Journeys you trust
jevitate source pull acme # fetch new refs, never advances the pin
jevitate source update acme # the only command that advances the pin
jevitate source trust acme checkout # trust one Journey, bound to its content hash
jevitate source remove acme # drop the clone + lock entry source add <name> <gitUrl> [--accept-tou]— clone and pin.--accept-tourecords a Terms-of-Use acknowledgment (without it the run-gate keeps refusing the source's Journeys).source list— registered sources, annotated with which of their Journeys you've trusted.source pull <name>— fetch new refs. It never advances the pin.source update <name>— the only command that advances the pin (fetch + fast-forward).source trust <name> <journeyId>— record an explicit trust decision, bound to the Journey's current content hash. A later content change invalidates it.source remove <name>— remove the clone and its lock entry.
Publishing a Journey to a source
jevitate journey publish shares a promoted local Journey into a
registered source. It always lands on a new publish/<id> branch, never a
default branch. It opens a PR via gh when that's available, or prints branch + push
instructions when it isn't.
# --to is required. The Journey must be promoted first
jevitate journey publish checkout --to acme
# declare the origins it is authorized for (default: derived from its
# navigate steps) and optionally publish under a different id
jevitate journey publish checkout --to acme \
--declare-origin https://acme.test \
--as acme-checkout --to <source>— required. The registered source to publish into.--declare-origin <origin>— origins this Journey is authorized for (repeatable). Defaults to the origins derived from itsnavigatesteps.--as <id>— publish under a different id than the local one.--dir <path>— the local Journeys directory (default~/.jevitate/journeys).
Publishing fails closed on an unregistered source, an unpromoted Journey, a Journey that declares no origins, a materialized (non-redacted) secret value, or an origin the steps touch but the declarations don't cover.
Exploration mission targets
queue_exploration can only run against a target that has been promoted.
Registering a target is not the same as promoting it — a freshly added target is
unpromoted, and queue_exploration refuses it until a separate promote
flips the gate.
# register a target — UNPROMOTED, so queue_exploration cannot resolve it yet
jevitate mission target add staging \
--name "Staging" \
--authorized-origin https://staging.acme.test \
--base-url https://staging.acme.test/app \
--description "Shared staging environment"
jevitate mission target list # ALL targets, promoted and not
jevitate mission target promote staging # now queue_exploration can resolve it mission target add <id>— register a target (--name,--authorized-origin,--base-url, optional--description). Registers UNPROMOTED.mission target list— list all targets, promoted and unpromoted (a local/dev-facing listing).mission target promote <id>— promote a registered target soqueue_explorationcan resolve it.
UX review
The usability review asks whether a user got the job done and where the experience got in the way. Jev scores each screen against a cited rubric: Nielsen's 10 heuristics, cognitive-science principles from information scent to choice overload, dark-pattern detection, and a lightweight accessibility tier. Every finding names a real principle and anchors to observed behavior, so it stays advisory and never gates a pass or fail.
It runs two ways, offline over a saved Recording or live as an exploration strategy:
# offline: review a saved Recording. --app-class calibrates the rubric
jevitate ux ./checkout.recording.json --app-class consumer
# optional persona + the job the flow pursues, for sharper relevance
jevitate ux ./checkout.recording.json --app-class admin \
--persona "first-time buyer" --job "check out with a saved card"
# live: run usability as an exploration strategy (needs --goal + --app-class)
jevitate explore --url http://localhost:3000 \
--strategy usability --goal "check out" --app-class consumer --real ux <recording>— offline review of a saved Recording.--app-classis required for calibration (e.g.consumer,admin,internal).--persona <p>— an optional persona for calibration.--job <text>— the job the flow pursues, which sharpens relevance.explore --strategy usability— the live path. It needs--url,--goal(the job), and--app-class.--out <dir>— where the report is written.
A finding is advisory by design: it never sets a non-zero exit or gates a run. See Testing Modes.
The jevitate mcp server
jevitate mcp starts an MCP stdio server that exposes only the
allowlisted Jevitate tools below — it structurally cannot serve any raw browser primitive. Point
it at a specific store with --dir (default ~/.jevitate/journeys).
# starts an MCP stdio server on the local Journeys store
jevitate mcp
# point it at a different Journeys directory
jevitate mcp --dir ./my-journeys find_capabilities and run_journey are fully wired. The other allowlisted
tools, including queue_exploration, are served (they appear in
tools/list) but return a typed not_implemented error until their backing
services are wired next. No handler ever fabricates a success.
The MCP facade
The MCP surface is HITL-style: discover, then invoke. It exposes no raw browser
tools — an approved Journey is one allowlisted domain tool. The Status
column reflects what jevitate mcp serves today.
| Tool | Behavior | Status |
|---|---|---|
find_capabilities | Search the catalog, scoped to promoted / allowlisted Journeys, returning capabilities with their param-schemas | Wired |
run_journey | Resolve an already-published Journey by id only, never inline steps, and validate params against its schema | Wired |
queue_exploration | Enqueue a bounded exploration mission against a promoted target id (exactly one of goal/feature/route). It only enqueues, never drives the browser, and refuses out-of-schema params or over-ceiling budgets | Served · not_implemented |
queue_action / queue_retrieval | Enqueue a typed action or read. Cannot skip approval policy | Served · not_implemented |
approve_action | Record approval bound to the exact action hash, if the caller is authorized | Served · not_implemented |
get_command / cancel_command | Read command state / cancel queued work at a safe boundary | Served · not_implemented |
list_incoming / get_thread | Read normalized local records | Served · not_implemented |
get_site_health | Session and queue status, plus quarantine state, without browser internals | Served · not_implemented |
ai_generate_text | Bounded text generation for an authorized capability | Served · not_implemented |
Federated sources add findFederatedCapabilities behind a trust + terms-of-use run-gate.
Explicitly forbidden
The facade never exposes browser_click, browser_fill,
page_evaluate, run_selector, navigate_url,
get_dom, or get_cookies — these are an enforced denylist, not options.
queue_exploration lets an agent scope a bounded
mission (a goal, a named feature, or a route) behind the same allowlist, enqueued against a
promoted target and never touching the browser directly. Today missions are
strategy: "goal-based". Other strategies land as the schema grows. See
Testing Modes.