merge-orchestrator
Merge Orchestrator Skill
Local Git, Not Remote VCS
This skill performs local git merge of a subagent's worktree branch into the integration branch, recording a rollback SHA so a git reset --hard can undo the merge on any failure. It does not call the VCS provider (GitHub / GitLab / Azure DevOps) and does not require a PR id. For remote PR merging during the synthesize phase, see @skills/synthesis/SKILL.md (merge_pr action).
The mental model and the rationale for why these are two separate concerns are documented in references/local-git-semantics.md.
Overview
Closes the loop between /exarchos:delegate (which spawns subagents into worktrees) and the integration branch that needs their work. After a delegated task completes inside a worktree, this skill:
- Composes preflight guards (ancestry, current-branch protection, main-worktree assertion, working-tree drift).
- Records pre-merge
HEADof the integration branch as a rollback anchor. - Performs a local
git mergeof the source (subagent) branch into the target (integration) branch. - On any failure, runs
git reset --hard <rollbackSha>and surfaces a categorized failure reason. - Emits dedicated event types so the merge timeline is reconstructable from the event log alone.
Resumable: terminal phases (completed / rolled-back / aborted) short-circuit on re-entry without re-emitting events. Idempotent: re-dispatch with the same taskId collapses via the next_actions idempotency key.
Triggers
Activate this skill when:
- The HSM is parked in
feature/merge-pending(entry guard fires when the most recenttask.completedcarries a worktree association). - The
next_actionsenvelope surfaces amerge_orchestrateverb with idempotency key${streamId}:merge_orchestrate:${taskId}. - The user runs
exarchos merge-orchestrate ...(CLI) or invokesmcp__plugin_exarchos_exarchos__exarchos_orchestrate({ action: "merge_orchestrate", ... })directly.
Do not activate this skill:
- During the synthesize phase to merge a remote PR — that is
merge_pr. - When the workflow's
mergeOrchestrator.phaseis already terminal — the resume short-circuit runs but no fresh dispatch is needed.
Process
Schema: discover the action's argument schema with
mcp__plugin_exarchos_exarchos__exarchos_orchestrate({ action: "describe", actions: ["merge_orchestrate"] }). Strategy is required (no schema-level default) — picksquash/merge/rebasedeliberately.
Step 1: Pick the merge strategy
| Strategy | Local git operation | When to choose |
|---|---|---|
merge |
git merge --no-ff --no-edit <source> — explicit merge commit |
Preserves the subagent's commit history with a visible merge boundary. |
squash |
git merge --squash <source> then git commit — single squash commit on target |
Subagent commit history is noise; one logical change should land as one commit. |
rebase |
rebases an ephemeral copy of source onto target then ff-merges target — linear history | No merge commit; integration branch stays linear. The original source ref is preserved (the rebase runs on a temporary branch that is deleted afterward), so an executor rollback only needs to reset target. |
Strategy is required at the schema layer (#1127 collision check, #1109 §2 user-visible parity). There is no implicit default — operator intent is always explicit in the event log.
Step 2: Invoke
Via MCP:
mcp__plugin_exarchos_exarchos__exarchos_orchestrate({
action: "merge_orchestrate",
featureId: "<id>",
sourceBranch: "<subagent-branch>",
targetBranch: "<integration-branch>",
taskId: "<task-id>", // present when auto-dispatched from next_actions
strategy: "squash", // required
dryRun: false, // optional — preflight only, no executor invocation
resume: false, // optional — short-circuit on terminal phases
})
Via CLI:
exarchos merge-orchestrate \
--feature-id <id> \
--source-branch <subagent-branch> \
--target-branch <integration-branch> \
--task-id <task-id> \
--strategy squash
# add --dry-run for preflight-only, --resume for terminal-phase short-circuit
CLI exit codes: 0 = success, 1 = invalid input, 2 = merge failed (preflight blocked or rollback executed), 3 = uncaught exception.
Step 3: Interpret the result
The handler returns a ToolResult whose data.phase discriminates the outcome:
phase |
Meaning | Operator action |
|---|---|---|
completed |
Local merge landed; mergeSha is the new HEAD of target. |
None — workflow exits merge-pending back to delegate (HSM) and continues. |
aborted |
Preflight failed; no merge attempted. data.preflight carries the structured guard sub-results. |
Inspect preflight.ancestry / worktree / currentBranchProtection / drift to identify which guard failed. Resolve the underlying condition (e.g., commit/stash drift, switch off a protected branch) and re-dispatch. |
rolled-back |
Merge was attempted, failed (reason: 'merge-failed' / 'verification-failed' / 'timeout'), and git reset --hard <rollbackSha> ran. The integration branch is restored. |
Inspect data.reason. If data.rollbackError is also present, the reset itself failed — the working tree is stranded and requires operator intervention. |
For the full recovery flow per outcome, see references/recovery-runbook.md.
Step 4: Confirm event emissions
Three events are emitted directly to the workflow's event stream (stream id = featureId) — not wrapped in gate.executed:
| Event type | When | Carries |
|---|---|---|
merge.preflight |
Always (after preflight runs, before any merge attempt) | Full structured guard sub-results + failureReasons if passed: false |
merge.executed |
On successful local merge | mergeSha, rollbackSha, taskId, source/target branches |
merge.rollback |
On post-merge failure followed by reset | rollbackSha, reason, taskId, source/target branches |
These events are auto-emitted by the handler — do not manually append them via mcp__plugin_exarchos_exarchos__exarchos_event during normal operation. Manual emission is only sanctioned during the documented manual-recovery flow in recovery-runbook.md when a merge has been completed out-of-band (e.g., conflict resolution) and the event log must be brought back in sync — follow that runbook's event-first sequencing.
Discover the event payload schemas via
mcp__plugin_exarchos_exarchos__exarchos_event({ action: "describe", eventTypes: ["merge.preflight", "merge.executed", "merge.rollback"] }).
Disambiguation: merge_orchestrate vs merge_pr
Two related actions, two distinct concerns:
| Aspect | merge_orchestrate (this skill) |
merge_pr (synthesis skill) |
|---|---|---|
| Layer | Local SDLC handoff | Remote PR primitive |
| Phase affinity | merge-pending (between delegate and review) |
synthesize |
| What it merges | A subagent worktree branch into the integration branch | A user-facing PR via the VCS provider API |
| Identifier required | sourceBranch + targetBranch |
prId |
| Underlying operation | git merge (local) |
provider.mergePr() (remote API) |
| Rollback | git reset --hard <rollbackSha> (real, undoes the merge) |
None — the VCS provider owns merge state |
| Events | merge.preflight / merge.executed / merge.rollback |
pr.merged |
If you reach for merge_orchestrate thinking "I want to merge a PR," you want merge_pr instead.
Resume Semantics
When invoked with resume: true, the handler reads existing mergeOrchestrator state. Terminal phases (completed / rolled-back / aborted, members of EXCLUDED_MERGE_PHASES) short-circuit and return the recorded result with no new events and no executor call. Non-terminal phases (pending / executing) fall through to a fresh preflight + executor run, which is safe because the underlying git operations are idempotent on already-merged branches.
When invoked without resume, prior state is deliberately ignored — fresh-dispatch semantics.
Dry-Run
dryRun: true runs preflight, emits merge.preflight, and short-circuits before the executor runs and before any state persistence. Returns { dryRun: true, preflight, phase: 'pending' | 'aborted' }. Useful for CI integrations that check merge readiness before the merge window opens.
Anti-Patterns
| Don't | Do Instead |
|---|---|
| Use this skill to merge a remote PR | Use merge_pr in the synthesize phase |
Manually emit merge.preflight / merge.executed / merge.rollback in normal flow |
Let the handler auto-emit; manual emission causes duplicates (one exception: documented manual-recovery flow in recovery-runbook.md) |
Wrap merge events under gate.executed |
Direct stream append with the dedicated event type — these are state transitions, not gate executions |
Re-dispatch after a rolled-back outcome without inspecting the reason |
Read data.reason and data.rollbackError; address the root cause first |
Omit --strategy / strategy: field expecting a default |
Strategy is required; supply squash / merge / rebase explicitly |
| Invoke from a subagent worktree | Preflight refuses (main-worktree assertion); invoke from the main worktree |
Phase Transitions and Guards
For the full transition table, consult @skills/workflow-state/references/phase-transitions.md.
Quick reference:
delegate→merge-pendingrequires guardmerge-pending-entry— fires when the most recenttask.completedcarries a worktree association ANDmergeOrchestrator.phaseis not inEXCLUDED_MERGE_PHASES.merge-pending→delegaterequires guardmerge-pending-exit— fires whenmergeOrchestrator.phaseenters a terminal value (completed/rolled-back/aborted).
The HSM exits merge-pending back to delegate regardless of merge outcome — delegate then re-evaluates whether more worktree-bearing tasks remain and either re-enters merge-pending for the next, or transitions on to review when all delegation is complete.
Schema Discovery
For the argument schema, call mcp__plugin_exarchos_exarchos__exarchos_orchestrate({ action: "describe", actions: ["merge_orchestrate"] }). The full feature-workflow phase playbook (which includes merge-pending) is available via mcp__plugin_exarchos_exarchos__exarchos_workflow({ action: "describe", playbook: "feature" }). Event payload shapes come from mcp__plugin_exarchos_exarchos__exarchos_event({ action: "describe", eventTypes: ["merge.preflight", "merge.executed", "merge.rollback"] }).
Completion Criteria
- Preflight result
passed: true(or operator has decided to proceed despite a documented preflight gap) -
mergeOrchestrator.phase === 'completed'in workflow state -
merge.executedevent present in the stream with the recordedmergeShaandrollbackSha - HSM has exited
merge-pendingback todelegate - Integration branch's HEAD matches the recorded
mergeSha
If any criterion fails, consult references/recovery-runbook.md before re-dispatching.
More from lvlup-sw/exarchos
xml-tags
A skill with <xml-tag> characters in the description.
13debug
Bug investigation and fix workflow. Triggers: 'debug', 'fix bug', 'investigate issue', 'something is broken', or /debug. Hotfix track for quick fixes, thorough track for root cause analysis. Do NOT use for feature development or refactoring. Do NOT escalate to /ideate unless the fix requires architectural redesign.
13refactor
Code improvement workflow with polish and overhaul tracks. Triggers: 'refactor', 'clean up', 'restructure', 'reorganize', or /refactor. Phases: explore, brief, implement, validate. Existing code only — Do NOT use for bug fixes (/debug) or new features (/ideate).
13shepherd
Shepherd PRs through CI and reviews to merge readiness. Operates as an iteration loop within the synthesize phase (not a separate HSM phase). Uses assess_stack to check PR health, fix failures, and request approval. Triggers: 'shepherd', 'tend PRs', 'check CI', or /shepherd.
13dogfood
Review failed Exarchos MCP tool calls from the current session, diagnose root causes, and categorize into code bug, documentation issue, or user error. Use when the user says 'dogfood', 'review failures', 'what went wrong', 'triage errors', or runs /dogfood. Scopes exclusively to Exarchos tools (exarchos_workflow, exarchos_event, exarchos_orchestrate, exarchos_view, exarchos_sync). Do NOT use for debugging application code or non-Exarchos tool failures.
13cleanup
Post-merge workflow resolution. Verifies PR merge status, backfills synthesis metadata, force-resolves review statuses, transitions to completed, and cleans up worktrees/branches. Use when the user says 'cleanup', 'resolve workflow', 'mark as done', or runs /cleanup. Do NOT use before PRs are merged.
13