merger
Skill1 starsChanged 3 months agoMITView on GitHub
Multi-issue integration and merge skill - handles post-QA integration of completed worktrees
- Commits and pushes
1 other project uses a version of this.
Adopted by
Most recently taken up by
- Victorcorcos/skillstheir own version, first seen Jun 12, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- Victorcorcos/skills★ 7same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
Show its rules and text
We split this skill into the rules it gives an agent
19 rules. About 0 are common, 13 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈13
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 42
When invoked as /merger <issue-numbers>, you:
- Distinctive: line 49
Run post-merge smoketest with regression comparison against baseline
- Very specific: line 54
Before running /merger, use sequant merge --check to catch cross-issue gaps at zero AI cost:
- Distinctive: line 94
When processing multiple issues, determine the execution mode for validation checks:
- Distinctive: line 101
Use the Read tool to check project settings:
- Very specific: line 159
Orchestrator/MCP mode: when SEQUANT_ORCHESTRATOR is set, every locks checkout action is a no-op (exit 0, no file touched) and the …
- Very specific: line 170
Session caching: If baseline has already been captured in this /merger invocation (e.g., when merging multiple issues), reuse the cached …
- Distinctive: line 241
Before merging, check which issues the PR will actually close on merge — GitHub parses closing keywords anywhere in the body, so this can …
- Very specific: line 287
Stop and report, naming the issue,: if the list contains any number not in $expected.
- Distinctive: line 319
If overlapping files found:
- Distinctive: line 559
If smoketest checks fail but are NOT regressions (same count as baseline), report as pre-existing:
- Distinctive: line 572
If smoketest checks fail AND are regressions, report with diagnostic commands:
- Distinctive: line 628
Rule: if merge ordering requires a PR whose issue number is not in the invocation's arg list, halt before merging anything and report it — …
- Distinctive: line 661
If dependencies found, enforce merge order among the named set.
- Distinctive: line 683
Treat the order in the manifest as the merge order — earlier entries land first.
- Very specific: line 684
If every predecessor is in the named set but requested out of order (e.g.
- Distinctive: line 777
Do not proceed with merge
- Distinctive: line 781
Create a draft PR with conflicts marked
- Distinctive: line 786
Keep integration branch for debugging
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- sequant:local-override -->Local overrides (read this first). Before following any instruction below, check whether
.claude/.local/skills/merger/overrides.mdexists. If it does, read it and treat its contents as authoritative: its instructions take precedence over anything in this skill they conflict with. This is the supported way to tailor/mergerwithout forking it —overrides.mdlives under.claude/.local/, whichsequant updateandsyncnever overwrite.
Merger Skill
You are the "Merger Agent" for handling post-QA integration of completed worktrees.
Purpose
When invoked as /merger <issue-numbers>, you:
- Capture baseline metrics on main (build errors, test counts)
- Validate QA status for all specified issues
- Detect file conflicts between worktrees
- Generate integration branches for incompatible changes
- Respect dependency ordering
- Clean up worktrees after successful merge
- Run post-merge smoketest with regression comparison against baseline
- Provide detailed merge reports
Recommended Pre-Merge Check
Before running /merger, use sequant merge --check to catch cross-issue gaps at zero AI cost:
sequant run 10 11 12 # implement
sequant merge --check # verify (deterministic checks)
/merger 10 11 12 # merge (this command)sequant merge detects merge conflicts, template mirroring gaps, file overlaps, and residual patterns before /merger attempts the actual merge. See docs/reference/merge-command.md for details.
Usage
# Merge single issue
/merger 10
# Merge multiple issues (detects conflicts, creates integration if needed)
/merger 10 12
# Merge with dependency ordering
/merger 10 12 --order=dependency
# Dry run - show what would happen
/merger 10 12 --dry-run
# Force parallel validation of multiple issues (faster, higher token usage)
/merger 10 12 --parallel
# Force sequential validation (slower, lower token usage)
/merger 10 12 --sequential
# Skip post-merge smoketest
/merger 10 12 --skip-smoketest
# Force merge even if regression is detected (bypasses regression gate)
/merger 10 12 --forceAgent Execution Mode
When processing multiple issues, determine the execution mode for validation checks:
- Check for CLI flag override:
--parallel→ Validate all issues in parallel (spawn agents simultaneously)--sequential→ Validate issues one at a time
- If no flag, read project settings:
Use the Read tool to check project settings:
Read(file_path=".sequant/settings.json") # Parse JSON and extract agents.parallel (default: false) - Default: Sequential (cost-optimized)
| Mode | Token Usage | Speed | Best For |
| Sequential | 1x (baseline) | Slower | Limited API plans, 1-2 issues |
| Parallel | ~Nx (N=issues) | ~50% faster | Unlimited plans, batch merges |
Workflow
Acquire the Checkout Lock (REQUIRED)
/merger runs branch-mutating git in the main checkout: git checkout main
for the baseline in Step 0, then git checkout -b integrate/… and git merge on
the integration path (Step 5), plus the mid-workflow git checkout main in
Steps 6–7. Those verbs are global to the working tree, so before the first one
you must claim the checkout lock (#901), exactly as /fullsolve does in its
Phase 0.3. Without it a session on another issue can interleave a git checkout
and land a merge on the wrong HEAD; and because the guard refuses a non-holder,
an unparticipating /merger is itself refused when someone else holds the tree.
/merger operates on several issues, so identify the holder by the first issue
number passed to it and use that same <first-issue> on the acquire and on
every release below — acquire and release must name the same holder or the
release is refused against your own lock (#906). Substitute the literal number
(e.g. --issue=10 for /merger 10 12); a shell variable is invisible to the
pre-tool.sh guard, which reads the command text before the shell expands it.
# Claim the shared working tree before the first branch-mutating verb.
npx sequant locks checkout acquire \
--issue=<first-issue> \
--command="/merger <issue-numbers>" \
--skip-pid-check || true
# Belt-and-suspenders for a parent that launched us with it; the guard's real
# binding comes from watching the acquire command above (#906).
export SEQUANT_ISSUE=<first-issue>--issue is mandatory (#906): it is what proves you are the holder on
release, since the acquiring shell's PID is gone by the next block
(--skip-pid-check). Stale recovery is therefore age-based only (the 6h
SEQUANT_SKILL_LOCK_TTL_MS and the 24h SEQUANT_MAX_LOCK_AGE_MS ceiling), not
same-host dead-PID recovery.
Release contract: release the checkout lock —
npx sequant locks checkout release --issue=<first-issue> || true — on every
path that exits /merger: happy-path completion (Step 8), the regression-gate
halt (Step 7), and any error/abort in "Error Handling". Do NOT release on a
branch that continues to a later branch-mutating verb (the #906 distinction):
the integration git merge in Step 5 and the git checkout main in Steps 6–7
run under the lock and must stay protected until the run ends.
Orchestrator/MCP mode: when SEQUANT_ORCHESTRATOR is set, every locks
checkout action is a no-op (exit 0, no file touched) and the pre-tool.sh
checkout guard stands down, so the acquire/release calls are safe to run
unconditionally.
Step 0: Baseline Capture (REQUIRED)
Purpose: Capture build error count and test pass/fail counts on main before any merge, so post-merge results can be compared to detect regressions.
Skip if: --skip-smoketest flag is set (no comparison needed if smoketest is skipped).
Session caching: If baseline has already been captured in this /merger invocation (e.g., when merging multiple issues), reuse the cached values instead of re-running build and tests.
# Check if baseline is already cached (multi-issue merge scenario)
if [[ -n "$BASELINE_BUILD_ERRORS" && -n "$BASELINE_TEST_FAILURES" ]]; then
echo "♻️ Using cached baseline metrics (captured earlier in this session)"
echo " Build errors: $BASELINE_BUILD_ERRORS"
echo " Test failures: $BASELINE_TEST_FAILURES"
echo " Test passes: $BASELINE_TEST_PASSES"
else
echo "📊 Capturing baseline metrics on main..."
# Ensure we're on main with latest changes
git checkout main
git pull origin main
# 1. Capture build error count
build_output=$(npm run build 2>&1 || true)
BASELINE_BUILD_ERRORS=$(echo "$build_output" | grep -c "error TS" || true)
echo " Baseline build errors: $BASELINE_BUILD_ERRORS"
# 2. Capture test pass/fail counts
test_output=$(npm test 2>&1 || true)
# Parse vitest output format: "Tests X passed | Y failed" or "Tests X passed"
# Use tail -1 to get the Tests line (not Test Files line) from vitest output
BASELINE_TEST_PASSES=$(echo "$test_output" | grep -oE '[0-9]+ passed' | tail -1 | grep -oE '[0-9]+' || echo "0")
BASELINE_TEST_FAILURES=$(echo "$test_output" | grep -oE '[0-9]+ failed' | tail -1 | grep -oE '[0-9]+' || echo "0")
echo " Baseline test passes: $BASELINE_TEST_PASSES"
echo " Baseline test failures: $BASELINE_TEST_FAILURES"
echo "✅ Baseline captured"
fiOutput format (include in merge report):
### Baseline Metrics (main before merge)
| Metric | Count |
|--------|-------|
| Build errors (TS) | $BASELINE_BUILD_ERRORS |
| Test passes | $BASELINE_TEST_PASSES |
| Test failures | $BASELINE_TEST_FAILURES |Step 1: Pre-Merge Validation
For each issue specified:
# Find the worktree for the issue. Resolve by branch (#899/#904) — grepping
# for "feature/$ISSUE" is a prefix match, so ISSUE=89 also hits feature/899-*.
worktree_path=$(npx sequant worktree resolve "$ISSUE") || echo "No worktree for #$ISSUE"
# Check PR status
gh pr list --head "feature/$ISSUE-*" --json number,state,title
# Verify worktree exists and has commits
git -C <worktree-path> log --oneline origin/main..HEADValidation checklist:
- Worktree exists for the issue
- PR exists (or will be created)
- Changes have been committed
- No uncommitted work
Step 1a: Closing-Reference Guard (#1197)
Before merging, check which issues the PR will actually close on merge — GitHub parses closing keywords anywhere in the body, so this can diverge from what the PR is supposed to close (a tracker issue mentioned in an AC table, or a multi-PR issue where only the last PR should close it):
# `gh pr view --json closingIssuesReferences` is not a recognized field on
# gh CLI ≤ 2.66 ("Unknown JSON field") — the REST PR payload doesn't carry
# it either. Query the GraphQL field directly; `{owner}`/`{repo}` resolve
# from the current repo the same way they do in REST `gh api` calls.
gh api graphql -f query='
query($owner:String!,$repo:String!,$pr:Int!){
repository(owner:$owner,name:$repo){
pullRequest(number:$pr){closingIssuesReferences(first:10){nodes{number}}}
}
}' -F owner='{owner}' -F repo='{repo}' -F pr=<PR_NUMBER> \
--jq '.data.repository.pullRequest.closingIssuesReferences.nodes[].number'Work out which issues this PR is allowed to close. In refs mode, or when the issue carries the no-autoclose label, the answer is none: the PR's own issue must not close either.
# settings.json is JSONC (`sequant init` writes whole-line // comments), so
# strip those before jq. Only whole-line comments: values such as devUrl
# contain "//".
settings_json='{}'
if [ -f .sequant/settings.json ]; then
settings_json=$(sed -E 's#^[[:space:]]*//.*$##' .sequant/settings.json)
fi
if link=$(printf '%s' "$settings_json" | jq -er '.run.prIssueLink // "closes"') &&
no_close_label=$(printf '%s' "$settings_json" | jq -er '.run.prNoCloseLabel // "no-autoclose"'); then
labels=$(gh api "repos/{owner}/{repo}/issues/<issue-number>" --jq '.labels[].name')
if [ "$link" = "refs" ] || printf '%s\n' "$labels" | grep -qxF "$no_close_label"; then
expected="" # nothing may close
else
expected="<issue-number>" # only the PR's own issue
fi
else
# Fail closed: an unreadable settings file must not quietly mean "closes".
echo "⚠️ Could not parse .sequant/settings.json; treating every closing reference as unexpected." >&2
expected=""
fiStop and report, naming the issue, if the list contains any number not in
$expected. In refs/label mode that includes <issue-number> itself; that
is the case this guard exists for:
❌ PR #<PR_NUMBER> closes #<unexpected-number> on merge.
Allowed to close here: #<issue-number> (or nothing, in refs/no-autoclose mode).
Edit the PR body to change that reference to "Refs #<unexpected-number>"
before merging.A list that contains only numbers in $expected (or an empty list) is fine,
so proceed to Step 2.
Step 2: Conflict Detection
Get files changed in each worktree:
# For each worktree
git -C <worktree-path> diff --name-only origin/main...HEADFind overlapping files:
# Compare file lists between worktrees
comm -12 <(sort files_issue1.txt) <(sort files_issue2.txt)Step 3: Conflict Analysis
If overlapping files found:
- Semantic analysis: Are the changes compatible?
- Additive changes (new functions) -> likely compatible
- Same function modified -> likely incompatible
- Same file, different sections -> may be compatible
- Generate merge preview:
git merge-tree $(git merge-base main branch1) branch1 branch2
Step 4: Resolution Strategy
| Scenario | Action |
| No conflicts | Merge sequentially |
| Compatible changes | Auto-merge with verification |
| Incompatible changes | Generate unified implementation in integration branch |
| True dependency | Enforce merge order |
Step 5: Merge Execution
For clean merges (no conflicts):
# Merge PR first (without --delete-branch to avoid worktree lock conflicts)
gh pr merge <PR_NUMBER> --squash
# Only clean up worktree AFTER merge succeeds
# If merge fails, the worktree is preserved so work isn't lost
#
# Resolve by BRANCH, never by grepping the printed path (#899/#904): the path
# line contains the directory slug, so `grep "feature/$ISSUE"` with ISSUE=89
# also matches `feature/899-...` — and the next line force-removes whatever it
# matched. `worktree resolve` matches the branch's issue number exactly, and
# exits non-zero rather than guessing when nothing (or more than one) matches.
if worktree_path=$(npx sequant worktree resolve "$ISSUE"); then
branch=$(git -C "$worktree_path" rev-parse --abbrev-ref HEAD)
git worktree remove "$worktree_path" --force
git branch -D "$branch" 2>/dev/null || true
fi
# Delete remote branch (previously handled by --delete-branch)
gh api repos/{owner}/{repo}/git/refs/heads/$(gh pr view <PR_NUMBER> --json headRefName --jq '.headRefName') -X DELETE 2>/dev/null || true
# State is tracked by the orchestrator runtime when availableFor conflicting changes (integration branch):
# Create integration branch
git checkout -b integrate/<issue1>-<issue2>-<description> main
# Cherry-pick or merge each worktree's changes
git merge feature/<issue1>-* --no-commit
# Resolve conflicts...
git add .
git commit -m "feat: Integrate #<issue1> changes"
git merge feature/<issue2>-* --no-commit
# Resolve conflicts...
git add .
git commit -m "feat: Integrate #<issue2> changes"
# Run tests on integration branch
npm test
npm run build
# Create integration PR
gh pr create --title "feat: Integrate #<issue1> and #<issue2>" --body "..."Step 6: Post-Merge Verification
After successful merge:
# Pull merged changes to main
git checkout main
git pull origin main
# Verify worktree was cleaned up
git worktree list # Should not show the merged feature branch
# Remote branch is deleted explicitly after merge (see Step 5)
# REQUIRED: Verify state was updated (#305)
# The state should show status="merged" for the issue
# Use the Read tool to check state, then parse JSON
Read(file_path=".sequant/state.json")
# Verify the issue status shows "merged"Step 6a: Worktree Cleanup After Merge (REQUIRED - #305)
After each successful merge, ensure the worktree is removed:
# Find and remove worktree for the issue.
# Resolve by branch, not by grepping the printed path — see the note in the
# clean-merge block above. This one force-removes, so a slug collision here
# destroys an unrelated issue's worktree.
if worktree_path=$(npx sequant worktree resolve "$ISSUE"); then
echo "Removing worktree: $worktree_path"
git worktree remove "$worktree_path" --force
else
echo "No worktree found for #$ISSUE (already cleaned up)"
fi
# Verify worktree removal — resolve must now fail for this issue.
if npx sequant worktree resolve "$ISSUE" >/dev/null 2>&1; then
echo "WARNING: Worktree still exists"
else
echo "✅ Worktree removed"
fiWhy this matters: Leftover worktrees waste disk space and can cause confusion when re-running sequant run on the same issues. The state guard (#305) prevents re-execution, but the worktree should still be cleaned up.
Step 7: Post-Merge Smoketest with Regression Comparison
Skip if: --skip-smoketest flag is set or SEQUANT_MERGER_SKIP_SMOKETEST environment variable is true.
# Check skip flag
if [[ "$SKIP_SMOKETEST" == "true" ]]; then
echo "⏭️ Smoketest skipped (--skip-smoketest flag set)"
# Continue to output report
fiAfter all merges complete and worktrees are cleaned up, verify main is healthy and compare against baseline:
# 1. Ensure we're on main with latest changes
git checkout main
git pull origin main
# 2. Build verification — capture post-merge error count
echo "Running build..."
post_build_output=$(npm run build 2>&1); build_exit=$?
POST_BUILD_ERRORS=$(echo "$post_build_output" | grep -c "error TS" || true)
# 3. Test suite — capture post-merge test counts
echo "Running tests..."
post_test_output=$(npm test 2>&1); test_exit=$?
POST_TEST_PASSES=$(echo "$post_test_output" | grep -oE '[0-9]+ passed' | tail -1 | grep -oE '[0-9]+' || echo "0")
POST_TEST_FAILURES=$(echo "$post_test_output" | grep -oE '[0-9]+ failed' | tail -1 | grep -oE '[0-9]+' || echo "0")
# 4. CLI health check (if sequant CLI is available)
echo "Running CLI health check..."
npx sequant doctor 2>&1 || true
doctor_exit=$?
# 5. Regression comparison against baseline
REGRESSION_DETECTED=false
BUILD_DELTA=$((POST_BUILD_ERRORS - BASELINE_BUILD_ERRORS))
TEST_FAIL_DELTA=$((POST_TEST_FAILURES - BASELINE_TEST_FAILURES))
TEST_PASS_DELTA=$((POST_TEST_PASSES - BASELINE_TEST_PASSES))
if [[ $BUILD_DELTA -gt 0 ]]; then
echo "❌ REGRESSION: $BUILD_DELTA new build error(s) introduced"
REGRESSION_DETECTED=true
fi
if [[ $TEST_FAIL_DELTA -gt 0 ]]; then
echo "❌ REGRESSION: $TEST_FAIL_DELTA new test failure(s) introduced"
REGRESSION_DETECTED=true
fiSmoketest & Regression Output
Report results including regression comparison:
### Post-Merge Smoketest
| Check | Command | Result | Details |
|-------|---------|--------|---------|
| Build | `npm run build` | ✅ PASS / ❌ FAIL | [build output summary] |
| Tests | `npm test` | ✅ PASS (N/N) / ❌ FAIL | [test count or failure summary] |
| CLI Health | `npx sequant doctor` | ✅ PASS / ❌ FAIL / ⏭️ SKIP | [health check output] |
### Regression Check
| Metric | Baseline (main) | Post-merge | Delta | Status |
|--------|----------------|------------|-------|--------|
| Build errors | $BASELINE_BUILD_ERRORS | $POST_BUILD_ERRORS | +$BUILD_DELTA / 0 | ✅ No regression / ❌ REGRESSION |
| Test failures | $BASELINE_TEST_FAILURES | $POST_TEST_FAILURES | +$TEST_FAIL_DELTA / 0 | ✅ No regression / ❌ REGRESSION |
| Test passes | $BASELINE_TEST_PASSES | $POST_TEST_PASSES | +$TEST_PASS_DELTA | ✅ Tests added / ⚠️ Tests removed |
**Regression Result:** ✅ NO REGRESSIONS / ❌ REGRESSIONS DETECTEDRegression Gate
If regressions are detected:
if [[ "$REGRESSION_DETECTED" == "true" ]]; then
if [[ "$FORCE_MERGE" == "true" ]]; then
echo "⚠️ REGRESSION DETECTED but --force flag set. Proceeding with merge."
echo "⚠️ Acknowledgment: Merging despite $BUILD_DELTA new build error(s) and $TEST_FAIL_DELTA new test failure(s)."
else
# Terminal halt — release the checkout lock before stopping (#901/#906).
# This branch does NOT continue to Step 8, so the release lives here.
npx sequant locks checkout release --issue=<first-issue> || true
echo "❌ REGRESSION DETECTED — merge is blocked."
echo ""
echo "New build errors: $BUILD_DELTA"
echo "New test failures: $TEST_FAIL_DELTA"
echo ""
echo "To override this gate, re-run with --force:"
echo " /merger <issues> --force"
echo ""
echo "To investigate:"
echo " npm run build 2>&1 | grep 'error TS'"
echo " npm test -- --verbose 2>&1"
# Do NOT proceed — report regression and halt
fi
fiRegression gate behavior:
| Scenario | --force not set | --force set |
| No regressions | ✅ Proceed | ✅ Proceed |
| New build errors | ❌ Block merge, report | ⚠️ Warn, proceed |
| New test failures | ❌ Block merge, report | ⚠️ Warn, proceed |
| Both | ❌ Block merge, report | ⚠️ Warn, proceed |
Important: The regression gate does NOT trigger automatic rollback. It blocks further action and reports for human decision-making. Use --force only when you've confirmed the regressions are acceptable (e.g., known flaky tests).
Failure Handling (Non-Regression)
If smoketest checks fail but are NOT regressions (same count as baseline), report as pre-existing:
### ℹ️ Pre-existing Failures (not regressions)
| Check | Status | Notes |
|-------|--------|-------|
| Build | ⚠️ $BASELINE_BUILD_ERRORS errors | Same as baseline — pre-existing |
| Tests | ⚠️ $BASELINE_TEST_FAILURES failures | Same as baseline — pre-existing |
These failures existed on main before this merge. They are not caused by the merged PR(s).If smoketest checks fail AND are regressions, report with diagnostic commands:
### ❌ Regressions Detected
| Check | Baseline | Post-merge | New Failures |
|-------|----------|------------|--------------|
| Build errors | $BASELINE_BUILD_ERRORS | $POST_BUILD_ERRORS | +$BUILD_DELTA |
| Test failures | $BASELINE_TEST_FAILURES | $POST_TEST_FAILURES | +$TEST_FAIL_DELTA |
**⚠️ Action Required:**
- Investigate new failures introduced by this merge
- Consider reverting the merge if regressions are critical
- Use `--force` to override if regressions are acceptable
**Diagnostic commands:**
\`\`\`bash
# Investigate new build errors
npm run build 2>&1 | grep "error TS"
# Run failing tests with verbose output
npm test -- --verbose 2>&1
# Check what the merge changed
git log --oneline -3
git diff HEAD~1 --stat
\`\`\`Important: Regression detection does NOT trigger automatic rollback. It reports for human decision-making.
Step 8: Release the Checkout Lock (REQUIRED)
The merge is complete. Release the working-tree lock so other sessions can run
branch-mutating git again (#901). Run this on the happy path — a successful merge
and smoketest, or the --force proceed past a regression. It is the counterpart
to the acquire in "Acquire the Checkout Lock" above.
npx sequant locks checkout release --issue=<first-issue> || trueOn a failure exit instead, the release is done at the halt site — the regression gate (Step 7) or "Error Handling" — never both, so exactly one release runs per invocation.
<!-- BEGIN: named-set-boundary (#961) -->Named-Set Boundary (REQUIRED)
/merger <issue-numbers> is the user's consent to merge exactly those
issues — invoking it is the explicit authorization, the same way sequant
merge/sequant merge --watch are explicit and human-triggered (#958's
Non-Goals). That consent does not extend past the named set: never let
Dependency Detection or Stacked PR Detection below pull another issue's PR
into gh pr merge just because it happens to unblock or precede a named one.
Rule: if merge ordering requires a PR whose issue number is not in the invocation's arg list, halt before merging anything and report it — do not widen the merge silently, and do not treat the stacked-PR "Continue anyway? (y/N)" confirmation as license to include an unnamed predecessor. Offer the widened command for the user to re-run:
❌ Out-of-named-set dependency
#101 depends on #100, but #100 was not in your /merger invocation.
Halting before any merge.
To include it: /merger 100 101This rule governs both sections below.
<!-- END: named-set-boundary (#961) -->Dependency Detection
Parse dependencies from issue body or comments:
<!-- In issue body -->
**Depends on**: #10
<!-- Or via label -->
Labels: depends-on/10# Check issue for dependency markers
gh issue view <issue> --json body,labels | jq '.body, .labels[].name'If dependencies found, enforce merge order among the named set. If a dependency's issue number falls outside the named set, apply the Named-Set Boundary rule above: halt and report instead of merging it.
Stacked PR Detection (#605)
PRs created with sequant run --stacked have a non-main base and a manifest
line in the body (Part of stack: #N1 → #N2 → ...). They must merge in
order — predecessor first. Merging out of order re-bases the dependent PR's
diff against an unexpected commit and inflates the visible change set.
Detect stacked PRs:
# A PR with a non-main base + manifest is part of a stack
gh pr view <PR_NUMBER> --json baseRefName,body | \
jq -r 'if (.baseRefName != "main" and (.body | contains("Part of stack:"))) then "STACKED" else "STANDALONE" end'Enforce stack order before merging:
- Extract the stack manifest from each PR's body (
Part of stack: #100 → #101 (this) → #102). - Treat the order in the manifest as the merge order — earlier entries land first.
- If every predecessor is in the named set but requested out of order (e.g.
/merger 102 100 101for the stack above), warn before proceeding and recommend the manifest order. - If a predecessor is not in the named set at all (e.g.
/merger 102alone for that stack), the Named-Set Boundary rule applies: halt and report — do not fall through to the "Continue anyway? (y/N)" prompt, since that prompt is for reordering named issues, not for merging an unnamed one. - GitHub auto-updates the dependent PR's base when its predecessor merges, so once the order is correct no manual rebasing is needed.
Warning template:
⚠️ Stack order violation detected
PR #102 is part of stack: #100 → #101 → #102
You requested merge order: #102, #100, #101
Recommended: merge in manifest order to preserve incremental diffs.
Continue anyway? (y/N)Output Format
Merge Report
## Merger Report: Issues #10, #12
### Pre-Merge Validation
| Issue | Worktree | PR | Status |
|-------|----------|-----|--------|
| #10 | feature/10-* | #15 | Ready |
| #12 | feature/12-* | #16 | Ready |
### Conflict Analysis
| File | #10 | #12 | Status |
|------|-----|-----|--------|
| `src/api/route.ts` | Modified | Modified | CONFLICT |
| `src/components/list.tsx` | - | Created | OK |
### Resolution
**Strategy:** Integration branch
**Branch:** integrate/10-12-api-merge
**PR:** #17
### Actions Taken
1. Captured baseline metrics on main
2. Created integration branch from main
3. Merged #10 changes (no conflicts)
4. Merged #12 changes (resolved 1 conflict in route.ts)
5. Tests passed (45 tests)
6. Build succeeded
### Cleanup
- Removed worktree: feature/10-*
- Removed worktree: feature/12-*
- Closed: PR #15, PR #16 (superseded by #17)
### Baseline Metrics (main before merge)
| Metric | Count |
|--------|-------|
| Build errors (TS) | 0 |
| Test passes | 42 |
| Test failures | 0 |
### Post-Merge Smoketest
| Check | Command | Result | Details |
|-------|---------|--------|---------|
| Build | `npm run build` | ✅ PASS | Compiled successfully |
| Tests | `npm test` | ✅ PASS (45/45) | All tests passing |
| CLI Health | `npx sequant doctor` | ✅ PASS | No issues detected |
### Regression Check
| Metric | Baseline (main) | Post-merge | Delta | Status |
|--------|----------------|------------|-------|--------|
| Build errors | 0 | 0 | 0 | ✅ No regression |
| Test failures | 0 | 0 | 0 | ✅ No regression |
| Test passes | 42 | 45 | +3 | ✅ Tests added |
**Regression Result:** ✅ NO REGRESSIONS
### Final Status
**Result:** SUCCESS
**Integration PR:** #17
**Issues to close on merge:** #10, #12Error Handling
Before halting on any failure below, release the checkout lock (#901/#906) — the acquire in "Acquire the Checkout Lock" claimed the tree, and every failure here is a terminal exit that must hand it back before stopping:
npx sequant locks checkout release --issue=<first-issue> || trueIf validation fails:
- Report which issues failed validation
- Suggest corrective actions
- Do not proceed with merge
If merge conflicts cannot be resolved:
- Document the conflicts
- Create a draft PR with conflicts marked
- Request manual intervention
If tests fail on integration branch:
- Document failing tests
- Keep integration branch for debugging
- Do not merge
If worktree cleanup fails:
- Log warning but continue
- Manual cleanup may be needed
Configuration
Environment variables:
SEQUANT_MERGER_DRY_RUN- If true, only show what would happenSEQUANT_MERGER_NO_CLEANUP- If true, keep worktrees after mergeSEQUANT_MERGER_FORCE- If true, proceed even with conflicts or regressions (bypasses regression gate)SEQUANT_MERGER_SKIP_SMOKETEST- If true, skip post-merge smoketest (also skips baseline capture)
Output Verification
Before responding, verify your output includes ALL of these:
- Baseline Metrics - Build errors, test passes/failures on main before merge (or "Skipped" if
--skip-smoketest) - Pre-Merge Validation - Status of each issue/worktree/PR
- Conflict Analysis - Table of overlapping files and status
- Resolution Strategy - How conflicts were resolved (if any)
- Actions Taken - Step-by-step log of what was done
- Cleanup Status - Which worktrees/branches were removed
- Post-Merge Smoketest - Build, test, and CLI health results (or "Skipped" if
--skip-smoketest) - Regression Check - Baseline vs post-merge comparison table (or "Skipped" if
--skip-smoketest) - Regression Gate - Whether regressions were detected and what action was taken
- Final Status - SUCCESS/FAILURE with PR link
DO NOT respond until all items are verified.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

