lvlup-sw/exarchos

prune

Interactively prune stale non-terminal workflows from the pipeline.

查看源码
仓库原始内容

按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。

Prune Workflows Skill

VCS Provider

This skill's safeguards use VCS operations internally (open PR detection). The orchestrate handler manages VCS provider dispatch automatically. No gh/glab/az commands needed — the MCP server handles provider dispatch.

Overview

Bulk-cancel stale non-terminal workflows that have accumulated in the pipeline. Wraps the prune_stale_workflows orchestrate action with an interactive dry-run-then-confirm UX so the user always sees the candidate set before any state mutates.

Pruning is a maintenance operation -- not a workflow phase. It produces workflow.pruned events alongside the standard workflow.cancelled events emitted by the underlying cancel path, so downstream views can distinguish user-intent cancellations from batch cleanup.

Triggers

Activate this skill when:

  • User runs prune command
  • User says "prune workflows", "clean stale workflows", "pipeline cleanup"
  • exarchos:exarchos_view({ action: "pipeline", scope: "all" }) shows many inactive workflows the user wants to clear in bulk. Prune observes candidates with scope: "all" because the default view is repo-scoped and hides the legacy rows (workflows started before repo identity was recorded) that prune exists to drain — a repo-scoped observation would miss the very inventory it targets.

Prerequisites

  • An exarchos state directory with one or more non-terminal workflows
  • For safeguard checks against live PRs: gh available in PATH (the orchestrate handler shells out)
  • For safeguard checks against branch activity: git available in PATH

Process

Step 1: Dry-Run Preview

Always start with dryRun: true. This call performs candidate selection and safeguard evaluation but does not mutate any workflow state.

typescript
exarchos:exarchos_orchestrate({
  action: "prune_stale_workflows",
  args: {
    dryRun: true
  }
})

The response shape is:

ts
{
  candidates: [
    { featureId: string, phase: string, workflowType: string, stalenessMinutes: number }
  ],
  skipped: [
    { featureId: string, reason: "open-pr" | "active-branch" }
  ]
}

Optional args:

  • thresholdMinutes -- staleness cutoff. Default is 10080 (7 days).
  • includeOneShot -- whether to include oneshot workflows in the candidate set. Default true.
  • force -- not relevant in dry-run; only honored in apply mode (Step 4).

Step 2: Display Candidate Table

Render a table to the user so they can review what would be pruned. Use this format:

markdown
## Prune Candidates (3)

| Feature ID | Type | Phase | Stale (min) |
|---|---|---|---|
| feat-old-experiment | feature | implementing | 14430 |
| oneshot-typo-fix | oneshot | plan | 9120 |
| debug-flaky-test | debug | investigate | 8650 |

## Skipped by Safeguards (2)

| Feature ID | Reason |
|---|---|
| feat-active-pr | open-pr |
| feat-recent-work | active-branch |

If candidates.length === 0 AND skipped.length === 0, output:

No stale workflows to prune. Pipeline is clean.

Then exit -- no further action.

Step 3: Prompt for Confirmation

Ask the user one of three choices:

proceed -- prune the listed candidates (skipped workflows stay) abort -- exit without changes force -- bypass safeguards and prune skipped workflows too

Wait for explicit user input. Do not auto-proceed.

Step 4a: Apply (proceed)

On proceed, invoke the same action with dryRun: false. Pass through thresholdMinutes and includeOneShot if the user set them in Step 1.

typescript
exarchos:exarchos_orchestrate({
  action: "prune_stale_workflows",
  args: {
    dryRun: false
  }
})

The response now includes a pruned array:

ts
{
  candidates: [...],
  skipped: [...],
  pruned: [
    { featureId: string, previousPhase: string }
  ]
}

Each entry in pruned corresponds to a workflow that transitioned to cancelled and emitted a workflow.pruned event.

Step 4b: Apply (force)

On force, set force: true. Safeguards are bypassed but the bypass is recorded in the workflow.pruned event payload as skippedSafeguards: [...] so the audit trail is intact.

typescript
exarchos:exarchos_orchestrate({
  action: "prune_stale_workflows",
  args: {
    dryRun: false,
    force: true
  }
})

In force mode, workflows that were in the skipped list during dry-run are now eligible for pruning.

Step 4c: Apply (abort)

On abort, exit without invoking the action a second time. The dry-run has not mutated any state.

Step 5: Report Results

After the apply call returns, summarize the outcome:

markdown
## Prune Complete

**Pruned:** 3 workflows transitioned to cancelled
**Skipped:** 2 workflows preserved by safeguards
**Force bypass:** no

### Pruned Workflows
- feat-old-experiment (was: implementing)
- oneshot-typo-fix (was: plan)
- debug-flaky-test (was: investigate)

If force was used, also list any safeguards that were bypassed:

markdown
### Safeguards Bypassed
- feat-active-pr: open-pr
- feat-recent-work: active-branch

Safeguards Explained

Two safeguards run automatically in the orchestrate handler before each cancel:

SafeguardBehaviorReason key
Open PRSkip if gh pr list --head <branch> --state open returns any resultsopen-pr
Recent commitsSkip if git log --since "24 hours ago" origin/<branch> shows commitsactive-branch

A workflow without a branchName in state (e.g., abandoned at ideate/plan before delegation) cannot have a PR or branch activity, so safeguards short-circuit and the workflow is eligible for pruning.

force: true bypasses both checks but does not bypass the audit -- the bypassed safeguard names are recorded in the workflow.pruned event payload.

Error Handling

  • No state directory: initialize an exarchos workflow first — there is nothing to prune.
  • `gh` / `git` not available: the safeguard checks short-circuit with errors. Verify no PRs are open manually, then re-run with force: true.
  • All workflows clean: report "No stale workflows to prune" and exit (see Example 3).

Anti-Patterns

Don'tDo Instead
Skip the dry-run stepAlways start with dryRun: true so the user sees candidates first
Auto-confirm without showing the tableRender the candidate table and wait for explicit user input
Use force: true by defaultReserve force for cases where the user has explicitly opted in
Manually call cancel for each stale workflowUse this skill -- it batches the cancel loop and emits the workflow.pruned audit event
Run on every sessionPruning is a maintenance operation; run when pipeline accumulation is observable

Examples

Example 1: Clean dry-run, user proceeds

> prune

## Prune Candidates (2)

| Feature ID | Type | Phase | Stale (min) |
|---|---|---|---|
| feat-old-spike | feature | plan | 12880 |
| oneshot-readme-tweak | oneshot | implementing | 9700 |

## Skipped by Safeguards (0)

(none)

Proceed? (proceed/abort/force)

> proceed

## Prune Complete

**Pruned:** 2 workflows transitioned to cancelled
**Skipped:** 0
**Force bypass:** no

### Pruned Workflows
- feat-old-spike (was: plan)
- oneshot-readme-tweak (was: implementing)

Example 2: Safeguard skip, user forces

> prune

## Prune Candidates (1)

| Feature ID | Type | Phase | Stale (min) |
|---|---|---|---|
| feat-stale-no-pr | feature | implementing | 11200 |

## Skipped by Safeguards (1)

| Feature ID | Reason |
|---|---|
| feat-stale-with-pr | open-pr |

Proceed? (proceed/abort/force)

> force

## Prune Complete

**Pruned:** 2 workflows transitioned to cancelled
**Skipped:** 0
**Force bypass:** yes

### Pruned Workflows
- feat-stale-no-pr (was: implementing)
- feat-stale-with-pr (was: implementing)

### Safeguards Bypassed
- feat-stale-with-pr: open-pr

Example 3: Empty pipeline

> prune

No stale workflows to prune. Pipeline is clean.

Schema Discovery

For the canonical argument schema and any future fields, use:

typescript
exarchos:exarchos_orchestrate({
  action: "describe",
  actions: ["prune_stale_workflows"]
})

Exarchos Integration

The prune_stale_workflows action emits two events per pruned workflow:

  • workflow.cancelled (auto-emitted by the underlying handleCancel path)
  • workflow.pruned (emitted by this handler with triggeredBy: 'manual' and optional skippedSafeguards)

Both are projected into the workflow state's _events array by the standard projection. Downstream views can filter on workflow.pruned to identify batch cleanups versus user-initiated cancels.

来自同一仓库

更多 Skills

全部 Skills