Validate section completion in backlog, then either release or identify gaps.
Compatibility Note
This pi wrapper preserves the original milestone workflow while treating confirmation points as explicit manual checkpoints in the current chat instead of a runtime interactive-question dependency.
All arguments are optional with smart defaults.
Argument Parsing
Parse $ARGUMENTS into:
| Variable | Source | Required | Default |
|---|---|---|---|
BACKLOG_PATH |
1st arg | No | Auto-detect: BACKLOG.md, specs/backlog.md, or skip |
SECTION |
2nd arg | No | Latest incomplete section, or skip if no backlog |
BASE_BRANCH |
3rd arg | No | origin/main (fetches first) |
VERSION |
4th arg (if not quoted) | No | Auto-bump from VERSION file or latest git tag |
VALIDATION_PROMPT |
Last quoted string "..." |
No | Auto-derive from checklist |
SKIP_TAG |
--skip-tag flag |
No | false (tags created by default) |
AUTO_MODE |
--auto flag |
No | false (confirmation gates enabled) |
WITH_SQUASHED_COMMITS |
--with-squashed-commits flag |
No | false (squashed commits list excluded by default) |
Parsing Rules:
- If an argument starts and ends with
", treat asVALIDATION_PROMPT - Version is optional; if 4th arg is quoted, there's no version
- If
--skip-tagflag is present anywhere in arguments, setSKIP_TAG=true - If
--with-squashed-commitsflag is present anywhere in arguments, setWITH_SQUASHED_COMMITS=true - If
--autoflag is present anywhere in arguments, setAUTO_MODE=true(skips confirmation gates) - Empty
$ARGUMENTStriggers full auto-detect mode
Phase 0: Smart Defaults Resolution
When NO arguments provided:
0.1 Fetch Remote
git fetch origin main || git fetch origin master
0.2 Determine BASE_BRANCH
# Try origin/main first, fallback to origin/master
git show-ref --verify --quiet refs/remotes/origin/main && echo "origin/main" || echo "origin/master"
0.3 Auto-Detect BACKLOG_PATH
Search in order:
BACKLOG.md(root)specs/backlog.mddocs/backlog.mdbacklog.md
If none found → SKIP backlog validation (proceed without backlog)
0.4 Auto-Detect SECTION (if backlog exists)
Find first incomplete section (has - [ ] items). If all complete → use most recent section.
0.5 Auto-Detect VERSION
If SKIP_TAG=false:
Priority order:
VERSIONfile → parse, increment patch:X.Y.Z→X.Y.(Z+1), prefix withv- Latest git tag matching
v*.*.*→ increment patch - Default:
v0.1.0
If SKIP_TAG=true:
Set VERSION="" (no version/tag will be created)
0.6 CHANGELOG Consistency Check (Critical for No-Args Mode)
# Check if CHANGELOG.md exists and has [Unreleased] content
if [ -f CHANGELOG.md ]; then
grep -A 100 "\\[Unreleased\\]" CHANGELOG.md | grep -E "^- |^### " | head -20
fi
If CHANGELOG [Unreleased] is EMPTY but commits exist since BASE_BRANCH:
CHANGELOG SYNC REQUIRED
Commits since {BASE_BRANCH}:
{commit list}
But CHANGELOG.md [Unreleased] section is empty.
Please update CHANGELOG.md with these changes before proceeding.
-> STOP and wait for user to update changelog.
If CHANGELOG [Unreleased] has content -> proceed.
0.7 Project-Specific Enforcement
Check if AGENTS.md contains project-specific rules:
test -f AGENTS.md && echo "exists" || echo "none"
If exists:
- Read
AGENTS.mdcontent - Parse and store rules for validation in Phase 4.5
- Common rules to detect:
no emojis/DO NOT use emojis-> flag emoji restrictionsproject-agnostic/anonymous-> flag content anonymity requirementsrelative symlinks-> flag symlink requirements
Store parsed rules as PROJECT_RULES for later validation.
Phase 1: Pre-Flight Checks
- Git state: Must be clean (no uncommitted changes)
- Commits exist: Must have commits since
BASE_BRANCH - CHANGELOG exists:
CHANGELOG.mdmust exist with[Unreleased]section - Backlog exists (if path provided): File at
BACKLOG_PATHmust exist - Section exists (if backlog provided): Section
SECTIONmust be found in backlog
If any fail → STOP with specific error message.
Phase 2: Extract Checklist (if backlog provided)
- Read backlog file at
BACKLOG_PATH - Find section matching
SECTION(patterns:#### 1.2,### Phase 1.2,## 1.2) - Extract ALL checklist items until next section:
- [ ]= unchecked- [x]= checked
- Report:
Found X items (Y checked, Z unchecked)
If no backlog: Skip to Phase 4 with auto-approval path.
Phase 3: Validate Implementation (if backlog provided)
If VALIDATION_PROMPT provided:
Use it as explicit criteria. Spawn validation agent with prompt:
VALIDATE: {VALIDATION_PROMPT}
For each criterion, search codebase and report:
- Status: FOUND | MISSING
- Evidence: file:line references
- Notes: any issues
If NO VALIDATION_PROMPT:
For each UNCHECKED item (- [ ]):
Parse item to identify expected:
- Files/components (look for nouns)
- Interfaces/functions (look for code terms)
- Tests (if mentioned)
Search codebase:
- Grep for key terms
- Glob for expected file patterns
- Check test directories
Classify:
- IMPLEMENTED: Found despite unchecked
- MISSING: No evidence found
Phase 4: Decision Gate
Path A: No Backlog (Changelog-Only Validation)
Display:
✅ CHANGELOG Validated
Changes since {BASE_BRANCH}:
- {N} commits
- Key changes: {summary}
CHANGELOG [Unreleased] entries:
{entries}
Release Configuration:
- Base: {BASE_BRANCH}
- Version: {VERSION or "(no tag)" if SKIP_TAG=true}
- Commits to squash: N
Proceed with squash + tag? (yes/no)
If AUTO_MODE=true: Skip confirmation, proceed directly to squash/tag.
→ On "yes" (or auto): proceed to squash/tag.
Path B: Backlog - ALL COMPLETE (all items implemented or checked)
Display:
✅ Section {SECTION} COMPLETE
Validated Items:
- [x] Item 1 - evidence: file:line
- [x] Item 2 - evidence: file:line
...
Release Configuration:
- Base: {BASE_BRANCH}
- Version: {VERSION or "(no tag)" if SKIP_TAG=true}
- Commits to squash: N
- CHANGELOG: [Unreleased] → [{VERSION or section name if SKIP_TAG=true}]
Proceed with squash? (yes/no)
If AUTO_MODE=true: Skip confirmation, proceed directly.
On "yes" (or auto):
- Update backlog: mark all items
[x], add checkmark to section header - Update CHANGELOG.md:
- Move all entries from
[Unreleased]to new[{VERSION}] - {YYYY-MM-DD}section - Keep empty
[Unreleased]section at top - If no VERSION provided or
SKIP_TAG=true, use section name as header
- Move all entries from
- Commit:
docs: mark {SECTION} as completed - Create backup:
{branch}-backup/{YYYY}/{MM}/{DD}/001 - Soft reset to
BASE_BRANCH - Generate Conventional Commit message (see Phase 4B)
- Create squashed commit with generated message
- If
VERSIONandSKIP_TAG=false: create annotated tag
→ Proceed to Phase 5: Push Confirmation
Phase 4B: Conventional Commit Message Generation
Generate a standardized commit message following Conventional Commits extended format.
4B.1 Analyze Changes
# Get full diff for analysis
git diff {BASE_BRANCH}..HEAD --stat
git diff {BASE_BRANCH}..HEAD --name-status
4B.2 Determine Commit Type
Parse changed files and categorize by primary change type:
| Type | When to Use |
|---|---|
feat |
New feature or capability added |
fix |
Bug fix |
docs |
Documentation only changes |
chore |
Maintenance, deps, configs (no production code) |
refactor |
Code restructuring without behavior change |
test |
Adding or modifying tests |
style |
Formatting, whitespace, linting |
perf |
Performance improvements |
build |
Build system or external dependencies |
ci |
CI/CD configuration changes |
Selection Priority:
- If ANY
featchanges exist -> type =feat - Else if ANY
fixchanges exist -> type =fix - Else use dominant change type
4B.3 Determine Scope
Analyze changed file paths to identify scope:
# Get unique top-level directories/components
git diff --name-only {BASE_BRANCH}..HEAD | cut -d'/' -f1-2 | sort -u
Scope Rules:
- Single component modified -> use component name (e.g.,
commands,skills) - Multiple related components -> use parent (e.g.,
core) - Unrelated changes -> omit scope or use
release - Version/release changes -> scope =
releaseor version number
4B.4 Generate Commit Title
Format: <type>(<scope>): <description>
Description Rules:
- Imperative mood ("add" not "added")
- Lowercase first letter
- No period at end
- Max 72 characters total
- Summarize the main purpose
Examples:
feat(commands): add milestone validation workflowfix(parser): handle empty input gracefullydocs(readme): update installation instructionschore(deps): bump typescript to v5.3
4B.5 Generate Commit Body
Structure the body with these sections (include only non-empty):
## Added
- New feature 1
- New feature 2
## Changed
- Modified behavior 1
- Updated component 2
## Fixed
- Bug fix 1
- Issue resolution 2
## Removed
- Deprecated item 1
Content Generation:
- Parse
git diff {BASE_BRANCH}..HEADfile by file - Categorize each file's changes:
- New files -> Added
- Modified files -> Changed (or Fixed if bug-related)
- Deleted files -> Removed
- Summarize meaningful changes (not every line)
- Reference file paths where helpful
4B.6 Include Original Commits (Optional)
Only if WITH_SQUASHED_COMMITS=true, append squashed commit references:
# Get original commit messages
git log --oneline {BASE_BRANCH}..HEAD
Format as:
Squashed commits:
- {sha7} {message}
- {sha7} {message}
- {sha7} {message}
If WITH_SQUASHED_COMMITS=false (default): Omit this section entirely from the commit message.
4B.7 Complete Message Template
<type>(<scope>): <description>
## Added
- {additions}
## Changed
- {changes}
## Fixed
- {fixes}
## Removed
- {removals}
<!-- Only if WITH_SQUASHED_COMMITS=true -->
Squashed commits:
- {sha} {message}
- {sha} {message}
<!-- End conditional -->
4B.8 Commit Message Example
feat(milestone): add validation workflow with smart defaults
## Added
- Smart defaults resolution for all arguments
- CHANGELOG consistency check
- AGENTS.md validation
- Push confirmation gate
## Changed
- Refactored argument parsing to support quoted strings
- Updated backup branch naming format
## Fixed
- Backlog detection now searches multiple locations
Path C: Backlog - INCOMPLETE (missing items)
Display:
❌ Section {SECTION} INCOMPLETE
Missing:
1. {item} - {what's missing}
2. {item} - {what's missing}
Implemented but unchecked:
1. {item} - {evidence}
Options:
(A) Create /spec for missing items
(B) Abort - review manually
On "A": Output spec creation commands:
Missing items require specs:
/skill:ac-workflow-spec CREATE {item-1-title}
/skill:ac-workflow-spec CREATE {item-2-title}
On "B": STOP cleanly.
Phase 4.5: AGENTS.md Validation (Pre-Push Gate)
If PROJECT_RULES were parsed in Phase 0.7, validate all changes against AGENTS.md rules:
4.5.1 Get Changed Files
git diff --name-only {BASE_BRANCH}..HEAD
4.5.2 Validate Against PROJECT_RULES
For each rule detected, run validation:
Emoji Check (if emoji restriction detected):
# Check all changed .md files for emoji characters
git diff {BASE_BRANCH}..HEAD -- '*.md' | grep -P '[\x{1F300}-\x{1F9FF}]' || echo "clean"
Project-Agnostic/Anonymous Check (if anonymity rule detected):
# Check for personal identifiers, hardcoded usernames, local paths
git diff {BASE_BRANCH}..HEAD | grep -iE '(/Users/[a-z]+|/home/[a-z]+|@[a-z]+\.com)' || echo "clean"
Symlink Check (if symlink rule detected):
# Check for absolute symlinks in changed files
for f in $(git diff --name-only {BASE_BRANCH}..HEAD); do
if [ -L "$f" ]; then
target=$(readlink "$f")
[[ "$target" = /* ]] && echo "ABSOLUTE: $f -> $target"
fi
done
4.5.3 Violation Handling
If ANY violations found:
AGENTS.md VIOLATIONS DETECTED
The following changes violate project-specific rules:
Rule: {rule description}
Violations:
- {file}: {violation details}
- {file}: {violation details}
Rule: {rule description}
Violations:
- {file}: {violation details}
Fix these violations before proceeding with release.
-> STOP - Do not proceed to Phase 5.
If NO violations -> proceed to Phase 5.
Phase 5: Push Confirmation
After successful squash/tag, display:
## Release Prepared Locally
Commit: {sha} {message}
Branch: {branch}
Tag: {VERSION} (if created, otherwise "(none)")
Backup: {backup-branch}
Push to origin?
Commands to execute:
git push --force-with-lease origin {branch}
git push origin {VERSION} # if tag created (SKIP_TAG=false)
Proceed with push? (yes/no)
If AUTO_MODE=true: Skip confirmation, proceed directly with push.
On "yes" (or auto):
- Execute:
git push --force-with-lease origin {branch} - If
VERSIONandSKIP_TAG=false: Execute:git push origin {VERSION} - Report success with remote URLs
On "no" (only when AUTO_MODE=false):
Display manual commands and exit:
Skipped push. Run manually when ready:
git push --force-with-lease origin {branch}
git push origin {VERSION} # if tag was created
Abort Conditions
| Condition | Action |
|---|---|
| Backlog not found (when path specified) | STOP: "File not found: {path}" |
| Section not found (when specified) | STOP: "Section {SECTION} not found. Available: [list]" |
| No commits to squash | STOP: "No commits between {BASE_BRANCH} and HEAD" |
| Git dirty | STOP: "Uncommitted changes. Commit or stash first." |
| CHANGELOG missing | STOP: "CHANGELOG.md not found or missing [Unreleased] section" |
| CHANGELOG empty + commits exist | STOP: "Update CHANGELOG [Unreleased] before proceeding" |
| AGENTS.md violations | STOP: List violations, require fixes before release |
| User declines | STOP cleanly, no changes |
| Push fails | STOP: show error, suggest manual resolution |
Usage Examples
# NO ARGUMENTS - full auto mode
# Auto-detects: backlog, section, base branch, version, validates changelog
/skill:ac-tools-milestone
# With backlog and section (base branch auto-detected)
/skill:ac-tools-milestone specs/backlog.md 1.2
# Full release with all args
/skill:ac-tools-milestone specs/backlog.md 1.2 main v0.1.1-alpha
# With validation prompt
/skill:ac-tools-milestone specs/backlog.md 1.2 main v0.1.1-alpha "NoteMeta extended, parser exists, 20 tests pass"
# Without custom prompt (auto-detect from checklist)
/skill:ac-tools-milestone docs/roadmap.md 2.1 main v2.1.0
# Validate only, no version tag
/skill:ac-tools-milestone CHANGELOG.md phase-3 develop
# Quoted prompt without version
/skill:ac-tools-milestone specs/features.md 4.0 main "API endpoints implemented, auth working"
# Skip tag creation with --skip-tag flag
/skill:ac-tools-milestone specs/backlog.md 1.2 main --skip-tag
# Skip tag with validation prompt
/skill:ac-tools-milestone specs/backlog.md 1.2 main --skip-tag "All tests passing"
# Auto-detect mode without tags
/skill:ac-tools-milestone --skip-tag
# Autonomous mode (skip all confirmation gates)
/skill:ac-tools-milestone --auto
# Autonomous mode with skip-tag (used by orchestrators)
/skill:ac-tools-milestone --skip-tag --auto
# Include squashed commits in message (opt-in)
/skill:ac-tools-milestone --with-squashed-commits