Skip to content

feat: add /speckit.ship command — release engineering automation#2045

Closed
arunt14 wants to merge 3 commits intogithub:mainfrom
arunt14:feat/ship-command
Closed

feat: add /speckit.ship command — release engineering automation#2045
arunt14 wants to merge 3 commits intogithub:mainfrom
arunt14:feat/ship-command

Conversation

@arunt14
Copy link
Copy Markdown
Contributor

@arunt14 arunt14 commented Apr 1, 2026

Description

Problem

Spec-Kit generates GitHub issues from tasks (/speckit.taskstoissues), but has no command to automate the actual release process. After implementation, review, and QA, developers must manually: verify all tasks are complete, sync branches, write changelog entries, check CI status, compose PR descriptions, and create the pull request. This manual process is error-prone, inconsistent, and loses the traceability that spec-driven development creates.

The .specify/ directory contains rich artifacts (spec, plan, tasks, review reports, QA reports) that should flow directly into a well-structured PR — but today this connection is broken.

Industry context: GStack's /ship command demonstrates that automating the release pipeline — with pre-flight checks, CI verification, and artifact-backed PR descriptions — eliminates an entire class of release errors and saves significant time per feature.

Solution

Adds /speckit.ship — a new core command that automates the complete release engineering workflow:

  1. Pre-flight readiness checks — verifies task completion, review verdict, QA status, and clean working tree. Blocks shipping if blockers exist.
  2. Branch synchronization — fetches latest, offers rebase or merge, handles conflict guidance
  3. Changelog generation — composes structured changelog from spec summary + completed tasks + git commit history
  4. CI verification — checks pipeline status via GitHub CLI (gh), waits for completion, reports failures
  5. PR creation — generates comprehensive PR description from all .specify/ artifacts with full traceability
  6. Release archival — records release metadata, artifact links, and git commit range

Safe by default: Every destructive operation (force push, PR creation) requires explicit user confirmation.

Graceful fallback: If gh CLI is unavailable, generates PR description as a markdown file for manual creation.

Business Value

  • Eliminates manual release toil — the entire PR creation process is automated with one command
  • Enforces release readiness — pre-flight checks prevent shipping incomplete or failing features
  • Creates auditable releases — every PR links back to spec, plan, tasks, review, and QA artifacts
  • Reduces release errors — automated changelog and branch sync eliminate common mistakes
  • Completes the delivery pipeline: implement → review → qa → ship → retro

Workflow Position

/speckit.implement → /speckit.review → /speckit.qa → /speckit.ship ⭐ → /speckit.retro

Files Added

File Purpose
templates/commands/ship.md Command template with pre-flight checks, branch sync, changelog, CI verification, PR creation, extension hooks (before_ship, after_ship)
templates/ship-template.md Release artifact template with PR description, readiness results, changelog entry, and git metadata

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest — 878/972 pass (44 failures are pre-existing, unrelated to this change)
  • Verified YAML frontmatter is valid and parseable
  • Verified command file is auto-discovered by specify init
  • Confirmed no changes to Python source code — template-only addition

AI Disclosure

  • AI assistance was used in this PR
  • How: GitHub Copilot CLI (Claude) was used to draft the command template and output template content, following the existing patterns established by implement.md and analyze.md. All content was reviewed and validated against the project's template conventions.

Note: Happy to discuss the scope and approach with maintainers. This is one of five related-but-independent PRs adding lifecycle commands inspired by GStack's role-based workflow.

@arunt14 arunt14 requested a review from mnriem as a code owner April 1, 2026 05:57
Copilot AI review requested due to automatic review settings April 1, 2026 05:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new /speckit.ship core command template and a corresponding release/PR output template to automate a spec-driven “ship” workflow (readiness checks → branch sync → changelog/PR creation → archival), including extension hook integration points.

Changes:

  • Add templates/commands/ship.md command template describing the end-to-end release engineering workflow (with before_ship / after_ship hook handling).
  • Add templates/ship-template.md as the structured release record + PR description scaffold to be written under a feature’s releases/ directory.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
templates/commands/ship.md New /speckit.ship command template outlining readiness checks, branch sync, CI verification, PR creation, and artifact archival.
templates/ship-template.md New markdown template for release notes + traceability links to spec/plan/tasks/review/QA artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +105 to +120
- Fetch latest from remote: `git fetch origin`
- Check if feature branch is behind target branch:
```bash
git rev-list --count HEAD..origin/{target_branch}
```
- If behind, offer to rebase or merge:
- **Rebase** (recommended for clean history): `git rebase origin/{target_branch}`
- **Merge**: `git merge origin/{target_branch}`
- If conflicts arise: **STOP** and provide conflict resolution guidance
- After sync, push the updated feature branch: `git push origin {feature_branch}`

5. **Changelog Generation**:
- Collect changelog inputs:
- Feature summary from `spec.md` (overview section)
- Implementation highlights from completed tasks in `tasks.md`
- Git commit messages: `git log origin/{target_branch}..HEAD --oneline`
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 3 says to detect the remote name (defaulting to origin), but branch sync hard-codes origin (git fetch origin). This will fail for repos whose primary remote isn't named origin (fork workflows, corporate defaults). Use the detected remote consistently in the fetch/compare/push commands.

Suggested change
- Fetch latest from remote: `git fetch origin`
- Check if feature branch is behind target branch:
```bash
git rev-list --count HEAD..origin/{target_branch}
```
- If behind, offer to rebase or merge:
- **Rebase** (recommended for clean history): `git rebase origin/{target_branch}`
- **Merge**: `git merge origin/{target_branch}`
- If conflicts arise: **STOP** and provide conflict resolution guidance
- After sync, push the updated feature branch: `git push origin {feature_branch}`
5. **Changelog Generation**:
- Collect changelog inputs:
- Feature summary from `spec.md` (overview section)
- Implementation highlights from completed tasks in `tasks.md`
- Git commit messages: `git log origin/{target_branch}..HEAD --oneline`
- Fetch latest from remote: `git fetch {remote_name}`
- Check if feature branch is behind target branch:
```bash
git rev-list --count HEAD..{remote_name}/{target_branch}
```
- If behind, offer to rebase or merge:
- **Rebase** (recommended for clean history): `git rebase {remote_name}/{target_branch}`
- **Merge**: `git merge {remote_name}/{target_branch}`
- If conflicts arise: **STOP** and provide conflict resolution guidance
- After sync, push the updated feature branch: `git push {remote_name} {feature_branch}`
5. **Changelog Generation**:
- Collect changelog inputs:
- Feature summary from `spec.md` (overview section)
- Implementation highlights from completed tasks in `tasks.md`
- Git commit messages: `git log {remote_name}/{target_branch}..HEAD --oneline`

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +120
- Fetch latest from remote: `git fetch origin`
- Check if feature branch is behind target branch:
```bash
git rev-list --count HEAD..origin/{target_branch}
```
- If behind, offer to rebase or merge:
- **Rebase** (recommended for clean history): `git rebase origin/{target_branch}`
- **Merge**: `git merge origin/{target_branch}`
- If conflicts arise: **STOP** and provide conflict resolution guidance
- After sync, push the updated feature branch: `git push origin {feature_branch}`

5. **Changelog Generation**:
- Collect changelog inputs:
- Feature summary from `spec.md` (overview section)
- Implementation highlights from completed tasks in `tasks.md`
- Git commit messages: `git log origin/{target_branch}..HEAD --oneline`
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch sync continues to hard-code origin in the behind-check and push steps (origin/{target_branch} and git push origin ...). If the remote name is detected earlier, these should use that value as well so the command works in non-standard remote setups.

Suggested change
- Fetch latest from remote: `git fetch origin`
- Check if feature branch is behind target branch:
```bash
git rev-list --count HEAD..origin/{target_branch}
```
- If behind, offer to rebase or merge:
- **Rebase** (recommended for clean history): `git rebase origin/{target_branch}`
- **Merge**: `git merge origin/{target_branch}`
- If conflicts arise: **STOP** and provide conflict resolution guidance
- After sync, push the updated feature branch: `git push origin {feature_branch}`
5. **Changelog Generation**:
- Collect changelog inputs:
- Feature summary from `spec.md` (overview section)
- Implementation highlights from completed tasks in `tasks.md`
- Git commit messages: `git log origin/{target_branch}..HEAD --oneline`
- Fetch latest from remote: `git fetch {remote_name}`
- Check if feature branch is behind target branch:
```bash
git rev-list --count HEAD..{remote_name}/{target_branch}
```
- If behind, offer to rebase or merge:
- **Rebase** (recommended for clean history): `git rebase {remote_name}/{target_branch}`
- **Merge**: `git merge {remote_name}/{target_branch}`
- If conflicts arise: **STOP** and provide conflict resolution guidance
- After sync, push the updated feature branch: `git push {remote_name} {feature_branch}`
5. **Changelog Generation**:
- Collect changelog inputs:
- Feature summary from `spec.md` (overview section)
- Implementation highlights from completed tasks in `tasks.md`
- Git commit messages: `git log {remote_name}/{target_branch}..HEAD --oneline`

Copilot uses AI. Check for mistakes.

## Operating Constraints

**SAFE BY DEFAULT**: Every destructive operation (force push, branch delete, PR creation) requires explicit user confirmation. Default to dry-run mode for destructive git operations.
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The template states "SAFE BY DEFAULT" and that destructive operations require explicit user confirmation, but the branch sync flow instructs a rebase/merge and then a push without an explicit confirm gate immediately before those actions. Add a required confirmation (default "no") before rebase/merge, and another before pushing, since both can change history and/or update the remote.

Suggested change
**SAFE BY DEFAULT**: Every destructive operation (force push, branch delete, PR creation) requires explicit user confirmation. Default to dry-run mode for destructive git operations.
**SAFE BY DEFAULT**: Every destructive or potentially destructive operation (e.g., rebase/merge during branch sync, push/force push, branch delete, PR creation) requires explicit user confirmation.
- For the branch sync flow, add a required confirmation prompt **immediately before** performing any rebase/merge, with the default answer set to **no**.
- Add a separate required confirmation prompt **immediately before** performing any push (including force push) to the remote, with the default answer set to **no**.
- Default to dry-run mode for destructive git operations wherever possible.

Copilot uses AI. Check for mistakes.
Comment on lines +186 to +192
```bash
gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file}
```
- If `gh` is not available:
- Save the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md`
- Provide instructions for manual PR creation
- Output the PR title and description for copy-paste
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR creation is called out as requiring explicit user confirmation in the operating constraints, but Step 8 goes straight to gh pr create without an explicit confirmation prompt right before executing it. Add a confirm gate (default "no") prior to PR creation, and ensure the manual fallback also asks before writing the PR description file if you're treating file writes as destructive.

Suggested change
```bash
gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file}
```
- If `gh` is not available:
- Save the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md`
- Provide instructions for manual PR creation
- Output the PR title and description for copy-paste
- Prompt the user for explicit confirmation **right before** creating the PR (default **no**). For example:
```bash
read -r -p "Proceed to create a GitHub pull request now? [y/N] " confirm_pr
case "${confirm_pr}" in
[Yy][Ee][Ss]|[Yy])
gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file}
;;
*)
echo "Skipping PR creation; you can run 'gh pr create' manually later."
;;
esac
```
- If `gh` is not available:
- Prompt the user for explicit confirmation **before** writing any PR description file (default **no**). For example:
```bash
read -r -p "Save PR description and proceed with manual PR creation steps? [y/N] " confirm_pr_file
case "${confirm_pr_file}" in
[Yy][Ee][Ss]|[Yy])
pr_description_path="FEATURE_DIR/releases/pr-description-{timestamp}.md"
# Write PR description content to "${pr_description_path}"
echo "PR description saved to ${pr_description_path}."
echo "Use this file when creating your PR manually in the Git provider UI."
;;
*)
echo "Skipping PR description file write and manual PR instructions."
;;
esac
```
- Provide instructions for manual PR creation
- Output the PR title and description for copy-paste (only if the user confirmed saving or otherwise requested output)

Copilot uses AI. Check for mistakes.
Add a new core command that automates the full release pipeline:

1. Pre-flight readiness checks (tasks, review, QA, working tree)
2. Branch synchronization with target branch
3. Changelog generation from spec + tasks + git commits
4. CI pipeline verification
5. PR creation with full traceability to .specify/ artifacts
6. Release artifact archival

Supports GitHub CLI (gh) for automated PR creation with fallback to manual flow.
Inspired by GStack's /ship command.
@arunt14 arunt14 force-pushed the feat/ship-command branch from 04875ca to b17b14e Compare April 1, 2026 05:59
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 1, 2026

Please deliver this as an extension. See https://github.com/github/spec-kit/tree/main/extensions

- Use {remote_name} consistently instead of hard-coded 'origin'
- Add explicit user confirmation before rebase/merge operations
- Add explicit user confirmation before push operations
- Add explicit user confirmation before PR creation
Copilot AI review requested due to automatic review settings April 1, 2026 12:26
@arunt14
Copy link
Copy Markdown
Contributor Author

arunt14 commented Apr 1, 2026

Thanks for the review! All 4 comments addressed in the latest push:

1-2. Hard-coded origin: Replaced all hard-coded origin references in branch sync (fetch, rev-list, rebase, merge, push) and changelog generation (git log) with {remote_name}, consistent with the detection logic in Step 3.
3. Branch sync confirmation gates: Added required user confirmation prompts (default no) immediately before rebase/merge and immediately before push. Updated the SAFE BY DEFAULT operating constraint to explicitly enumerate all operations requiring confirmation.
4. PR creation confirmation: Added required user confirmation prompt (default no) before gh pr create execution, and a separate confirmation before writing the PR description file in the manual fallback path.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


3. **Determine Shipping Configuration**:
- Detect the current feature branch: `git branch --show-current`
- Determine the target branch (default: `main`; override via user input or `.specify/config.yml`)
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Determine the target branch mentions overriding via .specify/config.yml, but this repo doesn’t reference a project-level .specify/config.yml anywhere else (search only finds this line). This is likely misleading; either document the actual supported config location/key (if one exists) or remove this reference and rely on user input/defaults.

Suggested change
- Determine the target branch (default: `main`; override via user input or `.specify/config.yml`)
- Determine the target branch (default: `main`; allow override via user input/prompt)

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +82
- If any tasks are incomplete: **STOP** and warn. Ask user to confirm proceeding or run `/speckit.implement` first.

**Review Status** (if FEATURE_DIR/reviews/ exists):
- Read the most recent review report
- If verdict is ❌ CHANGES REQUIRED: **STOP** and warn. Recommend running `/speckit.review` after fixes.
- If verdict is ⚠️ APPROVED WITH CONDITIONS: Warn but allow proceeding with confirmation.

**QA Status** (if FEATURE_DIR/qa/ exists):
- Read the most recent QA report
- If verdict is ❌ QA FAILED: **STOP** and warn. Recommend running `/speckit.qa` after fixes.
- If verdict is ⚠️ QA PASSED WITH NOTES: Warn but allow proceeding with confirmation.
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flow recommends /speckit.review and /speckit.qa, but those commands don’t appear to exist in this repository (no corresponding templates/commands entries, and no other references found). Either add/land those commands first, gate these instructions behind “if available”, or update the guidance to match the currently shipped command set.

Copilot uses AI. Check for mistakes.
Comment on lines +192 to +197
```bash
gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file}
```
- If `gh` is not available:
- Prompt the user for explicit confirmation **before** writing the PR description file (default **no**)
- Save the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md`
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gh pr create example uses --body-file {pr_description_file}, but the template never defines/writes {pr_description_file} in the gh-available path (it only specifies a filename when gh is unavailable). Clarify where the PR body file is written (ideally always write it to FEATURE_DIR/releases/pr-description-{timestamp}.md and reuse that path for both branches).

Suggested change
```bash
gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file}
```
- If `gh` is not available:
- Prompt the user for explicit confirmation **before** writing the PR description file (default **no**)
- Save the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md`
- Write the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md` and use that path as `{pr_description_file}`:
```bash
gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file}
```
- If `gh` is not available:
- Prompt the user for explicit confirmation **before** writing the PR description file (default **no**)
- Save the PR description to the same path: `FEATURE_DIR/releases/pr-description-{timestamp}.md`

Copilot uses AI. Check for mistakes.
Comment on lines +221 to +225

Next steps:
- Review the PR at {pr_url}
- After merge, run `/speckit.retro` for a retrospective
```
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The post-ship message suggests running /speckit.retro, but that command doesn’t exist in this repository (no template/command file, and no other references found). Either add the retro command in the same PR series or adjust this “Next steps” guidance to only mention commands that are currently available.

Copilot uses AI. Check for mistakes.
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 1, 2026

Please review https://github.com/github/spec-kit/blob/main/extensions/EXTENSION-PUBLISHING-GUIDE.md for publishing a community hosted extension

- Remove misleading .specify/config.yml reference for target branch
- Gate /speckit.review, /speckit.qa, /speckit.retro references with (if available)
- Always write PR description to FEATURE_DIR/releases/ before gh pr create
- Align QA verdict terminology with qa command (PARTIAL PASS/FAILURES FOUND)
@arunt14
Copy link
Copy Markdown
Contributor Author

arunt14 commented Apr 1, 2026

Addressed the 4 new review comments in the latest push:

  1. .specify/config.yml\ reference: Removed the misleading reference — now uses user input/prompt for target branch override since no config file is defined elsewhere in the project.
  2. Cross-command references: Gated all references to /speckit.review, /speckit.qa, and /speckit.retro\ with '(if available)' since they may not exist in the user's installation.
  3. PR description file path: Now always writes to \FEATURE_DIR/releases/pr-description-{timestamp}.md\ first, then reuses that path for both the \gh pr create --body-file\ and manual fallback flows.
  4. QA verdict terminology: Aligned with the standardized qa command terminology (PARTIAL PASS / FAILURES FOUND instead of PASSED WITH NOTES / QA FAILED).

Regarding the extension delivery model — will respond separately.

@arunt14
Copy link
Copy Markdown
Contributor Author

arunt14 commented Apr 1, 2026

Thanks @mnriem! I've reviewed the Extension Publishing Guide. Will restructure this as a community extension following the extension.yml manifest pattern and resubmit as an extension contribution to catalog.community.json.

@arunt14
Copy link
Copy Markdown
Contributor Author

arunt14 commented Apr 1, 2026

Closing in favor of PR #2049 — restructured as a community extension per maintainer feedback. Extension repo and v1.0.0 release are available.

@arunt14 arunt14 closed this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants