Problem Statement
Integrations that drive or visualise Spec Kit workflows (for example, a GitHub Action that renders workflow progress and human review gates in issue comments) need the workflow definition that a run was created with, not just its runtime state.
Today:
specify workflow status <run_id> --json returns runtime state only (run_id, workflow_id, status, current_step_index, per-step statuses, timestamps). It does not include the step tree, step types, or gate configuration (message, options, on_reject, ...).
specify workflow info <workflow_id> resolves the currently installed workflow by ID, has no --json output, and only lists top-level step IDs and types.
- The only way to get the exact definition used by a run is to read
.specify/workflows/runs/<run_id>/workflow.yml directly. The engine already writes this snapshot at run start, and workflow resume prefers it over the installed workflow. However, the file is an internal run-state detail, not a supported contract.
As a result, integrations either depend on Spec Kit's internal storage layout and file format, or they load the installed workflow by ID. The second option breaks as soon as the workflow is updated or removed after the run started.
Proposed Solution
Add a supported, run-scoped view of the workflow definition. It should be separate from workflow status, which stays focused on execution progress.
The exact surface is open for assessment. One option is a CLI command with JSON output, for example specify workflow definition <run_id> --json (or a --definition flag on an existing command), backed by a library function that integrations can call directly.
The view should return:
- workflow metadata (
id, name, version, and other top-level fields as appropriate);
- the step tree, including nested steps (e.g. inside
if / switch / loop / fan-out constructs);
- gate configuration: message, options, verdict/
on_reject behaviour;
- the definition exactly as persisted for the run, resolved from the run and not from the currently installed workflow.
Illustrative shape (from the discussion, not final):
{
"run_id": "662bf791",
"definition": {
"workflow": {"id": "spec-review", "name": "Spec review", "version": "1.0.0"},
"steps": [
{"id": "draft", "type": "command", "command": "speckit.specify"},
{
"id": "approve",
"type": "gate",
"message": "Review the specification.",
"options": ["approve", "reject"],
"on_reject": "abort"
}
]
}
}
This should be a stable abstraction over the run's definition, not a raw dump of the underlying YAML.
Alternatives Considered
- Reading
.specify/workflows/runs/<run_id>/workflow.yml directly. This is the current interim approach. It works, but it couples integrations to internal layout and format.
- Loading the installed workflow by
workflow_id (e.g. via workflow info). This is inaccurate once the installed workflow changes or is removed after the run started.
- Extending
workflow status --json with the full definition. This mixes execution state with static definition data and bloats every status poll.
Component
Specify CLI (initialization, commands)
AI Agent (if applicable)
Not applicable
Use Cases
- A GitHub Action posts an issue comment that shows every step of a workflow run with its current status. It needs the full step tree, including steps that have not yet started, and the status alone does not provide these.
- At a human review gate, the Action renders the gate's message and available options (e.g. approve / reject) so reviewers can respond from the issue.
- After a workflow is updated or removed, the Action still renders historical or in-flight runs accurately against the definition they were started with.
Acceptance Criteria
Additional Context
AI Disclosure
Drafted with opencode using Claude Opus 5.5 (github-copilot/claude-opus-5.5), default reasoning settings, human-supervised. The agent wrote the issue text from discussion #4727 and a read of the workflow engine source (workflows/engine.py, command_status.py, command_info.py). It was reviewed and submitted by a human on behalf of the original discussion author.
Problem Statement
Integrations that drive or visualise Spec Kit workflows (for example, a GitHub Action that renders workflow progress and human review gates in issue comments) need the workflow definition that a run was created with, not just its runtime state.
Today:
specify workflow status <run_id> --jsonreturns runtime state only (run_id,workflow_id,status,current_step_index, per-step statuses, timestamps). It does not include the step tree, step types, or gate configuration (message, options,on_reject, ...).specify workflow info <workflow_id>resolves the currently installed workflow by ID, has no--jsonoutput, and only lists top-level step IDs and types..specify/workflows/runs/<run_id>/workflow.ymldirectly. The engine already writes this snapshot at run start, andworkflow resumeprefers it over the installed workflow. However, the file is an internal run-state detail, not a supported contract.As a result, integrations either depend on Spec Kit's internal storage layout and file format, or they load the installed workflow by ID. The second option breaks as soon as the workflow is updated or removed after the run started.
Proposed Solution
Add a supported, run-scoped view of the workflow definition. It should be separate from
workflow status, which stays focused on execution progress.The exact surface is open for assessment. One option is a CLI command with JSON output, for example
specify workflow definition <run_id> --json(or a--definitionflag on an existing command), backed by a library function that integrations can call directly.The view should return:
id,name,version, and other top-level fields as appropriate);if/switch/ loop / fan-out constructs);on_rejectbehaviour;Illustrative shape (from the discussion, not final):
{ "run_id": "662bf791", "definition": { "workflow": {"id": "spec-review", "name": "Spec review", "version": "1.0.0"}, "steps": [ {"id": "draft", "type": "command", "command": "speckit.specify"}, { "id": "approve", "type": "gate", "message": "Review the specification.", "options": ["approve", "reject"], "on_reject": "abort" } ] } }This should be a stable abstraction over the run's definition, not a raw dump of the underlying YAML.
Alternatives Considered
.specify/workflows/runs/<run_id>/workflow.ymldirectly. This is the current interim approach. It works, but it couples integrations to internal layout and format.workflow_id(e.g. viaworkflow info). This is inaccurate once the installed workflow changes or is removed after the run started.workflow status --jsonwith the full definition. This mixes execution state with static definition data and bloats every status poll.Component
Specify CLI (initialization, commands)
AI Agent (if applicable)
Not applicable
Use Cases
Acceptance Criteria
--jsonand/or library API) returns the workflow definition for a givenrun_idworkflow status --json)Additional Context
AI Disclosure
Drafted with opencode using Claude Opus 5.5 (
github-copilot/claude-opus-5.5), default reasoning settings, human-supervised. The agent wrote the issue text from discussion #4727 and a read of the workflow engine source (workflows/engine.py,command_status.py,command_info.py). It was reviewed and submitted by a human on behalf of the original discussion author.