Synthesis Skill
VCS Provider
This skill uses VCS operations through Exarchos MCP actions (create_pr, merge_pr, list_prs, check_ci, etc.).
These actions automatically detect and route to the correct VCS provider (GitHub, GitLab, Azure DevOps).
No gh/glab/az commands needed — the MCP server handles provider dispatch.
Not to be confused with the integration merge. This skill calls
merge_prto land a user-facing PR onmainvia the VCS provider — a remote operation. The upstream sibling isserialize_merge(@skills/merge-orchestrator/SKILL.md): the integration-merge path that holds a single-writer lease and composes a localgit mergeof a subagent worktree branch onto the integration branch during thedelegate → merge-pending → delegateHSM loop (rawmerge_orchestrateis that composed executor / the non-integration path). Synthesize never invokesserialize_mergeormerge_orchestrate; merge-pending never invokesmerge_pr.
Overview
Submit stacked PRs after review phase completes. The prepare_synthesis composite action consolidates readiness checks, stack verification, test validation, and quality signal analysis into a single call -- eliminating the multi-script coordination that historically caused synthesis failures.
Prerequisites:
- All delegated tasks complete with reviews passed (spec + quality)
- The integration branch already exists from delegation phase
- Task branches present and pushed to remote
Do NOT proceed if either review is incomplete or failed -- return to review first.
Entry points: Synthesis is normally reached from the review phase of
feature / debug / refactor workflows. It is also reachable from oneshot
workflows via the opt-in path — when a user signals "let's open a PR for
this" during plan or implementing, the request_synthesize event is
appended, and finalize_oneshot then resolves the choice state and
transitions the workflow to synthesize. See
@skills/oneshot/SKILL.md for the opt-in mechanics and
synthesisPolicy semantics.
Triggers
Activate this skill when:
- User runs
synthesizecommand - All reviews have passed successfully
- Ready to submit PRs
- Oneshot workflow resolved to
synthesizeviafinalize_oneshot
Process
Runbook: Follow the synthesis-flow runbook:
exarchos_orchestrate({ action: "runbook", id: "synthesis-flow" })If runbook unavailable, usedescribeto retrieve action schemas:exarchos_orchestrate({ action: "describe", actions: ["prepare_synthesis"] })
Step 1: Verify Readiness
Call the prepare_synthesis composite action to validate all preconditions in a single operation:
exarchos:exarchos_orchestrate({
action: "prepare_synthesis",
featureId: "<id>",
repoRoot: "<absolute path of the repo under synthesis>"
})
repoRoot is required. All four readiness legs (test suite, typecheck, stack, changed files) shell out with it as their working directory, so it names the tree the verdict is about. The gate will not fall back to whatever directory the server was launched in — omit it and the call is rejected rather than answered about the wrong repo. During a stacked synthesis, pass the integration worktree's absolute path.
This action performs:
- Phase readiness -- Confirms workflow is in the correct phase with all reviews complete
- Stack integrity -- Detects diverged branches, missing task branches, or broken parent chains and reconstructs automatically
- Test verification -- Runs
npm run test:run && npm run typecheckfrom the stack top - Benchmark regression -- If
state.verification.hasBenchmarksis true, checks for performance regressions - Quality signals -- Queries
code_qualityview for regressions and actionable hints - Document readiness -- Touched doc-surfaces must carry corresponding doc updates (auto-waives when no doc surface is touched)
- Gate events -- Auto-emits
gate.executedevents for each check (tests, benchmarks, CodeRabbit)
For the full breakdown of individual checks the composite action performs, see references/synthesis-steps.md.
On success: All checks passed. The response includes a readiness summary with any quality hints to present to the user. Proceed to Step 2.
On failure: The response identifies which check failed and provides remediation guidance. Follow the guidance -- typically returning to review or delegate.
If any quality hint has confidenceLevel: 'actionable', present the suggestedAction to the user before proceeding.
Step 2: Write and Validate PR Descriptions
For each PR in the stack, write a structured description following references/pr-descriptions.md. Required sections: Summary, Changes, Test Plan, plus a footer. Projects can override required sections via .exarchos/pr-template.md.
Title format: <type>: <what> (max 72 chars)
Write the PR body to a temp file:
cat > /tmp/pr-body.md <<'EOF'
## Summary
[2-3 sentences: what changed, why it matters]
## Changes
- **Component** -- Description of change
## Test Plan
[Testing approach and coverage]
---
**Results:** Tests X pass · Build 0 errors
**Design:** [doc](path)
**Related:** #issue
EOF
Validate before creating the PR:
exarchos:exarchos_orchestrate({
action: "validate_pr_body",
bodyFile: "/tmp/pr-body.md"
})
Do NOT call create_pr until validation passes. If validation fails, fix the body and re-validate.
Step 3: Submit and Merge
Create PRs using the validated body and enable auto-merge. For each branch in the stack (bottom-up):
// Create PR via VCS MCP action
exarchos_orchestrate({
action: "create_pr",
base: "<parent-branch>",
head: "<branch>",
title: "<type>: <what>",
body: "<pr-body>"
})
// Enable auto-merge
exarchos_orchestrate({
action: "merge_pr",
prId: "<number>",
strategy: "squash"
})
After submission:
- Apply benchmark label -- If
verification.hasBenchmarksis true, apply label:gh pr edit <number> --add-label has-benchmarks - Record PR URLs -- Capture URLs via
exarchos_orchestrate({ action: "list_prs", state: "open" }) - Update state:
exarchos:exarchos_workflow({
action: "update", featureId: "<id>", updates: {
"artifacts": { "pr": ["<url1>", "<url2>"] },
"synthesis": { "mergeOrder": ["<branch1>", ...], "prUrl": ["<url1>", ...], "prFeedback": [] }
}
})
For merge ordering strategy, see references/merge-ordering.md.
Human checkpoint: Output "Stacked PRs enqueued: [URLs]. Waiting for CI/merge queue." then PAUSE for user input: "Merge stack? (yes/no/feedback)"
- 'yes' -- PRs merge; transition to completed via
cleanup - 'feedback' -- Route to
shepherd [PR_URL]to address comments, then return here - 'no' -- Pause workflow; resume later with
rehydrate
Event Emissions
After PRs are created and auto-merge is enabled, record the submission with a stack.submitted event. This is a telemetry record of what went up — nothing decides anything from it, and check-event-emissions does not ask for it:
exarchos:exarchos_event({ action: "append", stream: "<featureId>", event: {
type: "stack.submitted",
data: {
branches: ["task-001-branch", "task-002-branch"],
prNumbers: [101, 102]
}
}})
During shepherd iterations (CI monitoring loop), emit after each assessment (REQUIRED — the escalation policy counts these events to bound the loop):
exarchos:exarchos_event({ action: "append", stream: "<featureId>", event: {
type: "shepherd.iteration",
data: {
iteration: 1,
prsAssessed: 2,
fixesApplied: 0,
status: "all-green"
}
}})
Checked by check-event-emissions in this phase: team.spawned, team.disbanded, shepherd.iteration.
A missing one comes back as a hint with complete: false — on the explicit gate call, and on the _eventHints field the telemetry middleware adds to tool results while hints are outstanding. stack.submitted is not checked.
Post-Merge Cleanup
After PRs merge, invoke cleanup:
exarchos:exarchos_workflow({
action: "cleanup", featureId: "<id>", mergeVerified: true,
prUrl: ["<url>", ...], mergedBranches: ["<branch>", ...]
})
Then sync: git fetch --prune and reclaim worktrees.
Worktree GC cadence — after synthesize (INV-12). Once a workflow reaches synthesis its governed worktrees are no longer needed, so this is the point to reclaim them. Use the governed garbage-collector
prune_worktreesrather than ad-hocgit worktree remove: dry-run first (the default — reports candidates
- reclaimable bytes, deletes nothing), then re-invoke with
dryRun: falseto apply.exarchos:exarchos_orchestrate({ action: "prune_worktrees", repoRoot: "<repo-root>" }) // dry-run (default) exarchos:exarchos_orchestrate({ action: "prune_worktrees", repoRoot: "<repo-root>", dryRun: false }) // applyThe
next_actionsprojection surfaces this sameprune_worktreesdry-run affordance once the workflow is parked in synthesis. The full apply flow lands in@skills/cleanup/SKILL.md.
Idempotency
create_pr is the single authority for "PR already exists" — do NOT pre-check synthesis.prUrl / artifacts.pr before deciding whether to create. Just call create_pr: it either returns the existing open PR for this (head, base) via its remote-recovery guard, or refuses with PR_ALREADY_OWNED when the workflow already owns a PR. Branch on that structured response instead of pre-checking.
The post-merge cleanup case is distinct from create-time idempotency and is NOT governed by create_pr: if the PR is already merged, transition to completed via action: "transition", target: "completed" (the runtime rejects updates.phase; the canonical transition action runs the HSM guard and emits workflow.transition). This completed transition is normally owned by cleanup via action: "cleanup"; the bare phase-only transition is a manual-cleanup escape hatch.
Direct Edits to Stack Branches
You can make direct edits to stack branches at any time — edit files, then stage and amend (git add <files> && git commit --amend). Push with the explicit-SHA lease, never a bare --force-with-lease:
git push --force-with-lease=<ref>:<expected-sha>
A bare lease anchors to the (possibly stale) local remote-tracking ref and can clobber a concurrent push. <expected-sha> is the remote SHA the loop last observed via assess_stack, or read fresh with git ls-remote --heads origin <ref>.
Completion Output
When the PR is created and checks pass, report:
## Synthesis Complete
PR: [URL]
Tests: X pass | Build: 0 errors
Anti-Patterns
| Don't | Do Instead |
|---|---|
| Skip review phase | Always run review first |
| Force push stack branches | Use normal push |
| Delete worktrees before merge | Wait for merge confirmation |
| Create PR with failing tests | Ensure review phase passes first |
| Run readiness scripts manually | Use prepare_synthesis composite action |
Handling Failures
See references/troubleshooting.md for test failures, PR check failures, merge queue rejections, and MCP tool errors.
Phase Transitions and Guards
For the full transition table, consult @skills/checkpoint/references/phase-transitions.md.
Quick reference: The synthesize → completed transition requires guard pr-url-exists — set synthesis.prUrl or artifacts.pr in the same set call as phase.
Schema Discovery
Use exarchos_workflow({ action: "describe", actions: ["update", "init"] }) for
parameter schemas and exarchos_workflow({ action: "describe", playbook: "feature" })
for phase transitions, guards, and playbook guidance. Use
exarchos_orchestrate({ action: "describe", actions: ["prepare_synthesis"] })
for orchestrate action schemas.
Completion Criteria
-
prepare_synthesisreadiness check passed - PR descriptions written per
references/pr-descriptions.md - PRs created and auto-merge enabled
- PR links provided to user
- State updated with PR URLs and merge order