specrail is a Rust CLI for an outcome-gated, test-driven workflow. It keeps project state under .specrail/ and guides work through features, outcomes, registered tests, implementation, verification, and advancement to the next outcome.
The tool is designed to help you:
- define a feature before writing code
- break work into explicit outcomes with goals and path constraints
- register tests up front and track their status
- run an implementation agent only when the outcome is ready
- verify each outcome with your project's test command
- keep an audit trail of project activity
specrail stores workflow state in a .specrail/ directory at the project root:
.specrail/
├── project.yaml
├── specrail.db
├── agents/
└── state/
└── ledger.jsonl
The local database stores solutions, projects, components, features, outcomes,
registered tests, and active workflow state. project.yaml remains human-editable,
and state/ledger.jsonl remains the append-only audit trail.
Key rules:
specrail initcreates the project structure and immediately walks through solution, project, component, feature, and outcome setup.specrail init --no-wizardcreates only the project structure (and seeds default solution/project/component).- All other commands require an existing
.specrail/directory and will discover it by walking upward from the current directory. implementrequires an active feature, an active outcome, at least one registered test for that outcome, and no outcome tests left inplanned.verifyruns thetest_commandfrom.specrail/project.yaml.advanceonly works after the active outcome has been verified.
From the repository root:
cargo build
cargo testInitialize a project:
specrail initIf you want only the project files without the walkthrough:
specrail init --no-wizardCreate a feature:
specrail feature new auth \
--title "Authentication" \
--purpose "Authenticate users before they access protected routes." \
--outcome "Users can sign in" \
--constraint "Keep login logic inside the auth module"Create outcomes for the feature:
specrail outcome new auth outcome-1 \
--title "Validation" \
--goal "Validate credentials and reject bad input." \
--order 1 \
--allow "src/auth/**" \
--forbid "src/billing/**"
specrail outcome new auth outcome-2 \
--title "Persistence" \
--goal "Persist authenticated users." \
--order 2Register the tests for an outcome:
specrail test add validate-email \
--feature auth \
--outcome outcome-1 \
--path tests/auth/validate_email.rs \
--kind unitOr let an AI agent generate the required tests declared in your outcome:
specrail test generate --agent copilotMark a test as ready for implementation:
specrail test set-status validate-email writtenActivate the feature and outcome:
specrail feature activate auth
specrail outcome activate auth outcome-1Run the workflow:
specrail implement
specrail verify
specrail advanceInspect progress:
specrail status
specrail trace --limit 20specrail initspecrail init --no-wizard
-
specrail solution new <id> --title <title> --purpose <purpose> -
specrail solution list -
specrail solution show <id> -
specrail solution edit <id> --title <title> --purpose <purpose> -
specrail solution activate <id> -
specrail project new <solution_id> <id> --title <title> --purpose <purpose> -
specrail project list <solution_id> -
specrail project show <id> -
specrail project edit <id> --title <title> --purpose <purpose> -
specrail project activate <id> -
specrail component new <project_id> <id> --title <title> --purpose <purpose> -
specrail component list <project_id> -
specrail component show <id> -
specrail component edit <id> --title <title> --purpose <purpose> -
specrail component activate <id>
specrail feature new <id> --title <title> --purpose <purpose>specrail feature listspecrail feature show <id>specrail feature edit <id> --title <title> --purpose <purpose>specrail feature activate <id>
Optional feature flags:
--outcome--constraint--non-goal--dep--component(override the active component)
specrail outcome new <feature_id> <outcome_id> --title <title> --goal <goal> --order <n>specrail outcome list <feature_id>specrail outcome show <feature_id> <outcome_id>specrail outcome edit <feature_id> <outcome_id> --title <title> --goal <goal> --order <n>specrail outcome activate <feature_id> <outcome_id>
Optional outcome flags:
--prereq--allow--forbid--test--test-file
specrail test add <id> --feature <feature_id> --outcome <outcome_id> --path <path>specrail test generate --agent <generic-shell|copilot|codex>specrail test suggest [--feature <feature_id>] [--outcome <outcome_id>]specrail test list [--feature <feature_id>] [--outcome <outcome_id>]specrail test set-status <id> <planned|written|passing|failing>
specrail implement [--agent <generic-shell|copilot|codex>]specrail verifyspecrail advancespecrail statusspecrail trace [--limit <n>]
Global flag:
-v,-vv,-vvvfor more verbose logging
.specrail/project.yaml contains the project-level settings:
versionnametest_commanddefault_agent
Default values created by specrail init include:
test_command: cargo testdefault_agent: generic-shell
specrail works best as the workflow state machine around another AI tool, not as the tool that invents the work on its own. Your outer CLI or program should translate requirements into specrail features, outcomes, and tests, then let specrail enforce the handoff points.
Recommended model:
- Your program collects requirements from the user.
- Your program turns those requirements into:
- one
feature - one or more ordered
outcomes - one or more tests per outcome
- one
- Your program calls
specrailcommands to persist that plan under.specrail/. - Your AI coding CLI writes tests and implementation code.
specrailverifies the outcome and decides whether work can advance.
Use the specrail CLI as the write interface:
specrail init
specrail feature new <id> --title <title> --purpose <purpose> ...
specrail outcome new <feature> <outcome> --title <title> --goal <goal> --order <n> ...
specrail test add <test-id> --feature <feature> --outcome <outcome> --path <path> ...
specrail test set-status <test-id> written
specrail feature activate <feature>
specrail outcome activate <feature> <outcome>Use the CLI as the read interface too when your orchestrator needs to inspect progress:
specrail statusspecrail trace --limit <n>specrail feature show <feature>specrail outcome show <feature> <outcome>specrail test list --feature <feature> --outcome <outcome>
Then run the control loop:
- Requirements → specrail
- Ask your AI tool to break the requirement into a feature, ordered outcomes, and tests.
- Register each artifact with
specrail feature new,specrail outcome new, andspecrail test add.
- Test authoring
- Hand the active outcome goal to your coding CLI and ask it to create the test files for that outcome.
- After each test file exists, mark it ready with
specrail test set-status <id> written.
- Implementation
- Activate the feature and outcome.
- Either call your coding CLI directly from your program, or run
specrail implementto hand the structured outcome prompt to an adapter.
- Verification
- Run
specrail verify. - If verification fails, hand the failure output back to your coding CLI and repeat the implementation step.
- Run
- Advancement
- When verification passes, run
specrail advance. - Repeat until there is no next outcome.
- When verification passes, run
For another CLI or automation layer, prefer this ownership split:
- Your orchestrator decides what feature, outcomes, and tests to create.
- specrail stores the plan, tracks active state, blocks implementation until tests are registered, and blocks advancement until verification passes.
- Your AI coding CLI writes the tests and code.
- Your project's test command is the final authority through
specrail verify.
There are three practical options:
specrail implement --agent generic-shell- Best when you have a wrapper command that can read
SPECRAIL_PROMPT,SPECRAIL_ALLOWED_PATHS, andSPECRAIL_FORBIDDEN_PATHSand then invoke your preferred AI CLI. - Configure it with
SPECRAIL_AGENT_CMD.
- Best when you have a wrapper command that can read
specrail implement --agent copilot- Uses
copilot -p <prompt>with the generated implementation brief. - Treat this as a prompt/suggestion adapter, not a full autonomous edit pipeline.
- Uses
specrail implement --agent codex- Sends the generated prompt to the
codexCLI.
- Sends the generated prompt to the
Example generic-shell setup:
export SPECRAIL_AGENT_CMD="your-ai-wrapper"
specrail implement --agent generic-shellInside your-ai-wrapper, read:
SPECRAIL_PROMPTfor the full implementation briefSPECRAIL_ALLOWED_PATHSfor editable path hintsSPECRAIL_FORBIDDEN_PATHSfor restricted path hints
This repository now ships a first-party Copilot CLI plugin under .github/plugin/, a repo-scoped VS Code custom agent under .github/agents/specrail.agent.md, and a built-in MCP server entrypoint at specrail mcp-server.
Prerequisites:
specrailis installed and onPATHcopilotis installed and authenticatedcopilot -p "echo ready"works in your shell
Install the plugin from the repository root or from GitHub:
copilot plugin install /path/to/spec-railOr:
copilot plugin install SamMRoberts/spec-railThe plugin manifest points Copilot CLI at this MCP server command:
specrail mcp-serverIn VS Code, the Specrail workspace agent is the repo-aware entrypoint. It should begin with specrail_status, use structuredContent.workflow.recommended_skill to decide the next stage, and rely on the specrail_* MCP tools instead of editing .specrail/ files directly.
For troubleshooting in VS Code, the workspace MCP config enables stderr logging for the server. Open MCP: List Servers, select specrail, then choose Show Output to inspect the live MCP log stream.
After installing, verify that the plugin and MCP server are loaded:
copilot plugin listIn an interactive Copilot CLI session, you should see the plugin skill and the specrail_* MCP tools. The MCP server exposes workflow-aware tools such as:
specrail_statusspecrail_feature_newspecrail_outcome_newspecrail_test_addspecrail_implementspecrail_verifyspecrail_advance
Use those tools instead of editing .specrail/ files directly.
The copilot adapter is a good fit when you want specrail to own the workflow state and prompt construction, while GitHub Copilot CLI suggests the shell commands to run next.
Prerequisites:
specrailis installed and onPATHcopilotis installed and authenticatedcopilot -p "echo ready"works in your shell
Example end-to-end flow for a small Rust project:
mkdir demo-auth
cd demo-auth
cargo init --lib .
specrail init --no-wizardSet Copilot as the default implementation agent:
# .specrail/project.yaml
version: 1
name: demo-auth
test_command: cargo test
default_agent: copilotCreate a feature, an outcome, and a test entry:
specrail feature new email-validation \
--title "Email validation" \
--purpose "Reject malformed email addresses before account creation." \
--outcome "Only valid email addresses are accepted."
specrail outcome new email-validation outcome-1 \
--title "Reject invalid email input" \
--goal "Add validation logic for malformed email addresses." \
--order 1 \
--allow "src/**" \
--allow "tests/**"
specrail test add rejects-invalid-email \
--feature email-validation \
--outcome outcome-1 \
--path tests/email_validation.rs \
--kind integrationUse Copilot CLI directly to draft the outcome test, then register it as ready:
copilot -p \
"Create tests/email_validation.rs with an integration test that proves malformed email addresses are rejected."
# Review or adapt the suggested shell command, run it, then mark the test as written.
specrail test set-status rejects-invalid-email writtenActivate the feature and outcome, then hand the structured implementation brief to Copilot through specrail:
specrail feature activate email-validation
specrail outcome activate email-validation outcome-1
specrail implement --agent copilotspecrail implement --agent copilot sends Copilot a prompt containing:
- the feature purpose and outcomes
- the active outcome goal and order
- the allowed and forbidden paths for the outcome
- the registered tests that must pass
Copilot CLI prints a suggested response from the generated prompt. Review it, run or adapt the suggested changes yourself, then continue the gated workflow:
cargo test
specrail verify
specrail advanceFor the next outcome, repeat the same loop:
- write or update the next outcome tests with Copilot CLI
- mark those tests as
written - run
specrail implement --agent copilot - review and apply Copilot's suggested changes
- run
specrail verify - run
specrail advance
If you want a Copilot-or-other-agent driven workflow, the safest sequence is:
- Feed requirements into your own orchestrator.
- Use the orchestrator to call
specrail feature newandspecrail outcome new. - Ask the coding agent to write the outcome tests.
- Register those tests with
specrail test add. - Mark them
written. - Activate the feature and outcome.
- Ask the coding agent to implement only the active outcome.
- Run
specrail verify. - If tests pass, run
specrail advance; otherwise loop back to step 7 with the failure output.
This gives you a repeatable contract: the AI can generate code, but specrail decides when implementation may start and when the work is allowed to move forward.
- The binary name is
specrail. - The default shell-based agent assumes a Unix-like
sh -cenvironment. - Integration tests in
tests/demonstrate expected CLI behavior and end-to-end workflow.