Skip to content
17 changes: 17 additions & 0 deletions docs/skills/flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Each step's key outputs (PR numbers, plan names, file paths) are captured and th

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.

The flow's own directory is a read-only **definition** (its steps and per-step implementations). A run never mutates it: the run's identity, checkbox progress, and accumulating context are materialized into a local **run instance** at `.codevoyant/runs/<slug>/` (`run.md` + `progress.md` + `context.md`). `run.md` records the resolved identity of the run (slug, definition, and the branch/spec-slug/worktree it produces) — the concrete anchor `/flow doctor` uses to tell a live interrupted run apart from a clobbered one, since the definition itself only holds `{{placeholders}}`. This keeps a global flow a pristine, reusable template — running it from any project writes progress only to that project's run instance, so concurrent or cross-project runs never clobber each other. Resume reads the local run instance; `/flow status` shows its progress.

```bash
/flow go auth-refactor # execute all pending steps
/flow go ship "add OAuth login" # bind free text to {{input}}
Expand All @@ -71,6 +73,21 @@ Print the `flow.md` checklist with current step status, scope, and parameters.
/flow status ship --global # inspect a global flow
```

### doctor — diagnose and repair flows

Check flows for corruption and, with `--fix`, repair what is safe to repair. Diagnose-only by default. With no name, it scans every flow in both scopes.

```bash
/flow doctor # diagnose all flows (local + global), change nothing
/flow doctor autospec # diagnose one flow
/flow doctor autospec --fix # apply safe repairs
/flow doctor autospec --fix --global # target the global copy
```

Checks (reported PASS/WARN/FAIL per flow): cross-run **clobber** (a `context.md` naming a branch/spec-slug/worktree that differs from this run's recorded identity in `run.md`), **stale** context (present although Status is Complete), **orphaned** worktree/branch (referenced but gone), **step-file drift** (step lines ≠ `step-N.md` files), **schema drift** (missing template sections), and **placeholder coherence** (undeclared or unused `{{tokens}}`). Doctor also inspects a legacy `context.md` sitting beside the definition (pre-run-instance layout), independently of any run-instance context.

Repairs (`--fix`, each announced before it runs): remove a `context.md` **only** on a positive clobber signal (its identifiers differ from `run.md`'s) or when Status is Complete — a context that matches the run's identity, or one whose identity can't be determined, is **preserved** (it may be the resume payload); reset Status `Active → Complete` when all steps are done; regenerate missing `step-N.md` stubs; conservatively migrate an old-schema `flow.md` to the current template; and prune references to deleted worktrees from `context.md`. Deleting a file under `~/.codevoyant/flows` (global scope) is announced explicitly before it happens.

### save — create a composite skill

Turn a completed flow into a reusable skill scaffolded via `/skill new`. The generated skill, when invoked, spins up a fresh flow instance from the saved steps and runs it end-to-end.
Expand Down
20 changes: 13 additions & 7 deletions skills/flow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ Aliases:
"run" → go
"exec" → go
"start" → go
"ls" → list
"show" → status
"review" → status
"export" → save
"publish" → save
"ls" → list
"show" → status
"review" → status
"export" → save
"publish" → save
"fix" → doctor
"diagnose" → doctor
"check" → doctor

Dispatch to: references/workflows/{VERB}.md
```
Expand All @@ -43,21 +46,24 @@ The `--global` / `-g` flag (store or read a flow under `~/.codevoyant/flows` ins

Any flag other than the flow-control flags (`--global`/`-g`, and `--set` for `go`) is **not** dropped: `references/flow-dir.md` collects it into `PASSTHROUGH_FLAGS`, and the `new`/`go` workflows forward it to the step commands. This is how `--branch feature/x` reaches the skills a flow runs (e.g. so `spec new` works on a separate branch).

The `--fix` flag (used by `doctor` to apply repairs instead of only diagnosing) is likewise **not** a verb — pass it through unchanged to the workflow.

## 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 |
| status | `references/workflows/status.md` | Print flow checklist state (from the local run instance if present) |
| doctor | `references/workflows/doctor.md` | Diagnose (and with `--fix` repair) broken flows across both scopes |
| save | `references/workflows/save.md` | Turn a flow into a reusable composite skill via /skill new |
| help | `references/workflows/help.md` | Usage reference |

## Instructions

1. Extract VERB from the user's message (first non-flag positional argument after "flow").
2. Apply aliases (run/exec/start → go; ls → list; show/review → status; export/publish → save).
2. Apply aliases (run/exec/start → go; ls → list; show/review → status; export/publish → save; fix/diagnose/check → doctor).
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 (including any `--global`/`-g` flag and any other unrecognized flags such as `--branch`) to the workflow unchanged, **as a preserved argv array** — each original argument stays one element, so multi-word step strings (`/spec new {{objective}}`) and quoted flag values (`feature="add OAuth"`) survive intact. The workflow iterates this argv (`"$@"`) to parse flow-control flags and bucket the rest into `PASSTHROUGH_FLAGS` via `references/flow-dir.md`; it must never flatten the args into a single string and re-split them.
34 changes: 34 additions & 0 deletions skills/flow/references/flow-dir.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,37 @@ Set `FLOW_DIR` to the resolved `{FLOWS_DIR}/{slug}/` and use it for the rest of
```
FLOW_DIR = {FLOWS_DIR}/{slug}/ # global if --global, else local
```

## Run instance (mutable run-state — for `go`, `status`, `doctor`)

A flow **definition** (`{FLOWS_DIR}/{slug}/` with `flow.md` + `implementation/step-N.md`) is a **read-only template**. `go` must never mutate it — mutating a *global* definition clobbers the shared template and lets concurrent/other-project runs overwrite each other's state.

All mutable run-state lives in a **run instance**, which is **always local to the current project**, regardless of whether the definition is local or global:

```
.codevoyant/runs/{slug}/
run.md # this run's resolved identity (slug, definition, branch/spec-slug/worktree) — written at go start
progress.md # a copy of the definition's Steps checklist; the ONLY place [ ] → [x] is flipped
context.md # the accumulating handoff log (persisted for resume)
```

`run.md` is the run instance's **identity record**. Because the definition and `progress.md` only ever hold `{{placeholders}}`, the resolved branch / spec-slug / worktree of a real run live nowhere in the definition — `run.md` (and `context.md`'s handoffs) are the only place they exist. `doctor` reads `run.md` as the authoritative "what is this run" anchor to distinguish a legitimately-interrupted `context.md` from one clobbered by a different run.

`run.md` uses these field names, and **`go` (backfill) and `doctor` (Check 1) must use the same ones** — one canonical name per identifier, no synonyms:

- `slug:` — the **flow's** own slug (the definition directory name); set at first run, never overwritten.
- `branch:` — receives a handoff `branch=` value.
- `spec-slug:` — receives a handoff `slug=` value (the resolved **spec** slug from a `spec new`/`spec go` step). Note the handoff token is `slug=` but the recorded field is `spec-slug:` precisely so it is never confused with the flow `slug:` above.
- `worktree:` — receives a handoff `worktree=` value.

Resolve it the same way in every workflow that runs or inspects a flow:

```bash
RUNS_DIR=".codevoyant/runs" # always local — never under $HOME, even for a global definition
RUN_DIR="$RUNS_DIR/{slug}" # {slug} is the resolved definition's directory name
```

- `{slug}` is the directory name of the resolved definition (from `FLOW_DIR`), so the run instance is stable whether the definition was found locally or globally.
- Step **implementations** are always read from the definition (`FLOW_DIR/implementation/step-N.md`), never copied into the run instance — only the checklist (`progress.md`) and the handoff log (`context.md`) are instance-local.
- Create on demand: `mkdir -p "$RUN_DIR"` (safe if it already exists).
- A run instance whose **definition is global** is expected and normal — it is not corruption or drift.
Loading
Loading