@popoverai/dotrequirements
v0.39.5
Published
Requirements as testable, human-readable data — CLI and test harness for spec-driven development with AI coding agents
Maintainers
Readme
dot•requirements
One source of truth for what your software should do. Readable. Testable. AI-accessible.
Tests prove something works—but nobody is certain it's the right something. Requirements live scattered across docs, issue trackers, and people's heads. They drift out of sync with actual code. And AI assistants can't access them at all.
dot•requirements closes this gap. Write requirements as structured Markdown, reference them directly in tests, and see coverage update automatically. When a requirement changes, the tests that validate it are one click away.
Alpha Software — Under active development. Please report issues to [email protected].
Who Is This For?
- Developers who want tests that prove the right behavior, not just "80% coverage"
- Product managers who want visibility into what's actually being tested
- AI-first builders who want clear requirements for faster, more accurate implementations
Installation
npm install @popoverai/dotrequirements
# or
pnpm add @popoverai/dotrequirementsNote: Examples use
dotreqfor brevity. The full commanddotrequirementsalso works.
Quick Start
1. Initialize a project
npx @popoverai/dotrequirements@latest initThis creates a .requirements/ directory with example requirements and configures your project.
2. Write requirements
Create *.requirements.md files in .requirements/ or colocate them with your code:
---
document:
defaultPrefix: AUTH-LOGIN
---
# Authentication Requirements
```dotrequirements
AUTH-LOGIN-1: A registered user, Jamie, can log in to their account
0. → When Jamie provides a valid username and password, they are authenticated and brought to their dashboard
1. → When Jamie provides an incorrect password, they see an error message and remain on the login page
2. → When Jamie's account has been deactivated, but they provide otherwise correct credentials, they see a message explaining their account statusIf your team prefers a structure such as Gherkin, you can add labels:
AUTH-LOGIN-2: A user with two-factor authentication enabled must provide an OTP
0. Given → Jamie has two-factor authentication enabled on their account
1. When → Jamie provides valid credentials
2. Then → Jamie is prompted to enter an OTP before accessing their dashboard3. Reference requirements in tests
import { requirement } from '@popoverai/dotrequirements/test';
describe(requirement('AUTH-LOGIN-1'), () => {
it(requirement('AUTH-LOGIN-1.0'), () => {
// valid credentials → authenticated
});
it(requirement('AUTH-LOGIN-1.1'), () => {
// incorrect password → error message
});
});4. Track coverage
After running tests, you'll see a coverage report showing which requirements have been tested.
CLI Commands
dotreq init
Initialize a new project. Creates .requirements/ directory, example files, and configuration.
dotreq init
dotreq init --name my-project
dotreq init --invite abc123xyzOptions:
| Option | Description |
|--------|-------------|
| --name <name> | Set project name (skips prompt) |
| --invite <token> | Join a team using an invite token |
Joining a team via invite:
If a team admin shares an invite command with you, join the team and connect in one step:
npx @popoverai/dotrequirements@latest init --invite abc123xyzThis shows the team name, prompts you to sign in, adds you to the team, and lets you select a project.
dotreq link
Connect your local project to the cloud — selecting an existing project, or creating one when the team has room. Opens a browser for authentication, then prints the account it signed in as (Signed in as [email protected]).
dotreq link
dotreq link --yes --json # non-interactive (for AI assistants/scripts)
dotreq link --connect my-project # connect to a specific project
dotreq link --create -n my-api # create a new project with this nameOptions:
| Option | Description |
|--------|-------------|
| -y, --yes | Non-interactive: resolve every decision from defaults or flags; never prompt |
| --json | Machine-readable output (one JSON object on stdout) |
| --team <nameOrId> | Use this team (implies --yes) |
| --connect <slug> | Connect to this existing project (implies --yes) |
| --create | Create a new project (implies --yes) |
| -n, --name <name> | Project name when creating |
In non-interactive mode the only human step is completing the browser login. When a genuine choice exists — multiple teams, existing projects, a plan at its project limit — link exits with code 2 and (with --json) a decision_needed object listing the options, each with the exact flag to retry with where a flag can express it (remedies that happen outside the CLI, like upgrading the team, carry no retry flag). Non-interactive link never syncs the cloud down, so freshly generated local requirements are never overwritten.
dotreq diff
Show how the repo and the cloud differ, read-only. Each document gets a verdict (in sync, additions in repo, additions in cloud, conflict, only in repo, only in cloud, invalid file).
dotreq diff
dotreq diff auth.requirements.md # detail for one or more documents
dotreq diff --exit-code # exit 1 on any drift (for CI)dotreq sync
Reconcile the repo and the cloud. With no flags, both sides contribute their additions and nothing contested is touched.
dotreq sync # both sides contribute (additive, safe)
dotreq sync --cloud-contributes # bring the cloud's additions down only
dotreq sync --repo-contributes # send the repo's additions up only
dotreq sync --repo-wins # repo is authoritative (may delete in cloud)
dotreq sync --cloud-wins # cloud is authoritative (may delete locally)
dotreq sync --yes # skip the deletion confirmationAdditive modes never delete; a --wins mode can, and lists every document it will permanently delete before writing.
First-time setup with a share token:
If a team member shares a sync command with you, you can sync requirements down without creating an account:
npx @popoverai/dotrequirements@latest sync --share drt_abc123...This gives you read-only access to view requirements. To contribute changes or report coverage, run dotreq link afterward.
dotreq validate
Validate requirements files against the schema.
dotreq validate
dotreq validate --file .requirements/auth.requirements.mddotreq search
Search requirements by text or regex across every .requirements.md file. Searches IDs, content, and labels.
dotreq search "login"
dotreq search "AUTH-.*" --regexdotreq get
Print a requirement (or subtree) by ID, with test references and source locations. Accepts both numeric paths (AUTH-LOGIN-1.0.1) and label paths (AUTH-LOGIN-1.given.and).
dotreq get AUTH-LOGIN-1
dotreq get AUTH-LOGIN-1.0dotreq list
Summarize requirements in the project. Without flags, lists every root with its child count. With --untested, filters to roots with no requirement() references in any test.
dotreq list
dotreq list --untesteddotreq requirements-for
Show which requirements a test file references, with the line where each requirement() call lives.
dotreq requirements-for src/auth.test.tsdotreq tests-for
Show which tests reference each requirement in a .requirements.md file. The inverse of requirements-for.
dotreq tests-for .requirements/auth.requirements.mddotreq acceptance-test
Run browser-based acceptance tests against requirements. Uses AI-powered browser automation to verify that your application behaves as specified.
dotreq acceptance-test LOGIN-1
dotreq acceptance-test LOGIN-1 https://example.com
dotreq acceptance-test LOGIN-1 --jsonOptions:
| Option | Description |
|--------|-------------|
| --json | Output results as JSON (for CI/CD integration) |
Configuration required:
Browser testing needs a Stagehand model and the API key for that model's provider in project-settings.json:
{
"defaultURL": "https://your-app.com",
"browserTest": {
"modelName": "gateway/anthropic/claude-haiku-5.5",
"modelApiKey": "your-api-key"
}
}Pick any Stagehand-supported model. Example values: gateway/anthropic/claude-haiku-5.5 (Vercel AI Gateway key), google/gemini-3-flash-preview (Gemini key).
Optional settings: vercelBypassSecret, browserbaseApiKey, browserbaseProjectId. Setting both Browserbase fields switches runs from LOCAL (spawns Playwright on your machine) to BROWSERBASE (managed cloud browsers).
dotreq cts (Alpha)
Generate behavioral requirements from an existing codebase — it plans a behavioral outline, drafts the requirements for each area, converges each through independent review, then reconciles the whole spec in a final cross-area pass, and writes the result to .requirements/.
It runs as a Claude Code skill backed by a dynamic workflow. Install it, then invoke it from Claude Code:
dotreq cts skill-install # install into this project's .claude/
dotreq cts skill-install --global # …or into ~/.claude/ for every projectThen, in Claude Code, run /codebase-to-spec (or just ask — e.g. "spec the auth module"). You confirm the scope; the workflow autonomously plans the areas, drafts and reviews each one, reconciles them in a cross-area pass, and writes the result to .requirements/. Requires a Claude Code version with dynamic-workflow support.
Alpha: output quality is prompt-sensitive and varies by codebase. See the Codebase to Spec docs for prerequisites, scoping, and known rough edges. Feedback to [email protected] welcome.
dotreq ai-setup
Install the requirements-driven workflow guidance for AI assistants (Claude Code, Cursor, Codex, Antigravity, GitHub Copilot) — and clean up any MCP configuration an earlier version wrote (the local MCP server is retired; agents use the CLI verbs directly).
dotreq ai-setupdotreq harness prepare
Parse requirements and build a lookup cache for multi-language test tracking. Run before tests in non-JavaScript projects. JavaScript projects don't need this — the test harness calls prepare() automatically.
dotreq harness prepare
dotreq harness prepare --quietdotreq harness finalize
Aggregate test tracking data and print a coverage report. Run after tests in non-JavaScript projects.
dotreq harness finalize
dotreq harness finalize --push
dotreq harness finalize --push --context pytest| Option | Description |
|--------|-------------|
| --push | Push coverage to dot•requirements cloud |
| --quiet | Output only coverage percentage (for scripting) |
| --context <label> | Attribution label identifying the reporter (e.g. pytest, Jest) |
dotreq report
View coverage from the most recent local test run, or from the cloud-persisted record.
dotreq report # local cache (default)
dotreq report --source cloud # cloud-persisted record
dotreq report --source cloud --branch main # filter to a branch
dotreq report --source cloud --since 1700000000000 # filter to records after a timestamp
dotreq report --requirement AUTH-LOGIN # scope to one requirement
dotreq report --format json| Option | Description |
|--------|-------------|
| --source <source> | Where to read coverage from: local (default) or cloud |
| --format <format> | Output format: console (default), json, markdown |
| --requirement <id> | Filter to a specific requirement (and its children for local source) |
| --branch <name> | Cloud-only: filter coverage to a specific git branch |
| --since <timestamp> | Cloud-only: only show coverage recorded after this Unix-ms timestamp |
--branch and --since only apply with --source cloud; using them with the local source errors out. Cloud queries require running dotreq link first.
dotreq style-check
Get AI feedback on a requirements file or a test file. Works on both *.requirements.md files (catches vagueness, missing preconditions, untestable assertions) and test files (checks semantic alignment with referenced requirements).
dotreq style-check .requirements/auth.requirements.md
dotreq style-check src/auth.test.ts
dotreq style-check .requirements/auth.requirements.md --keys AUTH-LOGIN-1,AUTH-LOGIN-2| Option | Description |
|--------|-------------|
| --source <local\|cloud> | Where the review runs. Default local emits the style guide plus your content for your AI agent to judge — no account needed. cloud runs a hosted review (requires dotreq link). |
| --keys <list> | Comma-separated requirement keys to limit the review (requirements files only) |
| --model <name> | Override the AI model used for the review (--source cloud only) |
When .requirements/STYLE.md exists in your project, its contents are included so project-specific style preferences influence the feedback.
dotreq review-test
AI-powered semantic review of a test file against its referenced requirements. Validates that test setup matches GIVEN conditions, actions match WHEN triggers, and assertions match THEN outcomes.
dotreq review-test src/auth.test.tsCatches tests that reference a requirement but don't actually validate what the requirement specifies — especially valuable when AI assistants write tests. By default this emits the referenced requirements plus your test content for your AI agent to judge locally — no account needed. Add --source cloud for a hosted review (requires dotreq link).
dotreq create-requirement-document
Print a Markdown template demonstrating the requirements file format, with format guidance and style examples. Use it to seed a new .requirements.md file or to prime an AI assistant's context before authoring.
dotreq create-requirement-document
dotreq create-requirement-document .requirements/auth.requirements.mdWhen a file path is provided, the template references that filename. If .requirements/STYLE.md exists, its contents replace the bundled default style body in the output. The template is printed to stdout.
What Works Locally
The following features work fully offline—no account required:
- Write requirements (
.requirements.mdfiles) - Validate requirements (
dotreq validate) - Search and explore (
dotreq search,get,list,requirements-for,tests-for) - Reference requirements in tests (
requirement()) - Local coverage reporting (
dotreq report, default--source local) - Generate a requirements template (
dotreq create-requirement-document) - Local style-review materials for AI agents (
dotreq style-check,dotreq review-test)
The following features require a dot•requirements cloud account:
- Sync requirements (
dotreq sync,dotreq diff) - Cloud coverage queries (
dotreq report --source cloud) - Hosted style checking and test review (
dotreq style-check --source cloud,dotreq review-test --source cloud) - Team collaboration
To enable cloud features, run dotreq link to connect your project to the cloud.
Test Harness
Stop wondering "did we test that?" The test harness tracks which requirements are exercised by your tests and shows gaps instantly.
Setup with Vitest
vitest.config.ts:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globalSetup: './vitest.setup.ts',
},
});vitest.setup.ts:
import { prepare, finalize } from '@popoverai/dotrequirements/test';
// Named exports: Vitest calls setup() before tests, teardown() after
export function setup() {
prepare();
}
export async function teardown() {
await finalize();
}Alternatively, you can use the default export pattern that returns a teardown function—see the Vitest globalSetup docs.
Customizing output: finalize() accepts options to control verbosity:
await finalize({ showTestedList: true }); // Include tested requirements
await finalize({ showSummary: false, showUntestedList: false }); // Quiet modeAttribution: tag cloud coverage rows with the name of the framework that produced them:
await finalize({ context: 'Vitest' });The Coverage tab uses this label to show which tool produced each result. Any string works — useful when you have multiple test suites ("Vitest — unit", "Vitest — integration").
By default, only untested requirements are shown. See the test harness docs for all options.
Setup with Jest
jest.config.cjs:
module.exports = {
globalSetup: './jest.setup.cjs',
globalTeardown: './jest.teardown.cjs',
};jest.setup.cjs:
const { prepare } = require('@popoverai/dotrequirements/test');
module.exports = async function setup() {
prepare();
};jest.teardown.cjs:
const { finalize } = require('@popoverai/dotrequirements/test');
module.exports = async function teardown() {
await finalize();
};Note: Jest global setup/teardown files run in a separate process from your tests. If using ES modules, configure Jest's
transformoption accordingly.
Using requirement() in Tests
The requirement() function returns a formatted string for test descriptions and tracks coverage:
import { requirement } from '@popoverai/dotrequirements/test';
// Reference root requirement
test(requirement('AUTH-LOGIN-1'), () => {
// Returns: "A registered user, Jamie, can log in to their account"
});
// Reference by numeric path
test(requirement('AUTH-LOGIN-1.0'), () => {
// Returns: "When Jamie provides a valid username and password..."
});
// Reference by label path (for requirements with labels)
test(requirement('AUTH-LOGIN-2.given'), () => {
// Returns: "Given: Jamie has two-factor authentication enabled on their account"
});
// Track multiple requirements in one test
test(requirement('AUTH-LOGIN-1', 'AUTH-SECURITY-1'), () => {
// Both requirements tracked; returns first one's content
});Path Reference Patterns
| Pattern | Example | Description |
|---------|---------|-------------|
| Root | AUTH-LOGIN-1 | Root requirement |
| Numeric | AUTH-LOGIN-1.0 | First child (position 0) |
| Numeric nested | AUTH-LOGIN-1.2.0 | First child of third child |
| Label | AUTH-LOGIN-2.given | First "Given" criterion |
| Label disambiguated | AUTH-LOGIN-2.given#1 | Second "Given" criterion |
| Label nested | AUTH-LOGIN-2.then.and | First "And" under first "Then" |
Coverage Reporting
Coverage isn't just a number—it's a map of which features have been tested and which haven't.
Local Report
After tests complete, a coverage summary prints to the console:
=== Requirements Coverage Report ===
Total Requirements: 12
Tested Requirements: 10
Untested Requirements: 2
Coverage: 83.3%
✓ Tested Requirements:
- AUTH-LOGIN-1: A registered user, Jamie, can log in to their account
- AUTH-LOGIN-1.0: When Jamie provides a valid username and password...
✗ Untested Requirements:
- AUTH-LOGIN-2: A user with two-factor auth must provide an OTP
- AUTH-SECURITY-1: Session tokens expire after 8 hours
====================================Cloud Reporting
With cloud credentials configured, coverage is automatically reported to dot•requirements cloud:
- Historical tracking of when requirements were last tested
- Branch-based coverage (tracks
main, feature branches, etc.) - Query cloud coverage from the terminal (
dotreq report --source cloud)
Run dotreq link to connect your project to the cloud and enable coverage reporting.
Cloud reporting is fire-and-forget—it never blocks or fails your tests.
Requirements File Format
Requirements use Markdown with YAML frontmatter and dotrequirements fenced code blocks.
File Naming
Files must match the pattern *.requirements.md:
.requirements/
auth.requirements.md
checkout.requirements.md
src/components/
Button.requirements.md # Colocated with implementation
Button.tsxStructure
---
document:
defaultPrefix: AUTH-LOGIN
---
# Document Title
The leading H1 is the document's title. You can include any Markdown for context.
## Requirement Heading
```dotrequirements
AUTH-LOGIN-1: A registered user, Jamie, can log in to their account
0. → When Jamie provides valid credentials, they are authenticated
1. → When Jamie provides an incorrect password, they see an error
2. → When Jamie's account is deactivated, they see a status messageMore Markdown content between requirements...
Another Requirement (with labels)
AUTH-LOGIN-2: A user with two-factor auth must provide an OTP
0. Given → Jamie has two-factor authentication enabled
1. When → Jamie provides valid credentials
2. Then → Jamie is prompted to enter an OTP
### Format Details
- **Frontmatter**: YAML metadata (must be present, but no field is required — sync adds `document.id` to link the file to its cloud document)
- **Title**: The body's leading H1 (a legacy frontmatter `document.title` is tolerated as a fallback)
- **Headings**: Optional documentation (not parsed as requirement data)
- **Fenced blocks**: `dotrequirements` blocks contain structured requirement data
- **First line**: `KEY: content` — the requirement identifier and summary
- **Criteria**: `position. → content` or `position. Label → content`
- **Arrow delimiter**: `→` (Unicode) or `->` (ASCII) both work
- **Labels**: Optional — use `Given`, `When`, `Then`, `And` if your team prefers BDD style
See [MARKDOWN_SCHEMA.md](https://github.com/PopoverAI/dotrequirements/blob/main/docs/reference/MARKDOWN_SCHEMA.md) for the complete specification.
---
## AI Assistant Integration
AI coding assistants use the CLI verbs directly — no MCP server to install or configure. `dotreq ai-setup` writes the requirements-driven workflow guidance into your assistant's context file (CLAUDE.md / AGENTS.md), which tells the agent when to explore, validate, style-review, and sync. For chat apps (Claude, ChatGPT), use the dot•requirements remote connector instead.
> The local MCP server shipped by earlier versions is retired. `dotreq ai-setup` removes stale MCP registrations; `dotreq mcp` now exits with a pointer to this migration.
### CI/CD Mode
In CI/CD environments (GitHub Actions, etc.) where no `.requirements/project-settings.json` is present, the CLI authenticates from environment variables automatically — no flag required — and prints a notice to stderr:
```bash
dotreq sync --repo-contributes
dotreq style-check .requirements/auth.requirements.md --source cloudRequired environment variables:
DOTREQ_PROJECT_ID— Your project slugDOTREQ_PROJECT_SECRET— Your project secret
Important: A settings file on disk always wins over these environment variables, so a local checkout is never overridden by an ambient environment. The environment is used only when no settings file is found.
See the CI/CD Integration docs for complete examples.
Package Exports
// CLI (main entry point)
import '@popoverai/dotrequirements';
// Test harness
import { requirement, prepare, finalize } from '@popoverai/dotrequirements/test';
// Schema utilities
import { parseRequirementsFile, validateRequirementsFile } from '@popoverai/dotrequirements/schema';
// Browser-compatible schema (no Node.js dependencies)
import { parseRequirementBlock } from '@popoverai/dotrequirements/schema/browser';Configuration
The CLI stores project credentials in .requirements/project-settings.json:
{
"projectId": "your-project-id",
"projectSecret": "your-project-secret"
}This file is automatically added to .gitignore during initialization.
Links
License
MIT
