███████╗██████╗ ███████╗ ██████╗██╗███████╗██╗ ██╗
██╔════╝██╔══██╗██╔════╝██╔════╝██║██╔════╝╚██╗ ██╔╝
███████╗██████╔╝█████╗ ██║ ██║█████╗ ╚████╔╝
╚════██║██╔═══╝ ██╔══╝ ██║ ██║██╔══╝ ╚██╔╝
███████║██║ ███████╗╚██████╗██║██║ ██║
╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝
Write specs. Validate behavior. Ship with evidence.
Specify turns functional requirements into machine-verifiable specs. Define what your app should do — pages, flows, assertions, API contracts — and Specify tells you what's met, what's not, and what's untested. Every assertion shows its work: expected value, actual value, raw output.
No opinions about your test framework. No lock-in. Just structured truth.
npm install
npm run build# 1. Create a contract
specify create # interactive interview → spec + narrative
# 2. Capture existing behavior
specify capture --url http://localhost:3000
# 3. Compare remote vs local
specify compare --remote https://prod.example.com --local http://localhost:3000
# 4. Review the contract
specify review --spec app.spec.yaml
# 5. Verify the implementation
specify verify --spec app.spec.yaml --url http://localhost:3000
specify verify --spec app.spec.yaml --capture ./captures| Command | What |
|---|---|
create |
Interactive interview → spec + narrative |
capture |
Agent-driven capture from live system (--url) or code (--from code) |
compare |
Live side-by-side comparison of remote and local targets |
review |
Inspect the contract in a browser |
verify |
Verify against captures (--capture) or live (--url) |
cli run |
Run CLI commands defined in spec, validate output |
lint |
Structural validation (no captures needed) |
spec export |
Generate Playwright or Cypress tests from spec |
spec import |
Import existing e2e tests as spec items |
spec sync |
Bidirectional diff: spec vs e2e tests |
schema |
Emit JSON Schema for spec, report, or commands |
mcp |
MCP server — any LLM client can use Specify as a tool |
Every validation report includes expected vs actual evidence for every assertion. No "100% passed, trust me" — you get the raw output, the exact match, and the assertion logic.
Formats: JSON (machine), Markdown (diff-friendly), HTML (interactive, filterable, single file).
| Status | Type | Expected | Actual |
|--------|----------------|-------------------|-------------------------------------|
| ✅ | text_contains | spec validate | ..."name": "spec validate", ... |
| ✅ | json_path | 0.1.0 | 0.1.0 |
| ❌ | json_schema | matches schema | /items: must have >= 5 items |
# Local (stdio)
specify mcp
# Remote (HTTP)
specify mcp --http --port 8080Claude Desktop / Cursor / Claude Code config:
{ "mcpServers": { "specify": { "command": "specify", "args": ["mcp"] } } }7 tools exposed: get_authoring_guide, lint_spec, validate_spec, export_tests, list_commands, parse_spec, spec_to_yaml.
YAML or JSON. Human-readable, machine-verifiable.
version: "1.0"
name: "My App"
description: "Behavioral contract for My App"
pages:
- id: dashboard
path: /dashboard
title: "Dashboard"
visual_assertions:
- type: element_exists
selector: "nav.sidebar"
description: "Navigation sidebar is present"
expected_requests:
- method: GET
url_pattern: "/api/v1/stats"
scenarios:
- id: user-login
description: "User logs in and sees dashboard"
steps:
- action: fill
selector: "#email"
value: "{{email}}"
- action: click
selector: "button[type=submit]"
- action: wait_for_navigation
url_pattern: "/dashboard"
- action: assert_visible
selector: ".welcome-message"
variables:
base_url: "${TARGET_BASE_URL}"Specify eats its own dogfood. The repo includes specify.spec.yaml — a spec for Specify itself — validated on every run. Current status: 178 assertions, 100% coverage, 0 failures. See the report →
GPL-3.0