run_command() forwarded shell= straight to subprocess.run, so a caller passing shell=True would invoke a shell. Reject shell=True with ValueError (keeping the parameter for signature compatibility) and drop shell= from both subprocess.run calls. Enable ruff S602/S604/S605 to flag any future shell=True reintroduction, annotate the one intentional workflow shell sink with # noqa: S602, and document the shell-step execution risk in workflows/PUBLISHING.md.
10 KiB
Workflow Publishing Guide
This guide explains how to publish your workflow to the Spec Kit workflow catalog, making it discoverable by specify workflow search.
Table of Contents
- Prerequisites
- Prepare Your Workflow
- Submit to Catalog
- Verification Process
- Release Workflow
- Best Practices
Prerequisites
Before publishing a workflow, ensure you have:
- Valid Workflow: A working
workflow.ymlthat passesspecify workflow runvalidation - Git Repository: Workflow hosted on GitHub (or other public git hosting)
- Documentation: README.md with description, inputs, and step graph
- License: Open source license file (MIT, Apache 2.0, etc.)
- Versioning: Semantic versioning in the
workflow.versionfield - Testing: Workflow tested on real projects
Prepare Your Workflow
1. Workflow Structure
Host your workflow in a repository with this structure:
your-workflow/
├── workflow.yml # Required: Workflow definition
├── README.md # Required: Documentation
├── LICENSE # Required: License file
└── CHANGELOG.md # Recommended: Version history
2. workflow.yml Validation
Verify your definition is valid:
schema_version: "1.0"
workflow:
id: "your-workflow" # Unique lowercase-hyphenated ID
name: "Your Workflow Name" # Human-readable name
version: "1.0.0" # Semantic version
author: "Your Name or Organization"
description: "Brief description (one sentence)"
integration: claude # Default integration (optional)
model: "claude-sonnet-4-20250514" # Default model (optional)
requires:
speckit_version: ">=0.6.1"
integrations:
any: ["claude", "gemini"] # At least one required
inputs:
spec:
type: string
required: true
prompt: "Describe what you want to build"
scope:
type: string
default: "full"
enum: ["full", "backend-only", "frontend-only"]
steps:
- id: specify
command: speckit.specify
input:
args: "{{ inputs.spec }}"
- id: review
type: gate
message: "Review the output."
options: [approve, reject]
on_reject: abort
Validation Checklist:
- ✅
idis lowercase alphanumeric with hyphens (single-character IDs are allowed) - ✅
versionfollows semantic versioning (X.Y.Z) - ✅
descriptionis concise - ✅ All step IDs are unique
- ✅ Step types are valid:
command,prompt,shell,gate,if,switch,while,do-while,fan-out,fan-in - ✅ Required fields present per step type (e.g.,
conditionforif,expressionforswitch) - ✅ Input types are valid:
string,number,boolean - ✅ Step IDs do not contain
:(reserved for engine-generated nested IDs likeparentId:childId)
3. Test Locally
# Run with required inputs
specify workflow run ./workflow.yml --input spec="Build a user authentication system with OAuth support"
# Check validation
specify workflow info ./workflow.yml
# Resume after a gate pause
specify workflow resume <run_id>
# Check run status
specify workflow status <run_id>
4. Create GitHub Release
Create a GitHub release for your workflow version:
git tag v1.0.0
git push origin v1.0.0
The raw YAML URL will be:
https://raw.githubusercontent.com/your-org/spec-kit-workflow-your-workflow/v1.0.0/workflow.yml
5. Test Installation from URL
specify workflow add your-workflow
# (once published to catalog)
Submit to Catalog
Understanding the Catalogs
Spec Kit uses a dual-catalog system:
catalog.json— Official, verified workflows (install allowed by default)catalog.community.json— Community-contributed workflows (discovery only by default)
All community workflows should be submitted to catalog.community.json.
1. Fork the spec-kit Repository
git clone https://github.com/YOUR-USERNAME/spec-kit.git
cd spec-kit
2. Add Workflow to Community Catalog
Edit workflows/catalog.community.json and add your workflow.
⚠️ Entries must be sorted alphabetically by workflow ID. Insert your workflow in the correct position within the
"workflows"object.
{
"schema_version": "1.0",
"updated_at": "2026-04-10T00:00:00Z",
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.community.json",
"workflows": {
"your-workflow": {
"id": "your-workflow",
"name": "Your Workflow Name",
"description": "Brief description of what your workflow automates",
"author": "Your Name",
"version": "1.0.0",
"url": "https://raw.githubusercontent.com/your-org/spec-kit-workflow-your-workflow/v1.0.0/workflow.yml",
"repository": "https://github.com/your-org/spec-kit-workflow-your-workflow",
"license": "MIT",
"requires": {
"speckit_version": ">=0.15.0"
},
"tags": [
"category",
"automation"
],
"created_at": "2026-04-10T00:00:00Z",
"updated_at": "2026-04-10T00:00:00Z"
}
}
}
3. Submit Pull Request
git checkout -b add-your-workflow
git add workflows/catalog.community.json
git commit -m "Add your-workflow to community catalog
- Workflow ID: your-workflow
- Version: 1.0.0
- Author: Your Name
- Description: Brief description
"
git push origin add-your-workflow
Pull Request Checklist:
## Workflow Submission
**Workflow Name**: Your Workflow Name
**Workflow ID**: your-workflow
**Version**: 1.0.0
**Repository**: https://github.com/your-org/spec-kit-workflow-your-workflow
### Checklist
- [ ] Valid workflow.yml (passes `specify workflow info`)
- [ ] README.md with description, inputs, and step graph
- [ ] LICENSE file included
- [ ] GitHub release created with raw YAML URL
- [ ] Workflow tested end-to-end with `specify workflow run`
- [ ] All gate steps have clear review messages
- [ ] Input prompts are descriptive
- [ ] Added to workflows/catalog.community.json (alphabetical order)
Verification Process
After submission, maintainers will review:
- Definition validation — valid
workflow.yml, correct schema - Step correctness — all step types used correctly, no dangling references
- Input design — clear prompts, sensible defaults and enums
- Security — no malicious shell commands, safe operations
- Documentation — clear README explaining what the workflow does and when to use it
Once verified, the workflow appears in specify workflow search.
Release Workflow
When releasing a new version:
- Update
versioninworkflow.yml - Update CHANGELOG.md
- Tag and push:
git tag v1.1.0 && git push origin v1.1.0 - Submit PR to update
versionandurlinworkflows/catalog.community.json
Best Practices
Step Design
- Use gates at decision points — place
gatesteps after each major output so users can review before proceeding - Keep steps focused — each step should do one thing; prefer more steps over complex single steps
- Provide clear gate messages — explain what to review and what approve/reject means
Inputs
- Use descriptive prompts — the
promptfield is shown to users when running the workflow - Set sensible defaults — optional inputs should have defaults that work for the common case
- Constrain with enums — when there's a fixed set of valid values, use
enumfor validation - Type appropriately — use
numberfor counts,booleanfor flags,stringfor names
Shell Steps
- Avoid destructive commands — don't delete files or directories without explicit confirmation via a gate
- Quote variables — use proper quoting in shell commands to handle spaces
- Check exit codes — shell step failures stop the workflow; make sure commands are robust
Security: shell steps execute arbitrary code
Workflow shell steps execute their run field through /bin/sh (POSIX) or the platform shell. There is no sandbox between the step and the user's machine: a malicious or buggy run block can read environment variables, modify files outside the project, exfiltrate data, or escalate privileges.
Catalog-listed workflows are reviewed at submission time (see Verification Process), but you should still treat every install as code-execution from an untrusted source until you have read the workflow.yml:
- Before installing a workflow, fetch the raw YAML and audit every
shellstep'srunfield directly.specify workflow info <name>only shows metadata (name, version, inputs, step IDs/types) — not the shell content that would actually execute. - Prefer explicit commands over interpolation in
runblocks:{{ inputs.something }}substitutions should be quoted and constrained viaenumso a malicious input can't inject shell syntax. - Limit privilege: shell steps inherit the user's environment. Workflows that need elevated access (sudo, secrets, GitHub tokens) should call them out explicitly in the README so reviewers can spot the requirement.
- Authors: if your workflow has shell steps that look risky out of context (deletions, network calls, credential reads), document the rationale in your README. Maintainers will reject submissions whose shell steps can't be justified at review time.
Integration Flexibility
- Set
integrationat workflow level — use theworkflow.integrationfield as the default - Allow per-step overrides — let individual steps specify a different integration if needed
- Document required integrations — list which integrations must be installed in
requires.integrations
Expression References
- Only reference prior steps — expressions like
{{ steps.plan.output.file }}only work ifplanran before the current step - Use
defaultfilter —{{ val | default('fallback') }}prevents failures from missing values - Keep expressions simple — complex logic should be in shell steps, not expressions