Skill: athola/nm-egregore-summon (version 1.0.2)

--- name: summon description: | Autonomous orchestrator processing manifest work items through the development lifecycle with budget tracking version: 1.9.5 triggers: - autonomous - pipeline - orchestrator - mission metadata: {"openclaw": {"homepage": "https://github.com/athola/claude-night-market/tree/master/plugins/egregore", "emoji": "\ud83e\udd9e", "requires": {"config": ["night-market.attune:project-brainstorming", "night-market.attune:project-specification", "night-market.attune:project-planning", "night-market.attune:project-execution", "night-market.pensive:code-refinement", "night-market.conserve:bloat-detector", "night-market.sanctum:pr-prep", "night-market.sanctum:pr-review", "night-market.sanctum:commit-messages", "night-market.conserve:clear-context"]}}} source: claude-night-market source_plugin: egregore --- > **Night Market Skill** — ported from [claude-night-market/egregore](https://github.com/athola/claude-night-market/tree/master/plugins/egregore). For the full experience with agents, hooks, and commands, install the Claude Code plugin. ## Table of Contents - [Overview](#overview) - [When To Use](#when-to-use) - [When NOT To Use](#when-not-to-use) - [Orchestration Loop](#orchestration-loop) - [Pipeline-to-Skill Mapping](#pipeline-to-skill-mapping) - [Context Overflow Protocol](#context-overflow-protocol) - [Token Budget Protocol](#token-budget-protocol) - [Failure Handling](#failure-handling) - [Module Reference](#module-reference) # Summon ## Overview Summon is the egregore orchestration loop. It reads the manifest (`.egregore/manifest.json`), selects the next active work item, maps the current pipeline step to a specialist skill, and invokes that skill. After each step it advances the pipeline, checks context and token budgets, and repeats until all items are completed or the budget is exhausted. The orchestrator never re-implements phase logic. Each pipeline step delegates to an existing skill via `Skill()` calls. Summon only manages state transitions, retries, and budget guards. ## When To Use - Processing one or more work items through the full intake-build-quality-ship pipeline. - Resuming an interrupted egregore session (manifest already exists with active items). - Running autonomously under a watchdog that relaunches on exit. ## When NOT To Use - Running a single skill in isolation (call the skill directly instead). - Exploratory work where the pipeline does not apply. - When human review is needed before every step (use manual skill invocations). ## Launching the Orchestrator **Always launch the orchestrator agent in the FOREGROUND.** Do not use `run_in_background: true`. The main session becomes the egregore -- it blocks on the orchestrator agent until the egregore finishes or is dismissed. ``` Agent( subagent_type: "egregore:orchestrator", prompt: "<context about work items and current state>", run_in_background: false // Required ) ``` If you launch the orchestrator in the background, the main session will have nothing to do and will stop. This defeats the entire purpose of the egregore. The stop hook cannot prevent this because background agents are detached. ## Manifest Mode Before launching the orchestrator, ensure the manifest has the correct run mode: - **Default (no `--bounded` flag)**: set `"indefinite": true` in the manifest. The egregore will scan for new work after completing all items and run until dismissed. - **With `--bounded` flag**: set `"mode": "bounded"` in the manifest. The egregore stops after all items are completed or failed. If the manifest already exists and has `"mode": "bounded"` but the user did NOT pass `--bounded`, update the manifest to `"indefinite": true` before launching. After launching, do NOT produce any summary, status table, or "what's happening" output. The orchestrator IS the session now. Let it run. ## Orchestration Loop Follow these steps exactly. Each iteration processes one pipeline step for one work item. ### 1. Load state ``` manifest = Read(".egregore/manifest.json") config = Read(".egregore/config.json") budget = Read(".egregore/budget.json") ``` If `manifest.json` does not exist, stop with an error: "No manifest found. Run `egregore init` first." ### 2. Pick the next work item ``` item = manifest.next_active_item() ``` If `item` is `None`, all work is done. Save the manifest, report completion, and exit. ### 3. Map current step to a skill Look up `item.pipeline_stage` and `item.pipeline_step` in the Pipeline-to-Skill Mapping table below. Determine the skill name or action to invoke. ### 4. Invoke the skill Call `Skill()` or execute the mapped action. Pass any required context (branch name, issue ref, etc.) from the work item. ### 5. Handle the result **On success:** - Call `manifest.advance(item.id)` to move to the next step. - Reset `item.attempts` to 0. - Save the manifest. **On failure:** - Call `manifest.fail_current_step(item.id, reason)`. - If `item.attempts < item.max_attempts`, retry the same step on the next iteration. - If `item.status` is now `"failed"`, log the failure and move to the next work item. - Save the manifest. ### 6. Check context budget Estimate context window usage. If usage exceeds 80%: 1. Save the manifest to disk. 2. Write a continuation note to `.egregore/continuation.json` with the current item ID, stage, and step. 3. Invoke `Skill(conserve:clear-context)`. 4. The watchdog or caller will relaunch a fresh session that resumes from the saved state. ### 7. Check token budget If the last skill call returned a rate limit error: 1. Record the rate limit in `budget.json` via `budget.record_rate_limit(cooldown_minutes)`. 2. Save `budget.json`. 3. Alert the overseer (see `notify.py`). 4. **Schedule in-session recovery** (2.1.71+): use `CronCreate` to schedule a one-shot resume prompt at the cooldown expiry time. The session stays alive and resumes automatically with context preserved. 5. **Fallback** (pre-2.1.71 or cooldown > 7 days): exit gracefully. The watchdog checks cooldown before relaunching. ### 8. Repeat Go back to step 2. Continue until all items are completed, all items are failed, or a budget limit is reached. ## Pipeline-to-Skill Mapping | Stage | Step | Skill/Action | |-------|------|--------------| | intake | parse | Parse prompt or fetch issue via `gh issue view` | | intake | validate | Validate requirements are actionable | | intake | prioritize | Order by complexity (single item = skip) | | build | brainstorm | `Skill(attune:project-brainstorming)` | | build | specify | `Skill(attune:project-specification)` | | build | blueprint | `Skill(attune:project-planning)` | | build | execute | `Skill(attune:project-execution)` | | quality | code-review | `Skill(pensive:code-refinement)` | | quality | unbloat | `Skill(conserve:bloat-detector)` | | quality | code-refinement | `Skill(pensive:code-refinement)` | | quality | update-tests | `Skill(sanctum:test-updates)` | | quality | update-docs | `Skill(sanctum:doc-updates)` | | ship | prepare-pr | `Skill(sanctum:pr-prep)` | | ship | pr-review | `Skill(sanctum:pr-review)` | | ship | fix-pr | Apply review fixes | | ship | merge | `gh pr merge` (if auto_merge enabled) | The intake stage steps (parse, validate, prioritize) are handled inline by the orchestrator. See `modules/intake.md` for details. ## Context Overflow Protocol The orchestrator runs inside a finite context window. To avoid losing state when the window fills: 1. **Monitor usage.** After each skill invocation, estimate how much of the context window has been consumed. 2. **At 80% capacity**, trigger a context save: - Persist the full manifest to disk. - Write `.egregore/continuation.json` with a snapshot of the current position. - Invoke `Skill(conserve:clear-context)`. 3. **On relaunch**, load `continuation.json` and resume from the saved position. The manifest on disk is the source of truth for pipeline progress. 4. **Increment** `manifest.continuation_count` each time a context-overflow handoff occurs. This protocol ensures zero lost progress across context boundaries. ## Progress Monitoring & Self-Healing (2.1.71+) After loading state (step 1), schedule a recurring heartbeat that both reports status and recovers stalled pipelines: ``` CronCreate( cron: "*/5 * * * *", prompt: "Check .egregore/manifest.json. If there are pending or active items that are not being processed, resume the orchestration loop by invoking Skill(egregore:summon). Otherwise, report status via /egregore:status.", recurring: true ) ``` This serves two purposes: 1. **Visibility**: emits a status summary every 5 minutes so autonomous runs are observable. 2. **Self-healing**: if a user prompt, context compaction, or unexpected error breaks the orchestration loop, the next heartbeat detects stalled items and re-enters the pipeline automatically. The cron task auto-expires after 7 days by default. Use `durable: true` to persist across restarts, or `CronDelete` to cancel early. ## Token Budget Protocol Egregore sessions consume API tokens across a budget window (default: 5 hours). The budget protocol prevents runaway spending: 1. **Before each skill call**, check `budget.json` for an active cooldown. If `is_in_cooldown(budget)` returns true, exit and let the watchdog retry later. 2. **On rate limit error**, record the event via `budget.record_rate_limit(cooldown_minutes)`. The cooldown duration equals the API retry-after header plus `config.budget.cooldown_padding_minutes`. 3. **Save and exit.** Write `budget.json`, alert the overseer, and exit with code 0. 4. **The watchdog** checks `budget.json` before relaunching. It will not start a new session until the cooldown expires. See `modules/budget.md` for the full calculation and state schema. ## Failure Handling Each work item allows up to `max_attempts` retries per step (default: 3, configurable in `config.json`). - **Retry**: If a step fails and `attempts < max_attempts`, the orchestrator retries the same step on the next iteration. The manifest is saved between retries. - **Mark failed**: If `attempts >= max_attempts`, the item status changes to `"failed"` and `failure_reason` is set. The orchestrator moves to the next active item. - **Alert**: On failure, notify the overseer via the configured notification channel. - **Never block**: The orchestrator must never wait for human input. If a step requires clarification, record a decision (see `modules/decisions.md`) and proceed with the best available option. ## Module Reference - **pipeline.md**: Stage and step definitions, transition rules, idempotency guarantees. - **budget.md**: Token window management, rate limit detection, cooldown calculation, graceful shutdown. - **intake.md**: Work item parsing for prompts and GitHub issues, brainstorm skip logic. - **decisions.md**: Autonomous decision-making framework, decision log format, examples.

path: modules/budget.md
content: ---
name: budget
description: Token window management protocol
category: orchestration
---

# Budget Module

Manages token budget windows, detects rate limits, calculates
cooldown periods, and triggers graceful shutdown when limits
are reached.

## Budget Window

An egregore session operates within a budget window (default:
5 hours).
The window tracks cumulative token usage and rate limit
events across multiple sessions.

The budget state lives in `.egregore/budget.json`:

```json
{
  "window_type": "5h",
  "window_started_at": "2026-03-04T10:00:00+00:00",
  "estimated_tokens_used": 0,
  "session_count": 1,
  "last_rate_limit_at": null,
  "cooldown_until": null
}
```

## Rate Limit Detection

The orchestrator detects rate limits through two signals:

1. **API error response**: a skill invocation fails with an
   HTTP 429 or a rate-limit error message from the Claude
   API.
2. **Explicit retry-after header**: the error includes a
   retry-after duration in seconds.

When either signal is detected, the orchestrator must stop
work immediately and enter cooldown.

## Cooldown Calculation

The cooldown duration is computed as follows:

```
cooldown_minutes = retry_after_seconds / 60
                 + config.budget.cooldown_padding_minutes
```

The padding (default: 10 minutes) prevents the watchdog from
relaunching too early and hitting the same rate limit again.

If no retry-after header is present, use a default cooldown
of 30 minutes plus padding.

## Rate Limit Recovery

When a rate limit is detected:

1. **Save manifest**: write the current pipeline state to
   `.egregore/manifest.json` so no progress is lost.
2. **Record rate limit**: call
   `budget.record_rate_limit(cooldown_minutes)` to update
   the budget state.
3. **Save budget**: write `.egregore/budget.json` with the
   updated cooldown timestamp.
4. **Alert overseer**: send a notification via the configured
   channel (see `notify.py`) with the rate limit details and
   expected resume time.

### In-Session Recovery (2.1.71+, all providers 2.1.73+)

Use `CronCreate` to schedule a one-shot resume at the
cooldown expiry time. As of 2.1.73, `/loop` and
`CronCreate` are available on Bedrock, Vertex, Foundry,
and with telemetry disabled (previously first-party API
only).

```
CronCreate(
  cron: "<min> <hour> * * *",
  prompt: "Cooldown expired. Read .egregore/manifest.json
    and resume the pipeline. Invoke
    Skill(egregore:summon) to continue.",
  recurring: false
)
```

**Advantages over watchdog restart:**

- Session stays alive: no context loss, no manifest
  re-read overhead, no fresh session startup cost
- Exact timing: fires at cooldown_until instead of
  polling every 5 minutes
- No OS-level setup: works without launchd/systemd

The session remains idle between the rate limit and the
scheduled prompt. When the cron fires, the orchestration
loop resumes with the full conversation context intact.

### Fallback: Exit and Watchdog

If `CronCreate` is unavailable (pre-2.1.71, or
pre-2.1.73 on Bedrock/Vertex/Foundry), the cooldown
exceeds 7 days (cron task auto-expiry), or the session
itself needs to exit for other reasons:

5. **Exit cleanly**: exit with code 0. A non-zero exit
   would trigger the watchdog's crash handler instead of
   the cooldown-aware restart path.

The watchdog checks `budget.json` before relaunching and
waits until the cooldown expires.

## Pre-Launch Cooldown Check

Before starting any work, the orchestrator must check:

```python
if is_in_cooldown(budget):
    # Do not start. Exit and let the watchdog retry later.
    sys.exit(0)
```

The watchdog also performs this check before launching a new
session.
This double-check prevents races where the watchdog reads a
stale budget file.

## Window Reset

The budget window resets when `window_started_at` is older
than the configured `window_type` duration.
On reset:

1. Set `estimated_tokens_used` to 0.
2. Set `session_count` to 0.
3. Set `window_started_at` to the current time.
4. Clear `last_rate_limit_at` and `cooldown_until`.
5. Save `budget.json`.

## Token Estimation

Exact token counts are not always available.
The orchestrator uses these heuristics:

- **Per-session estimate**: each Claude session uses roughly
  100k-200k tokens depending on task complexity.
- **Increment on session start**: add the per-session
  estimate to `estimated_tokens_used` when a new session
  begins.
- **Post-hoc correction**: if the session completes
  normally, adjust the estimate based on actual conversation
  length (word count * 1.3 as a rough token multiplier).

These estimates are for observability and alerting, not for
hard enforcement.

### `rate_limits` Statusline Field (2.1.80+)

The statusline input now includes `rate_limits` with
5-hour and 7-day rate limit usage (`used_percentage`,
`resets_at`). The orchestrator can use this for more
accurate rate limit detection than the heuristic
estimates in the budget window, triggering cooldown
before hitting hard limits.

### Token Estimation Fix (2.1.75+)

Claude Code fixed token estimation over-counting for
`thinking` and `tool_use` blocks, which previously
triggered premature context compaction. Sessions now
use more of their available context window before
compaction. This is especially relevant for egregore
sessions using Opus 4.6 with extended thinking: the
orchestrator can maintain longer conversation context
before compaction interrupts the pipeline loop.

Combined with the 1M context default for Max/Team/
Enterprise (2.1.75+), egregore sessions benefit from
significantly longer uninterrupted orchestration runs.
Rate limit errors are the authoritative signal for budget
exhaustion.


path: modules/decisions.md
content: ---
name: decisions
description: Autonomous decision-making framework
category: orchestration
---

# Decisions Module

Defines how the egregore orchestrator makes autonomous
decisions, logs them for auditability, and avoids blocking
on ambiguity.

## Decision Principles

The orchestrator follows three core principles when facing
a choice:

### 1. Prefer the simpler option

When two approaches could work, choose the one with fewer
moving parts, fewer dependencies, and less surface area for
failure.
Simpler solutions are easier to review, easier to revert,
and faster to ship.

### 2. Log the rationale

Every decision must be recorded in the manifest with enough
context for a human reviewer to understand why the choice
was made.
The log is the audit trail that makes autonomous operation
trustworthy.

### 3. Never block

The orchestrator must never pause and wait for human input.
If requirements are ambiguous, make the conservative choice
and document the assumption.
A shipped PR with a documented assumption is more useful
than a stalled pipeline waiting for clarification.

## Decision Log Format

Decisions are recorded on the work item via
`manifest.record_decision()`:

```json
{
  "step": "intake/validate",
  "chose": "interpret-as-bug-fix",
  "why": "Issue title says 'fix' and label is 'bug'. Body is ambiguous about scope but the referenced file path narrows it to a single module."
}
```

**Fields:**

- **step**: the pipeline stage/step where the decision was
  made, in `"stage/step"` format.
- **chose**: a short identifier for the chosen option.
  Use kebab-case. Keep it under 40 characters.
- **why**: a one-to-three sentence explanation of the
  reasoning. Reference concrete evidence (labels, file
  paths, word counts, config values).

## When to Record a Decision

Record a decision whenever the orchestrator:

- Skips a step (e.g., brainstorm skip, prioritize skip,
  merge skip).
- Chooses between two valid approaches during a skill
  invocation.
- Interprets ambiguous requirements in a specific way.
- Falls back to a simpler strategy on a retry attempt.
- Ignores a non-blocking warning or lint issue.

Do not record trivial operational facts (e.g., "loaded
manifest successfully").
The decision log is for choices, not events.

## Examples

### Skipping brainstorm for a well-defined issue

```json
{
  "step": "build/brainstorm",
  "chose": "skip-brainstorm",
  "why": "Source is github-issue #42, body has 250 words, labels include 'bug'. Config skip_brainstorm_for_issues is true."
}
```

### Choosing a simpler implementation approach

```json
{
  "step": "build/execute",
  "chose": "inline-helper-over-new-module",
  "why": "The helper function is 15 lines. Creating a separate module would add import overhead and a new test file for minimal reuse benefit."
}
```

### Interpreting ambiguous scope

```json
{
  "step": "intake/validate",
  "chose": "narrow-scope-to-api-layer",
  "why": "Issue mentions both API and CLI but only the API endpoint is referenced in the reproduction steps. Narrowing to API only to avoid unbounded scope."
}
```

### Falling back on retry

```json
{
  "step": "quality/code-review",
  "chose": "skip-lint-warning-on-retry",
  "why": "Attempt 2 of 3. Previous attempt failed on a style lint warning in generated code. Skipping the warning since the generated file is not hand-maintained."
}
```

## Decision Review

Decisions are visible in two places:

1. **Manifest**: each work item's `decisions` array contains
   the full log. Inspect with:
   ```bash
   cat .egregore/manifest.json | jq '.work_items[0].decisions'
   ```
2. **PR body**: the `prepare-pr` step includes a summary of
   key decisions in the PR description so reviewers
   understand the autonomous choices that were made.


path: modules/intake.md
content: ---
name: intake
description: Work item parsing for prompts and GitHub issues
category: orchestration
---

# Intake Module

Handles the intake stage of the pipeline: parsing work item
sources into validated requirements, creating branches, and
determining whether the brainstorm step can be skipped.

## Source Types

Egregore accepts two source types for work items.

### Prompt Source

A free-text prompt provided directly by the user or by the
`egregore init` command.

**Parsing steps:**

1. Extract the requirement text from the prompt.
2. Identify any explicit constraints (language, framework,
   file paths, performance targets).
3. Generate a slug from the first meaningful phrase for the
   branch name.
4. Create a work item with `source: "prompt"` and
   `source_ref` set to the prompt text (truncated to 200
   characters).

### GitHub Issue Source

A GitHub issue number or URL.

**Parsing steps:**

1. Fetch the issue:
   ```bash
   gh issue view <number> --json title,body,labels,comments
   ```
2. Extract the title as the primary requirement.
3. Extract the body as the detailed specification.
4. Parse labels for metadata (e.g., `bug`, `enhancement`,
   `priority:high`).
5. Scan comments for additional requirements or
   clarifications from maintainers.
6. Create a work item with `source: "github-issue"` and
   `source_ref` set to `"#<number>"`.

## Validation

The validate step checks that parsed requirements are
specific enough to act on.

**A requirement is actionable when it has:**

- A clear description of what needs to change.
- Enough context to identify which files or components are
  involved.
- No open questions that would block implementation.

**When validation fails:**

- For prompts: record a decision explaining what is missing
  and proceed with the best interpretation. Never block
  waiting for human input.
- For issues: check the issue comments for clarifications.
  If still unclear, record a decision and proceed with
  the conservative interpretation.

## Prioritization

The prioritize step orders multiple work items by estimated
complexity.

**Complexity heuristics:**

- **Low**: single-file change, clear fix, no new
  dependencies.
- **Medium**: multi-file change, new function or class, test
  updates needed.
- **High**: new feature spanning multiple modules, new
  dependencies, API changes.

When there is only one work item, skip this step entirely.

When there are multiple items, sort by ascending complexity
so simpler items complete first, building momentum and
reducing the risk of context overflow on the first item.

## Branch Creation

During the parse step, create a git branch for the work
item:

```bash
git checkout -b egregore/wrk-001-slug main
```

The branch name is generated by `manifest.add_work_item()`
using the pattern `egregore/wrk-NNN-slug` where the slug is
derived from the source reference.

If the branch already exists (from a previous interrupted
session), check it out without creating a new one:

```bash
git checkout egregore/wrk-001-slug
```

## Deferred Capture for Discoveries

During the intake stage, the orchestrator may encounter items
whose `content_type` is `tangential_idea` or `discovery`.
These are captured automatically without waiting for human
input, per egregore's "never wait for human input" rule.

For each such item, run:

```bash
python3 scripts/deferred_capture.py \
  --title "<discovery title>" \
  --source egregore \
  --context "<discovery description>" \
  --captured-by explicit
```

The `<discovery title>` and `<discovery description>` values
come from the parsed work item's `title` and `body` fields.
This call is made during the validate step, immediately after
the item is confirmed as a `tangential_idea` or `discovery`
type.
The item is then removed from the active pipeline queue so the
orchestrator does not attempt to build or ship it.

If `scripts/deferred_capture.py` is not present, log a warning
and continue processing the queue.

## Brainstorm Skip Logic

The brainstorm step can be skipped when the source already
provides enough context to move directly to specification.

**Skip brainstorm when all of these are true:**

1. `config.pipeline.skip_brainstorm_for_issues` is `true`.
2. The source is `"github-issue"`.
3. The issue body contains at least 100 words of
   description.
4. The issue has labels that indicate a well-defined scope
   (e.g., `bug`, `enhancement`, not `question` or `rfc`).

**When brainstorm is skipped**, the orchestrator calls
`manifest.advance(item.id)` to jump past the brainstorm
step without invoking `Skill(attune:project-brainstorming)`.
Record a decision explaining why brainstorm was skipped.


path: modules/pipeline.md
content: ---
name: pipeline
description: Pipeline stage and step definitions with transition rules
category: orchestration
---

# Pipeline Module

Defines the four stages of the egregore pipeline, their
steps, transition rules, and idempotency guarantees.

## Stages and Steps

The pipeline has four stages, executed in fixed order.
Each stage contains ordered steps that run sequentially.

### 1. Intake

Parse the input, validate it, and prioritize across
multiple items.

| Step | Purpose |
|------|---------|
| parse | Extract requirements from prompt text or GitHub issue |
| validate | Confirm requirements are specific enough to act on |
| prioritize | Order items by complexity (single item = skip this step) |

### 2. Build

Transform requirements into working code through the
attune project lifecycle.

| Step | Purpose |
|------|---------|
| brainstorm | Explore approaches and constraints |
| specify | Produce a formal specification document |
| blueprint | Create an implementation plan with task breakdown |
| execute | Implement the plan, writing code and tests |

### 3. Quality

Review, refine, and verify the implementation.

| Step | Purpose |
|------|---------|
| code-review | First-pass review for correctness and style |
| unbloat | Detect and remove unnecessary code or files |
| code-refinement | Apply review feedback and polish |
| update-tests | Add or fix tests to match implementation |
| update-docs | Update documentation to reflect changes |

### 4. Ship

Prepare, review, and merge the pull request.

| Step | Purpose |
|------|---------|
| prepare-pr | Create the PR with title, body, and labels |
| pr-review | Run automated PR review checks |
| fix-pr | Apply fixes from the PR review |
| merge | Merge the PR (requires `auto_merge: true` in config) |

## Parallel Execution (Quality Stage)

Within the quality stage, some steps are independent and can
run concurrently. The `stage_parallel` module groups steps
into waves based on a dependency graph.

### Dependency Graph

```
code-review  ──┐
               ├──>  code-refinement
               └──>  update-tests
unbloat       (independent)
update-docs   (independent)
```

### Wave Execution

`plan_stage_execution("quality", steps)` produces waves:

- **Wave 1** (parallel): `code-review`, `unbloat`,
  `update-docs` -- no interdependencies.
- **Wave 2** (parallel): `code-refinement`, `update-tests`
  -- both depend on `code-review` completing first.

All steps in a wave can be dispatched simultaneously via
`build_parallel_dispatch(wave, item_id)`. The orchestrator
waits for every step in wave N to finish before starting
wave N+1.

### Failure Handling

`WaveResult` tracks per-step pass/fail outcomes within a
wave. If any step in a wave fails, the orchestrator can
inspect `wave_result.failed_steps` and decide whether to
retry individual steps or fail the entire stage.

### Extending the Graph

To add a new quality step:

1. Add the step name to `PIPELINE["quality"]` in
   `manifest.py`.
2. Add an entry in `STEP_DEPENDENCIES` in
   `stage_parallel.py` with its dependency list (empty
   list if independent).
3. The planner will automatically place it in the correct
   wave.

## Transition Rules

A work item advances through the pipeline via
`manifest.advance(item_id)`.
The transition logic follows these rules:

1. **Within a stage**: move to the next step in the list.
   Reset `attempts` to 0.
2. **Across stages**: when the last step of a stage
   completes, move to the first step of the next stage.
   Reset `attempts` to 0.
3. **Pipeline complete**: when the last step of the last
   stage (ship/merge) completes, set `item.status` to
   `"completed"`.
4. **No backward movement**: the pipeline only moves
   forward. If a step needs rework, it retries in place
   up to `max_attempts`.

## Step Skipping

Certain steps can be skipped based on configuration or
context:

- **brainstorm**: skipped when `config.pipeline
  .skip_brainstorm_for_issues` is `true` and the source is
  a GitHub issue (the issue body serves as the brainstorm
  output).
- **prioritize**: skipped when there is only one work item.
- **merge**: skipped when `config.pipeline.auto_merge` is
  `false`. The PR remains open for human review.

When a step is skipped, `advance()` is called immediately
without invoking any skill.

## Idempotency Guarantees

Every step must be safe to retry without side effects.
The pipeline enforces idempotency through these mechanisms:

1. **State on disk**: the manifest is saved after every
   transition. If the process crashes mid-step, the same
   step will be retried on relaunch.
2. **Branch isolation**: each work item operates on its own
   git branch (`egregore/wrk-NNN-slug`). Partial work from
   a failed attempt remains on the branch and is visible
   to the retry.
3. **Attempt counter**: `item.attempts` tracks how many
   times the current step has been tried. Skills can read
   this value to adjust behavior on retries (e.g., using a
   simpler approach on attempt 2).
4. **No destructive resets**: retrying a step never reverts
   work from previous steps. The retry operates on whatever
   state the branch is in.
5. **PR deduplication**: the prepare-pr step checks for an
   existing open PR on the work item branch before creating
   a new one. If a PR exists, it updates the existing PR
   instead.

## Parallel Execution

When multiple active work items are independent (no shared
files or dependencies), the orchestrator can process them
concurrently using git worktrees.
The `parallel` module (`scripts/parallel.py`) provides the
detection, dispatch, and merge primitives.

### Independence Detection

`detect_independent_items()` groups active work items by
their `source_ref` values.
Items with different source refs are assumed independent
and placed in the same parallel group.
Items sharing a source ref are kept in separate groups so
they execute sequentially.

### Worktree Lifecycle

Each parallel work item gets its own git worktree via
`WorktreeAssignment`.
The assignment tracks the item ID, worktree filesystem
path, branch name, and a status that progresses through:
`pending`, `active`, `completed`, `failed`, `merged`.

The manifest's `max_concurrent_worktrees` field (default 3)
controls how many worktrees run at once.
`build_agent_dispatch()` splits item IDs into batches that
respect this limit.

### Merge Strategy

After a worktree completes its pipeline,
`merge_worktree_result()` generates the git commands to
merge the feature branch back into the target branch using
`--no-ff` for a clear merge commit.
If the merge encounters conflicts, the conflict strategy
marks the work item as failed so the orchestrator can
handle it.


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)