diff --git a/docs/skills/flow.md b/docs/skills/flow.md index 9386e84..9f76d7e 100644 --- a/docs/skills/flow.md +++ b/docs/skills/flow.md @@ -10,33 +10,65 @@ End-to-end pipeline orchestration — chain multiple skill workflows into a name ### new — define a flow -Create a named pipeline with an ordered list of skill invocations; generates `flow.md` and per-step implementation files under `.codevoyant/flows/{name}/`. +Create a named pipeline with an ordered list of skill invocations; generates `flow.md` and per-step implementation files under `.codevoyant/flows/{name}/`. Add `--global` to store it under `~/.codevoyant/flows/` instead, making it reusable across every project. ```bash /flow new auth-refactor \ "/dev explore how the auth middleware works" \ "/spec new refactor auth middleware" \ "/spec go" + +# reusable across projects, with a run-time parameter: +/flow new ship \ + "/spec new {{input}}" \ + "/spec go" \ + "/git commit" \ + "/pr open" \ + --global ``` Pass descriptions inline to skip interactive prompts within each step (e.g. `/spec new my-feature add dark mode`). +#### Parameters — dynamic input + +Put `{{placeholders}}` in any step and supply values when you run the flow: + +- Bare text after the name binds to `{{input}}` — `/flow go ship "add dark mode"`. +- `--set key=value` binds a named `{{key}}` — `/flow go ship --set env=staging`. +- Anything still unset is prompted for once. + +Each step's key outputs (PR numbers, plan names, file paths) are captured and threaded forward as **flow context**, so later steps can use them automatically — e.g. `/pr open` produces a PR number that a later `/pr address` step picks up without you re-typing it. Flow context is persisted, so an interrupted flow resumes with it intact. + +**Chaining interactive skills.** Steps run as subagents and can't prompt you directly, so write each step to run non-interactively — pass its input inline or as a `{{param}}` (give steps that need different values distinct params, not one shared `{{input}}`), and wire a consumer step to the artifact its producer wrote (e.g. `/dev explore` → `.codevoyant/explore/{slug}/` → `/spec new` plans from it). If a step still hits a decision it can't resolve, it escalates one question back to you (`NEEDS_INPUT`) and re-runs with your answer — a fallback, not the plan. + ### go — execute a flow -Run all pending steps sequentially as blocking subagents. Resumes from the first incomplete step if re-run after interruption. +Run all pending steps sequentially as blocking subagents. Resumes from the first incomplete step if re-run after interruption. Resolves the flow locally first, then globally; pass `--global` to force the global copy. ```bash /flow go auth-refactor # execute all pending steps +/flow go ship "add OAuth login" # bind free text to {{input}} +/flow go ship --set env=staging # bind a named parameter ``` A failing step stops the pipeline; re-run `/flow go` to resume from where it stopped. +### list — list flows + +Show every saved flow across both scopes (local and global) with step counts, status, and parameters. + +```bash +/flow list # local + global +/flow list --global # global only +``` + ### status — check flow status -Print the `flow.md` checklist with current step status. +Print the `flow.md` checklist with current step status, scope, and parameters. ```bash /flow status auth-refactor # print checklist with step status +/flow status ship --global # inspect a global flow ``` ### save — create a composite skill @@ -46,9 +78,10 @@ Turn a completed flow into a reusable skill scaffolded via `/skill new`. The gen ```bash /flow save auth-refactor --skill auth-refactor /flow save auth-refactor --skill auth-refactor --desc "Explore, plan, and execute auth middleware refactor" +/flow save ship --skill ship --global # source flow lives in ~/.codevoyant/flows ``` -The new skill is created at `skills/{skill-name}/SKILL.md`. Run `/skill critique {skill-name}` to audit it before shipping. +The new skill is created at `skills/{skill-name}/SKILL.md`. If the source flow has `{{parameters}}`, the generated skill forwards the text you pass it to `/flow go`. Run `/skill critique {skill-name}` to audit it before shipping. ### help — list commands diff --git a/docs/skills/pr.md b/docs/skills/pr.md index 152394a..7cc50a6 100644 --- a/docs/skills/pr.md +++ b/docs/skills/pr.md @@ -32,6 +32,8 @@ The body is written in a **terse, human, junior-dev-friendly voice** — short s Read a PR/MR diff and generate AI-authored inline comments. Comments are terse (see the voice guide): one or two sentences — problem, then ask — with a code suggestion where it's clearer. Severities are `BLOCKING`, `CONSIDER`, `NOTE`. +Reviews evaluate the change against its **stated intent** first — does the diff actually deliver the PR/MR's purpose end-to-end (tracing the headline use case), not just whether the code is clean? A well-formed change that fails its intent is flagged `BLOCKING`. + Runs a **dedicated slop-detector pass** in parallel: a subagent whose only job is catching AI slop and unwanted agent-introduced change — unnecessary/out-of-scope edits, stochastic churn (random renames, reordering, reformatting), verbose boilerplate, dead/debug leftovers, dependency creep. A prevalent problem with agentic coding. Its findings are prefixed `Slop:`. ```bash diff --git a/skills/flow/SKILL.md b/skills/flow/SKILL.md index 232cc5b..d5558a6 100644 --- a/skills/flow/SKILL.md +++ b/skills/flow/SKILL.md @@ -30,8 +30,8 @@ Aliases: "run" → go "exec" → go "start" → go + "ls" → list "show" → status - "list" → status "review" → status "export" → save "publish" → save @@ -39,12 +39,15 @@ Aliases: Dispatch to: references/workflows/{VERB}.md ``` +The `--global` / `-g` flag (store or read a flow under `~/.codevoyant/flows` instead of the local `.codevoyant/flows`) is **not** a verb — pass it through unchanged; each workflow parses it via `references/flow-dir.md`. + ## Workflow index | Verb | File | Purpose | | --- | --- | --- | | new | `references/workflows/new.md` | Define a new flow (create flow.md + step files) | | go | `references/workflows/go.md` | Execute pending steps sequentially as blocking subagents | +| list | `references/workflows/list.md` | List all flows (local and global) | | status | `references/workflows/status.md` | Print flow.md checklist state | | save | `references/workflows/save.md` | Turn a flow into a reusable composite skill via /skill new | | help | `references/workflows/help.md` | Usage reference | @@ -52,7 +55,7 @@ Dispatch to: references/workflows/{VERB}.md ## Instructions 1. Extract VERB from the user's message (first non-flag positional argument after "flow"). -2. Apply aliases (run/exec/start → go; show/list/review → status; export/publish → save). +2. Apply aliases (run/exec/start → go; ls → list; show/review → status; export/publish → save). 3. If VERB is empty or unrecognized, default to `help`. 4. Read and execute the corresponding workflow file from `references/workflows/{VERB}.md`. -5. Pass all remaining arguments to the workflow. +5. Pass all remaining arguments (including any `--global`/`-g` flag) to the workflow unchanged. diff --git a/skills/flow/references/flow-dir.md b/skills/flow/references/flow-dir.md new file mode 100644 index 0000000..332d02f --- /dev/null +++ b/skills/flow/references/flow-dir.md @@ -0,0 +1,43 @@ +# Flow directory resolution (local vs global) + +Shared logic for locating flows. Every flow workflow (`new`, `go`, `status`, `list`, `save`) resolves storage the same way. + +## Scopes + +- **Local** (default) — flows live under the current project: `.codevoyant/flows/{slug}/` +- **Global** — flows live under the user's home, reusable across every project: `~/.codevoyant/flows/{slug}/` + +A flow is a directory `{slug}/` containing `flow.md` and `implementation/step-N.md` files, in either scope. + +## The `--global` flag + +`--global` (alias `-g`) selects the global scope. Parse it out of the arguments in every workflow **before** reading the flow name, and strip it from the positional args. + +```bash +GLOBAL=false +case " $ARGS " in *" --global "*|*" -g "*) GLOBAL=true ;; esac +FLOW_ROOT="$( [ "$GLOBAL" = true ] && echo "$HOME/.codevoyant" || echo ".codevoyant" )" +FLOWS_DIR="$FLOW_ROOT/flows" +``` + +- `~` always means the real home directory — use `"$HOME"` in bash, never a literal `~` inside quotes. +- Create the global root on demand: `mkdir -p "$HOME/.codevoyant/flows"` (safe if it already exists). + +## Resolving a flow by name (for `go`, `status`, `save`) + +When the user names an existing flow to run/inspect, resolve which scope holds it: + +1. **If `--global` was passed:** look only in `~/.codevoyant/flows/{slug}/`. +2. **Otherwise:** look in **local first** (`.codevoyant/flows/{slug}/`), then fall back to **global** (`~/.codevoyant/flows/{slug}/`). +3. If found in exactly one scope, use it. If found in **both** and `--global` was not given, prefer local but note: `ℹ Using local flow '{slug}' (a global flow with the same name also exists — pass --global to run that one).` +4. If found in neither: error `Flow '{slug}' not found (looked in local and global). Run /flow new {slug} first.` + +Set `FLOW_DIR` to the resolved `{FLOWS_DIR}/{slug}/` and use it for the rest of the workflow. + +## Creating a flow (for `new`) + +`new` does not search — it writes to the scope selected by `--global`: + +``` +FLOW_DIR = {FLOWS_DIR}/{slug}/ # global if --global, else local +``` diff --git a/skills/flow/references/flow-template.md b/skills/flow/references/flow-template.md index d8cd823..fd16824 100644 --- a/skills/flow/references/flow-template.md +++ b/skills/flow/references/flow-template.md @@ -3,9 +3,22 @@ ## Metadata - **Slug**: {slug} +- **Scope**: {local|global} - **Created**: {timestamp} - **Status**: {Active|Complete} +## Parameters + + + +- `{{input}}` — {what the free-text argument means for this flow} +- `{{param-name}}` — {description} + ## Steps 1. [ ] {step-1-command} diff --git a/skills/flow/references/step-template.md b/skills/flow/references/step-template.md index 94d55d2..d820980 100644 --- a/skills/flow/references/step-template.md +++ b/skills/flow/references/step-template.md @@ -5,12 +5,39 @@ Flow: {flow-name} Step: {N} of {total} +## Parameters + + +{param-name} = {resolved-value} + +## Flow context so far + + +{prior-step-handoffs, or "(nothing yet — this is the first step)"} + ## Agent prompt -You are executing step {N} of the "{flow-name}" flow. +You are executing step {N} of the "{flow-name}" flow, running as a **subagent**. You CANNOT prompt the user — `AskUserQuestion` does not reach them from here. Your task: {step-command} -{Any relevant context from prior steps — e.g., "Step N-1 produced output at .codevoyant/explore/..."} +**Inputs — use what the flow already gave you.** Treat the **Parameters** and **Flow context so far** above as ground truth: a PR number, plan name, branch, or file path there was produced by an earlier step or supplied by the user. Prefer them over asking or guessing. If the Flow context names an **artifact** a prior step produced (an exploration directory, a plan, a doc), **consume it** — do not start that work over. (E.g. if a prior `/dev explore` wrote `.codevoyant/explore/{slug}/`, point this step's skill at that exploration instead of re-researching.) + +**Run the skill non-interactively.** Follow all rules of the skill, but pass inputs inline so it never stops to ask. Do NOT call `AskUserQuestion` — it will not reach the user. + +**If you truly cannot proceed** — a decision is required that Parameters and Flow context don't cover and that has no safe, clearly-stated default — do NOT guess and do NOT block. Stop and end your report with exactly one line: + +``` +NEEDS_INPUT: {the single question the user must answer} +``` + +The flow (running on the main thread) will ask the user and re-run you with the answer added to Parameters. Use this sparingly — only for a decision that would change the outcome. + +When you finish successfully, end your report with a single handoff line listing any values later steps may need — IDs, URLs, paths, names, **and any artifact paths you created** — so the flow can thread them forward: -Execute the skill command above. Follow all rules and conventions of that skill exactly as if the user had invoked it directly. Report clearly when done. +``` +HANDOFF: {key=value; key=value; ...} (or "HANDOFF: none" if nothing to pass on) +``` diff --git a/skills/flow/references/workflows/go.md b/skills/flow/references/workflows/go.md index 43f995c..87565c4 100644 --- a/skills/flow/references/workflows/go.md +++ b/skills/flow/references/workflows/go.md @@ -1,60 +1,92 @@ # Workflow: flow go -Execute all pending (unchecked) steps of a named flow sequentially. Each step runs as a blocking foreground subagent. After each step completes, mark it `[x]` in `flow.md` before proceeding. +Execute all pending (unchecked) steps of a named flow sequentially. Each step runs as a blocking foreground subagent. Parameters (`{{placeholders}}`) are resolved from user input before running, and each step's key outputs are threaded forward into later steps as **flow context**. After each step completes, mark it `[x]` in `flow.md` before proceeding. + +Steps run **non-interactively** — a subagent cannot prompt the user. When a step genuinely needs an answer it can't derive, it returns a `NEEDS_INPUT:` line and this orchestrator (on the main thread) asks the user and re-runs the step. This is how interactive skills chained in a flow still reach the human. ## Step 0: Parse arguments ``` +--global / -g → read the flow from ~/.codevoyant/flows (see references/flow-dir.md) +--set key=value → bind a named parameter (repeatable, e.g. --set feature="add OAuth" --set env=staging) FLOW_NAME = first non-flag positional arg (required) -FLOW_DIR = .codevoyant/flows/{FLOW_NAME}/ +INPUT = all remaining bare (non-flag, non-name) positional text, joined with spaces → the {{input}} parameter ``` -If `FLOW_NAME` is missing, error: "Usage: /flow go . A flow name is required." +If `FLOW_NAME` is missing, error: "Usage: /flow go [input text] [--set k=v] [--global]. A flow name is required." + +Build the parameter map `PARAMS`: +- `input` = `INPUT` (the joined free text), if any +- each `--set key=value` → `PARAMS[key] = value` + +## Step 0.5: Resolve the flow location + +Resolve `FLOW_DIR` per `references/flow-dir.md` (local-first, then global; `--global` forces global only). If not found in any scope, error: "Flow '{FLOW_NAME}' not found (looked in local and global). Run /flow new {FLOW_NAME} first." -If `FLOW_DIR/flow.md` does not exist, error: "Flow '{FLOW_NAME}' not found. Run /flow new {FLOW_NAME} first." +## Step 1: Read flow.md and resolve parameters -## Step 1: Read flow.md +Read `FLOW_DIR/flow.md`. Parse the Steps checklist and the Parameters section. -Read `FLOW_DIR/flow.md` and parse the Steps checklist section. +**Resolve every `{{placeholder}}` used anywhere in the steps:** +1. Scan all step commands for `{{name}}` tokens; collect the unique set `NEEDED`. +2. For each token in `NEEDED`: + - If `PARAMS[name]` is already set (from `--set`, or `input` from free text) → use it. + - Else → **prompt the user once** for the value, using AskUserQuestion (free-text via Other): question `Value for {{name}}?`, header `Parameter`, and (for `{{input}}`) show the flow's Parameters description as help. Store the answer in `PARAMS[name]`. +3. Do not proceed with any unresolved token. If the user dismisses a prompt, abort: "Cancelled — {{name}} is required to run this flow." -Collect all lines matching the pattern `N. [ ] ...` (unchecked) in order. These are the **pending steps**. +Collect the pending steps: all lines matching `N. [ ] ...` (unchecked), in order. If none are pending, report "Flow '{FLOW_NAME}' is already complete." and exit. -If all steps are already `[x]` (no pending steps found): report "Flow '{FLOW_NAME}' is already complete." and exit. +Initialize the **flow context** accumulator `CONTEXT`. **On resume:** if `FLOW_DIR/context.md` exists (an earlier, interrupted run), load it into `CONTEXT` so the remaining steps keep the handoffs from steps already marked `[x]`. Otherwise start empty. (Without this, a resumed flow loses e.g. the PR number a completed `pr open` step produced.) ## Step 2: Execute steps sequentially For each pending step in order: -1. Report: `▶ Step {N}: {step-command}` +1. **Substitute parameters** in the step command: replace every `{{name}}` with `PARAMS[name]`. Call the result `RESOLVED_COMMAND`. Report: `▶ Step {N}: {RESOLVED_COMMAND}` -2. Read `FLOW_DIR/implementation/step-N.md` to get the agent prompt. +2. Read `FLOW_DIR/implementation/step-N.md` to get the agent prompt. Prepare the prompt for this run by filling its injection points: + - Replace `{step-command}` occurrences with `RESOLVED_COMMAND` (substitute `{{placeholders}}` here too). + - Fill the **Parameters** section with the resolved `key = value` pairs (or "none"). + - Fill the **Flow context so far** section with `CONTEXT` (or "(nothing yet — this is the first step)" when empty). 3. Launch a **blocking** (foreground) subagent: ``` Agent( subagent_type: general-purpose, run_in_background: false, - description: "Flow step {N}: {step-command}", - prompt: {full contents of step-N.md} + description: "Flow step {N}: {RESOLVED_COMMAND}", + prompt: {filled contents of step-N.md} ) ``` - Wait for the subagent to return before continuing. + Wait for the subagent to return. It runs the skill **non-interactively** and, if it can't resolve a required decision from Parameters/Flow context, returns a `NEEDS_INPUT:` line rather than guessing or blocking. -4. After the subagent returns: update `FLOW_DIR/flow.md` — change the step's `[ ]` to `[x]`: +4. **Handle NEEDS_INPUT (interactive escalation).** If the subagent's report ends with `NEEDS_INPUT: {question}`: + a. You are on the main thread — ask the user that `{question}` with **AskUserQuestion** (free-text via Other). + b. Add the answer to `PARAMS` (so later steps can reuse it) and note it in `CONTEXT`, then **re-run this step** from sub-step 2 with the answer now available. + c. Cap at 3 escalations per step; if the step still returns `NEEDS_INPUT` after that, treat it as a step failure (below). + This is what lets an interactive skill's mid-run question (e.g. `/dev explore` asking "generate proposals?", or `/spec new` needing to pick an exploration) reach the user even though the step ran in a subagent. + +5. **Capture the handoff.** Read the subagent's returned report. Extract the `HANDOFF:` line if present; otherwise summarize the key outputs (IDs, URLs, paths, names) in one line yourself. Append to `CONTEXT`: ``` - N. [x] {step-command} + [step {N} · {RESOLVED_COMMAND}] → {handoff or one-line summary} ``` - Also update `{Status}` in the Metadata section to `Active` (leave as Active until all steps complete). + Keep `CONTEXT` terse — it is injected into every later step, so it must stay a short bulleted log, not full transcripts. **Persist it:** write the accumulated `CONTEXT` to `FLOW_DIR/context.md` so an interrupted flow can resume with it (see Step 1). + +6. Update `FLOW_DIR/flow.md` — change this step's `[ ]` to `[x]` (keep the original `{{placeholder}}` text in flow.md; only the run used resolved values). Leave `Status` as `Active` until all steps complete. -5. Report: `✓ Step {N} complete.` +7. Report: `✓ Step {N} complete.` -6. Proceed to next pending step. +8. Proceed to next pending step. + +**On step failure:** if a subagent reports it could not complete (blocking error), stop the loop, leave the step unchecked, and report which step failed and why. `CONTEXT` is already persisted to `FLOW_DIR/context.md`, so re-running `/flow go` resumes from this step with prior context intact. Do not run later steps — they likely depend on this one's context. ## Step 3: Final report -After all steps are complete, update `{Status}` in `FLOW_DIR/flow.md` to `Complete`. +After all steps are complete, update `Status` in `FLOW_DIR/flow.md` to `Complete` and remove `FLOW_DIR/context.md` (a fresh run starts clean). Report: ``` ✅ Flow "{FLOW_NAME}" complete. All {N} steps finished. + + Parameters used: {key=value list, or "none"} ``` diff --git a/skills/flow/references/workflows/help.md b/skills/flow/references/workflows/help.md index ffb7407..7733e21 100644 --- a/skills/flow/references/workflows/help.md +++ b/skills/flow/references/workflows/help.md @@ -5,24 +5,54 @@ Print usage reference for the `flow` skill. ## Output ``` -/flow new [steps...] — define a new flow -/flow go — run pending steps sequentially -/flow status — show checklist state -/flow help — this message +flow — chain skill commands into a named, reusable pipeline + + /flow new [steps...] [--global] — define a new flow + /flow go [input] [--set k=v] [--global] + — run pending steps sequentially + /flow list [--global | --local] — list all flows (local + global) + /flow status [--global] — show checklist state + /flow save --skill [--global] — turn a flow into a reusable skill + /flow help — this message Verb aliases: run, exec, start → go - show, list → review + ls → list + show, review → status + export, publish → save + +Storage: + local (default) .codevoyant/flows// — this project only + global (--global) ~/.codevoyant/flows// — reusable across all projects + +Parameters (dynamic input): + Put {{placeholders}} in any step. At run time: + • bare text after the name binds to {{input}} + • --set key=value binds a named {{key}} + • anything still unset is prompted for once + Outputs from each step (PR numbers, plan names, paths) are captured and + threaded forward as "flow context" so later steps can use them automatically + (persisted, so an interrupted flow resumes with it). + +Chaining interactive skills: + Steps run as subagents and can't prompt you, so write them non-interactively — + pass input inline / as {{params}} (distinct params for steps needing different + values), and point a consumer step at the artifact its producer wrote. If a step + still can't decide, it escalates one question (NEEDS_INPUT) and re-runs with your answer. -Example: - /flow new jupyterpress \ - "/dev explore how to build jupyterpress" \ - "/spec new plan it" \ +Example — a global, parameterized ship pipeline: + /flow new ship \ + "/spec new {{input}}" \ "/spec go" \ - "/dev explore review the code" + "/git commit" \ + "/pr open" \ + "/pr address" \ + "/git commit --fix" \ + --global - /flow go jupyterpress - /flow status jupyterpress + /flow go ship "add OAuth login to settings" + /flow list + /flow status ship --global ``` Print the above message verbatim. diff --git a/skills/flow/references/workflows/list.md b/skills/flow/references/workflows/list.md new file mode 100644 index 0000000..dad8ff7 --- /dev/null +++ b/skills/flow/references/workflows/list.md @@ -0,0 +1,63 @@ +# Workflow: flow list + +List every saved flow across both scopes — local (`.codevoyant/flows`) and global (`~/.codevoyant/flows`) — so the user can discover what they can run. + +## Step 0: Parse arguments + +``` +--global / -g → list ONLY global flows +--local → list ONLY local flows +(neither) → list both scopes +``` + +## Step 1: Enumerate flows + +Resolve the two roots per `references/flow-dir.md`: +- Local: `.codevoyant/flows` +- Global: `$HOME/.codevoyant/flows` + +For each scope in play, list its immediate subdirectories that contain a `flow.md`: + +```bash +# local +[ -d .codevoyant/flows ] && for d in .codevoyant/flows/*/; do [ -f "$d/flow.md" ] && echo "local $d"; done +# global +[ -d "$HOME/.codevoyant/flows" ] && for d in "$HOME"/.codevoyant/flows/*/; do [ -f "$d/flow.md" ] && echo "global $d"; done +``` + +For each flow found, read its `flow.md` and extract: +- **slug** (directory name) +- **status** (Metadata → Status) +- **step counts** — `done` = number of `[x]` lines, `total` = total step lines +- **parameters** — the token names from the Parameters section (or "—") + +## Step 2: Render the table + +Print a table grouped by scope. If a scope has no flows, show a `(none)` row for it. + +``` +Flows + + SCOPE NAME STEPS STATUS PARAMS + local ship-feature 2/4 Active {{input}} + local nightly-audit 3/3 Complete — + global release-train 0/6 Active {{input}}, {{env}} + + local: .codevoyant/flows · global: ~/.codevoyant/flows +``` + +If both scopes are empty: +``` +No flows found. + +Create one: /flow new "" "" ... +Store it globally (reusable across projects): /flow new ... --global +``` + +## Step 3: Footer + +Remind the user how to act on a flow: +``` +Run: /flow go [ --global ] +Inspect: /flow status [ --global ] +``` diff --git a/skills/flow/references/workflows/new.md b/skills/flow/references/workflows/new.md index ac3ecc6..49702e9 100644 --- a/skills/flow/references/workflows/new.md +++ b/skills/flow/references/workflows/new.md @@ -1,15 +1,18 @@ # Workflow: flow new -Create a new named flow — a `.codevoyant/flows/{slug}/flow.md` checklist plus one `implementation/step-N.md` agent-prompt file per step. +Create a new named flow — a `{flows-dir}/{slug}/flow.md` checklist plus one `implementation/step-N.md` agent-prompt file per step. Stored locally by default, or under `~/.codevoyant/flows` with `--global`. ## Step 0: Parse arguments ``` +--global / -g → store under ~/.codevoyant/flows (see references/flow-dir.md); else local .codevoyant/flows FLOW_NAME = first non-flag positional arg (required; error if missing) STEPS = remaining positional args (each is one step command string) ``` -If `FLOW_NAME` is missing, error: "Usage: /flow new [steps...]. A flow name is required." +Resolve `FLOWS_DIR` per `references/flow-dir.md` (`.codevoyant/flows` local, `$HOME/.codevoyant/flows` if `--global`). Strip `--global`/`-g` before reading positionals. + +If `FLOW_NAME` is missing, error: "Usage: /flow new [steps...] [--global]. A flow name is required." If `STEPS` is empty, prompt the user: @@ -29,20 +32,39 @@ If still no steps after prompting, error: "A flow must have at least one step." ## Step 1: Resolve slug and create directory - `slug` = `FLOW_NAME` lowercased, spaces replaced with hyphens -- `FLOW_DIR = .codevoyant/flows/{slug}/` -- If `FLOW_DIR/flow.md` already exists: ask "Flow '{slug}' already exists. Replace it or cancel? (replace/cancel)" +- `FLOW_DIR = {FLOWS_DIR}/{slug}/` (global if `--global`, else local — from Step 0) +- If `--global`, first `mkdir -p "$HOME/.codevoyant/flows"`. +- If `FLOW_DIR/flow.md` already exists: ask "Flow '{slug}' already exists in {scope}. Replace it or cancel? (replace/cancel)" - If cancel: exit without changes. - If replace: proceed (overwrite all files). - Create `FLOW_DIR/` and `FLOW_DIR/implementation/` directories. +## Step 1.5: Detect parameters + +Scan every step command for `{{placeholder}}` tokens (double-brace, e.g. `{{feature}}`, `{{input}}`). Collect the unique set as `PARAMS`. + +- `{{input}}` is the conventional default parameter — the bare text a user passes to `/flow go `. If any step uses `{{input}}`, keep it first in the list. +- These are recorded in flow.md so users know what to supply at run time. They are **not** resolved now — they are filled in at `/flow go` time (see `go.md`). + +## Step 1.6: Make steps flow-safe (author for chaining) + +Steps run as subagents at `go` time and **cannot prompt the user**, so write each step to run without interaction: + +- **Pass each step's input inline or as a `{{param}}`.** A step that would otherwise ask (e.g. `/spec new` with no objective, or `/dev explore` with no topic) should carry its input in the command — give distinct steps distinct params (`/dev explore {{topic}}`, `/spec new {{objective}}`), not one shared `{{input}}`, when they need different values. +- **Avoid step forms that pause.** A bare-name `/spec new {{name}}` scaffolds an intent file and stops — use a descriptive objective (or an intent already filled) instead. +- **Chain producer → consumer explicitly.** When one step produces an artifact the next consumes (e.g. `/dev explore` writes `.codevoyant/explore/{slug}/`, then `/spec new` should plan *from* it), write the consumer step to consume that artifact — don't rely on the consumer's interactive picker. The producer's artifact path is threaded forward in flow context so the consumer subagent can find it. +- Anything a step still can't resolve at run time surfaces to the user via `NEEDS_INPUT` (see `go.md`) — a fallback, not the plan. If you find yourself relying on it, add a `{{param}}` instead. + ## Step 2: Write flow.md Use `references/flow-template.md` as the template. Fill in: - `{TITLE}` = `FLOW_NAME` (original casing) - `{slug}` = computed slug +- `{local|global}` = the scope from Step 0 - `{timestamp}` = current ISO timestamp - `{Status}` = `Active` -- Steps checklist: one line per step, numbered, all unchecked `[ ]` +- **Parameters** section: one bullet per token in `PARAMS` (`` - `{{name}}` — {short description you infer from how the step uses it} ``). If `PARAMS` is empty, replace the list with `_none_`. +- Steps checklist: one line per step, numbered, all unchecked `[ ]` — keep `{{placeholders}}` verbatim (do not substitute). Each step line format: ``` @@ -57,18 +79,21 @@ For each step N (1-based), create `FLOW_DIR/implementation/step-N.md` using `ref Fill in: - `{N}` = step number -- `{step-command}` = the step command string +- `{step-command}` = the step command string, with `{{placeholders}}` left **verbatim** (they are resolved at run time by `go.md`) - `{flow-name}` = slug - `{total}` = total number of steps -- Context notes: leave blank for step 1; for steps 2+, note "Step N-1 will have produced output — check `.codevoyant/` for artifacts." +- Leave the `## Parameters` and `## Flow context so far` sections as their template placeholders — `go.md` fills them in at run time. ## Step 4: Report ``` -✅ Flow "{slug}" created with {N} steps. +✅ Flow "{slug}" created with {N} steps ({scope}). + + {FLOW_DIR}/flow.md - .codevoyant/flows/{slug}/flow.md + Parameters: {comma-separated PARAMS, or "none"} -To run: /flow go {slug} -To review: /flow status {slug} +To run: /flow go {slug}{ --global if global}{ "" if it has {{input}}} +To review: /flow status {slug}{ --global if global} +To list: /flow list ``` diff --git a/skills/flow/references/workflows/save.md b/skills/flow/references/workflows/save.md index 3388b49..3c850c4 100644 --- a/skills/flow/references/workflows/save.md +++ b/skills/flow/references/workflows/save.md @@ -5,23 +5,25 @@ Turn a saved flow into a reusable composite skill by scaffolding it with `/skill ## Step 0: Parse arguments ``` +--global / -g read the source flow from ~/.codevoyant/flows (see references/flow-dir.md) FLOW_NAME first non-flag arg (required — name of an existing flow) SKILL_NAME --skill (required — name for the new skill, e.g. "auth-refactor") DESCRIPTION --desc "..." (optional — one-line description; derived from flow title if omitted) ``` -Error if FLOW_NAME missing: `Error: flow name required. Usage: /flow save --skill ` +Error if FLOW_NAME missing: `Error: flow name required. Usage: /flow save --skill [--global]` Error if --skill missing: `Error: --skill required.` ## Step 1: Read the flow -Read `.codevoyant/flows/{FLOW_NAME}/flow.md`. +Resolve `FLOW_DIR` per `references/flow-dir.md` (local-first, then global; `--global` forces global). Read `FLOW_DIR/flow.md`. Extract: - **Title** — from the `# Flow:` heading -- **Steps** — the ordered list of step commands (the text after each `[ ]` or `[x]`) +- **Steps** — the ordered list of step commands (the text after each `[ ]` or `[x]`), keeping any `{{placeholders}}` verbatim +- **Parameters** — the Parameters section, if any (the composite skill should forward these; see Step 3) -If the flow does not exist: `Error: flow "{FLOW_NAME}" not found. Run /flow new {FLOW_NAME} first.` +If the flow does not exist: `Error: flow "{FLOW_NAME}" not found (looked in local and global). Run /flow new {FLOW_NAME} first.` ## Step 2: Scaffold with /skill new @@ -51,21 +53,26 @@ compatibility: Works on Claude Code. Requires the flow skill. {numbered list of step commands from the flow} +## Parameters + +{If the source flow had parameters, list them here so the invoker knows what to supply; else "None."} + ## Instructions -1. Generate a unique run slug: `{SKILL_NAME}-{timestamp}` (use current date + short random suffix) -2. Create a new flow instance: +1. Capture any text the user passed when invoking `/{SKILL_NAME}` as `INPUT` (and any `--set key=value` flags). +2. Generate a unique run slug: `{SKILL_NAME}-{timestamp}` (use current date + short random suffix) +3. Create a new flow instance (keep any `{{placeholders}}` verbatim — they resolve at run time): ``` /flow new {run-slug} \ "{step 1}" \ "{step 2}" \ ... ``` -3. Execute it: +4. Execute it, forwarding the captured input so `{{placeholders}}` resolve: ``` - /flow go {run-slug} + /flow go {run-slug} "{INPUT}" {--set flags if any} ``` -4. Report completion with the run slug so the user can inspect it with `/flow status {run-slug}`. +5. Report completion with the run slug so the user can inspect it with `/flow status {run-slug}`. ``` ## Step 4: Report diff --git a/skills/flow/references/workflows/status.md b/skills/flow/references/workflows/status.md index 3820b1e..d6f72e5 100644 --- a/skills/flow/references/workflows/status.md +++ b/skills/flow/references/workflows/status.md @@ -5,21 +5,23 @@ Print the current checklist state of a named flow. ## Step 0: Parse arguments ``` +--global / -g → look under ~/.codevoyant/flows (see references/flow-dir.md) FLOW_NAME = first non-flag positional arg (required) -FLOW_DIR = .codevoyant/flows/{FLOW_NAME}/ ``` -If `FLOW_NAME` is missing, error: "Usage: /flow status . A flow name is required." +If `FLOW_NAME` is missing, error: "Usage: /flow status [--global]. A flow name is required." -If `FLOW_DIR/flow.md` does not exist, error: "Flow '{FLOW_NAME}' not found. Run /flow new {FLOW_NAME} first." +Resolve `FLOW_DIR` per `references/flow-dir.md` (local-first, then global; `--global` forces global). If not found in any scope, error: "Flow '{FLOW_NAME}' not found (looked in local and global). Run /flow new {FLOW_NAME} first." ## Step 1: Read and display flow.md Read `FLOW_DIR/flow.md`. Extract and print: 1. **Flow title** (from the `# Flow: {TITLE}` heading) -2. **Status** (from the Metadata section) -3. **Steps checklist** — print each step line as-is, preserving `[ ]` or `[x]` markers +2. **Scope** (local or global — from the resolved location / Metadata) +3. **Status** (from the Metadata section) +4. **Parameters** (from the Parameters section, if any) +5. **Steps checklist** — print each step line as-is, preserving `[ ]` or `[x]` markers and any `{{placeholders}}` Then print a summary line: @@ -32,13 +34,15 @@ Where `done` = count of `[x]` lines, `total` = total step lines. ## Example output ``` -Flow: jupyterpress +Flow: ship-feature +Scope: global Status: Active +Parameters: {{input}} — the feature to ship -1. [x] /dev explore "how to build jupyterpress" -2. [x] /spec new "plan it" -3. [ ] /spec go -4. [ ] /dev explore "review the code" +1. [x] /spec new {{input}} +2. [x] /spec go +3. [ ] /git commit +4. [ ] /pr open 2/4 steps complete ``` diff --git a/skills/pr/references/new-review-template.md b/skills/pr/references/new-review-template.md index 9dc64e8..2fc5645 100644 --- a/skills/pr/references/new-review-template.md +++ b/skills/pr/references/new-review-template.md @@ -12,9 +12,9 @@ Write this structure to `.codevoyant/review/{slug}/new-review.md`. - **Stats**: +{additions} -{deletions} across {changedFiles} files - **Reviewed**: {timestamp} -## Summary +## Summary — does this deliver its intent? -{One-paragraph overall impression. State the main concern first. No filler phrases.} +{Lead with an intent verdict: does the change deliver its stated purpose end-to-end? Trace the headline use case. Then the main concern. No filler phrases.} ## Inline Comments diff --git a/skills/pr/references/workflows/help.md b/skills/pr/references/workflows/help.md index 797ecfc..974f64d 100644 --- a/skills/pr/references/workflows/help.md +++ b/skills/pr/references/workflows/help.md @@ -21,7 +21,11 @@ Adjust whatever `open` / `review` / `address` produced last, from `` (minor) / `` (major) annotations you add inline to its local file, or a plain-language request (`/pr update "tighten the summary"`). Re-syncs to the platform if the artifact was already pushed. -## review — slop / scope pass +## review — intent + slop passes + +Reviews evaluate the change against its **stated intent** first — does the diff actually deliver the PR/MR's +purpose end-to-end, tracing the headline use case — not just line-level code quality. A clean diff that fails +its intent is flagged BLOCKING. Alongside the correctness review, a dedicated **slop-detector** agent audits the diff for AI slop and unwanted agent-introduced change: unnecessary/out-of-scope edits, stochastic churn (random renames, reordering, reformatting), diff --git a/skills/pr/references/workflows/review.md b/skills/pr/references/workflows/review.md index 99b42fd..7387a53 100644 --- a/skills/pr/references/workflows/review.md +++ b/skills/pr/references/workflows/review.md @@ -127,6 +127,13 @@ Diff: Write a thorough inline code review. Be thorough in what you CATCH, terse in what you WRITE. +INTENT ALIGNMENT (evaluate this FIRST — it usually matters more than line-level nits): +- Treat the PR/MR title and description above as the **stated intent** — the goal and its implicit acceptance criteria. If the description is thin, infer the intent from the branch name and the shape of the diff. +- Judge whether the diff actually **delivers that intent end-to-end**, not just whether the code is clean. **Trace the headline use case concretely** — walk the main path step by step and check it would really work as written. +- Flag anything that undercuts the stated purpose, even if the code is well-formed: a feature whose main path stalls or needs manual intervention, an abstraction that never connects to its consumer, something billed as "reusable/global/automatic" that isn't, a fix that doesn't actually cover the reported case, a config/flag that has no effect. +- These are **BLOCKING** when they mean the change doesn't do what it claims. A clean diff that fails its intent is still a failing change — say so, and name the exact scenario where it breaks. +- Do NOT rubber-stamp scope you didn't verify. If part of the intent can't be confirmed from the diff, say what you couldn't verify rather than assuming it works. + TONE (follow references/voice.md — terse, human, junior-dev friendly): - Each comment is usually ONE or TWO short sentences: name the problem, then the ask. Skip the mechanism walk-through and the list of every consequence — the author can read the code. - Human and respectful. No sarcasm, no faint praise ("nice work but…"), no rhetorical questions, no hype. @@ -134,12 +141,15 @@ TONE (follow references/voice.md — terse, human, junior-dev friendly): - Example — instead of: "Any logged-in user can POST any pathname and it'll be saved to the DB, so someone could record a path to another user's file or a made-up URL and it shows up as a legitimate upload…" write: "This accepts any pathname, even fake ones. Worth validating." Then a code suggestion if it helps. CONTENT: +- **Intent gaps** (does the change deliver its stated purpose?) come first — see INTENT ALIGNMENT above. - Flag bugs, logic errors, and security issues as **BLOCKING** - Flag style deviations, naming, and structure as non-blocking (CONSIDER) - For each non-trivial issue, prefer a concrete code suggestion (diff block or replacement snippet) over prose — it's usually clearer and shorter. - Cite external documentation, an RFC, or prior art (URL) only when it saves the author a search or justifies the point — not as decoration. - Skip comments on style that matches project conventions — do not nitpick conforming code -- Focus on correctness, security, and design. **Unnecessary/out-of-scope changes and AI "slop" are handled by a dedicated pass (Step 6b) — don't duplicate that here.** +- Focus on correctness, security, design, and intent. **Unnecessary/out-of-scope changes and AI "slop" are handled by a dedicated pass (Step 6b) — don't duplicate that here.** + +For an intent-gap finding, anchor the comment on the most relevant line of the change (the assumption that doesn't hold, the flag that does nothing, the seam that doesn't connect) and describe the concrete failure scenario in the body. OUTPUT FORMAT — always produce a valid JSON array (empty array if no comments): [ @@ -155,7 +165,7 @@ OUTPUT FORMAT — always produce a valid JSON array (empty array if no comments) Return `[]` if the code has no issues. Do not include an overall summary in this JSON — that goes in a separate field. ``` -Also produce a one-paragraph overall summary as a separate string. +Also produce a one-paragraph overall summary as a separate string. **Lead the summary with an intent verdict** — does the change deliver its stated purpose end-to-end? — then note the most important findings. If the headline use case wouldn't work as written, say so up front, not buried under line nits. ## Step 6b: Dedicated slop pass (run in parallel with Step 6)