Riteway
Simple, readable, helpful unit tests. Optimized for AI Driven Development.
Install / Use
/learn @paralleldrive/RitewayREADME
Riteway
The standard testing framework for AI Driven Development (AIDD) and software agents.
Riteway is a testing assertion style and philosophy which leads to simple, readable, helpful unit tests for humans and AI agents.
It lets you write better, more readable tests with a fraction of the code that traditional assertion frameworks would use, and the riteway ai CLI lets you write AI agent prompt evals as easily as you would write a unit testing suite.
Riteway is the AI-native way to build a modern test suite. It pairs well with Vitest, Playwright, Claude Code, Cursor Agent, Google Antigravity, and more.
- Readable
- Isolated/Integrated
- Thorough
- Explicit
Riteway forces you to write Readable, Isolated, and Explicit tests, because that's the only way you can use the API. It also makes it easier to be thorough by making test assertions so simple that you'll want to write more of them.
Why Riteway for AI Driven Development?
Riteway's structured approach makes it ideal for AIDD:
📖 Learn more: Better AI Driven Development with Test Driven Development
- Clear requirements: The given, should expectations and 5-question framework help AI better understand exactly what to build
- Readable by design: Natural language descriptions make tests comprehensible to both humans and AI
- Simple API: Minimal surface area reduces AI confusion and hallucinations
- Token efficient: Concise syntax saves valuable context window space
The 5 Questions Every Test Must Answer
There are 5 questions every unit test must answer. Riteway forces you to answer them.
- What is the unit under test (module, function, class, whatever)?
- What should it do? (Prose description)
- What was the actual output?
- What was the expected output?
- How do you reproduce the failure?
Installing
npm install --save-dev riteway
Then add an npm command in your package.json:
"test": "riteway test/**/*-test.js",
For projects using both core Riteway tests and JSX component tests, you can use a dual test runner setup:
"test": "node source/test.js && vitest run",
Now you can run your tests with npm test. Riteway also supports full TAPE-compatible usage syntax, so you can have an advanced entry that looks like:
"test": "nyc riteway test/**/*-rt.js | tap-nirvana",
In this case, we're using nyc, which generates test coverage reports. The output is piped through an advanced TAP formatter, tap-nirvana that adds color coding, source line identification and advanced diff capabilities.
Requirements
Riteway requires Node.js 16+ and uses native ES modules. Add "type": "module" to your package.json to enable ESM support. For JSX component testing, you'll need a build tool that can transpile JSX (see JSX Setup below).
riteway ai — AI Prompt Evaluations
The riteway ai CLI runs your AI agent prompt evaluations against a configurable pass-rate threshold. Write a .sudo test file, run it through any supported AI agent, and get a TAP-formatted report with per-assertion pass rates across multiple runs.
Authentication
All agents use OAuth authentication — no API keys needed. Authenticate once before running evals:
| Agent | Command | Docs |
|-------|---------|------|
| Claude | claude setup-token | Claude Code docs |
| Cursor | agent login | Cursor docs |
| OpenCode | See docs | opencode.ai/docs/cli |
Writing a test file
AI evals are written in .sudo files using SudoLang syntax:
# my-feature-test.sudo
import 'path/to/spec.mdc'
userPrompt = """
Implement the sum function as described.
"""
- Given the spec, should name the function sum
- Given the spec, should accept two parameters named a and b
- Given the spec, should return the correct sum of the two parameters
Each - Given ..., should ... line becomes an independently judged assertion. The agent is asked to respond to the userPrompt (with any imported spec as context), and a judge agent scores each assertion across all runs.
Running an eval
riteway ai path/to/my-feature-test.sudo
By default this runs 4 passes, requires 75% pass rate, uses the claude agent, runs up to 4 tests concurrently, and allows 300 seconds per agent call.
# Specify runs, threshold, and agent
riteway ai path/to/test.sudo --runs 10 --threshold 80 --agent opencode
# Use a Cursor agent with color output
riteway ai path/to/test.sudo --agent cursor --color
# Use a custom agent config file (mutually exclusive with --agent)
riteway ai path/to/test.sudo --agent-config ./my-agent.json
Options
| Flag | Default | Description |
|------|---------|-------------|
| --runs N | 4 | Number of passes per assertion |
| --threshold P | 75 | Required pass percentage (0–100) |
| --timeout MS | 300000 | Per-agent-call timeout in milliseconds |
| --agent NAME | claude | Agent: claude, opencode, cursor, or a custom name from riteway.agent-config.json |
| --agent-config FILE | — | Path to a flat single-agent JSON config {"command","args","outputFormat"} — mutually exclusive with --agent |
| --concurrency N | 4 | Max concurrent test executions |
| --color | off | Enable ANSI color output |
| --save-responses | off | Save raw agent responses and judge details to a companion .responses.md file |
Results are written as a TAP markdown file under ai-evals/ in the project root.
Saving raw responses for debugging
When --save-responses is passed, a companion .responses.md file is written alongside the .tap.md output. It contains the raw result agent response and per-run judge details (passed, actual, expected, score) for every assertion — useful for debugging failures without adding console noise.
riteway ai path/to/test.sudo --save-responses
Each test file produces its own uniquely-named pair of files (e.g. 2026-03-17-test-abc12.tap.md and 2026-03-17-test-abc12.responses.md), so multiple test files never conflict.
Capturing responses as CI artifacts
In GitHub Actions, use --save-responses and upload the ai-evals/ directory as an artifact:
- name: Run AI prompt evaluations
run: npx riteway ai path/to/test.sudo --save-responses
- name: Upload AI eval responses
if: always()
uses: actions/upload-artifact@v4
with:
name: ai-eval-responses
path: ai-evals/*.responses.md
retention-days: 14
The if: always() ensures responses are uploaded even when assertions fail, so you can inspect exactly what the agent produced.
Partial results on timeout
If some runs complete before another times out, the completed runs' responses are still written to the responses file. The timed-out run's partial agent output is also captured, followed by a [RITEWAY TIMEOUT] marker showing when and where the timeout occurred. This lets you debug why a run took too long and potentially optimize the prompt to run faster.
Custom agent configuration
riteway ai init writes all built-in agent configs to riteway.agent-config.json in your project root, so you can add custom agents or tweak existing flags:
riteway ai init # create riteway.agent-config.json
riteway ai init --force # overwrite existing file
The generated file is a keyed registry. Add a custom agent entry and use it with --agent:
{
"claude": { "command": "claude", "args": ["-p", "--output-format", "json", "--no-session-persistence"], "outputFormat": "json" },
"opencode": { "command": "opencode", "args": ["run", "--format", "json"], "outputFormat": "ndjson" },
"cursor": { "command": "agent", "args": ["--print", "--output-format", "json"], "outputFormat": "json" },
"my-agent": { "command": "my-tool", "args": ["--json"], "outputFormat": "json" }
}
riteway ai path/to/test.sudo --agent my-agent
Once riteway.agent-config.json exists, any agent key defined in it supersedes the library's built-in defaults for that agent.
Example Usage
import { describe, Try } from 'riteway/index.js';
// a function to test
const sum = (...args) => {
if (args.some(v => Number.isNaN(v))) throw new TypeError('NaN');
return args.reduce((acc, n) => acc + n, 0);
};
describe('sum()', async assert => {
const should = 'return the correct sum';
assert({
given: 'no arguments',
should: 'return 0',
actual: sum(),
expected: 0
});
assert({
given: 'zero',
should,
actual: sum(2, 0),
expected: 2
});
assert({
given: 'negative numbers',
should,
actual: sum(1, -4),
expected: -3
});
assert({
given: 'NaN',
should: 'throw',
actual: Try(sum, 1, NaN),
expected: new TypeError('NaN')
});
});
Testing React Components
import render from 'riteway/render-component';
import { describe } from 'riteway/index.js';
describe('renderComponent', async assert => {
const $ = render(<div className="foo">testing</div>);
assert({
given: 'some jsx',
should: 'render markup',
actual: $('.foo').html().trim(),
expected: 'testing'
});
});
N
Related Skills
node-connect
340.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.2kCommit, push, and open a PR
