Claude Code plugin · v3.0.1

Multi-step Claude Code work without drift.

Run research → plan → execute → verify → critique as one command — with three chat-approval gates and runtime guards that stop the work drifting off your spec. No YAML to hand-author.

v3.0.1 · Opus 4.8-native tests — see CI cleanroom smoke test Apache-2.0

The problem

Multi-step agentic work drifts. The assistant runs a plan, then in the middle of step 4 it reinterprets the goal, edits files it wasn't supposed to touch, and the user discovers what it actually did only after the damage is done.

The usual responses don't work. A second AI auditing the first AI gets caught in the same drift. A more careful single-AI loop just papers over the drift class. A long human checklist is unenforceable; people skim.

This plugin enforces a structural pattern. Every run starts with a manifest you approve via a chat keyword reply: APPROVE to start, REVISE with edit instructions to send back, VIEW to print the full YAML first. The orchestrator parses the first non-whitespace token of your next message, case-insensitive — no LLM interpretation surface. Stages are spawned as Agent sub-tasks with bounded role files. The drift-detector reads the actual diff and flags every file change outside the manifest. The critic runs as a separate Agent so it can't co-conspire. Auto-promote is six machine-checkable conditions; manager-merge runs only when those pass.

What a run looks like

You type one slash command. The plugin reads your project's spec, drafts a scope contract from it, and shows you YAML in chat.

/agent-pipeline-claude:run "close QA-005 conflict-409 race"
manifest-drafter → [gate 1: chat APPROVE / REVISE / VIEW] researcher → research.md planner → plan.md → [gate 2: chat APPROVE / REPLAN / BLOCK / VIEW] test-writer → failing-tests-report.md executor → implementation-report.md policy → policy-report.md (14 stdlib-only checks; v2.0) verifier → verifier-report.md drift-detector → drift-report.md critic → critic-report.md auto-promote → auto-promote-report.md (6 conditions; auto-fires on green) manager → manager-decision.md → [gate 3: chat APPROVE / BLOCK / REPLAN / VIEW]

Every stage writes an artifact to .agent-runs/<run-id>/. The run is resumable from any failed stage via /agent-pipeline-claude:run resume <run-id>. The judge layer (opt-in) sits between stages and supervises every external-facing or high-risk action against the manifest. The drift-detector catches edits to files outside allowed_paths. The critic runs as a separate Agent and can't co-conspire with the executor.

Three human gates — chat keyword reply, deterministic parsing

Gate 1 — Manifest approval. The drafter reads your project's spec / release plan / scope-lock / design notes and produces a YAML manifest with every field annotated by source. A chat prompt names the recognized keywords: APPROVE (start the run), REVISE (send back to drafter with edits), VIEW (print full manifest). The orchestrator parses the first non-whitespace token of your next message, case-insensitive.
Gate 2 — Plan approval. After research, the planner produces a step-numbered plan with blast radius. The chat prompt names APPROVE / REPLAN / BLOCK / VIEW. REPLAN followed by free-form text on the same line or in the next message sends the plan back with your revisions.
Gate 3 — Manager approval. After verify / drift / critic / auto-promote complete, the manager produces a structured decision document. The chat prompt names APPROVE / BLOCK / REPLAN / VIEW. When the six auto-promote conditions all pass, this gate skips entirely — no chat prompt fires.

v1.3.0 → v2.1.0 routed gates through AskUserQuestion modal prompts to eliminate the LLM's interpretive surface area on free-text gates. That worked on the LLM side but failed on the operator side: Cowork's modal overlay hid the chat context the operator needed at gate-decision time. v2.2.1 reverses to chat with deterministic first-token keyword parsing — the interpretive surface concern is now structurally addressed by the modal-budget hook (denies every AskUserQuestion during active non-drafting runs), the explicit keyword grammar in each prompt, and a no-parse branch that re-prints the gate instead of guessing. Runs survive across sessions; you can resume any run from its last gate.

Install

Two paths into the Cowork desktop app:

Plugin manager

/plugin marketplace add scottconverse/agent-pipeline-claude
/plugin install agent-pipeline-claude@agent-pipeline-claude

Then restart your Cowork session. /agent-pipeline-claude:pipeline-init, /agent-pipeline-claude:run, and /agent-pipeline-claude:audit-init appear in the / palette.

Local marketplace (when /plugin install isn't available)

git clone https://github.com/scottconverse/agent-pipeline-claude.git \
  ~/.claude/plugins/marketplaces/agent-pipeline-claude
/plugin marketplace add ~/.claude/plugins/marketplaces/agent-pipeline-claude
/plugin install agent-pipeline-claude@agent-pipeline-claude

Full install and first-use guide: USER-MANUAL.md.

First use

Drop into your project root and run:

/agent-pipeline-claude:pipeline-init

The plugin scans for your spec, release plan, scope-lock, design notes, CLAUDE.md, and HANDOFF.md. It scaffolds .pipelines/ (14 role files, 5 pipeline definitions, 3 templates) and scripts/policy/ (6 stdlib-only validation scripts) into your project. Then:

/agent-pipeline-claude:run "your task description"

The manifest-drafter runs. You reply APPROVE in chat (one word, case-insensitive — first non-whitespace token of your next message) to start the pipeline. Reply REVISE with edits to send the manifest back. Reply VIEW to print the full YAML before deciding. The pipeline executes end-to-end.

Verified — five testing tiers

v1.0.0 and v1.0.1 of this plugin shipped without actually loading. Manifest schema violations passed unit tests in isolation but the loader silently rejected the install. The v1.0.2 fix made it load; v1.1.0 closed the gap with a cleanroom layer that exercises the actual install path on every commit.

TierWhat it provesRuntimeAPI spendWhen
StaticManifests well-formed; shell/Python syntax OKms$0per commit
UnitPolicy scripts behave correctly on synthetic inputseconds$0per commit
SmokePlugin's skills self-contained in installed-cache shapeseconds$0per commit
CleanroomPlugin loads from a fresh copy (no .git, no caches, no host config) via claude --plugin-dirseconds$0per commit
End-to-endFull /run orchestrates research → … → manager against a fixtureminutes~$2/run Haiku
~$15/run Sonnet
tags + nightly

All tests pass on v3.0.1 (see CHANGELOG.md for the current count). The cleanroom tier (tests/test_cleanroom_install.py) is the layer that catches the v1.0.0-class regression — manifest valid in isolation but the install layout broken — that the earlier suite missed.

Full taxonomy + reproducer: tests/README.md.

Where it works

The Cowork desktop app has three tabs running different runtimes. Plugin behavior differs:

TabSlash commandsSkill bodiesHooks
CodeN/A — no hooks
Cowork-VMN/A — no hooks
Chat✗ (no shell)

v2.0 ships an eleven-event Cowork lifecycle hook layer (SessionStart, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, SubagentStop, Stop, SessionEnd). Hooks load automatically and write persistent run memory into .agent-runs/<run-id>/memory/ so context survives compaction and session resume. Earlier v1.x docs noted this plugin was hook-free — that changed with v2.0.

Honest caveats

  • Smaller models drift on summary-line format. The auto-promote check regex requires lines like **Findings: 7 total, 1 blocker, 0 critical, 3 major, 3 minor** exactly. Haiku doesn't always conform; Sonnet does. When the format drifts, auto-promote correctly identifies the miss and falls back to the human manager gate — that's the design. For routine runs Haiku is fine; for runs where you want auto-promote eligibility, use Sonnet (set --model claude-sonnet-4-6 at session start).
  • The plugin can't self-test E2E in CI. Pipeline runs require a real Claude session and real model spend. The cleanroom tier is the automated load-bearing layer; E2E is manual or on-tag.
  • run.log only logs the manifest stage today. The other stage roles don't append to it. v1.x followup; doesn't affect correctness.
  • Drafter quality depends on your spec quality. If the project lacks a release plan, scope-lock, or design note, the drafter falls back to a minimal skeleton manifest and asks you to fill in the gaps in chat before approval.

What's new in v3.0.1

  • Audit hardening. A five-role audit of v3.0.0 (zero blockers) drove fixes across secret-redaction coverage (GitHub/Slack/GitLab/Google/Stripe/npm/JWT/URL/bare-credential), the destructive-command and secret trust boundary (fail-closed PreToolUse hook), real-YAML manifest parsing, and a version-skew sweep guarded by a CI parity test. No behavior change for a healthy run.

What's new in v3.0.0 (Opus 4.8-native)

  • Per-stage model/effort binding, window-gated lean run-context on 1M-context models, parallel independent verify/drift/critique stages, context-exhaustion early warnings, SHA-256 per-run memory integrity, and the opt-in real-time judge (reincorporated in v2.3.0). All opt-in or additive — runs that don't set the new keys behave exactly as before.

What changed in v2.2.1

  • Chat-based gates with deterministic keyword grammar. Reverses the v1.3.0 → v2.1.0 modal-gate experiment after the operator-UX failure (Cowork's modal overlay hid chat context at gate-decision time). Each gate prints a structured prompt naming APPROVE / REVISE / REPLAN / BLOCK / VIEW as recognized keywords. The orchestrator parses the first non-whitespace token of your reply, case-insensitive. Anything unrecognized re-prints the prompt — no LLM interpretation.
  • Modal-budget hook tightened to deny-all. Every AskUserQuestion during an active non-drafting pipeline run returns deny with MODAL_BUDGET_EXCEEDED. The v2.1.0 gate-stage exception is gone.
  • Auto-delete stale plugin cache directories on SessionStart. Each plugin upgrade left the prior version's cache on disk (1.5-2 MB each). v2.2.1 deletes every sibling of the loaded version whose name parses as a strictly-lower semver. Idempotent, once per session.

What changed in v2.0.0 (base layer, preserved)

  • Eleven-event Cowork lifecycle hook layer. SessionStart / UserPromptSubmit / PreToolUse / PermissionRequest / PostToolUse / PostToolUseFailure / PreCompact / PostCompact / SubagentStop / Stop / SessionEnd. Records persistent run memory; re-injects handoff_current.md after context compaction.
  • Persistent file-backed run memory. .agent-runs/<run-id>/memory/ with events / turns / decisions / open_loops / probe / handoff_current. Layer A is unconditional (always written); Layer B (Mem0 OSS or platform) is best-effort behind a circuit breaker.
  • Directive contracts. Pre-approved manifest + scope-lock + acceptance assertions in .agent-runs/<id>/directive.yaml let a run auto-approve manifest/plan gates when content is byte-identical. SHA-256 hash bound at conformance; exit-3 on resume-time divergence.
  • Scope-lock authority. scripts/check_scope_lock.py + check_rung_file_ownership.py + check_release_docs_consistency.py validate edited paths, commit messages, and doc claims against the canonical release-plan rung.
  • v1.3.0 modal-gate surface — superseded by v2.2.1 chat gates. v2.0 carried forward v1.3.0's modal flow (one click per gate). v2.2.1 reverses to chat after the operator-UX failure described above. Evidence-driven auto-promote stays the path to hands-off; no grant files, no autonomous-mode token.

Full release notes: CHANGELOG.md.

Documentation

  • README — overview, install, quick start
  • User Manual — install paths, configuration, slash command reference, troubleshooting
  • Architecture — stage-by-stage data flow, manifest schema, role file contracts
  • Changelog — release-by-release
  • Contributing — how to extend roles, policies, fixtures
  • Testing — taxonomy, reproducer, fixtures