| name | pipeline-shared |
| description | Shared pipeline stage procedures used by pipeline-feature, pipeline-bugfix, and pipeline-refactor skills. Not invoked directly — referenced by pipeline-specific skills as reusable building blocks for environment setup, testing, security scanning, documentation, commit/PR, code review, merge, and retrospective stages.
|
Shared Pipeline Procedures
These procedures are referenced by name from the pipeline-feature, pipeline-bugfix, and pipeline-refactor skills. Each procedure is a self-contained stage with its own quality gate.
CRITICAL: You MUST execute ALL stages in the pipeline, from first to last. Do NOT stop after Commit & PR. The Code Review, Test Verification, Review Verdict, Merge PR, and Retrospective stages are mandatory — they are not optional follow-ups. After creating a PR, immediately continue to Code Review.
Step 0: Initialize State File (FIRST THING)
This is the very first action in any pipeline — before Environment Check, before anything else.
mkdir -p .pipeline-state
- Copy the appropriate template from the pipeline-skill repo's
templates/ directory:
- Feature:
templates/feature-state.json
- Bugfix:
templates/bugfix-state.json
- Refactor:
templates/refactor-state.json
- Fill in:
task_description, branch_name, pr_target_branch, project_path, started_at (ISO 8601)
- Write to
.pipeline-state/<branch-name>.json
- Ensure
.pipeline-state/ is in .gitignore
If a state file already exists for this branch, this is a resume — read it, find the first stage that isn't passed, and skip to that stage.
This must happen first so that if the pipeline is interrupted at ANY point — even during stage 1 — the state file exists and resume is possible.
Pipeline State File (Resume Support)
Pipelines write progress to .pipeline-state/<branch-name>.json in the project root. This enables resuming after interruptions (context limit, crash, user stop).
State File Format
{
"pipeline_type": "feature",
"task_description": "Add health check endpoint",
"branch_name": "feat/add-health-check",
"pr_target_branch": "main",
"project_path": "/path/to/project",
"started_at": "2026-03-18T14:30:00Z",
"current_stage": 6,
"stages": {
"1": {"name": "Environment Check", "status": "passed", "verdict": "ENV_OK"},
"2": {"name": "Change Detection", "status": "passed", "verdict": "CODE_CHANGES"},
"3": {"name": "Conflict Check", "status": "passed", "verdict": "MERGE_CLEAN"},
"4": {"name": "Planning", "status": "passed"},
"5": {"name": "Implementation", "status": "passed"},
"6": {"name": "Test Execution", "status": "running"}
},
"pr_number": null,
"pr_url": null,
"rewind_count": 0
}
Initializing State
At pipeline start, copy the appropriate template from the pipeline-skill repo's templates/ directory:
templates/feature-state.json for feature pipelines
templates/bugfix-state.json for bugfix pipelines
templates/refactor-state.json for refactor pipelines
Fill in: task_description, branch_name, pr_target_branch, project_path, started_at.
Each stage has a checklist array of objects:
{"action": "post review to GitHub: gh pr review --comment", "done": false, "mandatory": true}
action — what to do
done — set to true when completed
mandatory — if true, this action must not be skipped (GitHub posting, verdicts, log persistence)
Stages with "run_as": "subagent" run as Agent tool subagents with fresh context.
Stages with "skip_if": "DOCS_ONLY" are skipped when Change Detection returned DOCS_ONLY.
mkdir -p .pipeline-state
Writing State
After each stage completes (pass or fail), update the state file:
- Set each checklist item's
done to true as you complete it
- Set the stage's
status to passed or failed
- Record the
verdict string
- Increment
current_stage to the next stage
- Save any extracted data (PR number, PR URL)
Before marking a stage as passed, verify all mandatory checklist items have done: true. If a mandatory item was skipped, go back and do it before proceeding.
Reading State (Resume)
At pipeline start, before Stage 1:
- Check for
.pipeline-state/<branch-name>.json
- If found, read it and determine the last completed stage
- Skip all completed stages — jump directly to the first incomplete stage
- Print a resume summary:
Resuming pipeline from Stage 6 (Test Execution)
Stages 1-5 completed previously. Branch: feat/add-health-check
- If the branch already exists with commits,
git checkout <branch> instead of creating fresh
Resume Rules
- Passed stages: Skip entirely — their work is already done
- Failed stages: Re-run from the failed stage (not from the beginning)
- Running stages: Treat as not started — re-run them
- Rewind state: If
rewind_count > 0, resume at the rewind target stage
- PR already created: Skip Commit & PR, jump to Code Review
Cleanup
When the pipeline completes (all stages passed) or is abandoned:
rm .pipeline-state/<branch-name>.json
Add .pipeline-state/ to .gitignore — state files should not be committed.
Stage Loop — The State File Drives the Pipeline
The state file is the program counter. Do not try to remember all stages from the skill text — the skill text WILL be compressed out of context during long runs. Instead, follow this loop:
The Loop (repeat until all stages are done):
1. READ the state file: .pipeline-state/<branch-name>.json
2. FIND the next stage where status != "passed"
3. READ that stage's checklist items — these are your instructions
4. EXECUTE each checklist item, marking done: true as you go
5. For items marked mandatory: true — you MUST complete these
6. WRITE the verdict and update the state file
7. GO TO step 1
Before each stage:
- Read the state file. If it doesn't exist, create it from the template NOW.
- Find the current stage (first non-
passed stage).
- Read its
checklist array — these are the specific actions for this stage.
- If the stage has
"run_as": "subagent", spawn it as a subagent via the Agent tool.
- If the stage has
"skip_if": "DOCS_ONLY" and Change Detection returned DOCS_ONLY, mark it passed and go to next.
After each stage:
- Mark each checklist item's
done field.
- Verify all
mandatory items are done: true — if any mandatory item is not done, go back and do it before proceeding.
- Set the stage's
status to passed or failed, record the verdict.
- Write the updated state file to disk.
- Continue the loop.
Gate rules:
- Explicit FAILED overrides PASSED: If output contains both
TESTS_PASSED and TESTS_FAILED, the result is FAILED.
- Retry: On first failure, retry once. If second attempt fails, follow the stage's failure action (stop or rewind).
- Rewind: Carry failure details as context. Re-plan/re-diagnose. Maximum 1 rewind per pipeline run.
Why this works:
The state file is re-read from disk at each stage boundary. Even if the skill text is fully compressed out of context, the state file on disk still has every stage and every checklist item. The agent just needs to follow the loop: read → find next → execute checklist → write → repeat.
Configuration Gathering
At the start of any pipeline, gather project context:
- Read CLAUDE.md in the project root (if it exists) for project conventions
- Detect or read from CLAUDE.md:
test_command — how to run tests (e.g., make test, pytest, npm test)
venv_path — virtual environment location (.venv/, venv/, etc.)
default_branch — main branch name (main, master, development)
pr_target_branch — branch PRs should target (usually same as default_branch)
build_command — how to build the project
lint_command — how to lint
- If CLAUDE.md doesn't specify these, auto-detect:
- Check for
Makefile targets (make test, make lint)
- Check for
pyproject.toml, package.json, Cargo.toml
- Check for
.python-version
- Check git remote for repo URL
Environment Check
Validate the project environment and create a fresh branch from upstream.
Steps
-
Git freshness: Create a fresh branch from the upstream target.
- Run
git fetch origin
- Determine the target branch: check for
pr_target_branch first, then default_branch, then try main, master, development
- Create a new task branch:
git checkout -B <task-branch> origin/<target_branch>
- This sets HEAD to the remote target — no stale history, no carry-over from previous branches
- Do NOT use
git reset --hard or git checkout -- . — these don't move HEAD
-
Python version: Run python --version or python3 --version. Verify compatibility with .python-version or pyproject.toml if present.
-
Virtualenv: Check for venv (.venv/, venv/, env/, or project-configured path). If none found, create one: python -m venv .venv.
-
Dependencies: Activate venv, run install command (pip install -e ., uv sync, pip install -r requirements.txt, or project-configured command).
-
Smoke test: Run a minimal import check (e.g., run the profile-configured smoke test command if set).
-
Gitignore audit: Check if .gitignore contains rules that would block adding new source files (e.g., a rule like components/ that matches src/*/components/). If found, note it so the Implementation stage can use git add -f for blocked paths. Common gotcha: overly broad directory rules that match nested source directories.
If any step fails, attempt to fix it before proceeding.
Gate
- Pass:
ENV_OK — environment is ready
- Fail:
ENV_FAILED — followed by details of what could not be fixed
- On failure: Retry once. If retry fails, stop the pipeline.
Conflict Check
Check the working tree for unresolved merge conflict markers.
Steps
- Run
git diff --check — exits non-zero if conflict markers exist
- Run
grep -rn '^<<<<<<< \|^=======\|^>>>>>>> ' . --include='*.py' --include='*.js' --include='*.ts' --include='*.html' --include='*.css' --include='*.json' --include='*.yaml' --include='*.yml' --include='*.md' 2>/dev/null | head -20
Gate
- Pass:
MERGE_CLEAN — no conflict markers found
- Fail:
MERGE_CONFLICTS_FOUND — followed by list of affected files
- On failure: Stop the pipeline immediately. Do NOT attempt to resolve conflicts — report them so they can be resolved manually.
Change Detection
Determine whether changes are code or documentation-only to enable conditional stage skipping.
Steps
Run: git diff --name-only origin/<target_branch>...HEAD 2>/dev/null || git diff --name-only HEAD~1 2>/dev/null
- If ALL changed files match
*.md → documentation only
- If any non-markdown files were changed → code changes
- If no changed files or branch cannot be determined → treat as code changes
Gate
- Output exactly one of:
DOCS_ONLY or CODE_CHANGES
- This verdict is used by downstream stages to conditionally skip (Test Execution, Self-Review, Security Check skip on DOCS_ONLY)
Test Execution
Run the project test suite and report results. Read-only — do NOT create or modify any source files.
Steps
- Identify the test command from Configuration Gathering
- Run the full test suite
- Report: total tests run, pass/fail counts, any failing test details, coverage summary if available
Constraints
- Do NOT create or modify any source files
- If tests fail due to missing modules or import errors, report them as failures — do NOT fix them
Gate
- Pass:
TESTS_PASSED — all tests pass
- Fail:
TESTS_FAILED — any tests fail
- On failure: Retry once (go back and fix the failing code, then re-run tests). If retry fails, stop the pipeline.
Security Check
Scan files changed by this task for security vulnerabilities. Pre-existing issues in unchanged files are reported as improvements, not failures.
Steps
-
Get changed files: git diff --name-only origin/<target_branch>...HEAD 2>/dev/null || git diff --name-only HEAD~1 2>/dev/null
— This is your scope. Only issues in these files can cause failure.
-
Scan changed files for these patterns:
- Hardcoded secrets, API keys, passwords
shell=True — command injection risk
- Raw SQL queries (string interpolation in SQL)
eval() or exec() with user-controlled input — even with restricted builtins
- Additional framework-specific patterns are loaded from the pipeline profile (e.g., Django profile adds
mark_safe, csrf_exempt, |safe checks)
-
Broad codebase scan (for context): grep the full codebase for the same patterns. Hits in files NOT in your scope are pre-existing — report as IMPROVEMENT: lines, do NOT let them influence your verdict.
Gate
- Pass:
SECURITY_PASSED — no issues in changed files
- Fail:
SECURITY_FAILED — followed by issues found in changed files only
- On failure: Retry once (fix the security issues, then re-scan). If retry fails, stop the pipeline.
For pre-existing issues in unchanged files, output each as:
IMPROVEMENT: Security: <brief description of issue and file>
Important: Use the Agent tool to run this as a subagent for independent evaluation with clean context.
Scope discipline — leave pre-existing lint untouched (#5)
The same "changed files / changed lines only" rule that governs the security
scan governs lint and formatting: a scoped PR fixes only the lint it
introduces, not pre-existing warnings in code it happens to touch or sit near.
- If the project lint command (Self-Review stage) reports warnings, fix only
those attributable to this PR's diff. A warning on a line the PR did not
change is pre-existing — report it as
IMPROVEMENT: Lint: <file:line>,
do NOT fix it in this PR, and do NOT let it fail the gate.
- Bulk-fixing unrelated lint balloons the diff, breaks the batch-size limit,
and buries the real change under noise the reviewer can't separate from it.
- If pre-existing lint is worth fixing, that's a separate scoped pass — file it
via the normal capture channel (retro
IMPROVEMENT: line → tech-debt issue →
/pipeline-drain), exactly like the "capture what's out of scope" rule.
This mirrors the security stage's pre-existing-issue handling above: capture,
don't block, don't sprawl.
Documentation
Ensure all user-facing and developer documentation is complete, accurate, and well-structured for the changes made.
Steps
1. Discover the project's docs structure
Look for a documentation directory — common locations:
docs/ with a README.md index (organized by topic with guides/, components/, etc.)
docs/ with mkdocs/sphinx config
- Top-level
README.md only
Read the docs index (e.g., docs/README.md) to understand how documentation is organized. This tells you where new docs should go and what existing docs need updating.
2. Code-level documentation
- Docstrings: Add or update docstrings for all new/modified public classes, methods, and functions
- Type annotations: Ensure public APIs have type hints (they serve as documentation)
- Inline comments: Add comments only where logic isn't self-evident
3. User-facing documentation
For new features or significant changes, determine what documentation users need:
Guide or reference page — Does this feature need its own doc?
- New user-facing feature (attribute, decorator, mixin, command) → YES, create a guide
- Place it in the appropriate docs subdirectory (e.g.,
docs/guides/ for how-to guides)
- Follow the existing docs style and structure (check 2-3 nearby docs for conventions)
- Include: what it does, when to use it, API/usage, example code, common patterns
Existing docs update — Does this change affect an existing doc?
- Search docs for references to the feature area you changed
- Update any outdated examples, API references, or descriptions
- If a guide covers the area you modified, update it to reflect the new behavior
Docs index — If you created a new doc page, add it to the docs index/README under the appropriate section with a one-line description.
4. Component gallery / discovery
If the project has a component gallery or auto-discovery system:
- Add gallery examples for new components
- Update discovery tests if they hardcode expected component lists
- Verify the gallery renders new components correctly (if a
--dry-run flag exists, use it)
4.5. Enumerated-unit inventories (commonly missed — applies even for DOCS_ONLY)
If this change adds, renames, or removes a user-facing unit that is enumerated somewhere else — a skill, a CLI subcommand, a slash command, a plugin, a make target, a public API in a "supported X" list — then every inventory/index surface that lists its siblings also needs updating. These surfaces are the single most commonly-missed documentation update, because the new unit works immediately (it's auto-discovered by a glob/registry) while the human-facing lists silently go stale.
Find them mechanically: grep the repo for the name of an existing sibling unit across non-source files, and update every file that lists it.
grep -rIl --exclude-dir=.git "pipeline-drain" . | grep -v '^\./skills/'
A DOCS_ONLY classification does not exempt this step — adding a skill is itself a docs-only change, yet it must update three separate inventories. If the unit you changed is enumerated in N places, all N must change together or the docs drift one file at a time.
5. CHANGELOG
For feat: and fix: changes:
- Update
CHANGELOG.md (if the project has one)
- Add an entry under the current/unreleased version section
- Follow the existing format (typically:
- **Feature name** — description (#issue))
6. CLAUDE.md / project config
If the change introduces:
- New conventions, patterns, or architectural decisions
- New commands, make targets, or scripts
- New project structure (directories, key files)
Suggest updating CLAUDE.md to reflect these (note in your output, don't modify CLAUDE.md directly unless the pipeline is for that project).
7. ADR status reconciliation
If the project keeps Architecture Decision Records (docs/adr/,
docs/decisions/, or similar) and this PR ships a feature an ADR
proposed:
- Flip that ADR's
**Status**: from Proposed (or Accepted) to a
shipped marker — e.g. Accepted — shipped in <version> (PR #NNNN).
- Replace any
**Target version**: line with the actual shipped
version (**Shipped in**: <version>).
An ADR left at Proposed after its feature ships drifts silently — a
later reader can't distinguish proposed-but-unbuilt from built-and-
shipped. Flip it at the moment the feature lands, not at release time.
If the project has an ADR-status audit (e.g. make check-adr-status),
run it and confirm it passes.
8. Quality checks
- No orphaned docs — if you renamed/removed a feature, remove or redirect its docs
- No broken internal links — verify
[link text](path) references are valid
- Examples compile/run — code examples should be accurate and tested
- Consistent terminology — use the same names the code uses
Gate
Commit & PR
Create a branch, commit changes, push, and create a pull request.
Steps
-
Remote check: Run git remote -v
- If remote URL contains github.com, proceed normally
- If no remote or local/file-based remote, output
PR_SKIPPED: no GitHub remote configured and stop
-
Checkout/create branch: git checkout <branch-name> 2>/dev/null || git checkout -b <branch-name>
-
Pull if exists: git pull --rebase origin <branch-name> 2>/dev/null || true
-
Stage tracked changes: git add -u
-
Check for conflict markers: git diff --check — must be clean. If conflicts found, resolve them first.
-
Stage new files explicitly (do NOT stage .env, credentials, or secrets)
-
Commit with conventional commit format:
- Features:
feat: <description>
- Bug fixes:
fix: <description>
- Refactors:
refactor: <description>
- Docs:
docs: <description>
-
Push: git push -u origin <branch-name>
-
Create PR: gh pr create --base <pr_target_branch> --title "<type>: <description>" --body '<summary>'
-
Verify PR body: Re-read the PR description against git diff <pr_target_branch>...HEAD --stat. The PR body must not mention features, template tags, error codes, or APIs that don't exist in the diff. Must not cite incorrect test counts or file counts, or use terminology that contradicts the code. If discrepancies are found, fix with gh pr edit <pr_number> --body '<corrected body>'.
-
Substitute #TBD PR-number placeholders (#6): when a committed docs change (ROADMAP/RETRO/CHANGELOG entry, or in-repo doc) needs to reference this PR, you can't know the number until after gh pr create. Write the placeholder #TBD (or PR #TBD) in the commit, then after the PR exists substitute the real number and amend:
bash scripts/substitute-pr-number.sh <pr_number> <file> [file ...]
git add -u && git commit --amend --no-edit && git push --force-with-lease
The script is portable (bash 3.2 / BSD sed) and rejects a non-numeric argument. Files are explicit by design: the #TBD marker also appears as prose (e.g. a ROADMAP entry describing this feature), which must not be rewritten. This avoids the manual find-replace that otherwise leaves stale #TBD markers in merged docs.
Gate
- Pass:
PR_CREATED: <full PR URL> or PR_EXISTS: <full PR URL> or PR_SKIPPED: <reason>
- Fail: Stop the pipeline if push or PR creation fails unexpectedly
Code Review
Review the code changes in the current branch against the base branch.
IMPORTANT: This stage is mandatory. Do not skip it or stop the pipeline before reaching it.
Steps
- Run
git diff <pr_target_branch>...HEAD to see all changes
- Read changed files for full context where needed
- Check for a project PR checklist: Look for
docs/PULL_REQUEST_CHECKLIST.md, PULL_REQUEST_CHECKLIST.md, or .github/PULL_REQUEST_TEMPLATE.md in the project root. If found, use it as the primary review framework.
Environment premises (read before reviewing)
A reviewer runs with fresh context and will otherwise re-derive — or
silently miss — facts about repo state, producing false positives.
Treat these as given, and when this stage runs as a subagent, include
this brief in the subagent prompt so the reviewer doesn't have to
guess:
- CHANGELOG may be intentionally absent from the diff. Projects
using the two-commit shape land implementation+tests in one commit
and docs+CHANGELOG in a separate later commit. If a Documentation
stage is still pending in the state file, "CHANGELOG missing" is not
a defect — do not flag it.
- The branch base may be stale. A branch opened many commits ago
has its
git diff <base>...HEAD computed against an old base, which
is a different program than the merge will apply. Run
git fetch origin && git rev-list --count HEAD..origin/<base> — if
non-zero, state that the branch needs a rebase before the review is
trustworthy, rather than reviewing a stale diff.
- Some paths are intentionally gitignored (e.g.
.claude/,
generated artifacts, user-private config). A file "missing" because
it is gitignored is not a defect — verify with git check-ignore
before flagging an absent file.
Review Categories
Correctness:
- Logic errors, edge cases, off-by-one errors
- Test-implementation alignment: tests actually import and exercise code in the diff
- Import names match shipped code (no phantom modules or renamed APIs)
- No placeholder/stub implementations (
return True, hardcoded fake data, simulated APIs)
- No comments indicating incomplete code ("simulate", "would be implemented", "for now")
Testing:
- New features have tests; bug fixes have regression tests
- New JS feature files have corresponding test files
- Tests are deterministic (no flaky tests)
- All untracked files that tests depend on are included in the diff
- Edge cases covered (error conditions, boundary cases)
- Frame-sensitive behavior — anything whose correctness depends on the
caller's stack frame (deprecation-warning
stacklevel, traceback
depth, logger stacklevel) — has a test that asserts the frame the
warning/error points at, written at implementation time, not bolted
on in review. A change touching such a call site without that test
is a finding.
Security:
- No XSS, SQL injection, CSRF bypass, or secrets exposure
- Check profile-specific security patterns
Code Quality:
- No
print() statements — use the project's logging system
- No silent exception handling (
except: pass)
- Exception chaining (
raise X from e)
- Appropriate log levels (error/warning/info/debug)
exc_info=True for exception logging
Documentation:
- CHANGELOG.md updated for
feat: and fix: PRs
- Public APIs documented with docstrings
- No internal tracking documents committed to repo
- Breaking changes documented with migration path
Performance:
- Database query efficiency (if applicable)
- No memory leaks or excessive allocations
- Caching for expensive operations where appropriate
Architecture:
- Follows project patterns and conventions
- Single responsibility — focused functions and classes
- No code duplication — shared logic properly abstracted
Auto-Reject Triggers
Flag as critical if any of these are found:
print() instead of logging
- Silent exception handling (
except: pass)
- No tests for new functionality
- Tests reference modules/APIs that don't exist in the diff
- Placeholder/stub code shipped as production
- Additional auto-reject triggers from the pipeline profile
For each finding, include: file and line number, severity (critical/warning/suggestion), description, suggested fix.
Post Review to GitHub PR
If a PR number is available, post the review as a GitHub PR review:
For inline comments on specific files/lines, use:
gh api repos/{owner}/{repo}/pulls/{pr_number}/reviews \
--method POST \
-f body='## Automated Code Review\n\n<summary>' \
-f event='COMMENT' \
-f 'comments[][path]=<file>' \
-f 'comments[][line]=<line>' \
-f 'comments[][body]=<finding>'
For a general review comment (simpler, always works):
gh pr review <pr_number> --comment --body "$(cat <<'REVIEW'
## Automated Code Review
### Summary
<one paragraph summary>
### Findings
<categorized findings with file:line references>
### Checklist
- [x] Tests pass
- [x] No auto-reject triggers
- [ ] CHANGELOG updated (if applicable)
...
### Verdict
APPROVE / REQUEST_CHANGES / COMMENT
REVIEW
)"
Choose the approach based on findings:
- If you have specific line-level findings → use the inline comments API for the most useful ones, plus a summary review
- If findings are general → use the simple review comment
- Always include a checklist summary showing what was checked
Save Review Locally
Also save the review to pr/feedback/pr-<number>-<short-description>.md if the project has a pr/feedback/ directory.
Gate
- Output
REVIEW_COMPLETE — this stage always passes (informational)
- Critical findings will be evaluated in the Review Verdict stage
Test Verification
Re-run the test suite after PR creation to catch integration issues.
Steps
Same as Test Execution — run the full test suite, report results.
Gate
- Pass:
TESTS_PASSED
- Fail:
TESTS_FAILED
- On failure: Retry once. If retry fails, stop the pipeline.
Review Verdict
Synthesize all findings from Code Review and Test Verification into a final verdict.
IMPORTANT: This stage is mandatory. Do not skip it.
Decision Logic
- If any auto-reject triggers were found in Code Review →
REQUEST_CHANGES
- If tests failed in Test Verification →
REQUEST_CHANGES
- If only non-blocking suggestions →
APPROVE or COMMENT
- If
REQUEST_CHANGES: go back and fix the critical issues before proceeding to Merge
Output Structure
## Summary
One-paragraph summary of the PR quality.
## Checklist Compliance
(list auto-reject items checked and their pass/fail status)
## Verdict
APPROVE / REQUEST_CHANGES / COMMENT
## Critical Issues
(list any blocking issues, empty if APPROVE)
## Suggestions
(non-blocking improvements)
## Test Results
(summary of test pass/fail status)
Output exactly one of: APPROVE, REQUEST_CHANGES, or COMMENT on its own line as the final verdict.
Post Verdict to GitHub PR
Submit the verdict as a GitHub PR comment:
- If
APPROVE: gh pr comment <pr_number> --body '## ✅ Review Verdict: APPROVED\n\n<verdict summary>'
- If
REQUEST_CHANGES: gh pr review <pr_number> --request-changes --body '<verdict with critical issues>'
- If
COMMENT: gh pr comment <pr_number> --body '## Review Verdict: COMMENT\n\n<verdict with suggestions>'
Note: Do NOT use gh pr review --approve — GitHub blocks self-approval on PRs you authored. Use gh pr comment for approvals instead.
If REQUEST_CHANGES: fix the issues, then re-evaluate. Only proceed to Merge PR when verdict is APPROVE.
Merge PR
Approve and merge the pull request.
Steps
- Verify CI: Run
gh pr checks <pr_number>. All checks must pass before merging.
- If CI is failing due to changes in this PR, do NOT merge — go back and fix the issue.
- If CI is failing due to pre-existing issues (not introduced by this PR), document it in a PR comment (
gh pr comment <pr_number> --body 'CI note: <description of pre-existing failure>') and proceed.
- Note on
gh pr checks field names: gh pr checks --json exposes status as .state (values: SUCCESS, FAILURE, PENDING), NOT .conclusion. Polling loops like until [ "$(gh pr checks N --json conclusion ...)" != "" ] will run forever silently because the field is always empty. Use .state for PR-level checks. (Distinct from gh run view --json, which DOES use .conclusion.)
0.5. Verify the PR is not still a draft: Run gh pr view <pr_number> --json isDraft -q .isDraft. If true, gh pr merge will fail with GraphQL: Pull Request is still a draft (mergePullRequest).
- If the PR is intentionally a draft (user wants
--no-merge semantics), stop here.
- Otherwise, mark it ready:
gh pr ready <pr_number>. Observed cost: max-companion PR #10 merge tripped on this; saved by manual gh pr ready 10. The skill catches it now so the merge step doesn't fail at the gate.
- Merge:
gh pr merge <pr-number> --squash --delete-branch
- Note: Do NOT run
gh pr review --approve — GitHub blocks self-approval on PRs you authored. The review comment from the Code Review stage serves as the review record.
Gate
- Pass:
PR_MERGED
- Fail:
MERGE_FAILED — followed by error details
- On failure: Retry once. If retry fails, stop the pipeline.
Retrospective
Review the pipeline execution and provide feedback for continuous improvement.
Steps
- Get PR details:
gh pr view <pr_number> --json commits,title,body,mergedAt (the branch may have been deleted by squash merge — do NOT rely on git log <target>..HEAD)
- Rate the execution quality (1-5)
- What went well?
- What could improve? (prompt quality, stage ordering, quality gates)
- Lessons learned — insights about the codebase, architecture, or process
- Suggest follow-up tasks if needed
- Output improvement ideas as
IDEA: lines — one per line:
IDEA: Add retry backoff to reduce flaky test failures
IDEA: Split large prompts into focused sub-prompts
- If you created useful scripts or tools, output as:
TOOL: name | language | one-line description
Be concise. Focus on actionable improvements.
Important: Use the Agent tool to run this as a subagent for independent evaluation with clean context.
Persist Retrospective Output
Retrospective insights are valuable across pipeline runs. Save them to three places:
1. Pipeline Log (per-task record)
Append to .pipeline-log.md in the project root:
## <branch-name> — <date>
**Task**: <task description>
**PR**: #<number> — <status>
**Quality**: <rating>/5
**Duration**: <stages completed> stages
### What Went Well
- <bullet points>
### Lessons Learned
- <bullet points>
### Pipeline Improvements
- <IDEA: lines>
### Follow-up Tasks
- <if any>
---
This creates a running history of all pipeline executions on the project. Add .pipeline-log.md to .gitignore.
2. GitHub PR Comment
Post a retrospective summary as a comment on the PR (even if already merged):
gh pr comment <pr_number> --body "$(cat <<'RETRO'
## Pipeline Retrospective
**Quality**: <rating>/5
**What went well**: <summary>
**Lessons learned**: <summary>
**Suggested improvements**: <IDEA lines>
RETRO
)"
This keeps the retrospective attached to the PR for future reference.
Check if the project has a docs/LESSONS_LEARNED.md or similar file and append there. If not, the pipeline log and PR comment are sufficient — do not create new documentation files.
Edge Case Checklist
Before marking implementation complete, verify handling of:
- Null/None/empty values in all inputs
- Circular references (if working with recursive data structures)
- Boundary conditions (empty collections, single items)
- Concurrent access (if modifying shared state)
Note any edge cases found and how you handled them.
Clean Git State
Before finishing implementation, you MUST:
- Resolve any merge conflict markers (
git diff --check — must return clean)
- Stage all changes:
git add -u
- Stage any new files explicitly:
git add <new_file>
- Verify:
git status must show no untracked/unstaged changes relevant to the task
The Commit & PR stage expects a clean, fully-staged working tree.