CommunityCoding & Developmentgithub.com

picoduck/orchestrate-issues

Coordinate explicitly requested Wollipog child-session issue campaigns through merge, cleanup, recursive follow-ups, and archival. Use only when the user invokes this skill or explicitly asks to orchestrate or delegate issue implementation across sessions. A request to claim, implement, or fix multiple issues alone stays in the current session and does not trigger this skill. Do not trigger merely because the issues concern Orchestrator features.

What is orchestrate-issues?

orchestrate-issues is a Claude Code agent skill that coordinate explicitly requested Wollipog child-session issue campaigns through merge, cleanup, recursive follow-ups, and archival. Use only when the user invokes this skill or explicitly asks to orchestrate or delegate issue implementation across sessions. A request to claim, implement, or fix multiple issues alone stays in the current session and does not trigger this skill. Do not trigger merely because the issues concern Orchestrator features.

Works with✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/picoduck/wollipog/tree/HEAD/skills/orchestrate-issues

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Orchestrate Issues

Run a campaign of initial issues and their justified follow-ups. Coordinate through real Wollipog child sessions, not in-process subagents. The Orchestrator investigates, schedules, reviews outcomes, and maintains state; children implement. Creating or editing this skill does not start a campaign.

Activation Boundary

Issue count, dependencies, task size, and the availability of child-session tools do not authorize delegation. Require an explicit invocation of this workflow or a request to orchestrate, coordinate across sessions, or delegate implementation to children. Relevant authorization already established for an active campaign remains valid; it need not be repeated on each turn.

“Claim and implement issues 1089, 1090, and 1091” means the current session claims and implements those issues following the repository's issue workflow (such as an installed issue-workflow skill), in dependency order and with its required isolated worktrees and review. Do not launch child implementation sessions or ask whether to orchestrate merely because the request lists several issues. Issue titles or bodies about Orchestrator settings are task subject matter, not instructions to become an Orchestrator.

“Orchestrate child sessions to implement issues 1089, 1090, and 1091” or “Use orchestrate-issues for those issues” activates this workflow. A child receiving several assigned issues remains an implementation session; the parent's orchestration authorization does not automatically authorize that child to delegate again. A review the repository requires, including a cross-model review, remains governed by its own rules and is not a delegation of issue implementation.

If the current session is restricted by the Orchestrator permission preset and cannot implement directly, explain that concrete limitation and request direction rather than silently spawning children or attempting prohibited implementation. Merely having the preset available is not authorization to use it.

Inputs and Setup

  • count: any positive integer, the number of initial issues to select. Infer it from the request; if omitted, use 5 and state that assumption. An explicit issue list replaces priority selection and determines the count.
  • concurrency: optional ceiling, independent of count. Default to the smallest of count, the policy's maximumConcurrentChildren, and available live-child capacity. Queue excess issues; never raise platform limits to fit the count.
  • Child harness, model, and effort come from the campaign's Wollipog Orchestrator policy (childHarness, childModel, childEffort in get_campaign.behavior); this skill has no defaults of its own. Each value is either fixed or Automatic (null). See Resolve Child Model and Effort.
  • Reviewers retain the model specified by the repository's review workflow.
  • Optional user-specified cost, time, total-issue, or follow-up-depth limits. Preserve inherited guardrails. Do not invent budget values or an arbitrary successful stopping round.

Read using-wollipog, the repository instructions, and any issue workflow, review, and issue-reporting skills or policies the repository or user provides. Only using-wollipog is required; when the repository defines no issue workflow, children follow its contribution guidelines and the gates in this skill. Children must have the same skills available in their execution environment. Resolve skill paths from that environment's catalog; do not assume this machine's home paths exist elsewhere. Read the repository's issue-reporting policy before preparing publication payloads.

Discover the current runner, repository/workspace, available worker harnesses and model/effort capabilities, child capacity, and supported session tools. Select a harness advertising the chosen model; do not assume every model belongs to Codex. Inspect the current session and live child list before creating anything. Use only allowed Orchestrator operations; project writes and implementation belong in children. Keep the campaign ledger in persistent session artifacts or permitted scratch, never in the primary checkout. Summarize its latest state in conversation before yielding or compaction.

Resolve Child Model and Effort

Read childHarness, childModel, and childEffort from get_campaign.behavior before selecting anything, and read them again before each dispatch: a person can change them while the campaign runs, and only children created afterwards use the new values. Wollipog's Orchestrator settings are the only source of these values. Never fall back to a model or effort written in this skill, remembered from an earlier campaign, or inherited from the parent session.

  • Fixed value: use it exactly. The server fills in a fixed value when create_session omits it and rejects any different value, so do not override it. If the user's prompt asks for a different model or effort than a fixed setting, report the conflict and ask the user to change the Wollipog setting; do not dispatch the affected issue until it is resolved.
  • Fixed harness: a fixed childHarness names a harness, and each machine has its own agent for it. When get_campaign returns childHarnessAgents, pass the agentId listed for the machine you create the child on; a machine listed with null cannot run it. Do not derive the agent from childHarness.agentId; it need not be an agent on any machine.
  • Fixed model or effort: when get_campaign returns childModelMachines, create children only on machines marked supported; the others cannot run that model and effort, and creation there is refused.
  • Automatic (null): choose for each assignment from get_agent_capabilities (MCP) or wollipog session capabilities (CLI). Follow page.nextOffset until truncated is false. Pick a harness that advertises the chosen model; do not assume every model belongs to one harness. Base the choice on the issue's complexity, uncertainty, consequence of mistakes, context needs, and any cost or latency constraint the user stated. Model or effort preferences in the user's prompt guide an Automatic choice but do not change the Wollipog setting. Prefer an economical capable option for straightforward work and stronger reasoning for complex debugging, architecture, or broad changes. Do not invent model rankings, prices, or effort levels; use advertised capabilities and explain material uncertainty. If a model advertises no configurable effort, record effort as not applicable.

If a fixed value is absent from current capability discovery, report the mismatch and request a corrected setting while continuing independent triage. Never silently substitute.

Record each issue's harness, exact model and effort, whether each was fixed or Automatic, and a brief rationale for Automatic choices in the selection table and ledger before dispatch. Automatic mode authorizes these routine choices without asking per child; it does not authorize changing accounts, billing arrangements, permissions, budgets, or the Wollipog settings themselves.

Verify Model and Effort Before Implementation

Use create_session with useWorktree: true, the resolved harness, an advertised worker permission mode (not Orchestrator mode), and the resolved model and effort in the same call, plus campaignWorkItemId naming the child's recorded work item. The CLI equivalent is wollipog session create ... --model <model> --effort <effort> --work-item <id> --worktree. Omit a dimension only when it is fixed by policy (the server supplies it) or not applicable. Explicit values apply before the initial prompt. Prefer structured tool inputs for task text.

Read the effective pair back from the creation result or get_session and confirm it matches the resolved combination. If it does not, stop that child before it does work, record the mismatch, and report it; do not accept an unverified default. A client and server that do not support explicit effort fail closed; report that blocker rather than retrying without effort.

Inspect the actual creation schema: a runner protocol number alone does not expose an input. If a Custom host lacks campaignWorkItemId, use only a read-only bootstrap assignment at creation, verify the effective configuration, record the original work-item assignment with the supported assignment tool, and select a dedicated worktree before releasing implementation. Do not claim atomic work-item binding on that host or bypass required protected admission. If those operations are unavailable, report the compatibility blocker; never update the stack hosting the campaign.

Recheck configuration before reusing a child. For an Automatic assignment, reconsider the combination if evidence shows the previous choice was inadequate and record why; apply changes only through a supported configuration operation while idle and verify them before release, or create a replacement with a clear ownership handoff. A normal prompt_session message does not change session configuration. Never change a policy-fixed value.

Authority and Gates

Read the Campaign Authority Preflight reference shipped with using-wollipog. Before dispatch, record effective Custom/Full Control mode, the human-established boundary and revision, allowed operations, current owners, compatibility, evidence destination/provider disclosure and Human Required exceptions. Identify unresolved mandatory human rules by their exact instruction source; never silently rewrite external or user-authored instructions. Full Control applies only to eligible server-established authority permitted by repository policy. Custom preserves existing approval requirements. A changed policy must pass its own explicitly authorized contribution workflow.

Carry forward the user's actual campaign authorization and repository rules. Routine claims, isolated worktrees, testing, pushing, opening PRs, and required reviews need no repeated permission. Existing rules may still require per-PR merge authorization, UI evidence review, remote-branch deletion authorization, and approval of each exact sanitized issue payload. Do not silently convert a request for this workflow into a waiver of those gates.

Read the authoritative current campaign state and server-derived policy with get_campaign before dispatch and again before resolving a workflow decision; do not rely on a prompt copy when the server state is available. For typed decisions such as implementation_question, pr_merge, merged_branch_deletion, follow_up_issue_publication, ui_evidence_approval, and review_round_extension, the child must use request_workflow_decision, get_workflow_decision, and consume_workflow_decision for the exact occurrence immediately before the matching action. The parent must not create or consume a child's gate on its behalf. Discover pending occurrences with list_descendant_requests and resolve only a currently Orchestrator-owned exact occurrence with resolve_descendant_workflow_decision. Use answer_descendant_question and resolve_descendant_approval only for applicable non-workflow requests; they never substitute for a typed workflow gate. An ordinary prompt, a stale approval, or Parent Control availability is not authorization for a typed gate.

When you own a ui_evidence_approval decision with several images, prefer prepare_descendant_ui_evidence_review. It hands every image to a managed reviewer Session with a fresh context, so the images never enter your own conversation. Write its brief from the child's stated claims and the issue's UI acceptance criteria. While the reviewer works, end your turn or wait on its session instead of polling, then read the verdict with get_descendant_ui_evidence_review. Approve only with the exact delegatedImageReview reference it returns, listing every evidence id in evidenceReviewed. On a deny recommendation, deny with a childMessage that names the observed defects. Keep review_descendant_ui_evidence for a decision with one image, or for a targeted look at one image when the verdict leaves something unclear. Where the reviewer path is unavailable, it refuses with the reason; review directly instead. A reviewer is a campaign child like any other: verify its report and include it in cleanup.

Before approving a child's GitHub pr_merge, read what it closes: the decision's closingReferenceCheck lists every issue GitHub would close on merge, and the server created the decision only because they match the snapshot's intendedClosures. Approve a closure only when the campaign means that merge to close the issue; deny with a child message otherwise, so the child rewords the reference as "Refs #N". Where the check is absent (the child's runner predates it), run wollipog pr closures <pr-url> --json yourself before approving. Closing keywords bypass a typed issue_closure gate, so where the campaign closes issues through that route, a child's merge should normally close none.

Never change campaign control settings, approve a human-owned request, impersonate a human, or bypass a pending approval with a plain prompt. An eligible root Full Control occurrence may use server-recorded standing authorization through its exact typed resolution route; it cannot mint a new grant. UI evidence remains human-owned when the active policy says the Orchestrator cannot inspect the evidence bytes. For any human-owned or otherwise undelegated gate, relay the concrete decision through the harness's supported typed question mechanism and keep unrelated children progressing. Under Full Control no person sees the root's questions: the server dismisses them unanswered, so resolve Orchestrator-owned occurrences yourself and report a human-owned gate, which stays visible in Campaign Status, instead of asking. When the owner kept a decision for themselves (a design choice, risk consent to a merge, publication, an epic's closure), give it to them as a typed request rather than in chat: request_owner_decision for a new question with explicit options and decision material, or hand_workflow_decision_to_owner for a pending occurrence you own, such as a child's pr_merge. Neither parks you: keep unrelated children progressing, and act on the owner's choice when it comes back. A handoff is one way, so never resolve that occurrence afterwards (using-wollipog, Decisions the Owner Kept). Identify the exact policy requiring the gate. Do not imply that campaign ownership authorizes external effects beyond the active policy.

For unattended campaigns, explain up front which gates still need the user. A user may explicitly delegate eligible decisions for a campaign, subject to higher-priority and platform restrictions; record the exact scope and exceptions. Do not modify standing policies as part of execution.

Select and Schedule

  1. Read the repository's priority conventions and enough paginated open-issue data to identify the highest priorities. Inspect candidate bodies, acceptance criteria, assignments, linked PRs, and dependencies. Use explicit priority first, then severity/user impact and dependency-unblocking value; break remaining ties by age and issue number. Label inferred priorities as judgments.
  2. Publish a concise selection table with issue links, priority rationale, dependencies, and planned order. Record skipped claimed or blocked issues and reasons. If fewer than count eligible issues exist, report the shortfall rather than invent work. A specifically requested contested issue requires direction; for open-ended selection, choose the next eligible issue and disclose the substitution.
  3. Check active sessions, claims, worktrees, and overlapping open PRs. Assignment to the same GitHub account is not proof that this campaign owns an issue. Let exactly one child claim each issue after rechecking ownership immediately before work.
  4. Schedule independent issues concurrently within the available cap. Preserve high-priority selection even when overlapping files require serial execution. Do not duplicate claims or skip a selected blocker merely to fill slots. Start dependents after their prerequisites land unless a deliberate stack is justified.

Maintain a ledger with campaign ID, initial selection, issue lineage, child session IDs, event cursors, worktree/branch, PR/head SHA, review/check state, authorization evidence, merge commit, cleanup state, follow-up decisions, and blockers. Where Wollipog's campaign work ledger is available (below), it is the primary record: keep supplementary notes only for what it cannot hold, such as event cursors and authorization evidence, and update them when they change instead of rewriting a full copy every turn. Record mutations promptly. Before retrying an ambiguous create, publish, merge, or archive result, reconcile remote state; never blindly repeat it.

When the campaign exposes record_campaign_plan, also keep Wollipog's campaign work ledger current, because it is what the Campaign Status panel shows. Record the selected scope with record_campaign_plan before the first dispatch: one item per issue or planned slice, keyed stably (for example owner/repo#123), with dispatchState queued for work waiting only on capacity or dependencies and planned otherwise, recorded queue positions, and dependencies by key. Set planComplete once every selected item is listed. Report stages, blockers, next actions, and cancellations or scope removals (with a reason) through update_campaign_work_item, and close an attempt that failed or was abandoned with its endAttempt so the item returns to the queue; a reported merged stage never marks work delivered. Name each item's pull requests in its reported stage (pullRequests) so Wollipog can show their observed GitHub review, checks, and merge-queue state beside your report. Read it back with get_campaign_work_items. Ledger records grant no authority and never replace a typed decision.

For publication, retain the exact sanitized payload and approval, the child/conversation owning the draft, intent timestamp, and resulting issue URL. If an uncertain response has multiple plausible matches or GitHub is unavailable, keep that draft unresolved and continue independent work. A ledger does not replace the issue-reporting skill's requirement that the publishing session retain its drafting context.

Before the first dispatch, the root may record fixedBy: [{ issue: { repository, number }, workItemKeys: ["unit:a", "unit:b"] }] in record_campaign_plan for an already in-scope issue delivered by several units. Keys must name items in this campaign or the same plan call. List every required unit together: relationships are immutable and cannot be added after dispatch, even after attempts end. Each cited unit must remain in scope and independently pass delivery, report verification and exact merged-PR checks. A gap keeps closure human-owned with a server-derived reason. Existing requests gain no authority retroactively. Issues without this relationship keep their own-work-item behavior. Only the recorded plan is supported here; epic prose, closure evidence text and other agent-written text cannot establish relationships. This field requires protocol 268; on older servers retain human-owned closure, without updating the hosting stack.

Dispatch and Supervise

Use the child assignment when releasing each verified child. On hosts exposing work-item binding at creation, pass the work item to create_session so the child's attempt is recorded before its first prompt; if creation refuses the item, fix the plan rather than creating the child without it. A Custom host without that input uses only the read-only bootstrap compatibility sequence above, with recorded assignment before implementation. Use assign_campaign_work_item whenever a child is reused for another item or an item moves to another child; earlier attempts keep their verification and accounting. Reuse a suitable idle child for related follow-ups when possible; give it a fresh issue worktree based on the current default branch. Create another verified child if the old selected worktree has been retired or the session cannot resume safely. Count all campaign children for final verification and, under Stop and Archive, archival.

Never assign a child to update or restart the Wollipog installation (control plane, runner, or development stack) that hosts the campaign, and never approve or prompt such an action as post-merge cleanup. A detached helper is not an exception: it can stop the stack and then fail, leaving the parent and every child unable to recover it. Children report the merge commit and the currently deployed commit; making them match is an explicit handoff to a human terminal or another operator proven to be outside the target stack. If the Orchestrator itself is hosted by that stack, it must make the same handoff rather than executing the restart.

Idle children may still consume live capacity. If one cannot be safely reused, persist and adjudicate its report, verify it has no outstanding work or decisions, and stop it to release its slot before launching a replacement or the next queued issue. Verify the stop completed. Keep its history and include it in final verification, and in archival under Stop and Archive; do not wait for whole-campaign convergence to free an otherwise exhausted pool.

After dispatch, supervise through Wollipog's durable campaign continuations where they are available. A host whose campaign accepts record_campaign_plan records campaign events (a child becoming ready or blocked, an Orchestrator-owned request becoming actionable or resolved by someone else, a human settling a gate) and delivers them as a [Wollipog Campaign Continuation] prompt to the root campaign Orchestrator, a session with no parent session, once it is idle. An Orchestrator that has a parent session, including a nested Orchestrator, receives no continuations of its own. A turn that keeps polling only delays those wake-ups and re-reads the whole conversation on every check. A continuation names each event's request category and title, the child's status, how a resolved request ended and who resolved it, and compact campaign counts, and ends with an Action needed line. When it reads Action needed: no, nothing in it needs you: end the turn with a short status without calling get_campaign or list_descendant_requests, unless work you already started needs the turn. Otherwise, or when the line is absent, call get_campaign and list_descendant_requests, then read incremental events and status only for the children that the continuation or an actionable request names, from each child's recorded cursor. Resolve only currently Orchestrator-owned exact typed decisions with resolve_descendant_workflow_decision under the latest get_campaign policy, after reading the request itself; the continuation summarizes it but does not replace it. A request_resolved event for a decision you just resolved needs no further action; current hosts do not send one. Read complete result messages, not just truncated previews, and record updated cursors and decisions promptly.

Continue safe work in other children while one child waits at a human-owned gate, on a prerequisite, or on CI. Children watch their own branch checks and their own merge-queue entries, parking during long waits as using-wollipog describes: they end their turn while something model-free will wake them on the outcome, or make one long blocking wait where nothing can. Do not watch a child's pull request yourself, run a watcher for it, or hold your turn open for it; the child's turn end after the outcome reaches you like any other. A child that parked with park_on_pull_request after enqueueing appears in get_campaign under parkedChildren with its pull request, head and start time; its parking turn end sends no continuation, and Wollipog wakes it on the outcome or tells it the watch was lost. Only when a child reports that it has no way to wait on its queued pull request, watch that one pull request with a single model-free wait (before ending your turn, a background wollipog pr wait that wakes you on exit) and prompt the child on merged, queue_ejected, or queue_failed, because campaign continuations do not fire on merges or ejections. Never leave a queued child pull request with nobody watching it. A single empty descendant-request list, one idle child, or a dependent waiting on a prerequisite is not campaign completion. Once dispatch and every currently actionable request are handled, read get_campaign before ending the turn. End it with a short status update, and let the next continuation resume the campaign, only when continuations are available, this session is the root campaign Orchestrator (get_session reports no parentSessionId), the campaign status is active, its continuation (if present) is neither held, failed, nor missing_result, and no required worktree cleanup is still pending; do not hold the turn open with polling loops. While a Custom campaign is waiting_human, continuations stay held for the whole campaign until the human acts (under Full Control they keep coming, for example while an owner decision waits), so keep supervising children that can still progress and end the turn only when nothing else can progress without the human. Cleanup that starts after a child is verified, including a refused worktree retirement, produces no continuation: keep supervising until get_campaign reports cleanup settled or report the refused paths that need a human. Wherever continuations are unavailable, held, or stalled, keep supervising within the turn using bounded wait_session or CLI waits, including idle where supported, rotate fairly among children so one silent, CI-waiting, or blocked child cannot starve the others, keep the user updated during long waits, and report a stall that needs a human. Do not claim background monitoring unless continuations are available or an active wait loop is running. An explicit dispatch-only request remains dispatch-only, and a paused campaign remains paused: do not broaden either scope into continued execution.

idle, completed, and a successful enqueue are not issue completion. Independently verify the PR is merged into its intended base, the acceptance criteria are delivered, tracker updates are present, and cleanup is accounted for. If a slice leaves acceptance criteria incomplete, schedule the remaining work under that issue; do not hide it as optional follow-up work. Keep the exact review, check, and authorization snapshot rules from the repository's issue workflow.

For failures, inspect evidence and resume from the last verified step. Retry transient provider failures with backoff; stop repeating identical non-transient failures and report the specific blocker. Do not replace children while their ownership or mutation outcome is uncertain. A guardrail or required decision pauses affected work; it is not success or a reason to archive unfinished sessions.

Review and Execute Follow-Ups

After a child's issue reaches verified delivery and branch-cleanup accounting, inspect its Recommended Follow-Ups and the evidence behind each proposal. Collect every proposal in the ledger, including ones later rejected.

Accept only observed defects, unmet requirements, concrete review risks, or deliberately deferred work with testable scope. Independently agree with the evidence and value; do not rubber-stamp the child's list. Reject speculative polish or general refactors with a brief reason. Children must remain candid; never ask them to suppress valid findings to terminate the campaign.

Search open and closed issues, newly created issues, active PRs, and this campaign's pending drafts. Consolidate duplicates across children and record parent-issue lineage. Reuse a matching unresolved issue when appropriate; an already fixed match adds no work. A recurring proposal without new evidence is a convergence warning, not a new issue.

Record each proposal with record_campaign_follow_up before acting on it, naming the work items it came from in originWorkItemIds when the ledger is available. Then record your adjudication with adjudicate_campaign_recommendation: accepted (with the resulting work item key and, once published, the issue), rejected, deferred, or duplicate, each with a reason. Accepting records work; it does not authorize publishing or starting it. When the campaign's follow-up policy is Recommend Only, or the disposition is recommend_only_stop or duplicate_stop, stop at reporting: list the recommendation for the user and do not publish or dispatch it. Only requires_typed_gates under Execute Approved continues to the steps below, and that disposition is not itself approval.

For accepted new work, prepare the exact sanitized repository, title, body, and labels following the repository's issue-reporting skill or policy (for example .github/ISSUE_REPORTING.md), or GitHub's issue forms when none exists. Obtain the publication authorization required by the active policy. For a draft you wrote yourself, request follow_up_issue_publication through the usual typed request, get, and consume workflow; in a Custom campaign that decision is always the campaign owner's, and you never approve it yourself. Include the accepted recommendation's recommendationId when there is one, and consume with exactly the snapshot you requested. If authorized parent publication is unavailable in the Orchestrator tool boundary, have the child that owns the draft publish it after the exact authorization; do not escape the boundary. Recheck duplicates immediately before creation and verify the published issue by reading it back. Then record it on its recommendation with adjudicate_campaign_recommendation (accepted, a reason, and resultingIssue); without resultingWorkItemKey this links the work item the acceptance created, and the recommendation stops awaiting publication. Link it from the originating issue.

Queue each accepted, published or existing unresolved follow-up, prioritizing dependencies and impact. Dispatch it through the same claim, fix, review, merge, cleanup, and follow-up cycle. Continue through any number of generations. Do not backfill unrelated tracker issues after the initial selection; descendants of accepted work define the campaign's continuing scope.

If follow-ups continually expand into new product scope, recur after purported fixes, or exceed a user-specified limit, report the lineage and concrete remaining work and seek direction. Do not silently impose a round limit, declare convergence, or discard recommendations.

Finish and Archive

The campaign converges only when every selected and accepted issue is delivered, every child's latest follow-up report has been adjudicated, no accepted follow-up awaits publication or execution, and no PR, review, approval, or implementation task remains pending. Rejected or already-resolved proposals need recorded reasons; raw recommendations need not be empty if none remain actionable after review.

Before archival, save final child reports and verify remote branches are gone or retained for an explicitly documented dependency. Never delete a branch merely because a PR entered the merge queue. Retained branches or unresolved delivery obligations prevent reporting full completion. Where get_campaign reports mergedBranches, it lists each merged campaign pull request's head branch as deleted, retained (with the reason), or pending, and a pending one keeps the campaign from verified_complete. Have the child that merged a branch delete it before its final report. When a branch must stay, or its child can no longer delete it, record a handoff to human or external on the work item naming its pull request, with the reason and the next action; the branch then reads retained and the campaign can finish as complete_with_handoffs.

When a provider refuses an approved forge command (for example, Claude Code's auto-mode classifier refusing an approved enqueue or branch deletion), neither you nor the child retries it through another shell, wrapper, or permission change, and nobody turns the classifier off. The child calls execute_workflow_decision for that exact occurrence instead, and Wollipog performs the one approved action itself: a compare-and-delete pinned to the approved merged head for a merged_branch_deletion that names pullRequest and headSha, or the canonical pinned enqueue for an armed pr_merge. Its forgeAction records the outcome. A refusal that changed nothing leaves the approval in place for a retry; a stale snapshot revokes it and needs a new request.

Verify each finished child with verify_campaign_child, using its exact completed report event sequence, after its follow-ups are recorded. Pass workItem with the item and outcome (delivered or incomplete) so delivery is recorded against that item's attempt; without it no work item counts as delivered. Under the campaign's Retain completion policy, leave verified children unarchived and report them as retained. Only under Stop and Archive, where verification starts the durable stop/archive lifecycle, archive only this campaign's descendants using Wollipog's supported lifecycle operations; archive itself supports stop-before-archive. Verify archived: true and absence of pending/failed stop or archive state; an accepted request is not completed archival. Never archive the parent or unrelated sessions.

Retire runner-owned worktrees only through Wollipog discard/reconciliation. Active worktree retention before provider exit is an expected deferral. After children stop, verify reconciliation or use authorized descendant discard; inspect any remaining local branches and remove only verified merged campaign branches through supported cleanup. Preserve dirty or unpushed work and report it. Serialize shared-checkout refreshes and enforce the hosting-stack restriction above; neither the hosted parent nor any child may perform the deployment restart.

Finish with the initial and follow-up issue/PR links, delivered results, rejected/duplicate follow-up reasons, verified archived or retained session counts, and cleanup results. Clearly distinguish convergence from an interrupted or blocked campaign. Do not claim complete cleanup if resources remain unexpectedly retained.

Closing a GitHub Issue

The root Orchestrator can propose closing an issue in its human-authorized campaign scope with request_github_issue_closure (requestId, issue, reason: completed or not_planned, explanation, evidence, and an optional exact comment). The runner derives the repository, current issue, and related open pull requests; the server includes the assignments of active children whose work can bear on the issue. A child is left out only when its launch prompt is recorded, it has an open attempt (from create_session or assign_campaign_work_item), and every attempt it has ever had is on a work item that has never tracked the issue and has no follow-up links. Pass each child's work item at creation so unrelated activity does not revoke the approval; a prompt that mentions the issue does not bind an unassigned child by itself. Custom campaigns require a human-owned typed decision. Full Control delegates only when the server confirms a human-established issue boundary, verified delivered report and actual default-branch merges, or a supported recorded not-planned disposition. Never infer this authority from a prompt. The closure is created pending, and close_github_issue refuses a pending closure. The exact sequence is:

  1. request_github_issue_closure.
  2. Read the exact decision and its effective owner (authority) with get_workflow_decision.
  3. Approve it. When authority is orchestrator (Full Control's standing authorization), the root approves it itself: call resolve_descendant_workflow_decision with sessionId set to its own session ID, the occurrenceId, and outcome: "approve". No person will approve it, so do not ask one. When authority is human, a person approves it in Wollipog; wait for that, and never approve it yourself.
  4. Execute it with close_github_issue with its exact occurrenceId and resourceDigest.

Under Full Control, an in-scope closure that fails the delivery proof is still a person's decision, but its reason is closure_proof_incomplete, not outside_boundary. The response then carries proofGaps: each gap names its work item and pull requests and an action. Fix what you can (verify the child with verify_campaign_child, record the delivery pull request in the item's reported stage, or wait for a named open pull request to merge or close) and request the closure again: a request that passes the proof is Orchestrator-owned and supersedes the person's. An open pull request that GitHub still cross-references keeps blocking even after its mention is edited out. Leave a person_decides gap to the person, and never ask a person to approve a closure you could make Orchestrator-owned yourself.

An in-scope epic needs no fixed-by plan: when its completed closure has no other proof, the server has the runner read its members on the forge (sub-issues and the member checklist) and proves it from them. Every member must be in scope and closed as completed, and every dispatched work item of the epic must still be delivered; a placeholder item that was never dispatched neither blocks the closure nor, once the epic closes this way, the campaign's completion. A gap names each member that is open (close it through its own closure request first), closed another way, outside scope or unreadable. This needs runner protocol 278 on GitHub; elsewhere the epic's closure stays with the person. It never applies to a not-planned closure or to an issue with a fixed-by plan.

The CLI equivalents of steps 1, 2 and 4 are:

wollipog issue-closure request --proposal '<json>' --json
wollipog decision get <occurrence-id> --json
wollipog issue-closure execute <occurrence-id> --digest <resource-digest> --json

Approval expires 30 minutes after resolution. Changed issue evidence, policy, or included child work requires renewed review, as does a child moving into or out of the included set. Never substitute a shell command or generic approval, and never approve a human-owned request. A root may resolve an eligible Full Control occurrence only from its server-recorded standing authorization; the server rechecks it when the root resolves. Under Full Control nobody sees the root's own questions: the server dismisses them unanswered and tells the root to decide with these typed tools. Read issueClosureResult: closed and already_closed are verified outcomes. refused wrote nothing and used up the approval: its refusal.reason and refusal.summary say why and name any pull request that changed, so address that and request a new closure. uncertain means GitHub may have accepted the action. Inspect uncertain outcomes without replaying the comment or closure. Issue closure does not attest implementation or campaign completion. Unsupported peers, nonlocal execution targets, or incomplete bounded conflict evidence refuse the operation clearly.

Inspecting and Changing Campaign Issue Scope

Before delegating an epic, use get_campaign_issue_scope (CLI: wollipog issue-scope get --epic <number>). It returns authorized repository-qualified issues, a revision, recorded work outside scope, and reviewable umbrella/member candidates. Native GitHub sub-issues and leading checklist entries under Units, Members, Child Issues, Sub-Issues, or Implementation Issues are candidates; dependencies and incidental references are not members and never grant authority. Inspect candidates and select the intended members.

To recover or extend an existing campaign, use request_campaign_issue_scope_change (CLI: wollipog issue-scope request --proposal '<json>') with requestId, expectedRevision, explanation, and exact additions and removals, each an array of { "repository": "owner/repo", "number": 123 }. Custom requires an authenticated human to approve the exact change. In Full Control with a separate human-established issue boundary, use lineage: {kind: "epic", epic: <number>} for verified intended members or {kind: "follow_up", publicationOccurrenceId: <id>} for an exact authorized publication. A publication the boundary's author or a campaign owner approved as a person under the current objective also qualifies. When the owner's first message set the scope and its Scope Grant in Campaign Status failed, was uncertain, or asked the campaign to select issues, propose the issues you chose without lineage: the proposal goes to the owner as one typed approval, so put your rationale in explanation. The server refuses incidental references, foreign repositories and changes beyond human-set limits, naming the failed condition in a bounded code; a campaign owner can still propose the change from Campaign Status. Resolution applies and consumes scope atomically; do not separately consume it. A root can resolve only an eligible occurrence backed by its standing human authorization: when the effective owner is orchestrator, resolve it with resolve_descendant_workflow_decision and its own session ID as sessionId; nobody else will. Pending, denied, stale and replayed proposals leave scope unchanged. After approval, re-read the scope. Humans can inspect, resolve epic candidates, and request changes in Campaign Status's Authorized Issue Scope.

Scope changes preserve conversation and work history. Removals display affected assignments and revoke outstanding action decisions; issue closure retains its separate exact decision. Active Orchestrator participants must use the campaign's runner and repository workspace. Updates require protocol v208 on the control plane and participating runners; unsupported peers must be updated and reconnected. The authoritative revision is persisted on both sides, delivered on reconnect and restart, and checked again by closure execution. An offline or unsynchronized runner cannot execute a revised closure. Ledger recording, assignments, ordinary prompts, and epic links never modify authority.

Under Full Control the issue scope also bounds delivery. You may record a work item for an unscoped issue, but launching or assigning a child on it, or retargeting dispatched work at it, is refused, naming the scope route. A merge that would close an unscoped issue needs the campaign owner: a child's pr_merge naming one in intendedClosures is refused with each issue named, so have the child write "Refs #N" or add the issue to the scope first. A refused scope change is final for this campaign: do not recommit, dispatch, or merge around it. Report the issue as blocked work for the campaign owner. A merge whose closures cannot be read (a GitLab merge, or a GitHub merge from an older runner) is human-owned whatever it declares. Merges are evaluated again against the current scope before approval and arming.

Bounded Full Control issue writes require protocol v217 on every participant. The authorizing human remains distinct from agent scope dispositions. Related follow-up publication requires a deduplicated, accepted recommendation with authorized origin work items and exact sanitized repository, title, body and labels; include recommendationId in the workflow request. Review the exact public payload before resolving. Duplicate/sanitation and lineage checks repeat before one-shot consumption. Read the published issue back and record it on that recommendation before proposing its scope addition. Missing issue-boundary authority never turns ledger acceptance or ordinary prose into a grant.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Related Skills