Editors and agents

Editor setup

Everything below is optional: Saffron runs fine from the CLI alone, but completion from your own step vocabulary is what keeps wording (and token spend) under control.

VS Code

Full experience: the Saffron extension, on the VS Code Marketplace: search "Saffron" in the Extensions view, or

code --install-extension ChathurangaJayasinghe.saffron-vscode

You get .saffron syntax highlighting (first-class StepSet), Ctrl/Cmd+click on {env:VAR} tokens to open the variable in .env (or .env.example), step completion with //○ status badges, StepSet completion, go-to-definition on invocations, hover cards, and diagnostics (unknown/duplicate set names, near-duplicate wording warnings).

Run from the editor. Right-click a .saffron file or a folder of them (Explorer or editor) and pick Saffron: Run, Run (replay only, no AI), Run (headed browser) or Re-record; the play button in the editor title runs the open file. Commands run as a VS Code task in the workspace folder that owns the file, using that folder's own saffron-ai install (npx otherwise). Arguments reach the process directly, so a file name is never read as shell syntax. The Command Palette adds Run all feature files, Open latest report and Accept all pending proposals.

The Saffron side panel. The Saffron icon in the activity bar opens two views. Feature files lists every .saffron file with its scenarios as children (click one to jump to it), inline Run and Replay-only buttons per file, checkboxes with Run selected, and Run all. Run options and status holds the replay-only and headed toggles, which apply to every run started from the extension, the last run's totals with the report one click away, and the proposals pending review with Accept all. It refreshes as files, reports and proposals change. Four more sections read saffron status --json: Tags (tick and Run tagged), Proposals (tick, hover for the narrative, proof-replay verdict and cost, then Accept selected, Reject selected or Accept all; click one to open its scenario), Health and config (vocabulary counts, divergent steps, duplicate wordings proven by identical recordings, the effective config with one click to the file, recent pass rates) and Orphaned recordings (caches and proposals whose scenario no longer exists, with the reason; click one to open it, or use the title action to run saffron prune --yes after a confirmation). Saffron: Open dashboard shows the run report in an editor tab, refreshed after each run.

No-extension fallback (two commands):

// settings.json: Gherkin highlighting for .saffron
{ "files.associations": { "*.saffron": "feature" } }
npx saffron steps --snippets   # native completion from your vocabulary

Re-run --snippets after recording sessions to keep completions fresh.

JetBrains (IntelliJ IDEA, WebStorm, PyCharm, Rider, incl. Community)

The Saffron plugin (JetBrains Marketplace; source at https://github.com/s-chathuranga-j/saffron-jetbrains-plugin) makes this a one-click install, like the Cucumber plugin: it registers the .saffron file type with highlighting from the bundled grammar, and wires saffron lsp through the free LSP4IJ plugin, when it is installed, for *.saffron and *.feature: completion badges, StepSet go-to-definition, hover, diagnostics. The only prerequisite is saffron-ai in the project (npm i -D saffron-ai); the plugin runs the project-local binary and shows a hint if the package is missing.

Running from the IDE. Three ways, all landing in the Run tool window:

  • Run configurations: Run/Debug Configurations → +Saffron. run takes files or folders, tags, and replay-only / headed / re-record switches plus extra arguments; report opens the latest report; accept promotes every pending proposal. Tick Store as project file to share a configuration through .run/.
  • Right-click → Run on a .saffron file (project view or editor) or a folder holding them. The configuration it creates stays in the run widget for re-runs.
  • The Saffron tool window (right side, in projects with a saffron.config.json), six tabs. Files: every feature file with its scenario count, search, tick files and Run Selected, Run All, Open Report, Accept All Proposals, the last run's totals and the number of proposals pending review; double-click opens a file. Proposals: tick proposals, read the narrative, proof-replay verdict and cost, then Accept Selected, Reject Selected or Accept All. Tags: tick tags and Run Tagged. Health: vocabulary counts, divergent steps, duplicate wordings proven by identical recordings, the effective config with one click to the file. Orphans: caches and pending proposals whose scenario no longer exists, grouped and explained; double-click opens one, Remove All runs saffron prune --yes after a confirmation. Dashboard: the run report embedded in the IDE, reloaded after each run. The tabs read saffron status --json.

Runs use the login shell's environment, so Node from nvm or Homebrew is found even when the IDE was started from the Dock.

Install it from Settings → Plugins → Marketplace (search "Saffron"), or from the listing; install the free LSP4IJ plugin too for completion, go-to-definition and diagnostics. It is optional, so Saffron also installs on IDE builds LSP4IJ has not reached yet.

Manual setup (any JetBrains IDE, no plugin): two separate pieces, the LSP gives you intelligence, a TextMate bundle gives you colors:

  1. Syntax highlighting: Settings → Editor → TextMate Bundles+ and pick the bundle shipped inside the package: node_modules/saffron-ai/textmate/saffron.
  2. Completion, diagnostics, hover, go-to-definition, install the free LSP4IJ plugin (Red Hat), then Settings → Languages & Frameworks → Language Servers → +: command npx saffron lsp, working directory = your project root, file patterns *.saffron and *.feature. (On IntelliJ Ultimate 2023.2+ the native LSP API also works.)

npx saffron lsp is not something you run by hand, it is a stdio language server the IDE launches. Run it in a terminal and it prints exactly these instructions (with the bundle's absolute path).

You get the same completion badges, StepSet go-to-definition, hover, and diagnostics as VS Code: served by saffron lsp, which is backed by Saffron's real parser.

Neovim

vim.api.nvim_create_autocmd("FileType", {
  pattern = { "cucumber" },
  callback = function()
    vim.lsp.start({ name = "saffron", cmd = { "npx", "saffron", "lsp" } })
  end,
})
vim.filetype.add({ extension = { saffron = "cucumber" } })

AI assistants (any editor)

Assistants can't read completion popups: serve them the vocabulary over MCP so generated feature files reuse your exact wordings:

claude mcp add saffron -- npx saffron mcp     # Claude Code

Cursor/Copilot/JetBrains AI Assistant: add an MCP server with command npx saffron mcp in their respective MCP settings. Three tools are exposed: search_steps, list_step_sets and project_status (the same overview as saffron status --json: what is cached, pending review, tagged, and the vocabulary health). And for whole files from prose: npx saffron author requirements.txt.

Claude Code: the Saffron plugin

Claude Code users get the language server, the MCP server and the skill in one install, from the public marketplace repo:

/plugin marketplace add s-chathuranga-j/saffron-claude-plugin
/plugin install saffron@saffron

With the plugin, Claude sees diagnostics for .saffron and .feature files after every edit (unknown or duplicate StepSet names, a missing StepSet keyword, near-duplicate wordings) and can jump to StepSet definitions and {env:VAR} variables, the way an IDE does. The MCP tools and the skill are the same ones saffron init installs per project, so run npx saffron init --no-mcp there to avoid registering the server twice. The plugin pins the saffron-ai version it was built from and starts it through npx.

AI agents: the bundled skill

The npm package ships an Agent Skill, skills/saffron/SKILL.md plus reference sheets, that teaches any skill-aware agent (Claude Code, Codex, Cursor, Copilot, Gemini CLI, …) how to write Saffron tests well: reuse the recorded vocabulary before inventing wordings, keep Then steps as the sacred verdict, {env:VAR} for secrets, StepSet syntax, network waits, page furniture, and the run → review → accept workflow. Install it into your project with:

npx saffron init                       # .claude/skills + .agents/skills (default)
npx saffron init --agents claude,agents,copilot,cursor

init also registers the saffron mcp server in each host's project-scoped config: .mcp.json (Claude Code), .cursor/mcp.json, .vscode/mcp.json (Copilot/VS Code): merged into whatever servers are already there, so assistants get search_steps, list_step_sets and project_status with no manual setup (Codex has no project-level file; init prints the one-liner). And it appends a short managed block to AGENTS.md (created if absent) and to CLAUDE.md when one exists, pointers that tell agents to load the skill and never hand-edit caches. Everything is idempotent; re-run after npm update saffron-ai to refresh the copy. --no-instructions / --no-scaffold / --no-mcp narrow it. Projects using npx skills-npm discover the skill from node_modules automatically.