flow-next-flow
GitHub作为工作流调度器,自动读取输入并根据路由规则执行后续阶段技能(如捕获、计划、工作等),直至需要人类决策或达到指定目标。支持无头运行并输出裁决结果。
Trigger Scenarios
Install
npx skills add gmickel/flow-next --skill flow-next-flow -g -y
SKILL.md
Frontmatter
{
"name": "flow-next-flow",
"description": "Conductor for an idea, spec or task id, tracker issue, branch, bug report, or question; --auto runs a ready spec unattended and emits PILOT_VERDICT. Use when no skill is named or to pilot a spec.",
"allowed-tools": "Read, Bash, Grep, Glob, Write, Edit, Task, Skill",
"user-invocable": false
}
/flow-next:flow - the conductor
Flow chooses the next step so the user does not have to. It reads what it was given, routes from the shared routing reference, runs the routed stage skill, and continues until the next decision that belongs to a human. It re-implements no stage logic: capture, refine, plan, plan-review, work, qa, make-pr, resolve-pr, and land keep their own contracts, receipts, and gates.
Role: conductor, inline (no context: fork) so plain-text numbered prompt stays reachable. On hosts without it, fall back to a plain-text numbered prompt with a final Other - type your own answer option.
Read workflow.md for the hop loop. The routing rules live in references/, one file per rule, each opening with its decision record. Read a reference only at the step that names it; a step that does not name one reads nothing.
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="${CODEX_HOME:-$HOME/.codex}/scripts/flowctl"
[ -x "$FLOWCTL" ] || FLOWCTL="<plugin-root>/scripts/flowctl" # <plugin-root> = the directory two levels above this skill's SKILL.md file (the harness gave you that file's absolute path when the skill loaded); substitute it literally
[ -x "$FLOWCTL" ] || FLOWCTL=".flow/bin/flowctl"
Mode detection
Parse $ARGUMENTS as exact tokens (never substrings), before any read or write: --auto sets AUTO=1; --tick sets AUTO_TICK=1 (one hop, then stop; meaningful only with --auto); --explain sets EXPLAIN=1; --review=<backend> sets REVIEW_OVERRIDE and is passed through unchanged to every stage it dispatches. The destination parse is shared by both modes:
FLOW_UNTIL=""
FLOW_DESTINATION_ERROR=0
LAND_AUTHORIZED=0
LAND_SCOPE_SPEC=""
LAND_SCOPE_PR=""
AUTO=0
for ARG in $ARGUMENTS; do
case "$ARG" in
--auto) AUTO=1 ;;
--until=merge) FLOW_UNTIL=merge ;;
--until|--until=*) FLOW_DESTINATION_ERROR=1 ;;
esac
done
if [ "$FLOW_DESTINATION_ERROR" = 1 ]; then
if [ "$AUTO" = 1 ]; then
echo 'PILOT_VERDICT=NEEDS_HUMAN spec=- stage=- reason="invalid destination; use --until=merge"'
else
echo 'NEEDS_HUMAN: invalid destination; use --until=merge'
fi
exit 1
fi
export FLOW_UNTIL
--until=merge authorizes landing the selected item in this invocation, independently of --auto. Without it the pre-merge boundary remains; current explicit item-scoped user authorization can also authorize landing. Read references/tail.md when reaching that boundary. Consent is host context, never recovered from an environment variable, old transcript, or receipt. A fresh session needs the flag again or current explicit authorization; revocation stops subsequent mutations. Consume destination tokens rather than passing them to a build stage. Everything else is the starting point, verbatim - flow adds no input classifier. A tracker issue id or URL is read through the access the session already has (the sync bridge, an MCP, gh, glab); flow adds no input adapter.
AUTO=1: read auto.md and follow it. Attended runs never load it.
Autonomy refusal - runs right after the token parse
Attended flow, flow --auto, and Ralph are three drivers and are never nested. Without --auto, flow is attended: under any autonomy marker (scan the marker namespace: FLOW_RALPH, FLOW_AUTONOMOUS, REVIEW_RECEIPT_PATH, AUTONOMOUS=1, a mode:autonomous token), stop before any read or write:
NEEDS_HUMAN: /flow-next:flow is attended - run /flow-next:flow --auto for unattended runs
With --auto, the refusal is Ralph-only (FLOW_RALPH, REVIEW_RECEIPT_PATH, in auto.md's hard guards), because --auto sets FLOW_AUTONOMOUS and mode:autonomous for the stages it dispatches. A run that routed, dispatched, or asked under a marker it should have refused has broken this.
Invariants (every run)
- Route on content and context, never on input kind. Read what was given, decide what it is, then match
references/route-matrix.mdat the route step. - Ask only on a fork that is material and not observable. Before any "which approach" or "what should this do" question, classify the fork per
references/prototype-before-ask.md: an observable answer is settled by running something; only a product or preference call becomes a question, and at most one per hop. - Never fabricate a review, QA, or completion verdict to pass a gate. Every stage flow skips is recorded with its reason (
stage: <name> - skipped(<kind>: <detail>)), never omitted. - Land owns merge; make-pr owns spec close. The only driver-composition exception is a currently authorized, item-scoped flow invocation of land per
references/tail.md. Never dispatch another flow, pilot, Ralph, or a loop from inside a run. --explainwrites nothing and dispatches nothing. It prints the route, the positive signal, the safe skip and its kind, and why not the alternatives, in the recommendation shape fromreferences/route-matrix.md.- Host command form: print every copy-pasteable flow-next command in the spelling this host invokes - the flat
/flow-next-<name>form when the resolved plugin root carries.flow-next-opencode-manifest(an OpenCode install), otherwise exactly as spelled here.
Forbidden
- Running attended under any autonomy marker, or dispatching a second driver beyond the scoped land stage.
- Executing merge or spec close inline, invoking land without current scoped consent, or force-pushing.
- Re-implementing a stage's logic inline instead of invoking its skill.
- A plain-text numbered prompt whose answer a prototype or experiment could have observed.
- Writing under
.flow/on an--explainrun. - A stage skipped without a recorded reason.
Report shape (every stop)
Flow stopped at: <the human decision, "PR exists", or the observed landing outcome>
Route taken: <hop 1> -> <hop 2> -> ... (an inline pick reads `prospect [picked: <candidate>]`)
stage: <name> - ran [<start>..<end>] | skipped(<policy|config|empty|error>: <detail>) | failed(<reason>: <detail>) (one line per stage reached)
Next: <natural-language prompt or slash command, or the decision the user must make>
Version History
- b91f43c Current 2026-09-22 21:15


