Skip to content

Cross-language parity

Go, Ruby, Rust, Python, JVM, and .NET adapters must reach parity with the JavaScript/TypeScript adapters for core story semantics, the doc model, artifact outputs, and agent-consumable workflows.

Dimension Required outcome JS/TS baseline Non-JS status
Behavior semantics Given/When/Then/And/But keywords, auto-And for repeated keywords, explicit but() Vitest/Jest/Playwright/Cypress adapters Implemented; verified via RawRun fixtures and pnpm run verify:*
Doc model Same doc entry kinds and schema meaning (json, state, table, code, section, link, mermaid, screenshot, html, custom, note, tag, …) Full surface in JS adapters Implemented where host allows; gaps must be documented
Artifact outputs RawRun JSON → StoryReport v1 via formatters CLI Reporter rawRunPath + formatters RawRun default .executable-stories/raw-run.json; format with executable-stories format
$schema pointer Optional $schema in RawRun so editors validate the file as it is written Not emitted by the JS/TS reporters Emitted by all six non-JS adapters (Go, Ruby, Rust, pytest, JUnit 5, xUnit)
Agent workflow StoryReport JSON + list --list-format json index Agent artifact contract Same formatter pipeline for all languages
Verification Per-language verify script + formatter acceptance tests Example apps + pnpm quality verify:go, verify:pytest, verify:rust, verify:junit5, verify:xunit, verify:ruby

Status values used in release review:

  • required — must match JS/TS unless impossible on the host framework
  • intentional divergence — documented host limitation (must appear in README feature matrix)
  • in progress — tracked gap with owner and target release
Area JS/TS Non-JS Rationale
Init API story.init(task) (Vitest), story.init() (Jest), fixture-aware Playwright Language-native init (es.Init(t, …), ExecutableStories.init, …) Framework-native first — no shared interpreter
Reporter integration In-process Node reporters Write RawRun at end of test run Host runtime differs
ESLint plugins Per-framework plugins None (Ruby/Go use native linters) Host tooling
Cypress doc.story override Cypress-only title override N/A Cypress-specific legacy path

From repo root (requires language toolchain):

Terminal window
pnpm run verify:go
pnpm run verify:pytest
pnpm run verify:rust
pnpm run verify:junit5
pnpm run verify:xunit
pnpm run verify:ruby
./scripts/verify-all.sh

Each script:

  1. Runs the adapter example or package tests
  2. Asserts RawRun structure
  3. Validates schema via executable-stories validate
  4. Runs formatter pipeline (HTML + Markdown + StoryReport JSON + list index)

Formatter package tests also load cross-language RawRun fixtures (schemas/examples/go.json, rust.json, pytest.json, junit5.json, dotnet.json) and assert StoryReport v1 validation.

Every non-JS adapter tags its RawRun with a $schema pointer (https://executable-stories.dev/schemas/raw-run.schema.json) at write time, so an editor validates the file as the adapter produces it. The field is optional in the raw-run schema and the CLI ignores it — executable-stories doctor reports whether a run file carries one.

Before releasing adapter or formatter changes:

  1. No regression against this matrix without an explicit intentional divergence note
  2. Update README feature matrix when adding doc kinds or scenario options
  3. Extend verify scripts or acceptance fixtures when adding a new language or artifact field

Agents consume the same artifacts regardless of source language:

Terminal window
executable-stories format .executable-stories/raw-run.json --format story-report-json --output-dir reports --output-name index
executable-stories list .executable-stories/raw-run.json --list-format json > reports/scenario-index.json

Optional MCP: MCP server guide.