| name | flow-next-make-pr |
| description | Open a PR with a cognitive-aid body rendered from flow-next spec state via gh. Use whenever asked to make or open a PR in a flow-next repo. |
| user-invocable | false |
| allowed-tools | Read, Bash, Grep, Glob, Write, Edit, Task |
/flow-next:make-pr — PR-as-cognitive-aid
A reviewable PR body is itself an artefact: it lets a human decide where to focus before skimming the diff. flow-next already collects every input that body needs — the spec with R-IDs, per-task done summaries and evidence commits, decisions / bug / architecture-patterns memory entries, glossary changes, strategy alignment, deferred review findings, the git diff itself. This skill stitches those into a structured body, optionally adds mermaid diagrams for module-boundary changes, and pushes via gh pr create.
The host agent (Claude Code / Codex / Droid) reads the structured payload from flowctl spec export-cognitive-aid and synthesizes the body directly. Every claim in the body must trace to a structured field in the export payload — never fabricate file paths, SHAs, R-ID attributions, or "why" reasoning. Unknown attribution is honest ("uncovered" / "unclear") rather than invented. The host is competent at "what looks important here?" given the rich input; no second-model review pass is needed (the structured payload does the heavy lifting).
flowctl provides only thin plumbing: flowctl spec export-cognitive-aid <spec-id> --base <ref> --json aggregates the inputs into a single JSON payload (Task 1 of this spec). The skill renders the body, then pushes and creates the PR directly — no confirm prompt (invoking make-pr is the intent; the body is deterministic; the default is a reversible draft). --dry-run prints the body without creating; --ready/--draft set draft state.
Read workflow.md for Phases 0–3 (pre-flight → gather → render body → mermaid) + the §4.0 --dry-run short-circuit — each phase ends with its inline ### Done when checklist. The post-render create + finalize machinery (§4.1 title → §4.6 gh pr create/--update → Phase 5 receipt/footer) lives in create-and-finalize.md, read ONLY on a real create (after §4.0 does not short-circuit) — a --dry-run preview never loads it. Read mermaid-rules.md before emitting any mermaid codefence — it defines reserved words, escape patterns, shape selection, and the pre-emission validation checklist.
Preamble
CRITICAL: flowctl is BUNDLED — NOT installed globally. which flowctl will fail (expected). Define once; subsequent blocks (here and in workflow.md) use $FLOWCTL:
FLOWCTL="$HOME/.codex/scripts/flowctl"
[ -x "$FLOWCTL" ] || FLOWCTL=".flow/bin/flowctl"
Inline skill (no context: fork) — plain-text numbered prompt must stay reachable for the Phase 0 info prompts (resolve a missing base ref / undetected spec id — never a confirm gate). Subagents can't call plain-text numbered prompts (Claude Code issues #12890, #34592). There is no Phase 4 confirm prompt — make-pr creates the PR directly.
Mode Detection
Parse $ARGUMENTS as a flag list. Recognized flags: --draft, --ready, --no-mermaid, --memory, --dry-run, --base <ref> (consumes the next token), and the literal token mode:autonomous. Strip recognized tokens; the remainder (if any) is the optional spec id.
RAW_ARGS="$ARGUMENTS"
DRAFT_FORCE="auto"
NO_MERMAID=0
WRITE_MEMORY=0
DRY_RUN=0
BASE_REF=""
SPEC_ID=""
AUTONOMOUS=0
PREV=""
for ARG in $RAW_ARGS; do
case "$PREV" in
--base) BASE_REF="$ARG"; PREV=""; continue ;;
esac
case "$ARG" in
--draft) DRAFT_FORCE="draft" ;;
--ready) DRAFT_FORCE="ready" ;;
--no-mermaid) NO_MERMAID=1 ;;
--memory) WRITE_MEMORY=1 ;;
--dry-run) DRY_RUN=1 ;;
--base) PREV="$ARG" ;;
--base=*) BASE_REF="${ARG#--base=}" ;;
mode:autonomous) AUTONOMOUS=1 ;;
-*) echo "Unknown flag: $ARG" >&2; exit 2 ;;
*) SPEC_ID="$ARG" ;;
esac
done
[[ -n "$PREV" ]] && { echo "Flag $PREV given without a value" >&2; exit 2; }
if [[ "${FLOW_AUTONOMOUS:-}" == "1" ]]; then
AUTONOMOUS=1
fi
| Flag | Effect |
|---|
--draft | Force draft PR regardless of open-items count or Ralph context. |
--ready | Force non-draft PR. Conflicts with --draft (last flag wins; surface the conflict). |
--no-mermaid | Skip Phase 3 entirely. Mermaid prose summaries are also skipped. |
--memory | After PR creation, write a knowledge/architecture-patterns/ memory entry summarizing what shipped. Idempotent — rerun adds no second entry for the same spec id. |
--dry-run | Skip Phase 4 entirely. Render body to stdout. Useful for inspection or … --dry-run | pbcopy. |
--base <ref> | Override base-branch detection cascade. Useful when the team's default branch is develop, etc. |
mode:autonomous | Autonomous mode: Phase 0 info prompts hard-error instead of asking; draft forced. Sets AUTONOMOUS=1 only — NEVER RALPH. Also derived from FLOW_AUTONOMOUS=1. |
Ralph mode (FLOW_RALPH=1 or REVIEW_RECEIPT_PATH set) is detected separately in workflow.md §0.0 — the skill is not Ralph-blocked. Under Ralph the skill hard-errors instead of asking the Phase 0 info prompts, forces --draft, and emits the PR URL to stdout. (The PR is created directly in both modes — the only difference is forced-draft + no Phase 0 prompts under Ralph.) Autonomous mode is a SEPARATE flag: AUTONOMOUS=1 derives only from the mode:autonomous token or FLOW_AUTONOMOUS=1 and never sets RALPH. Under RALPH || AUTONOMOUS the Phase 0 info prompts hard-error and --draft is forced (--ready ignored with a note); the PR_URL= stdout contract and all receipt/harness semantics remain Ralph-only.
Interaction Principles
Ask the user via plain text. Render the options below as a numbered list 1. … N., followed by a final option N+1. Other — type your own answer. Print the question, then the numbered list, then stop and wait for the user's next message before continuing. Parse the reply as: a bare number 1–N+1 → that option; the literal text of an option label → that option; free text after Other → custom answer.
- Ask one question at a time via
plain-text numbered prompt. Never silently skip the question.
- Lead with the recommended option and a one-sentence rationale.
- No confirm gate. make-pr opens the PR without asking. Phase 0 asks only to resolve info it cannot derive (no
--base and no detection match; no spec detected) — never "do you want to create it?". Not-all-tasks-done warns and proceeds (the open items make it a draft). Skip questions when context resolves cleanly.
- Ralph and autonomous modes skip all questions. Detect both once at Phase 0 and route deterministically; a genuinely unanswerable gap hard-errors with a clear message (NEEDS_HUMAN-style) instead of hanging on a prompt.
Hallucination guardrails
The body is synthesized from the export payload. Every claim must trace to a structured field. The skill explicitly forbids:
- Inventing file paths. Only paths returned by
git diff --name-status (via the diff.files array) appear in Critical Changes / Review plan. No "I think there's also a config file" content.
- Inventing risk or verification claims. Every "must review because…" clause in the Review plan traces to a
diff_summary risk signal (churn / public export / security path / cross-module edge / user-facing surface); every "the pipeline verified…" line in the How-to-review block traces to tasks[].evidence / R-ID coverage / reviews.*. No narrated risk and no claimed verification without a payload anchor — absent verification is stated honestly ("no cross-model review recorded on this PR").
- Fabricating commit SHAs. SHAs come from
tasks[].evidence[].commits and git log --oneline base..HEAD only.
- Guessing R-ID coverage. Coverage is computed from task
satisfies frontmatter and commit-message R-ID references. Uncovered R-IDs get a ⚠️ flag, never a confident attribution.
- Inventing "why" reasoning. Decision context comes from
memory.decisions[] entries' bodies. If no decision entry exists for a change, the body says so explicitly rather than narrating a plausible-sounding rationale.
- Quoting raw diff content. The body talks ABOUT the diff (paths, churn, modules). Never includes code snippets — privacy + secret-leakage risk; GitHub renders the actual diff below the body.
- Synthesizing review findings. Findings come from
reviews.deferred[] and reviews.suppressed_count. The body never editorializes severity or fabricates findings.
- Generating fictitious memory IDs. When the body references memory entries (decisions / bugs / patterns), the IDs come from the export payload — never interpolated.
- Synthesizing strategy alignment. Strategy section content comes verbatim from
strategy.tracks[] and the spec's ## Strategy Alignment block. The body never invents alignment claims.
- Inventing glossary terms. Glossary section content comes from
glossary.changes[]. New terms / renamed terms are surfaced only if the export reports them.
- Hallucinating mermaid relationships. Diagram nodes + edges come from real cross-module imports detected via
git diff analysis (Phase 3 details in the mermaid-rules.md ref file). The skill never adds "I think module X also imports Y" edges.
When data is missing, the body says so honestly (e.g. *No decision-track memory entries for this spec. Surface decisions in PR review comments if needed.*) rather than confabulating content. Honest "unclear" beats plausible "wrong".
Forbidden
- Ralph-blocking the skill. This skill IS the autonomous-loop terminus per spec R24. Detect Ralph but proceed (with
--draft forced). Do NOT add a FLOW_RALPH/REVIEW_RECEIPT_PATH exit-2 guard at the top of the skill.
- Re-adding a confirm gate. make-pr creates the PR without prompting; do NOT reintroduce a "create / dry-run / abort"
plain-text numbered prompt before push. The escape hatch is --dry-run, not a question.
- Pushing or creating PRs in
--dry-run mode. Phase 4 short-circuits before any git push or gh pr create. The body lands on stdout only.
- Squashing the existing-PR check. A bare
gh pr view --json url 2>/dev/null returns rc=0 for CLOSED and MERGED PRs as readily as OPEN. Filter .state == "OPEN" via jq (validated empirically during fn-42 spike). Closed/merged PRs on a reused branch must NOT trigger refusal.
- Manual
git push workflows when gh is missing. When gh isn't installed or authenticated, surface the install / gh auth login instructions and exit. Don't try to fall back to half-baked PR creation.
- Writing memory entries without
--memory. Default off. The user opts in for structurally-significant specs — every-PR memory inflation is the failure mode this gate prevents.
- Quoting raw diff content in the body. See hallucination guardrails — the body describes the diff, never copies code.
- Calling
gh pr merge. Out of scope. The skill creates and exits; merge is a human decision.
git add -A (or any broad stage) for the PR-artifact commit. Phase 1.5 stages exactly .flow/artifacts/<spec-id>/pr.html with the fixed message chore(flow): pr artifact <spec-id> — unrelated working-tree changes are not make-pr's concern.
- Opening a Lavish session or running
lavish-axi poll from make-pr. The PR artifact is a read-only review instrument — no annotate loop, interactive or autonomous. Review conversation belongs to the code host.
- Emitting an artifact blob link that can 404. Gitignored
.flow/artifacts/ → local-open guidance only; committed mode links only after the narrow artifact commit landed on the branch being pushed.
Pre-check: Local setup version
Compare .flow/meta.json setup_version to the plugin version; on mismatch, escalate once per plugin version. Fail-open throughout: a missing jq, .flow/meta.json, or plugin manifest silently continues.
SETUP_MODE=$(jq -r '.setup_mode // empty' .flow/meta.json 2>/dev/null)
SETUP_VER=$(jq -r '.setup_version // empty' .flow/meta.json 2>/dev/null)
PLUGIN_JSON="${DROID_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-$HOME/.codex}}/.codex-plugin/plugin.json"
PLUGIN_VER=$(jq -r '.version' "$PLUGIN_JSON" 2>/dev/null || echo "unknown")
VERSION_ACK=$(jq -r '.version_ack // empty' .flow/meta.json 2>/dev/null)
if [[ "$SETUP_MODE" == "plugin" ]]; then
SNIP_ACK=$(jq -r '.snippet_ack // empty' .flow/meta.json 2>/dev/null)
SNIP_VER=$(grep -m1 -o 'flow-next:snippet:v[0-9]*' CLAUDE.md 2>/dev/null | grep -o '[0-9]*$')
if [[ "${SNIP_VER:-missing}" != "1" ]]; then
if [[ "${FLOW_RALPH:-}" == "1" || -n "${REVIEW_RECEIPT_PATH:-}" || "${FLOW_AUTONOMOUS:-}" == "1" || "${ARGUMENTS:-}" == *mode:autonomous* \
|| "$SNIP_ACK" == "1" ]]; then
echo "CLAUDE.md flow-next snippet contract v${SNIP_VER:-missing} != plugin v1. Refresh via /flow-next:setup or the interactive ask." >&2
else
echo "FLOW_SNIPPET_ASK ${SNIP_VER:-missing} 1"
fi
fi
elif [[ -n "$SETUP_VER" && "$PLUGIN_VER" != "unknown" && "$SETUP_VER" != "$PLUGIN_VER" ]]; then
if [[ "${FLOW_RALPH:-}" == "1" || -n "${REVIEW_RECEIPT_PATH:-}" \
|| "${FLOW_AUTONOMOUS:-}" == "1" || "${ARGUMENTS:-}" == *mode:autonomous* \
|| "$VERSION_ACK" == "$PLUGIN_VER" ]]; then
echo "Local setup v${SETUP_VER} differs from plugin v${PLUGIN_VER}. Run /flow-next:setup to refresh local scripts." >&2
else
echo "FLOW_SETUP_ASK ${SETUP_VER} ${PLUGIN_VER}"
fi
fi
If the block printed a FLOW_SNIPPET_ASK line (plugin mode only; suppressed to the stderr note under the autonomy markers above), before proceeding ask the user with plain-text numbered prompt (the CLAUDE.md flow-next snippet block is on an older contract than this plugin version; refresh the marker block?), offering exactly the options Refresh now, Remind me next version, Skip this run, then continue the skill whichever is chosen:
- Refresh now: run
"$HOME/.codex/scripts/flowctl" setup-block apply --file CLAUDE.md --template "$HOME/.codex/skills/flow-next-setup/templates/claude-md-snippet-plugin.md" --json; if it returns action: ask, re-run as setup-block resolve with the same --file/--template plus --choice overwrite --json - this question WAS the consent. Marker-bounded: content outside the block is never touched.
- Remind me next version: record the acknowledgement so this contract version is not re-asked (fail-open: on any error, continue anyway):
rm -f .flow/meta.json.tmp && jq '.snippet_ack = "1"' .flow/meta.json > .flow/meta.json.tmp && mv .flow/meta.json.tmp .flow/meta.json
- Skip this run: continue without writing anything; the next invocation asks again.
If the block printed a FLOW_SETUP_ASK line, before proceeding ask the user with plain-text numbered prompt (local setup differs from the plugin; refresh now?), offering exactly the options Refresh now, Remind me next version, Skip this run, then continue the skill whichever is chosen:
- Refresh now: pause and have the user run
/flow-next:setup in this session (do not run setup yourself), then continue once it finishes.
- Remind me next version: record the acknowledgement so this version is not re-asked (only a later plugin version re-arms it), then continue. Run this self-contained write (fail-open: on any error, continue anyway):
PJ="${DROID_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-$HOME/.codex}}/.codex-plugin/plugin.json"
PV=$(jq -r '.version' "$PJ" 2>/dev/null)
[[ -n "$PV" && "$PV" != "null" ]] && rm -f .flow/meta.json.tmp && jq --arg v "$PV" '.version_ack = $v' .flow/meta.json > .flow/meta.json.tmp && mv .flow/meta.json.tmp .flow/meta.json
- Skip this run: continue without writing anything; the next invocation asks again.
Any other output (the one-line differs notice, or nothing) is non-blocking: continue.
Workflow
Execute the phases in workflow.md in order:
- Pre-flight —
gh installed + authenticated; resolve spec id (arg or branch-match); base-branch detection cascade; branch validity (HEAD ahead of base); all tasks done (warn + proceed as draft if not — no prompt; Ralph exits 2); existing-PR refusal filtered on .state == "OPEN". Detects Ralph environment for downstream phases.
- Gather inputs — single call to
flowctl spec export-cognitive-aid <spec-id> --base <ref> --json; parse the structured payload (spec / tasks / memory / glossary / strategy / diff / reviews).
1.5. HTML render lens (opt-in) — only when artifacts.html.enabled is true AND not --dry-run: generate .flow/artifacts/<spec-id>/pr.html (read-only review instrument per the shared disclosure reference plugins/flow-next/references/html-artifacts.md §5 — diff-derived, R-ID-verified with flagged mismatch rows), commit it narrowly (chore(flow): pr artifact <spec-id>, artifact file only) when .flow/artifacts/ is tracked, and record the render-lens line for the body summary block. Never opens a Lavish session or polls (interactive AND autonomous). Failure is non-fatal — one stderr note, PR proceeds. With the mode off/unset there is zero artifact-related behavior or output beyond the single config read.
- Render body — TL;DR, R-ID coverage table, Critical changes, How to review this PR (trust-calibration coaching block), Review plan (risk-ranked Must review / Spot-check / Safe to skim with a ≤~30% focus budget), Decisions made, Memory left behind, Glossary/strategy notes, Open items, footer breadcrumb. Sections without content are omitted (never empty placeholder headings).
- Mermaid generation — gated by 5 trigger conditions (cross-module imports, public interface changes, new/removed top-level dirs, high fan-out spec). Hard caps: 3 diagrams, 12 nodes, 25 edges, 12K characters. Each codefence preceded by a 3-5 sentence plain-language prose summary (load-bearing for forges that don't render mermaid). Validates each codefence against the
mermaid-rules.md §6 checklist (reserved words, escape patterns, no emoji / MathJax, no inheritance cycles) before emitting. Skipped under --no-mermaid or when no triggers fire / a skip rule applies (pure-additive single-module diff <50 LOC, flat-layout repo).
- Push + create PR —
git push -u origin HEAD, then gh pr create --title --body. Draft when OPEN_ITEMS_COUNT > 0 OR Ralph OR --draft; ready when --ready. --dry-run short-circuits before push.
- Output + footer — emit PR URL on success; print breadcrumb (
Generated by /flow-next:make-pr from <spec-id> against <base>); optionally write knowledge/architecture-patterns/ memory entry under --memory.