diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 527f1d7..8ea8d64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,11 @@ jobs: set -euo pipefail EXCLUDE=(':!CHANGELOG.md' ':!.github/workflows/ci.yml') if git grep -nI -e 'claude-opus-4-7' -- "${EXCLUDE[@]}"; then - echo 'FAIL: claude-opus-4-7 found outside CHANGELOG.md (pin is claude-fable-5)' >&2 + echo 'FAIL: claude-opus-4-7 found outside CHANGELOG.md (pin is claude-opus-4-8)' >&2 + exit 1 + fi + if git grep -nI -e 'claude-fable-5' -- "${EXCLUDE[@]}"; then + echo 'FAIL: claude-fable-5 found outside CHANGELOG.md (Fable access is blocked — pin is claude-opus-4-8)' >&2 exit 1 fi if git grep -nIP -e '(?` and `` context slots — the Plan-completeness (#11) and Charter-compliance (#12) checks previously had instructions but no structured input. +- **Product reviewer context slots added**: the three product-reviewer copies gained `` and `` slots (alongside the existing ``), feeding the Product Brief validation (#6) and Charter compliance (#5) checks. +- **`/superflow-review` workflow passes context**: new optional `spec_path`, `plan_path`, `brief_path` args wired into both the product and technical reviewer prompts (superflow-review.js, 143 → 158 lines); missing inputs are flagged as unverifiable rather than passing silently. The technical lens now receives the plan too — a diff alone cannot reveal a stub. +- **Dispatch contract made explicit**: `references/phase2/steps/review-unified.md` now states both reviewers receive SPEC/plan + Charter + Brief + diff (pasted verbatim into the dispatch prompt); the codex overlay technical dispatches pass plan + charter for the plan-completeness and charter-compliance checks. + +## [5.5.0] - 2026-06-11 + +### Added — Hybrid Workflow Acceleration (opt-in) +- **`references/workflow-orchestration.md`** (202 lines): single authority on Workflow-tool usage inside Superflow — documented facts only (JS script orchestrating subagents in the background, Claude Code ≥ 2.1.154, intermediate results live in script variables, not orchestrator context), opt-in policy with the verbatim plan-approval wording, permission gates table (default: every run; Auto: first launch only; bypass/`-p`/SDK: never) with the Auto-mode recommendation for Phase 2, limits (16 concurrent / 1,000 total / no mid-run input / no script fs-shell access), saved-workflow locations and `/name` invocation, full specs of both saved workflows, the UNDOCUMENTED-API warning, the `/goal` watchdog section, and the Codex/fallback chain. Step files point here instead of re-explaining +- **Two saved workflow scripts** in `workflows/`, deployed via checksum sync to `~/.claude/workflows/` at startup (SKILL.md step 4, Claude runtime only, `mkdir -p ~/.claude/workflows`) — invocable as `/superflow-review` and `/superflow-wave` in any project: + - `workflows/superflow-review.js` (143 lines): unified review fan-out — parallel product reviewer (follows `standard-product-reviewer.md` + charter) and technical reviewer (applies the codex-exec-or-Claude fallback chain itself via Bash); returns `{product, technical, pass}` where `pass` requires both verdicts in APPROVE/ACCEPTED/PASS + - `workflows/superflow-wave.js` (96 lines): implementation-only wave (v5.4.0 parallel-wave dispatch rule: implementation-only fan-out; orchestrator runs review/docs/PAR/ship per sprint) — one implementer agent per sprint, worktree-isolated, no review/docs/PAR/PR; returns position-bound `[{sprint, status: "done"|"failed", summary, test_evidence}]`; the orchestrator still runs review → docs → PAR → ship per sprint afterwards + - Both: documented API surface only (`agent`, `parallel`, `phase`, `log`, `args`), `export const meta`, LAST-fenced-json extraction via regex + `JSON.parse` in try/catch, FAIL CLOSED on any parse failure or null result (REQUEST_CHANGES / `status: "failed"`), no clock or randomness calls (orchestrator stamps timestamps) +- **`context.use_workflows` opt-in**: Phase 1 Step 12 plan-approval summary states the workflows opt-in verbatim (incl. the permission-prompt heads-up and the "no-workflows" objection path); the decision is recorded post-approval in `.superflow-state.json` (`context.use_workflows`, boolean, default true; always false on Codex runtime) and in the Autonomy Charter YAML beside `model_profile`. State schema extended accordingly. The recorded opt-in is what justifies the orchestrator invoking saved workflows in Phase 2 +- **`/goal` watchdog suggestion**: at Phase 2 launch the orchestrator PRINTS a ready-to-paste `/goal Superflow Phase 2 complete: all sprints implemented, unified-reviewed, PRs created and CI-green, Completion Report delivered.` template (`references/phase2/overview.md` § Phase 2 Launch). `/goal` is user-only — the model cannot set it; the evaluator (Haiku, prompt-based Stop hook) judges only the transcript; one goal per session, survives `--resume`, cleared with `/goal clear`; subagents do NOT inherit goals — charter injection remains the per-sprint alignment mechanism +- **`workflow-review` provider**: `.par-evidence.json` provider enum extended to `codex|code-review-skill|split-focus|workflow-review` (enforcement Rule 3 step 7, `par-evidence.md`); workflow returns arrive pre-extracted — skip `extract_verdict` and assemble evidence from `{product, technical, pass}` directly + +### Notes +- **Hybrid, not a rewrite**: the markdown DAG and Agent-based dispatch remain the default path. Workflows accelerate exactly two Phase 2 spots — unified review fan-out (`review-unified.md`) and parallel implementation waves (`impl-dispatch.md`) — both presented as PREFERRED-WHEN-AVAILABLE with explicit fallback to the v5.4.0 Agent flow (no behavior change) +- **Codex runtime unaffected**: no Workflow tool, no `/goal` — Codex ignores `context.use_workflows` and keeps the spawn_agent paths (new Critical Codex Difference #6 in `references/codex/phase2-execution.md`) +- **Documented-API-only scripts**: shipped workflow scripts never use undocumented fields (`schema`, `agentType`, `isolation`, `resume-run-id` — observed in some builds, absent from official docs); structured data returns ONLY via the v5.4.0 fenced-JSON verdict contract with fail-closed parsing + ## [5.4.0] - 2026-06-11 ### Fixed — Critical diff --git a/CLAUDE.md b/CLAUDE.md index b3ee725..903c29c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ # Superflow — Claude Instructions ## Project Overview -Superflow is a pure Markdown skill that orchestrates a 4-phase dev workflow: onboarding, product discovery with expert panel brainstorming, Product Vision alignment, and git workflow selection, autonomous execution with a selected branch/PR strategy, and merge. v5.4.0, MIT License. Supports both **Claude Code** and **Codex CLI** as primary orchestrator (auto-detected at startup via `$CLAUDE_CODE_SESSION_ID`). +Superflow is a pure Markdown skill that orchestrates a 4-phase dev workflow: onboarding, product discovery with expert panel brainstorming, Product Vision alignment, and git workflow selection, autonomous execution with a selected branch/PR strategy, and merge. v5.6.0, MIT License. Supports both **Claude Code** and **Codex CLI** as primary orchestrator (auto-detected at startup via `$CLAUDE_CODE_SESSION_ID`). ## Key Rules - All documentation output in English — user communication follows their language preference @@ -12,7 +12,7 @@ Superflow is a pure Markdown skill that orchestrates a 4-phase dev workflow: onb ## Architecture ``` -SKILL.md (entry point, ~260 lines, 10-step startup checklist, auto-detects Claude/Codex runtime) +SKILL.md (entry point, ~280 lines, 10-step startup checklist, auto-detects Claude/Codex runtime) ├── superflow-enforcement.md (durable rules → ~/.claude/rules/, checksum-synced at startup) ├── codex/ │ ├── AGENTS.md (durable rules for Codex → ~/.codex/AGENTS.md) @@ -38,7 +38,8 @@ SKILL.md (entry point, ~260 lines, 10-step startup checklist, auto-detects Claud │ │ ├── workflow.json (DAG: 9-cell governance×complexity decision matrix + 7 stages + step_files map) │ │ ├── overview.md (Phase 2 high-level context, wave analysis, model selection) │ │ └── steps/ (10 step detail files: setup-reread, setup-worktree, impl-dispatch, review-unified, par-evidence, ship-pr, compaction-recovery, holistic-review, frontend-testing, completion-report) - │ └── phase3-merge.md (user-initiated merge, 3 stages) + │ ├── phase3-merge.md (user-initiated merge, 3 stages) + │ └── workflow-orchestration.md (single Workflow authority — opt-in policy, permission gates, limits, saved workflow specs, /goal watchdog, fallbacks) ├── prompts/ │ ├── implementer.md (TDD code agent) │ ├── expert-panel.md (expert persona prompt for brainstorming) @@ -52,6 +53,9 @@ SKILL.md (entry point, ~260 lines, 10-step startup checklist, auto-detects Claud │ ├── claude/ (Claude secondary prompts for Codex runtime: audit, code-reviewer, product-reviewer) │ └── codex/ (Codex-specific prompts: code-reviewer, product-reviewer, audit) ├── agents/ (12 agent definitions — deep/standard/fast tiers with model+effort frontmatter) + ├── workflows/ + │ ├── superflow-review.js (saved workflow: parallel product + technical review fan-out → ~/.claude/workflows/) + │ └── superflow-wave.js (saved workflow: implementation-only parallel sprint wave → ~/.claude/workflows/) ├── tools/ │ ├── sf-emit.sh (JSONL event emission library) │ ├── verify-phase2-dag.sh (static DAG verifier) @@ -88,6 +92,9 @@ SKILL.md (entry point, ~260 lines, 10-step startup checklist, auto-detects Claud | `references/phase2-execution.md` | Legacy router (~39 lines) — points at `references/phase2/workflow.json`, `overview.md`, and `steps/`; full prose preserved in git history (pre-Sprint-2) | | `references/phase2/workflow.json` | Phase 2 lifecycle DAG with governance×complexity decision matrix | | `references/phase3-merge.md` | 3 stages, sequential rebase merge with CI gate | +| `references/workflow-orchestration.md` | Single authority on Workflow-tool usage — documented API surface, opt-in policy, permission gates by mode, limits, saved workflow specs, UNDOCUMENTED-API warning, /goal watchdog, Codex/fallback chain (178 lines) | +| `workflows/superflow-review.js` | Saved `/superflow-review` workflow — parallel product + technical reviewers (technical applies the codex-or-Claude fallback chain itself via Bash); both lenses receive spec/plan/charter/brief context via optional `spec_path`/`plan_path`/`brief_path` args; returns `{product, technical, pass}`, fail-closed fenced-JSON parsing (158 lines) | +| `workflows/superflow-wave.js` | Saved `/superflow-wave` workflow — one implementer per sprint (worktree-isolated, implementation only, no review/docs/PAR/PR); returns position-bound `[{sprint, status, summary, test_evidence}]`, fail-closed (97 lines) | | `prompts/implementer.md` | Red-Green-Refactor TDD cycle for code agents | | `prompts/expert-panel.md` | Expert persona prompt — proposals, challenge, recommendation | | `prompts/llms-txt-writer.md` | llmstxt.org standard, no hard size limit | @@ -98,7 +105,7 @@ SKILL.md (entry point, ~260 lines, 10-step startup checklist, auto-detects Claud | `tools/cleanup-testcontainers.sh` | Testcontainers cleanup helper — label-based selection (`docker ps -aq --filter "label=org.testcontainers=true"`), optional ancestor filter, idempotent; the ONLY docker-touching command in the orchestrator's Rule 11 budget (37 lines) | | `hooks/precompact-state-externalization.sh` | PreCompact hook — sources sf-emit, emits `compact.pre`/`compact.post` events with absolute path to the dump file | | `templates/event-schema.json` | JSON Schema 2020-12 for all event types — envelope fields + 21 per-type data schemas incl. `pr.fail`, additive evolution policy (549 lines) | -| `.github/workflows/ci.yml` | Repo CI on push/PR to main — `shellcheck -S error` over `tools/*.sh hooks/*.sh`, `verify-phase2-dag.sh`, `jq empty` over tracked JSON, forbidden-token gate (stale Opus-4.7 model pin; Ryuk env var without the `TESTCONTAINERS_` prefix) (46 lines) | +| `.github/workflows/ci.yml` | Repo CI on push/PR to main — `shellcheck -S error` over `tools/*.sh hooks/*.sh`, `verify-phase2-dag.sh`, `jq empty` over tracked JSON, forbidden-token gate (stale Opus-4.7 model pin; the now-blocked Fable pin; Ryuk env var without the `TESTCONTAINERS_` prefix) (50 lines) | ## Conventions - Pure Markdown skill (no Python, no pip dependencies) @@ -108,19 +115,20 @@ SKILL.md (entry point, ~260 lines, 10-step startup checklist, auto-detects Claud - Both ` -Select the model tier for deep judgment roles (spec/code/product reviewers + deep-analyst) used throughout autonomous execution: +There is no model-profile question to ask. **Fable access is blocked**, so model assignment is fixed +for every run and depth is differentiated by *effort*, not by model: -- **frontier** (default): deep reviewers + deep-analyst use `model: "fable"`; Codex-runtime Claude secondary uses `claude-fable-5`. Best review quality; frontier-model token pricing. -- **balanced**: deep reviewers + deep-analyst use `model: "opus"`; Codex-runtime Claude secondary uses `claude-opus-4-8`. Strong review quality; significantly cheaper for long multi-sprint runs. +- deep judgment roles (spec/code/product reviewers + `deep-analyst`) → **Opus**, effort `max` +- standard reviewers + doc-writers → **Opus**, effort `high` +- implementers → **Sonnet** (`deep`/`standard`/`fast` = effort `max`/`high`/`low`) -All other roles are identical in both profiles (standard reviewers + doc-writers → opus, implementers → sonnet, fast → sonnet). - -Present the recommendation: -> "Model profile for this run: **frontier** (fable — best review quality, frontier-model pricing) or **balanced** (Opus 4.8 — strong quality, lower cost, recommended for 3+ sprint runs). Use frontier? (yes / switch to balanced)" - -Default to **frontier** if the user says "do what you recommend". Wait for confirmation. Store the selected profile in `.superflow-state.json`: -```bash -python3 -c "import json,datetime; s=json.load(open('.superflow-state.json')); s.setdefault('context',{})['model_profile']='PROFILE'; s['last_updated']=datetime.datetime.now(datetime.timezone.utc).isoformat(); json.dump(s,open('.superflow-state.json','w'),indent=2)" -``` -Replace `PROFILE` with `frontier` or `balanced`. +Nothing to ask or persist here — proceed to the next step. ### Light Mode Sprint Breakdown @@ -592,7 +585,7 @@ Present the complete plan overview: - Sprint breakdown with task counts and complexity tags - Key files touched per sprint - Selected git workflow mode and why it fits this task -- **Selected model profile** (frontier=fable / balanced=opus-4.8) — can still be changed here before execution starts (e.g. "switch to balanced") +- **Workflows opt-in** (Claude runtime only — omit this line on Codex runtime). State verbatim: "Autonomous execution will use saved multi-agent workflows for review fan-out and parallel waves (recommended). Heads-up: depending on permission mode, the FIRST workflow launch may show one approval prompt (Auto mode: first launch only; default mode: every launch — consider switching to Auto for Phase 2). Say no-workflows to use plain subagent dispatch." User objection ("no-workflows") → `use_workflows=false`. This recorded opt-in is what justifies the orchestrator invoking saved workflows during Phase 2. See `references/workflow-orchestration.md`. - **Sprint wave plan** — show which sprints run in parallel: ``` Wave 1: [Sprint 1, Sprint 2, Sprint 6] — parallel (independent files) @@ -612,6 +605,12 @@ mcp__plugin_telegram_telegram__reply(chat_id: , text: "Imp - User says "go" / "start" / "давай" / affirmative → proceed to auto-launch flow below - User requests changes → update plan, re-present +After approval, record the workflows opt-in decision in state (default `True`; `False` if the user said "no-workflows"; always `False` on Codex runtime): +```bash +python3 -c "import json,datetime; s=json.load(open('.superflow-state.json')); s.setdefault('context',{})['use_workflows']=USE_WORKFLOWS; s['last_updated']=datetime.datetime.now(datetime.timezone.utc).isoformat(); json.dump(s,open('.superflow-state.json','w'),indent=2)" +``` +Replace `USE_WORKFLOWS` with the Python literal `True` or `False`. + ```bash sf_emit stage.end stage=user-approval phase:int=1 sf_emit stage.start stage=charter phase:int=1 @@ -635,7 +634,7 @@ success_criteria: - "Measurable outcome 2" governance_mode: "light|standard|critical" # from Step 2 selection git_workflow_mode: "solo_single_pr|sprint_pr_queue|stacked_prs|parallel_wave_prs|trunk_based" # from Step 2b selection -model_profile: "frontier|balanced" # from Step 2c selection; controls deep reviewer + deep-analyst model at dispatch +use_workflows: true|false # from Step 12 opt-in; allows saved /superflow-review and /superflow-wave workflows in Phase 2 (Claude runtime only) --- ``` diff --git a/references/phase2/overview.md b/references/phase2/overview.md index 6c0fa0a..2691ec6 100644 --- a/references/phase2/overview.md +++ b/references/phase2/overview.md @@ -18,6 +18,27 @@ Report when all sprints are done. --- +## Phase 2 Launch + +At Phase 2 launch — right after plan approval, before the first sprint — PRINT this ready-to-paste +`/goal` suggestion for the user. `/goal` is a user-only command: the model CANNOT set it; never +pretend otherwise. + +> Optional watchdog for this run — paste: +> `/goal Superflow Phase 2 complete: all sprints implemented, unified-reviewed, PRs created and CI-green, Completion Report delivered.` + +Replace `` with the actual sprint count. Note: the evaluator (Haiku, prompt-based Stop hook) +judges only what is visible in the transcript, so the orchestrator must keep narrating sprint +completions (it already does); one goal per session; survives `--resume`; the user clears it with +`/goal clear`. Subagents do NOT inherit goals — per-sprint goal-direction remains the Autonomy +Charter injection (already shipped). + +For everything Workflow-tool related (saved `/superflow-review` and `/superflow-wave` workflows, +the `context.use_workflows` opt-in, availability checks, fallbacks), see +`references/workflow-orchestration.md` — the single authority on Workflow usage inside Superflow. + +--- + ## Wave Analysis Independent tasks within a sprint are dispatched in parallel waves: @@ -50,9 +71,9 @@ Sprint complexity tag in the plan drives implementer tier: **ALWAYS pass `model:` explicitly in every Agent() call** — agent definition frontmatter `model:` is NOT reliably inherited. Dispatch rule: implementers → `model: "sonnet"` (haiku permitted for mechanical Phase 0 file/config checks); standard reviewers + doc-writers → `model: "opus"`; deep -reviewers + `deep-analyst` → `"fable"` (model_profile=frontier, default) or `"opus"` (model_profile=balanced -— read `context.model_profile` from `.superflow-state.json`). A forgotten `model:` now silently inherits -the parent frontier model (Fable) — the cost of forgetting went UP. +reviewers + `deep-analyst` → `model: "opus"` (Fable is blocked — depth comes from effort: deep = max, +standard = high, set in agent frontmatter). A forgotten `model:` silently inherits the orchestrator's +session model (Opus), which is wrong for implementers — more expensive than the intended Sonnet. --- diff --git a/references/phase2/steps/impl-dispatch.md b/references/phase2/steps/impl-dispatch.md index 5ba315e..8e43a2d 100644 --- a/references/phase2/steps/impl-dispatch.md +++ b/references/phase2/steps/impl-dispatch.md @@ -35,6 +35,24 @@ Independent sprints (non-overlapping files, no `depends_on` links) run concurren worktrees. Parse all sprint `files:` and `depends_on:` metadata, build dependency graph, group into waves by topological sort. Store wave plan in `.superflow-state.json` under `context.sprint_waves`. +**Preferred when available — saved /superflow-wave workflow (Claude runtime, opt-in).** When +RUNTIME:claude, `context.use_workflows=true` in `.superflow-state.json`, and workflows are +available, PREFER invoking the saved `/superflow-wave` workflow for the wave instead of N manual +`Agent()` calls: + +``` +/superflow-wave args: {sprints: [{id, branch, worktree, task}], charter_path: ""} +``` + +It fans out one implementer per sprint in parallel (implementation ONLY — code, tests, commit +inside the given worktree) and returns a per-sprint status array; failed or unparseable results +are treated as implementation-failed (fail closed). REVIEW IS NOT IN THE WORKFLOW — exactly as +with manual dispatch, the ORCHESTRATOR runs review → docs → PAR → ship per sprint afterwards. +Details and availability checks: `references/workflow-orchestration.md`. + +**Fallback:** Codex runtime, `use_workflows=false`, or workflows unavailable → the existing +parallel Agent dispatch below, unchanged. + **Claude runtime — implementation-only parallelism.** Subagents CANNOT dispatch further subagents via the Agent tool, so a sprint agent can never run reviews or create PRs itself. A parallel wave is N implementers dispatched in parallel — one per sprint, each in its own worktree: @@ -74,8 +92,8 @@ Sprint complexity tag in the plan drives implementer tier: | complex | deep-implementer | sonnet | max | 5+ files, new architecture, security-sensitive | **ALWAYS pass `model: "sonnet"` explicitly for implementers** — frontmatter `model:` is NOT -reliably inherited. A forgotten `model:` now silently inherits the parent frontier model (Fable) — -the cost of forgetting went UP. +reliably inherited. A forgotten `model:` silently inherits the orchestrator's session model (Opus), +more expensive than the intended Sonnet. Include `llms.txt` content in agent context (if file exists). Extract and paste the exact task list, file paths, and expected behaviors verbatim into the diff --git a/references/phase2/steps/par-evidence.md b/references/phase2/steps/par-evidence.md index 525e7d2..c369a1c 100644 --- a/references/phase2/steps/par-evidence.md +++ b/references/phase2/steps/par-evidence.md @@ -19,7 +19,7 @@ complete before this stage). Required fields: - `technical_review` — technical review verdict - `docs_update` — `"UPDATED"` or `"UNCHANGED"` - `docs_review` — `"PASS"` -- `provider` — `"codex"`, `"code-review-skill"`, or `"split-focus"` +- `provider` — `"codex"`, `"code-review-skill"`, `"split-focus"`, or `"workflow-review"` - `ts` — ISO timestamp Standard/critical sprint example: @@ -93,6 +93,13 @@ jq -n \ If a reviewer's message has no parseable verdict block, that is not a verdict — re-engage the reviewer (SendMessage, see `review-unified.md`) for the block instead of inferring one from prose. +Workflow path: when review ran via the saved `/superflow-review` workflow, `product` and +`technical` in the return value are full verdict objects (same shape as the fenced-JSON block). +Evidence fields take the `.verdict` string — e.g. `PRODUCT=$(jq -r '.product.verdict' <<<"$WF_RESULT")`, +`TECH=$(jq -r '.technical.verdict' <<<"$WF_RESULT")`. Skip `extract_verdict` and record +`provider: "workflow-review"`. When `product:false` was passed, `product` is `null` — set +`PRODUCT="SKIPPED"` directly. + ## Verdict Mapping | Verdict from agent | Meaning | Action | @@ -117,6 +124,7 @@ Examples: - Codex → `{"provider":"codex","claude_product":"ACCEPTED","technical_review":"APPROVE",...}` - /code-review skill → `{"provider":"code-review-skill","claude_product":"ACCEPTED","technical_review":"APPROVE",...}` - Split-focus → `{"provider":"split-focus","claude_product":"ACCEPTED","technical_review":"APPROVE",...}` +- /superflow-review workflow → `{"provider":"workflow-review","claude_product":"ACCEPTED","technical_review":"APPROVE",...}` ## Gate Before `gh pr create` diff --git a/references/phase2/steps/review-unified.md b/references/phase2/steps/review-unified.md index fc039dc..ea5107e 100644 --- a/references/phase2/steps/review-unified.md +++ b/references/phase2/steps/review-unified.md @@ -6,6 +6,39 @@ --- +## Preferred Path — Saved /superflow-review Workflow (Claude runtime, opt-in) + +When ALL hold — RUNTIME:claude, `context.use_workflows=true` in `.superflow-state.json`, and +workflows available (not `disableWorkflows`, not `CLAUDE_CODE_DISABLE_WORKFLOWS=1`, CLI version +≥ 2.1.154) — PREFER invoking the saved `/superflow-review` workflow over manual two-agent dispatch: + +``` +/superflow-review args: {sprint: , branch: "", base: "", + charter_path: "", + workdir: "", + spec_path: "", (optional but STRONGLY recommended — enables spec-fit + plan-completeness) + plan_path: "", (optional — reviewers verify each task is implemented, not stubbed) + brief_path: "", (optional — product lens) + product: , (false for light-governance cells) + diff_hint: ""} +``` + +Light-governance cells (`par_skip_product: true`): pass `product: false` — the workflow runs +only the technical thunk and returns `{product: null, technical, pass}`. Standard and critical +cells: pass `product: true` (the default). + +The workflow runs the product reviewer and the technical reviewer (which applies the codex-CLI +fallback chain itself) in parallel and returns `{product, technical, pass}` — verdicts already +extracted from the fenced JSON blocks, failing closed (REQUEST_CHANGES) on parse failure. Consume +the returned verdicts directly and assemble `.par-evidence.json` from them with +`provider: "workflow-review"` (see `par-evidence.md`). If verdicts fail: fix confirmed issues, +commit, then re-invoke `/superflow-review` (fresh run) or re-review only the flagging lens via the +Agent-based flow below. Do not re-explain workflow internals here — the single authority is +`references/workflow-orchestration.md`. + +**Fallback:** in every other case (Codex runtime, `use_workflows=false`, workflows disabled or +unavailable) run the existing Agent-based flow below verbatim — no behavior change. + ## Two-Reviewer Protocol Principle: **specialize, don't duplicate** — Claude = Product lens, secondary = Technical lens. @@ -15,7 +48,16 @@ First, look up `decision_matrix.review_config[governance_mode+"+"+complexity]` i - `reviewers: 2` → Both Product + Technical in parallel - `tier` → `standard` or `deep` agent definitions -Both agents receive: the SPEC, the product brief, and the relevant git diff. +Both agents receive a COMPLETE context bundle — never just the diff: +- the SPEC / sprint plan tasks (for spec fit AND the plan-completeness check — the **technical** reviewer + needs this too, not only the product reviewer; a diff without the plan cannot reveal a stub), +- the Autonomy Charter (non-negotiables, success criteria), +- the Product Brief (product lens), +- the relevant git diff. + +Paste these into the dispatch `prompt:` verbatim — do NOT rely on the agent recalling the plan. The agent +definitions reserve `` + `` (code reviewer) and +`` + `` + `` (product reviewer) context slots for exactly this. **Dispatch Claude reviewers as NAMED background agents** so they can be re-engaged after fixes with their original context intact: @@ -23,10 +65,10 @@ with their original context intact: ``` Agent( subagent_type: "standard-product-reviewer", # deep-product-reviewer for deep tier - model: "opus", # standard tier; deep tier → "fable" (frontier) or "opus" (balanced — read context.model_profile) + model: "opus", # standard tier; deep tier also "opus" (effort: max via agent definition; Fable blocked) name: "sprint--product-reviewer", run_in_background: true, - prompt: "[SPEC + brief + diff context]" + prompt: "[SPEC/plan tasks + Product Brief + Autonomy Charter + git diff — fill the agent's // slots verbatim]" ) ``` @@ -47,10 +89,10 @@ Agent( ``` a. Agent(subagent_type: "standard-product-reviewer", model: "opus", name: "sprint--product-reviewer", run_in_background: true, - prompt: "Focus: spec fit, user scenarios, data integrity") + prompt: "Focus: spec fit, user scenarios, data integrity. Context (fill the agent's slots verbatim): SPEC/plan tasks + Product Brief + Autonomy Charter + git diff") b. Agent(subagent_type: "standard-code-reviewer", model: "opus", name: "sprint--technical-reviewer", run_in_background: true, - prompt: "Focus: correctness, security, architecture, performance") + prompt: "Focus: correctness, security, architecture, performance. Context (fill / verbatim): SPEC/plan tasks + Autonomy Charter + git diff") ``` Record `"provider": "split-focus"` in `.par-evidence.json`. diff --git a/references/workflow-orchestration.md b/references/workflow-orchestration.md new file mode 100644 index 0000000..6047046 --- /dev/null +++ b/references/workflow-orchestration.md @@ -0,0 +1,207 @@ +# Workflow Orchestration + +Single authority for using Claude Code dynamic workflows inside Superflow. Step files +(`references/phase2/steps/review-unified.md`, `references/phase2/steps/impl-dispatch.md`) +point here instead of re-explaining. Workflows are an OPT-IN acceleration for exactly two +Phase 2 spots — unified review fan-out and parallel implementation waves. The markdown DAG +and Agent-based dispatch remain the default path, and the only path on Codex runtime. + +Official docs: , +, . + +## What the Workflow Tool Is + +Documented facts only (per the workflows doc): + +- A dynamic workflow is a JavaScript script that orchestrates subagents at scale. A runtime + executes it in the background, in an isolated environment, while the session stays responsive. +- Requires Claude Code v2.1.154 or later (paid plans; Anthropic API, Bedrock, Vertex, Foundry). +- Intermediate results live in script variables, NOT in the orchestrator's context — only the + script's final result lands in the session. This is the context win: N reviewer/implementer + transcripts never enter the orchestrator's window. +- Script API (signatures verified by smoke run 2026-06-11; the official docs do not publish + the script API — re-verify after CLI upgrades): + - Script body runs **top-level** in an async context — no `export default async function run()` + wrapper; `await` and `return ` happen at the top level of the script. + - `export const meta = { name, description, phases }` where `phases` is an array of objects: + `[{ title: "..." }]` — not bare strings. `meta` must be a pure literal — no + concatenation/template literals/computed values (runtime rejects the script otherwise). + - `phase("Title")` is a **statement** that opens a phase group. It does NOT take a callback + and returns nothing. + - `parallel(thunks)` takes an array of **thunks**: `parallel(items.map((s) => () => agent(...)))`. + Passing bare promises is wrong. A thunk that fails resolves to null (never rejects) — keep + null handling. + - `agent(prompt)` returns the agent's final response text (string) or null. + - `args`, `log(message)` as documented. `args` may be delivered as a JSON string depending + on the invocation path — scripts must normalize with + `typeof args === "string" ? JSON.parse(args) : args` (fail closed on parse errors). +- Runs are resumable within the same session; exiting Claude Code starts the workflow fresh. + +## Opt-In Policy + +A workflow run requires user opt-in. Documented opt-in mechanisms: + +| Mechanism | Effect | +|-----------|--------| +| `ultracode` keyword in the prompt | That one task runs as a workflow | +| Own-words request ("use a workflow", "run a workflow") | Same as the keyword | +| `/effort ultracode` | Claude plans a workflow for every substantive task in the session | +| Invoking a saved workflow (`/`) | Runs that saved script | + +**Superflow records the opt-in at Phase 1 Step 12 (plan approval).** The plan-approval +summary states: + +> Autonomous execution will use saved multi-agent workflows for review fan-out and parallel +> waves (recommended). Heads-up: depending on permission mode, the FIRST workflow launch may +> show one approval prompt (Auto mode: first launch only; default mode: every launch — +> consider switching to Auto for Phase 2). Say no-workflows to use plain subagent dispatch. + +User objection → `context.use_workflows = false`. The decision is stored in +`.superflow-state.json` (`context.use_workflows`) and in the +Autonomy Charter. Workflow invocation by the orchestrator during Phase 2 is justified by this +recorded user opt-in — per docs, a direct user request is the opt-in mechanism, and plan +approval captures it. + +## Permission Gates by Mode + +Whether a launch prompt appears depends on permission mode (documented behavior): + +| Permission mode | Launch prompt | +|-----------------|---------------| +| Default, accept edits | Every run, unless "don't ask again for `` in this project" was selected | +| Auto | First launch only — any Yes records consent in user settings; skipped entirely when ultracode is on | +| Bypass permissions, `claude -p`, Agent SDK | Never — the run starts immediately | + +Practical recommendation for Phase 2: have the user switch to Auto mode before launch so the +entire autonomous run pays at most one approval prompt. The permission mode controls only the +launch prompt — subagents spawned by a workflow always run in `acceptEdits` mode and inherit +the session tool allowlist regardless of session mode. Shell commands, web fetches, and MCP +tools outside the allowlist can still prompt mid-run; add the commands agents need (git, test +runners, `codex`) to the allowlist before a long run. + +## Limits + +| Constraint | Consequence for Superflow | +|------------|---------------------------| +| Up to 16 concurrent agents (fewer on machines with limited CPU cores) | Cap wave width at 16; Superflow waves stay far below this | +| 1,000 agents total per run | Not a practical limit for the review/wave scripts | +| No mid-run user input | Workflows fit Phase 2 only (autonomous); never use them for Phase 1 gates | +| No direct filesystem or shell access from the script | Agents do ALL I/O; the script only coordinates and parses response text | + +## Saved Workflows + +- `.claude/workflows/` in a project — shared with everyone who clones the repo. +- `~/.claude/workflows/` — personal, available in every project. Superflow's deploy-sync + (SKILL.md startup step 4, Claude runtime only) checksums `workflows/*.js` from the skill + root into `~/.claude/workflows/`, so `/superflow-review` and `/superflow-wave` are + invocable in any project. +- A saved workflow runs as `/`. On a name collision, the project copy wins. +- Input arrives through `args`: the script reads it as a global, already structured + (arrays/objects usable directly, no parsing). If omitted, `args` is `undefined`. + +## The Two Superflow Saved Workflows + +Both scripts use ONLY the documented API surface and stay deterministic — no clock or +randomness calls (the runtime forbids them); the orchestrator stamps timestamps when it +assembles `.par-evidence.json`. Structured data returns via the v5.4.0 fenced-JSON contract: +each script extracts the LAST fenced `json` block from the agent's response with a regex and +`JSON.parse` in try/catch. On any parse failure it FAILS CLOSED — a review verdict degrades +to `REQUEST_CHANGES`, an implementation result to `status: "failed"`. A malformed agent +reply can never pass a gate. + +### /superflow-review — unified review fan-out + +`workflows/superflow-review.js`. Accelerates the review-unified step +(`references/phase2/steps/review-unified.md`). + +- **args:** `{sprint, branch, base, charter_path, workdir, spec_path, plan_path, brief_path, product, diff_hint}` + - `workdir` (required): absolute path to the sprint worktree (or repo root for + `solo_single_pr`). The technical reviewer cds into workdir before running `codex exec + review`; the product reviewer uses `git -C workdir diff` — without this, both would diff + the wrong checkout. + - `spec_path`, `plan_path`, `brief_path` (optional, strongly recommended): file paths the + reviewers Read for context. `spec_path`/`plan_path` feed the spec-fit and plan-completeness + checks for BOTH lenses (a diff alone cannot reveal a stub); `brief_path` feeds the product + lens. When absent, the prompts instruct the reviewer to flag the check as unverifiable + rather than pass silently. + - `product` (boolean, default `true`): pass `false` for light-governance sprints (single + technical reviewer only). Returns `{product: null, technical, pass}` when false. + - Returns `{product: null, technical: null, pass: false, error: "missing required args: ..."}` if + `sprint`, `branch`, `charter_path`, or `workdir` is missing — fails closed instead of + interpolating "undefined" into prompts. +- Runs in parallel: a product reviewer (follows `~/.claude/agents/standard-product-reviewer.md`, + reads the charter at `charter_path`, reviews `branch` vs `base` via `git -C workdir diff`) + and a technical reviewer (cds into `workdir`, applies the fallback chain itself via Bash: if + the Codex CLI exists, `$TIMEOUT_CMD 600 codex exec review --base -m gpt-5.5 -c model_reasoning_effort=high --ephemeral`; + else it acts as the Claude technical reviewer per `~/.claude/agents/standard-code-reviewer.md`). + When `product:false`, only the technical thunk runs. +- **returns:** `{product, technical, pass}` — `pass` is true only when passing verdicts hold for + all active reviewers (APPROVE/ACCEPTED/PASS); REQUEST_CHANGES/NEEDS_FIXES/FAIL and anything + unparseable fail. `product` is `null` when `product:false`. +- The orchestrator assembles `.par-evidence.json` from the returned verdicts with + `"provider": "workflow-review"`, then runs the docs gate and the fix/re-review loop per + the step file. Fixes are orchestrator work — re-run the workflow only if both reviewers + must look again; otherwise re-engage the single flagging lens via plain Agent dispatch. + +### /superflow-wave — implementation-only wave + +`workflows/superflow-wave.js`. Accelerates the v5.4.0 parallel-wave dispatch rule: +implementation-only fan-out; orchestrator runs review/docs/PAR/ship per sprint. +REVIEW IS NOT IN THIS SCRIPT. + +- **args:** `{sprints: [{id, branch, worktree, task}], charter_path}` +- `parallel()` dispatches one implementer agent per sprint. Each prompt: follow + `~/.claude/agents/standard-implementer.md`, read the charter, work ONLY inside the given + worktree on the given branch, implement the task, run tests, commit — no reviews, no docs, + no PAR evidence, no PRs. +- **returns:** array of `{sprint, status: "done"|"failed", summary, test_evidence}` — one + entry per input sprint, position-bound (null agent results fail closed to `"failed"`). +- Afterwards the ORCHESTRATOR runs review → docs → PAR → ship per sprint, exactly as in + `references/phase2/steps/impl-dispatch.md`. The sequencing (review/docs/PAR/ship per sprint) + is unchanged; only the implementation fan-out is accelerated. + +## UNDOCUMENTED-API Warning + +> **⚠️ Do not use undocumented script fields.** Fields like `schema`, `agentType`, +> `isolation`, and `resume-run-id` have been observed in some builds but appear nowhere in +> the official workflows doc. Shipped Superflow scripts MUST NOT rely on them — they can +> change or vanish in any release. The guaranteed surface is `agent(prompt)` → final +> response text, `parallel()`, `phase()`, `log()`, `args`. Structured data comes back ONLY +> through the fenced-JSON contract with fail-closed parsing. + +## /goal Watchdog + +`/goal` sets a session-level objective watchdog (see the goal doc). **It is a USER-ONLY +command — the model CANNOT set it.** Superflow never claims to have set a goal; it only +suggests one. At Phase 2 launch (right after plan approval, before the first sprint), the +orchestrator PRINTS a ready-to-paste suggestion: + +```text +/goal Superflow Phase 2 complete: all sprints implemented, unified-reviewed, PRs created and CI-green, Completion Report delivered. +``` + +Mechanics worth knowing: + +- The evaluator is Haiku, running as a prompt-based Stop hook: it judges ONLY what is + visible in the transcript. The orchestrator must keep narrating sprint completions (it + already does) so the evaluator can see progress. +- One goal per session; survives `--resume`; the user clears it with `/goal clear`. +- Subagents do NOT inherit goals. Per-sprint goal-direction remains the Autonomy Charter + injection into every implementer and reviewer prompt (already shipped) — the charter, not + `/goal`, is what keeps subagents aligned. + +## Codex Runtime and Fallbacks + +Codex runtime has NO Workflow tool and NO `/goal`. On `RUNTIME:codex` the markdown DAG with +`spawn_agent` dispatch is the only path — skip everything in this doc except the +charter-injection note above. + +The Agent-based v5.4.0 path is also the fallback on Claude runtime whenever ANY of: + +- `context.use_workflows = false` (user said no-workflows at plan approval) +- workflows disabled: `"disableWorkflows": true` in settings, or `CLAUDE_CODE_DISABLE_WORKFLOWS=1` +- Claude Code version < 2.1.154 + +Fallback means NO behavior change: `review-unified.md` and `impl-dispatch.md` describe the +Workflow path as PREFERRED-WHEN-AVAILABLE and keep the full Agent dispatch procedure. When +in doubt, fall back — the workflow path is an acceleration, never a requirement. diff --git a/superflow-enforcement.md b/superflow-enforcement.md index eeaa52e..71225a9 100644 --- a/superflow-enforcement.md +++ b/superflow-enforcement.md @@ -7,14 +7,14 @@ Survives context compaction. SKILL.md does not. 1. **Subagents write all code.** Orchestrator reads, plans, reviews, dispatches. 2. **Honor selected git workflow mode.** Read `context.git_workflow_mode` from `.superflow-state.json` before Phase 2 work. If missing, default to `sprint_pr_queue`. Valid modes: `solo_single_pr`, `sprint_pr_queue`, `stacked_prs`, `parallel_wave_prs`, `trunk_based`. See `references/git-workflow-modes.md`. 2a. **Use isolated branches/worktrees.** For sprint-based modes, use `git worktree add .worktrees/sprint-N feat/-sprint-N`. For `solo_single_pr`, use one `feat/` branch/worktree for the run. Verify `.worktrees/` is in `.gitignore` before creating (`git check-ignore -q .worktrees`). -3. **Unified Review before every PR** (2 agents for standard/critical sprints; single Technical reviewer for light-mode sprints): +3. **Unified Review before every PR** (2 agents for standard/critical sprints; single Technical reviewer for light-mode sprints): (When `context.use_workflows=true`, steps 1-3 may run via the saved `/superflow-review` workflow — see `references/workflow-orchestration.md`; steps 4-9 unchanged.) 1. Dispatch Claude product reviewer (subagent_type: standard-product-reviewer) as a named background agent: `name: sprint--product-reviewer`, `run_in_background: true`. 2. Dispatch secondary technical reviewer — fallback chain: (1) `$TIMEOUT_CMD 600 codex exec review --base main -m gpt-5.5 -c model_reasoning_effort=high --ephemeral`; (2) native `/code-review` skill via the Skill tool at high effort; (3) two split-focus Claude agents (Product + Technical). `/code-review ultra` is user-triggered and billed — NEVER launch it; only suggest it to the user as an optional extra gate at Phase 3 pre-merge. 3. Verdict contract: every reviewer ends its final message with a fenced `json` block — `{"verdict": "APPROVE|ACCEPTED|PASS|REQUEST_CHANGES|NEEDS_FIXES|FAIL", "findings": [{"severity": "critical|high|medium|low", "file": "...", "line": 0, "scenario": "breakage scenario", "description": "..."}], "summary": "..."}`. Extract the fence (awk/sed → jq) and assemble `.par-evidence.json` mechanically from the verdict fields — no prose parsing. 4. Wait for both. Fix confirmed issues (NEEDS_FIXES, REQUEST_CHANGES, or FAIL). Re-engage ONLY the flagging reviewer via SendMessage (its original context intact), scoped to the fix diff + its original findings. Cold re-dispatch is the fallback if the agent is gone. 5. Run mandatory sprint documentation update (`CLAUDE.md` + `llms.txt`) before PR creation. `llms.txt` must be explicitly checked on every sprint, even if unchanged. 6. Run documentation review after the update/unchanged decision. It must verify `llms.txt` and `CLAUDE.md` reflect the sprint diff and contain no stale paths/commands. - 7. Write `.par-evidence.json`: `{"sprint":N,"claude_product":"ACCEPTED","technical_review":"APPROVE","docs_update":"UPDATED|UNCHANGED","docs_review":"PASS","provider":"codex|code-review-skill|split-focus","ts":"..."}` + 7. Write `.par-evidence.json`: `{"sprint":N,"claude_product":"ACCEPTED","technical_review":"APPROVE","docs_update":"UPDATED|UNCHANGED","docs_review":"PASS","provider":"codex|code-review-skill|split-focus|workflow-review","ts":"..."}` 8. GATE: `git push` / `gh pr create` blocked until `.par-evidence.json` exists with review verdicts passing, `docs_update` set, and `docs_review` = `PASS`. 9. Pass verdicts: APPROVE, ACCEPTED, PASS. Fail verdicts: REQUEST_CHANGES, NEEDS_FIXES, FAIL. 4. **Tests with evidence.** Paste actual output before claiming done. @@ -44,7 +44,7 @@ $TIMEOUT_CMD 600 $SECONDARY_PROVIDER "PROMPT" 2>&1 ```bash $TIMEOUT_CMD 600 claude -p "PROMPT" 2>&1 # general $TIMEOUT_CMD 600 claude -p "$(cat prompts/claude/code-reviewer.md) DIFF_CONTEXT" 2>&1 # code review -# claude-fable-5 = frontier profile (default); claude-opus-4-8 = balanced profile — read context.model_profile +# Deep product/research secondary uses claude-opus-4-8 (Fable access is blocked — all judgment roles run on Opus, differentiated by effort) # No secondary → two Codex agents with split focus via spawn_agent (Product + Technical) ``` See `references/codex-dispatch-patterns.md` for the complete dispatch mapping. @@ -53,13 +53,13 @@ See `references/codex-dispatch-patterns.md` for the complete dispatch mapping. | Tier | Claude Agent (subagent_type) | Codex | When | |------|-------------------------------|-------|------| -| **deep** | `deep-spec-reviewer`, `deep-code-reviewer`, `deep-product-reviewer`, `deep-analyst` (fable, effort: max); `deep-doc-writer` (opus, effort: max); `deep-implementer` (sonnet, effort: max) | `-m gpt-5.5 -c model_reasoning_effort=xhigh` + `prompts/codex/` | Phase 0 audit+security, Phase 1 spec review, Phase 2 final holistic, llms.txt/CLAUDE.md generation | +| **deep** | `deep-spec-reviewer`, `deep-code-reviewer`, `deep-product-reviewer`, `deep-analyst` (opus, effort: max); `deep-doc-writer` (opus, effort: max); `deep-implementer` (sonnet, effort: max) | `-m gpt-5.5 -c model_reasoning_effort=xhigh` + `prompts/codex/` | Phase 0 audit+security, Phase 1 spec review, Phase 2 final holistic, llms.txt/CLAUDE.md generation | | **standard** | `standard-spec-reviewer`, `standard-code-reviewer`, `standard-product-reviewer`, `standard-doc-writer` (opus, effort: high); `standard-implementer` (sonnet, effort: high) | `-m gpt-5.5 -c model_reasoning_effort=high` + `prompts/codex/` | Phase 1 plan review, Phase 2 unified review, Phase 3 doc updates | | **fast** | `fast-implementer` (sonnet, effort: low) | `-m gpt-5.5 -c model_reasoning_effort=medium` | Simple implementation tasks | Agent definitions with effort frontmatter are deployed to `~/.claude/agents/` during SKILL.md startup (step 4). Agent() does NOT accept inline `effort` — controlled via agent definition files only. -**CRITICAL: Always pass `model:` explicitly in every Agent() call.** Frontmatter `model:` in agent definitions is NOT reliably inherited — a forgotten `model:` now silently inherits the parent frontier model (Fable); the cost of forgetting went UP. Rule: implementers → `model: "sonnet"` (haiku permitted for mechanical Phase 0 file/config checks); standard reviewers + doc-writers → `model: "opus"`; deep reviewers + `deep-analyst` → `"fable"` (model_profile=frontier, default) or `"opus"` (model_profile=balanced — read `context.model_profile` from `.superflow-state.json`). +**CRITICAL: Always pass `model:` explicitly in every Agent() call.** Frontmatter `model:` in agent definitions is NOT reliably inherited — a forgotten `model:` silently inherits the orchestrator's session model (Opus), which is wrong for implementers (more expensive than the intended Sonnet and defeats effort tiering). Rule: implementers → `model: "sonnet"` (haiku permitted for mechanical Phase 0 file/config checks); standard reviewers + doc-writers → `model: "opus"`; deep reviewers + `deep-analyst` → `model: "opus"`. **Fable access is blocked — every judgment role runs on Opus, depth differentiated by effort (deep = max, standard = high) via agent definition frontmatter.** ## Test & Process Discipline diff --git a/templates/superflow-state-schema.json b/templates/superflow-state-schema.json index b20c643..5b64342 100644 --- a/templates/superflow-state-schema.json +++ b/templates/superflow-state-schema.json @@ -189,14 +189,10 @@ "default": "sprint_pr_queue", "description": "Branch, PR, and merge workflow selected in Phase 1" }, - "model_profile": { - "type": "string", - "enum": [ - "frontier", - "balanced" - ], - "default": "frontier", - "description": "Model tier for deep judgment roles: frontier=fable (default), balanced=opus-4.8" + "use_workflows": { + "type": "boolean", + "default": true, + "description": "Opt-in for saved multi-agent workflows (/superflow-review, /superflow-wave) in Phase 2; Claude runtime only" }, "runtime": { "type": "string", diff --git a/workflows/superflow-review.js b/workflows/superflow-review.js new file mode 100644 index 0000000..8f8b4c9 --- /dev/null +++ b/workflows/superflow-review.js @@ -0,0 +1,158 @@ +// /superflow-review — Superflow unified review fan-out (Phase 2, step review-unified). +// +// OPT-IN acceleration of the two-reviewer protocol. The Agent-based dispatch in +// references/phase2/steps/review-unified.md remains the default and the fallback. +// Authority: references/workflow-orchestration.md +// +// Documented API surface ONLY: agent(prompt) -> final response text, parallel(), +// phase(), log(), args. Structured data comes back via the v5.4.0 fenced-JSON +// verdict contract; any parse failure FAILS CLOSED as REQUEST_CHANGES. +// Deterministic by design: no clock or randomness calls — the orchestrator stamps +// timestamps when it assembles .par-evidence.json (provider: "workflow-review"). +// +// args: { sprint: N, branch: "feat/x-sprint-N", base: "main", +// charter_path: "docs/superflow/specs/...-charter.md", +// workdir: "/abs/path/to/sprint-worktree", +// spec_path: "...", (optional — sprint spec/requirements; basis for spec-fit + plan-completeness) +// plan_path: "...", (optional — sprint plan tasks; reviewers verify each is implemented, not stubbed) +// brief_path: "...", (optional — Product Brief: user stories + success criteria) +// product: true, (default true; pass false for light-governance) +// diff_hint: "..." } +// returns: { product: |null, technical: , pass: } +// on missing required args: { product: null, technical: null, pass: false, error: "..." } + +export const meta = { + name: "superflow-review", + description: "Superflow Phase 2 unified review: product + technical reviewers in parallel over a sprint branch diff; returns fenced-JSON verdicts, fail-closed.", + phases: [{ title: "Review" }], +}; + +const PASS_VERDICTS = ["APPROVE", "ACCEPTED", "PASS"]; + +// v5.4.0 verdict contract: extract the LAST fenced json block, JSON.parse in +// try/catch. Null agent results, missing fences, bad JSON, or a missing verdict +// field all FAIL CLOSED — a malformed reviewer reply can never pass the gate. +// (Helper duplicated in superflow-wave.js — workflow scripts cannot import.) +function parseVerdict(text, lens) { + const failClosed = { + verdict: "REQUEST_CHANGES", + findings: [], + summary: lens + " reviewer returned no parseable fenced-JSON verdict (fail closed)", + }; + if (typeof text !== "string") return failClosed; + const fences = [...text.matchAll(/```json\s*([\s\S]*?)```/g)]; + if (fences.length === 0) return failClosed; + try { + const parsed = JSON.parse(fences[fences.length - 1][1]); + if (!parsed || typeof parsed.verdict !== "string") return failClosed; + return parsed; + } catch { + return failClosed; + } +} + +function isPass(verdict) { + return PASS_VERDICTS.includes(String(verdict).trim().toUpperCase()); +} + +const VERDICT_BLOCK = + "End your final message with a fenced json block and NOTHING after it:\n" + + "```json\n" + + '{"verdict": "...", "findings": [{"severity": "critical|high|medium|low", ' + + '"file": "", "line": 0, "scenario": "", "description": ""}], "summary": ""}\n' + + "```"; + +function productPrompt(a) { + return ( + "You are the PRODUCT reviewer for Superflow sprint " + a.sprint + ".\n" + + "1. Read ~/.claude/agents/standard-product-reviewer.md and FOLLOW it (role, checks, output format).\n" + + "2. Read and internalize the review context — compare the implementation against ALL of it:\n" + + " - Autonomy Charter: " + a.charter_path + " (goal, non-negotiables, success criteria)\n" + + (a.spec_path ? " - Spec / sprint requirements: " + a.spec_path + " (basis for the Spec fit check)\n" : "") + + (a.plan_path ? " - Sprint plan: " + a.plan_path + " (Plan completeness — every planned task must be implemented in substance, not stubbed)\n" : "") + + (a.brief_path ? " - Product Brief: " + a.brief_path + " (user stories + success criteria)\n" : "") + + " If a referenced file is missing or an input was not provided, say so explicitly and treat that check as unverifiable — never pass silently.\n" + + "3. Review the diff of " + a.branch + " against " + a.base + " (git -C " + a.workdir + " diff " + a.base + "..." + a.branch + ") " + + "through the product lens ONLY: spec fit, user scenarios, data integrity, plan completeness. " + + "Every finding needs a realistic breakage scenario.\n" + + (a.diff_hint ? "Diff hint from the orchestrator: " + a.diff_hint + "\n" : "") + + "Allowed verdicts: ACCEPTED or NEEDS_FIXES.\n" + + VERDICT_BLOCK + ); +} + +function technicalPrompt(a) { + return ( + "You are the TECHNICAL reviewer for Superflow sprint " + a.sprint + ". Apply the fallback chain YOURSELF via Bash:\n" + + "1. Run: command -v codex. If the Codex CLI exists, resolve TIMEOUT_CMD (gtimeout, else timeout).\n" + + " cd into " + a.workdir + " (the sprint worktree) so the sprint branch checkout is visible, then run:\n" + + " $TIMEOUT_CMD 600 codex exec review --base " + a.base + " -m gpt-5.5 -c model_reasoning_effort=high --ephemeral 2>&1\n" + + " Wrap its findings honestly into the verdict block below (verdict APPROVE or REQUEST_CHANGES).\n" + + "2. If codex is absent: act as the Claude technical reviewer — Read ~/.claude/agents/standard-code-reviewer.md and FOLLOW it " + + "over the diff of " + a.branch + " vs " + a.base + " (git -C " + a.workdir + " diff " + a.base + "..." + a.branch + "; correctness, security, architecture, performance).\n" + + "Review context — read and compare the implementation against ALL of it:\n" + + " - Autonomy Charter: " + a.charter_path + " (non-negotiables — violations are critical)\n" + + (a.spec_path ? " - Spec / sprint requirements: " + a.spec_path + "\n" : "") + + (a.plan_path ? " - Sprint plan: " + a.plan_path + " (Plan completeness check #11 — every planned task must be implemented in substance, not stubbed)\n" : "") + + " If a referenced file is missing, say so and treat plan completeness as unverifiable.\n" + + (a.diff_hint ? "Diff hint from the orchestrator: " + a.diff_hint + "\n" : "") + + VERDICT_BLOCK + ); +} + +// Normalize args: depending on the invocation path, args may arrive as a JSON +// string instead of a parsed object. Parse errors leave an empty object, which +// fails closed via the missing-required-args path below. +let _args = {}; +try { _args = typeof args === "string" ? JSON.parse(args) : (args || {}); } catch { _args = {}; } + +const a = { + sprint: _args.sprint, + branch: _args.branch, + base: _args.base || "main", + charter_path: _args.charter_path, + workdir: _args.workdir || "", + spec_path: _args.spec_path || "", + plan_path: _args.plan_path || "", + brief_path: _args.brief_path || "", + diff_hint: _args.diff_hint || "", + product: !(_args.product === false), +}; + +// Required-args validation — fail closed instead of interpolating "undefined" into prompts. +const _missing = []; +if (a.sprint == null || a.sprint === "") _missing.push("sprint"); +if (!a.branch) _missing.push("branch"); +if (!a.charter_path) _missing.push("charter_path"); +if (!a.workdir) _missing.push("workdir"); +if (_missing.length > 0) { + const _errMsg = "missing required args: " + _missing.join(", "); + log("superflow-review: " + _errMsg); + return { product: null, technical: null, pass: false, error: _errMsg }; +} + +log("superflow-review: sprint " + a.sprint + " — reviewing " + a.branch + " vs " + a.base + + (a.product ? "" : " (technical-only, product skipped)")); + +phase("Review"); +let _productText = null; +let _technicalText = null; + +if (a.product) { + const _texts = (await parallel([() => agent(productPrompt(a)), () => agent(technicalPrompt(a))])) || []; + _productText = _texts[0] != null ? _texts[0] : null; + _technicalText = _texts[1] != null ? _texts[1] : null; +} else { + const _texts = (await parallel([() => agent(technicalPrompt(a))])) || []; + _technicalText = _texts[0] != null ? _texts[0] : null; +} + +const product = a.product ? parseVerdict(_productText, "product") : null; +const technical = parseVerdict(_technicalText, "technical"); +const pass = (!a.product || isPass(product.verdict)) && isPass(technical.verdict); + +log( + "superflow-review: product=" + (product ? product.verdict : "SKIPPED") + + " technical=" + technical.verdict + " pass=" + pass +); +return { product, technical, pass }; diff --git a/workflows/superflow-wave.js b/workflows/superflow-wave.js new file mode 100644 index 0000000..1ba3da4 --- /dev/null +++ b/workflows/superflow-wave.js @@ -0,0 +1,96 @@ +// /superflow-wave — Superflow parallel implementation wave (Phase 2, step impl-dispatch). +// +// OPT-IN acceleration of the v5.4.0 parallel-wave dispatch rule: +// implementation-only fan-out; orchestrator runs review/docs/PAR/ship per sprint. +// Authority: references/workflow-orchestration.md +// +// Documented API surface ONLY: agent(prompt) -> final response text, parallel(), +// phase(), log(), args. Structured data comes back via the fenced-JSON contract; +// any parse failure FAILS CLOSED as status "failed". Deterministic by design: no +// clock or randomness calls — the orchestrator stamps timestamps. +// +// args: { sprints: [{ id, branch, worktree, task }], charter_path } +// returns: [{ sprint, status: "done"|"failed", summary, test_evidence }] — +// one entry per input sprint, position-bound. + +export const meta = { + name: "superflow-wave", + description: "Superflow Phase 2 implementation wave: one implementer agent per sprint in its own worktree; returns fenced-JSON results, fail-closed. Review/docs/PAR/ship stay with the orchestrator.", + phases: [{ title: "Implementation" }], +}; + +// Fenced-JSON extraction: take the LAST fenced json block, JSON.parse in try/catch. +// Null agent results, missing fences, bad JSON, or an invalid status FAIL CLOSED. +// (Helper duplicated in superflow-review.js — workflow scripts cannot import.) +function parseResult(text, sprintId) { + const failClosed = { + sprint: sprintId, + status: "failed", + summary: "implementer returned no parseable fenced-JSON result (fail closed)", + test_evidence: "", + }; + if (typeof text !== "string") return failClosed; + const fences = [...text.matchAll(/```json\s*([\s\S]*?)```/g)]; + if (fences.length === 0) return failClosed; + try { + const parsed = JSON.parse(fences[fences.length - 1][1]); + if (!parsed || (parsed.status !== "done" && parsed.status !== "failed")) return failClosed; + // Bind to the wave's sprint id — the orchestrator keys results positionally. + return { + sprint: sprintId, + status: parsed.status, + summary: typeof parsed.summary === "string" ? parsed.summary : "", + test_evidence: typeof parsed.test_evidence === "string" ? parsed.test_evidence : "", + }; + } catch { + return failClosed; + } +} + +function implementerPrompt(s, charterPath) { + return ( + "You are the implementer for Superflow sprint " + s.id + ".\n" + + "1. Read ~/.claude/agents/standard-implementer.md and FOLLOW it (TDD discipline, verification).\n" + + "2. Read the Autonomy Charter at " + charterPath + " — goal, non-negotiables, and success criteria bind you.\n" + + "3. Work ONLY inside the worktree at " + s.worktree + " on branch " + s.branch + ". Never touch files outside it.\n" + + "4. Implement this task:\n" + s.task + "\n" + + "5. Run the test suite (wrap with a 120s timeout), then commit your work on " + s.branch + " with a descriptive message.\n" + + "Do NOT review, update docs, write PAR evidence, or create PRs — the orchestrator does that per sprint afterwards.\n" + + "End your final message with a fenced json block and NOTHING after it:\n" + + "```json\n" + + '{"sprint": ' + JSON.stringify(s.id) + ', "status": "done|failed", "summary": "", "test_evidence": ""}\n' + + "```\n" + + 'Use status "done" only if tests pass and the commit exists; otherwise "failed" with the reason in summary.' + ); +} + +// Normalize args: depending on the invocation path, args may arrive as a JSON +// string instead of a parsed object. Parse errors leave an empty object, which +// fails closed via the "no sprints" early return below. +let a = {}; +try { a = typeof args === "string" ? JSON.parse(args) : (args || {}); } catch { a = {}; } + +const sprints = Array.isArray(a.sprints) ? a.sprints : []; +const charterPath = a.charter_path || ""; +if (sprints.length === 0) { + log("superflow-wave: no sprints in args — nothing to dispatch"); + return []; +} +log( + "superflow-wave: dispatching " + sprints.length + " implementer(s): " + + sprints.map((s) => s.id).join(", ") +); + +phase("Implementation"); +const texts = await parallel(sprints.map((s) => () => agent(implementerPrompt(s, charterPath)))); + +// Position-bound parsing; null/missing results fail closed inside parseResult. +const results = sprints.map((s, i) => + parseResult(texts && texts[i] != null ? texts[i] : null, s.id) +); +const done = results.filter((r) => r.status === "done").length; +log( + "superflow-wave: " + done + "/" + results.length + " sprint(s) done — " + + "orchestrator now runs review/docs/PAR/ship per sprint" +); +return results;