From 3314607a1520fa58e1d3983508a7d1bf2c62a7e2 Mon Sep 17 00:00:00 2001 From: Manfred Riem <15701806+mnriem@users.noreply.github.com> Date: Thu, 16 Apr 2026 13:18:20 -0500 Subject: [PATCH 1/2] docs: add workflows reference, reorganize into docs/reference/, and add --version flag - Move integrations.md, extensions.md, presets.md into docs/reference/ - New docs/reference/workflows.md: command reference for all workflow commands, built-in SDD Cycle workflow with Mermaid diagram, step types, expressions, input types, state/resume, and FAQ - Rename workflow input feature_name to spec with prompt 'Describe what you want to build' to match speckit.specify command terminology - Add --version / -V flag to root specify command with tests - Update docs/toc.yml, README.md links, and docs/upgrade.md cross-reference to use reference/ paths - Add workflow command to README CLI reference table --- README.md | 7 +- docs/{ => reference}/extensions.md | 0 docs/{ => reference}/integrations.md | 0 docs/{ => reference}/presets.md | 0 docs/reference/workflows.md | 289 +++++++++++++++++++++++ docs/toc.yml | 8 +- docs/upgrade.md | 2 +- src/specify_cli/__init__.py | 10 +- src/specify_cli/workflows/expressions.py | 2 +- tests/test_cli_version.py | 35 +++ tests/test_workflows.py | 8 +- workflows/PUBLISHING.md | 8 +- workflows/README.md | 20 +- workflows/speckit/workflow.yml | 14 +- 14 files changed, 369 insertions(+), 34 deletions(-) rename docs/{ => reference}/extensions.md (100%) rename docs/{ => reference}/integrations.md (100%) rename docs/{ => reference}/presets.md (100%) create mode 100644 docs/reference/workflows.md create mode 100644 tests/test_cli_version.py diff --git a/README.md b/README.md index b8be28b66c..a12c6cbb75 100644 --- a/README.md +++ b/README.md @@ -316,7 +316,7 @@ Community projects that extend, visualize, or build on Spec Kit: ## 🤖 Supported AI Coding Agent Integrations -Spec Kit works with 30+ AI coding agents — both CLI tools and IDE-based assistants. See the full list with notes and usage details in the [Supported AI Coding Agent Integrations](https://github.github.io/spec-kit/integrations.html) guide. +Spec Kit works with 30+ AI coding agents — both CLI tools and IDE-based assistants. See the full list with notes and usage details in the [Supported AI Coding Agent Integrations](https://github.github.io/spec-kit/reference/integrations.html) guide. Run `specify integration list` to see all available integrations in your installed version. @@ -367,6 +367,7 @@ and supports the following commands: | `extension` | Manage extensions | | `preset` | Manage presets | | `integration` | Manage integrations | +| `workflow` | Run, manage, and search workflows. See the [Workflows reference](https://github.github.io/spec-kit/reference/workflows.html) | ### `specify init` Arguments & Options @@ -510,7 +511,7 @@ specify extension add For example, extensions could add Jira integration, post-implementation code review, V-Model test traceability, or project health diagnostics. -See the [Extensions reference](https://github.github.io/spec-kit/extensions.html) for the full command guide. Browse the [community extensions](#-community-extensions) above for what's available. +See the [Extensions reference](https://github.github.io/spec-kit/reference/extensions.html) for the full command guide. Browse the [community extensions](#-community-extensions) above for what's available. ### Presets — Customize Existing Workflows @@ -526,7 +527,7 @@ specify preset add For example, presets could restructure spec templates to require regulatory traceability, adapt the workflow to fit the methodology you use (e.g., Agile, Kanban, Waterfall, jobs-to-be-done, or domain-driven design), add mandatory security review gates to plans, enforce test-first task ordering, or localize the entire workflow to a different language. The [pirate-speak demo](https://github.com/mnriem/spec-kit-pirate-speak-preset-demo) shows just how deep the customization can go. Multiple presets can be stacked with priority ordering. -See the [Presets reference](https://github.github.io/spec-kit/presets.html) for the full command guide, including resolution order and priority stacking. +See the [Presets reference](https://github.github.io/spec-kit/reference/presets.html) for the full command guide, including resolution order and priority stacking. ### When to Use Which diff --git a/docs/extensions.md b/docs/reference/extensions.md similarity index 100% rename from docs/extensions.md rename to docs/reference/extensions.md diff --git a/docs/integrations.md b/docs/reference/integrations.md similarity index 100% rename from docs/integrations.md rename to docs/reference/integrations.md diff --git a/docs/presets.md b/docs/reference/presets.md similarity index 100% rename from docs/presets.md rename to docs/reference/presets.md diff --git a/docs/reference/workflows.md b/docs/reference/workflows.md new file mode 100644 index 0000000000..abad8cb4c2 --- /dev/null +++ b/docs/reference/workflows.md @@ -0,0 +1,289 @@ +# Workflows + +Workflows automate multi-step Spec-Driven Development processes — chaining commands, prompts, shell steps, and human checkpoints into repeatable sequences. They support conditional logic, loops, fan-out/fan-in, and can be paused and resumed from the exact point of interruption. + +## Run a Workflow + +```bash +specify workflow run +``` + +| Option | Description | +| ------------------- | -------------------------------------------------------- | +| `-i` / `--input` | Pass input values as `key=value` (repeatable) | + +Runs a workflow from a catalog ID, URL, or local file path. Inputs declared by the workflow can be provided via `--input` or will be prompted interactively. + +Example: + +```bash +specify workflow run speckit -i spec="Build a kanban board with drag-and-drop task management" -i scope=full +``` + +> **Note:** All workflow commands require a project already initialized with `specify init`. + +## Resume a Workflow + +```bash +specify workflow resume +``` + +Resumes a paused or failed workflow run from the exact step where it stopped. Useful after responding to a gate step or fixing an issue that caused a failure. + +## Workflow Status + +```bash +specify workflow status [] +``` + +Shows the status of a specific run, or lists all runs if no ID is given. Run states: `created`, `running`, `completed`, `paused`, `failed`, `aborted`. + +## List Installed Workflows + +```bash +specify workflow list +``` + +Lists workflows installed in the current project. + +## Install a Workflow + +```bash +specify workflow add +``` + +Installs a workflow from the catalog, a URL (HTTPS required), or a local file path. + +## Remove a Workflow + +```bash +specify workflow remove +``` + +Removes an installed workflow from the project. + +## Search Available Workflows + +```bash +specify workflow search [query] +``` + +| Option | Description | +| ------- | --------------- | +| `--tag` | Filter by tag | + +Searches all active catalogs for workflows matching the query. + +## Workflow Info + +```bash +specify workflow info +``` + +Shows detailed information about a workflow, including its steps, inputs, and requirements. + +## Catalog Management + +Workflow catalogs control where `search` and `add` look for workflows. Catalogs are checked in priority order. + +### List Catalogs + +```bash +specify workflow catalog list +``` + +Shows all active catalog sources. + +### Add a Catalog + +```bash +specify workflow catalog add +``` + +| Option | Description | +| --------------- | -------------------------------- | +| `--name ` | Optional name for the catalog | + +Adds a custom catalog URL to the project's `.specify/workflow-catalogs.yml`. + +### Remove a Catalog + +```bash +specify workflow catalog remove +``` + +Removes a catalog by its index in the catalog list. + +### Catalog Resolution Order + +Catalogs are resolved in this order (first match wins): + +1. **Environment variable** — `SPECKIT_WORKFLOW_CATALOG_URL` overrides all catalogs +2. **Project config** — `.specify/workflow-catalogs.yml` +3. **User config** — `~/.specify/workflow-catalogs.yml` +4. **Built-in defaults** — official catalog + community catalog + +## Workflow Definition + +Workflows are defined in YAML files. Here is the built-in **Full SDD Cycle** workflow that ships with Spec Kit: + +```yaml +schema_version: "1.0" +workflow: + id: "speckit" + name: "Full SDD Cycle" + version: "1.0.0" + author: "GitHub" + description: "Runs specify → plan → tasks → implement with review gates" + +requires: + speckit_version: ">=0.6.1" + integrations: + any: ["copilot", "claude", "gemini"] + +inputs: + spec: + type: string + required: true + prompt: "Describe what you want to build" + integration: + type: string + default: "copilot" + prompt: "Integration to use (e.g. claude, copilot, gemini)" + scope: + type: string + default: "full" + enum: ["full", "backend-only", "frontend-only"] + +steps: + - id: specify + command: speckit.specify + integration: "{{ inputs.integration }}" + input: + args: "{{ inputs.spec }}" + + - id: review-spec + type: gate + message: "Review the generated spec before planning." + options: [approve, reject] + on_reject: abort + + - id: plan + command: speckit.plan + integration: "{{ inputs.integration }}" + input: + args: "{{ inputs.spec }}" + + - id: review-plan + type: gate + message: "Review the plan before generating tasks." + options: [approve, reject] + on_reject: abort + + - id: tasks + command: speckit.tasks + integration: "{{ inputs.integration }}" + input: + args: "{{ inputs.spec }}" + + - id: implement + command: speckit.implement + integration: "{{ inputs.integration }}" + input: + args: "{{ inputs.spec }}" +``` + +This produces the following execution flow: + +```mermaid +flowchart TB + A["specify
(command)"] --> B{"review-spec
(gate)"} + B -- approve --> C["plan
(command)"] + B -- reject --> X1["⏹ Abort"] + C --> D{"review-plan
(gate)"} + D -- approve --> E["tasks
(command)"] + D -- reject --> X2["⏹ Abort"] + E --> F["implement
(command)"] + + style A fill:#49a,color:#fff + style B fill:#a94,color:#fff + style C fill:#49a,color:#fff + style D fill:#a94,color:#fff + style E fill:#49a,color:#fff + style F fill:#49a,color:#fff + style X1 fill:#999,color:#fff + style X2 fill:#999,color:#fff +``` + +Run it with: + +```bash +specify workflow run speckit -i spec="Build a kanban board with drag-and-drop task management" +``` + +## Step Types + +| Type | Purpose | +| ------------ | ------------------------------------------------ | +| `command` | Invoke a Spec Kit command (e.g., `speckit.plan`) | +| `prompt` | Send an arbitrary prompt to the AI coding agent | +| `shell` | Execute a shell command and capture output | +| `gate` | Pause for human approval before continuing | +| `if` | Conditional branching (then/else) | +| `switch` | Multi-branch dispatch on an expression | +| `while` | Loop while a condition is true | +| `do-while` | Execute at least once, then loop on condition | +| `fan-out` | Dispatch a step for each item in a list | +| `fan-in` | Aggregate results from a fan-out step | + +## Expressions + +Steps can reference inputs and previous step outputs using `{{ expression }}` syntax: + +| Namespace | Description | +| ------------------------------ | ------------------------------------ | +| `inputs.spec` | Workflow input values | +| `steps.specify.output.file` | Output from a previous step | +| `item` | Current item in a fan-out iteration | + +Available filters: `default`, `join`, `contains`, `map`. + +Example: + +```yaml +condition: "{{ steps.test.output.exit_code == 0 }}" +args: "{{ inputs.spec }}" +message: "{{ status | default('pending') }}" +``` + +## Input Types + +| Type | Coercion | +| --------- | ------------------------------------------------- | +| `string` | Pass-through | +| `number` | `"42"` → `42`, `"3.14"` → `3.14` | +| `boolean` | `"true"` / `"1"` / `"yes"` → `True` | + +## State and Resume + +Each workflow run persists its state at `.specify/workflows/runs//`: + +- `state.json` — current run state and step progress +- `inputs.json` — resolved input values +- `log.jsonl` — step-by-step execution log + +This enables `specify workflow resume` to continue from the exact step where a run was paused (e.g., at a gate) or failed. + +## FAQ + +### What happens when a workflow hits a gate step? + +The workflow pauses and waits for human input. Run `specify workflow resume ` after reviewing to continue. + +### Can I run the same workflow multiple times? + +Yes. Each run gets a unique ID and its own state directory. Use `specify workflow status` to see all runs. + +### Who maintains workflows? + +Most workflows are independently created and maintained by their respective authors. The Spec Kit maintainers do not review, audit, endorse, or support workflow code. Review a workflow's source before installing and use at your own discretion. diff --git a/docs/toc.yml b/docs/toc.yml index 3f53367075..5666cbb230 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -16,11 +16,13 @@ - name: Reference items: - name: Integrations - href: integrations.md + href: reference/integrations.md - name: Extensions - href: extensions.md + href: reference/extensions.md - name: Presets - href: presets.md + href: reference/presets.md + - name: Workflows + href: reference/workflows.md # Development workflows - name: Development diff --git a/docs/upgrade.md b/docs/upgrade.md index e08c0b93ed..020360d222 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -76,7 +76,7 @@ Run this inside your project directory: specify init --here --force --ai ``` -Replace `` with your AI coding agent. Refer to this list of [Supported AI Coding Agent Integrations](integrations.md) +Replace `` with your AI coding agent. Refer to this list of [Supported AI Coding Agent Integrations](reference/integrations.md) **Example:** diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 5c079ece89..0608e7a8ac 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -351,8 +351,16 @@ def show_banner(): console.print(Align.center(Text(TAGLINE, style="italic bright_yellow"))) console.print() +def _version_callback(value: bool): + if value: + console.print(f"specify {get_speckit_version()}") + raise typer.Exit() + @app.callback() -def callback(ctx: typer.Context): +def callback( + ctx: typer.Context, + version: bool = typer.Option(False, "--version", "-V", callback=_version_callback, is_eager=True, help="Show version and exit."), +): """Show banner when no subcommand is provided.""" if ctx.invoked_subcommand is None and "--help" not in sys.argv and "-h" not in sys.argv: show_banner() diff --git a/src/specify_cli/workflows/expressions.py b/src/specify_cli/workflows/expressions.py index 3a2d3fbf2a..eb39a31e79 100644 --- a/src/specify_cli/workflows/expressions.py +++ b/src/specify_cli/workflows/expressions.py @@ -255,7 +255,7 @@ def evaluate_expression(template: str, context: Any) -> Any: ---------- template: The template string (e.g., ``"{{ steps.plan.output.task_count }}"`` - or ``"Processed {{ inputs.feature_name }}"``. + or ``"Processed {{ inputs.spec }}"``. context: A ``StepContext`` or compatible object. diff --git a/tests/test_cli_version.py b/tests/test_cli_version.py new file mode 100644 index 0000000000..80555d8b77 --- /dev/null +++ b/tests/test_cli_version.py @@ -0,0 +1,35 @@ +"""Tests for the --version CLI flag.""" + +from unittest.mock import patch + +from typer.testing import CliRunner + +from specify_cli import app + + +runner = CliRunner() + + +class TestVersionFlag: + """Test --version / -V flag on the root command.""" + + def test_version_long_flag(self): + """specify --version prints version and exits 0.""" + with patch("specify_cli.get_speckit_version", return_value="1.2.3"): + result = runner.invoke(app, ["--version"]) + assert result.exit_code == 0 + assert "specify 1.2.3" in result.output + + def test_version_short_flag(self): + """specify -V prints version and exits 0.""" + with patch("specify_cli.get_speckit_version", return_value="1.2.3"): + result = runner.invoke(app, ["-V"]) + assert result.exit_code == 0 + assert "specify 1.2.3" in result.output + + def test_version_flag_takes_precedence_over_subcommand(self): + """--version should work even when a subcommand follows.""" + with patch("specify_cli.get_speckit_version", return_value="0.7.2"): + result = runner.invoke(app, ["--version", "init"]) + assert result.exit_code == 0 + assert "specify 0.7.2" in result.output diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 96893249e2..c972945d04 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -54,7 +54,7 @@ def sample_workflow_yaml(): description: "A test workflow" inputs: - feature_name: + spec: type: string required: true scope: @@ -65,7 +65,7 @@ def sample_workflow_yaml(): - id: step-one command: speckit.specify input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" - id: step-two command: speckit.plan @@ -1152,8 +1152,8 @@ def test_inputs_parsed(self, sample_workflow_yaml): from specify_cli.workflows.engine import WorkflowDefinition definition = WorkflowDefinition.from_string(sample_workflow_yaml) - assert "feature_name" in definition.inputs - assert definition.inputs["feature_name"]["required"] is True + assert "spec" in definition.inputs + assert definition.inputs["spec"]["required"] is True assert definition.inputs["scope"]["default"] == "full" diff --git a/workflows/PUBLISHING.md b/workflows/PUBLISHING.md index 857aaf7d11..ce0d251826 100644 --- a/workflows/PUBLISHING.md +++ b/workflows/PUBLISHING.md @@ -62,10 +62,10 @@ requires: any: ["claude", "gemini"] # At least one required inputs: - feature_name: + spec: type: string required: true - prompt: "Feature name" + prompt: "Describe what you want to build" scope: type: string default: "full" @@ -75,7 +75,7 @@ steps: - id: specify command: speckit.specify input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" - id: review type: gate @@ -99,7 +99,7 @@ steps: ```bash # Run with required inputs -specify workflow run ./workflow.yml --input feature_name="user-auth" +specify workflow run ./workflow.yml --input spec="Build a user authentication system with OAuth support" # Check validation specify workflow info ./workflow.yml diff --git a/workflows/README.md b/workflows/README.md index 3ece00b6b0..31f736ff76 100644 --- a/workflows/README.md +++ b/workflows/README.md @@ -11,7 +11,7 @@ steps: - id: specify command: speckit.specify input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" - id: review type: gate @@ -35,10 +35,10 @@ specify workflow search specify workflow add speckit # Or run directly from a local YAML file -specify workflow run ./workflow.yml --input feature_name="user-auth" +specify workflow run ./workflow.yml --input spec="Build a user authentication system with OAuth support" # Run an installed workflow with inputs -specify workflow run speckit --input feature_name="user-auth" +specify workflow run speckit --input spec="Build a user authentication system with OAuth support" # Check run status specify workflow status @@ -59,20 +59,20 @@ specify workflow remove speckit ```bash specify workflow add speckit -specify workflow run speckit --input feature_name="user-auth" +specify workflow run speckit --input spec="Build a user authentication system with OAuth support" ``` ### From a Local YAML File ```bash -specify workflow run ./my-workflow.yml --input feature_name="user-auth" +specify workflow run ./my-workflow.yml --input spec="Build a user authentication system with OAuth support" ``` ### Multiple Inputs ```bash specify workflow run speckit \ - --input feature_name="user-auth" \ + --input spec="Build a user authentication system with OAuth support" \ --input scope="backend-only" ``` @@ -88,7 +88,7 @@ Invoke an installed Spec Kit command by name via the integration CLI: - id: specify command: speckit.specify input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" integration: claude # Optional: override workflow default model: "claude-sonnet-4-20250514" # Optional: override model ``` @@ -225,7 +225,7 @@ Workflow definitions use `{{ expression }}` syntax for dynamic values: ```yaml # Access inputs -args: "{{ inputs.feature_name }}" +args: "{{ inputs.spec }}" # Access previous step outputs args: "{{ steps.specify.output.file }}" @@ -245,10 +245,10 @@ Workflow inputs are type-checked and coerced from CLI string values: ```yaml inputs: - feature_name: + spec: type: string required: true - prompt: "Feature name" + prompt: "Describe what you want to build" task_count: type: number default: 5 diff --git a/workflows/speckit/workflow.yml b/workflows/speckit/workflow.yml index a440c5c507..bf18451029 100644 --- a/workflows/speckit/workflow.yml +++ b/workflows/speckit/workflow.yml @@ -7,15 +7,15 @@ workflow: description: "Runs specify → plan → tasks → implement with review gates" requires: - speckit_version: ">=0.6.1" + speckit_version: ">=0.7.2" integrations: any: ["copilot", "claude", "gemini"] inputs: - feature_name: + spec: type: string required: true - prompt: "Feature name" + prompt: "Describe what you want to build" integration: type: string default: "copilot" @@ -30,7 +30,7 @@ steps: command: speckit.specify integration: "{{ inputs.integration }}" input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" - id: review-spec type: gate @@ -42,7 +42,7 @@ steps: command: speckit.plan integration: "{{ inputs.integration }}" input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" - id: review-plan type: gate @@ -54,10 +54,10 @@ steps: command: speckit.tasks integration: "{{ inputs.integration }}" input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" - id: implement command: speckit.implement integration: "{{ inputs.integration }}" input: - args: "{{ inputs.feature_name }}" + args: "{{ inputs.spec }}" From aecc346b0d9520239de17a8ea36174ade01971f3 Mon Sep 17 00:00:00 2001 From: Manfred Riem <15701806+mnriem@users.noreply.github.com> Date: Thu, 16 Apr 2026 13:32:00 -0500 Subject: [PATCH 2/2] docs: update speckit_version requirement to >=0.7.2 in workflow example --- docs/reference/workflows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/workflows.md b/docs/reference/workflows.md index abad8cb4c2..e7e921e1e9 100644 --- a/docs/reference/workflows.md +++ b/docs/reference/workflows.md @@ -137,7 +137,7 @@ workflow: description: "Runs specify → plan → tasks → implement with review gates" requires: - speckit_version: ">=0.6.1" + speckit_version: ">=0.7.2" integrations: any: ["copilot", "claude", "gemini"]