wise-workflow-create · diff
git:20260906.8b0eb38 to git:20260911.c965a40
96 added, 574 removed. Audit A to A.
---
name: wise-workflow-create
description: >-
Scaffold a new workflow through a step-by-step wizard — collects name,
- description, project-selection policy, pre-flight pins, inputs, and
+ description, control mode, inputs, provider tuning, and
steps (id, type, type-specific fields, dependencies), previews the
generated YAML + README, and writes on confirmation. Writes to
- `${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>/` by default, or
+ `the engine-selected user definition directory<name>/` by default, or
offers the bundled `plugins/wise/workflows/<name>/` path when run
inside a clone of the marketplace repo. Invoked as
`/wise-workflow-create` (bare alias) or `/wise:wise-workflow-create`
(canonical). Use when the user says "create a workflow", "scaffold a
workflow", "new workflow", "author a workflow", or types
`/wise-workflow-create`.
argument-hint: "<name>"
- allowed-tools: Read, Write, AskUserQuestion, Bash(mkdir:*), Bash(test:*), Bash(bash:*), Bash(pwd:*), Bash(dirname:*), Bash(python3:*), Bash(${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap-deps.sh:*), Bash(${CLAUDE_PLUGIN_ROOT}/scripts/init-registry.py:*), Bash(${CLAUDE_PLUGIN_ROOT}/scripts/workflows.py:*)
+ allowed-tools: Read, Write, AskUserQuestion, Bash(mkdir:*), Bash(test:*), Bash(bash:*), Bash(pwd:*), Bash(dirname:*), Bash(python3:*), Bash(${WISE_PLUGIN_ROOT}/scripts/init-registry.py:*)
---
- # /wise-workflow-create — wizard for a new workflow
-
- ## Why this skill exists
-
- Writing workflow YAML by hand is error-prone (schema is strict, DAG
- edges are easy to mis-draw). This skill walks the user through the
- schema step-by-step via `AskUserQuestion`, validates as it goes, and
- produces a well-formed file.
-
- Two write destinations are supported:
-
- - **User-authored (default)** — `${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>/workflow.yaml`.
- Private to the user's machine; not tracked in any repo. This is
- the right place for one-off or personal workflows.
- - **Bundled (opt-in when in-repo)** — `<repo>/plugins/wise/workflows/<name>/workflow.yaml`
- inside a clone of the wise plugin's marketplace repo. Ships with
- the plugin, tracked in git, seen by every wise installer. The
- wizard only offers this mode when it detects it's running inside
- such a clone (see [§2.5](#25-detect-write-destination) below).
-
- Both destinations use the folder form — `<name>/workflow.yaml` —
- so a workflow can later grow sibling `templates/` / `prompts/`
- directories without a layout migration.
-
- The wizard deliberately **does not delegate to `skill-creator`** —
- workflows aren't skills; the YAML shape is our own.
-
- ## Arguments
-
- Read `$ARGUMENTS`. The first whitespace-separated token is the
- workflow `<name>`. When `$ARGUMENTS` is empty, stop with an error
- pointing at the expected form (`/wise-workflow-create my-flow`).
-
- - `name` — workflow name; kebab-case; matches the filename. Must not
- be `list|create|run|resume|remove|status` (those are reserved as
- subcommand verbs).
-
- ## Procedure
-
- ### 1. Bootstrap Python (fast-path via `/wise-init` registry)
-
- Prefer the cached registry `/wise-init` wrote; fall back to the live
- probe only when the registry is missing, stale, or Python itself
- isn't installed yet:
-
- ```bash
- STATUS="$(python3 "${CLAUDE_PLUGIN_ROOT}/scripts/init-registry.py" check 2>/dev/null || true)"
- case "$STATUS" in
- INIT:ok) : ;;
- *)
- echo "Tip: run /wise-init to cache dep probe results and speed up future runs." >&2
- bash "${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap-deps.sh"
- ;;
- esac
- ```
-
- Stop on `BOOTSTRAP:need-python` / `BOOTSTRAP:pip-failed` (only
- produced on fall-through; the `INIT:ok` path emits nothing).
+ # /wise-workflow-create - author a v2 workflow
- ### 2. Validate `name`
+ First read [host control](../../references/workflow-host-control.md). Resolve the
+ loaded installation, set `WISE_HOST` to this conductor and `WISE_PLUGIN_ROOT`
+ to that installation. Use its managed launcher for shell commands. Follow the
+ reference's diagnostics and explicit-answer fallback when MCP or a native picker
+ is unavailable. Conductor host and child provider are independent.
- - `name` matches `^[a-z][a-z0-9]*(-[a-z0-9]+)*$`. Reject otherwise.
- - `name` is not in the reserved list. Reject otherwise.
- - None of the following already exist (both layouts are checked —
- see the engine resolution order in `scripts/workflows.py`):
- - `${CLAUDE_PLUGIN_ROOT}/workflows/<name>/workflow.yaml` (bundled, folder)
- - `${CLAUDE_PLUGIN_ROOT}/workflows/<name>.yaml` (bundled, legacy flat)
- - `${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>/workflow.yaml` (user, folder)
- - `${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>.yaml` (user, legacy flat)
- If any exist, stop with a clear message pointing at the existing
- file; the user must `remove` first or pick a new name.
+ Create `version: 2` definitions for the Python engine. Use the host's
+ structured picker for choices and text inputs. Keep accepted answers
+ across stages; never create v1 `prompt`, `loop`, or `interactive` steps.
- ### 2.5. Detect write destination
+ ## 1. Resolve the destination
- Walk up from `$(pwd)` looking for a marker pair that identifies a
- clone of the wise plugin's marketplace repo: a sibling
- `plugins/wise/.claude-plugin/plugin.json` file AND a
- `.claude-plugin/marketplace.json` at the same ancestor. The first
- ancestor matching both is the repo root.
+ Run the init check in `${WISE_PLUGIN_ROOT}/references/init-check.md`,
+ then read canonical roots and existing definitions:
```bash
- REPO_ROOT=""
- d="$(pwd)"
- while [ "$d" != "/" ]; do
- if [ -f "$d/plugins/wise/.claude-plugin/plugin.json" ] \
- && [ -f "$d/.claude-plugin/marketplace.json" ] \
- && [ -d "$d/plugins/wise/workflows" ]; then
- REPO_ROOT="$d"
- break
- fi
- d="$(dirname "$d")"
- done
- echo "REPO_ROOT=${REPO_ROOT:-<none>}"
- ```
-
- - If `REPO_ROOT` is empty → `mode = user-authored` (no question).
- - If `REPO_ROOT` is set → `AskUserQuestion`:
- - Question: `You're inside the wise marketplace repo at <REPO_ROOT>. Save this workflow as bundled (shipped with the plugin, tracked in git) or user-authored (private to your machine)?`
- - Header: `Destination`
- - Options:
- - `Bundled (Recommended) — ships with plugin` — `Write to <REPO_ROOT>/plugins/wise/workflows/<name>/workflow.yaml. Tracked in git; seen by every wise installer after the next plugin release.`
- - `User-authored — private to your machine` — `Write to ${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>/workflow.yaml. Not tracked in any repo.`
-
- Store the choice as `mode`. Compute the target path — always folder
- form (`<name>/workflow.yaml`) so the workflow can ship its own
- artifacts in sibling `templates/` and `prompts/` directories without
- needing a future migration:
-
- - `mode = bundled` → `TARGET = "${REPO_ROOT}/plugins/wise/workflows/<name>/workflow.yaml"`
- - `mode = user-authored` → `TARGET = "${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>/workflow.yaml"`
-
- Re-check the collision rule from [§2](#2-validate-name) against
- `TARGET` specifically — in bundled mode the existing-bundled check
- is what matters; in user-authored mode the existing-user check is
- what matters.
-
- ### 3. Collect top-level fields
-
- Build up a Python-style dict **in your own working memory** as you
- ask; you will render YAML from it at the end. Start with:
-
- ```
- workflow = {
- "version": 1,
- "name": "<name>",
- "description": None,
- "author": None,
- "requires": [],
- "project-selection": None,
- "agents": None, # set by §3.2 only when policy is `auto`
- "preflight": {}, # filled by §3.3 if any key is pinned
- "inputs": [],
- "steps": [],
- }
- ```
-
- `AskUserQuestion`:
-
- - **Description.** Question: `One-sentence description of what this
- workflow does.` Header: `Description`. Options: "Other" only (user
- types free text). Save as `workflow["description"]`.
- - **Author (optional).** Question: `Your handle, for the author field?
- (Empty = skip.)` Header: `Author`. Options: `Skip`, `Other`. Save
- to `workflow["author"]` or leave None.
- - **Project selection policy.** Question: `How should the workflow
- resolve the project it runs against?` Header:
- `Project policy`. Options:
- - `current (recommended)` — `Auto-detect the project from the current git repository / working directory at run start.`
- - `prompt` — `Auto-detect, then ask the user at run start to confirm or override the project path/name/kind.`
- - `any` — `The workflow does not care about projects; no selection made.`
- Save as `workflow["project-selection"]`.
-
- ### 3.2. Agents policy (optional)
-
- `wise` ships an SDLC agent roster (`wise:architect`, `wise:software-engineer`,
- `wise:code-reviewer`, … — see `${CLAUDE_PLUGIN_ROOT}/AGENTS.md`). A
- workflow's `prompt` steps can be dispatched to a roster agent instead of
- the generic `general-purpose` subagent. The workflow-level `agents:`
- policy sets the default for every `prompt` step that doesn't pin its own
- `agent:`. `AskUserQuestion`:
-
- - Question: `Should this workflow's prompt steps default to the wise agent roster?`
- - Header: `Agents`
- - Options:
- - `Leave off (default)` — `Prompt steps run as a plain general-purpose subagent unless a step sets its own agent:. Matches pre-roster behaviour.`
- - `Auto-select per step` — `Each prompt step with no explicit agent: is routed to the best-fit roster role (the conductor picks). Individual steps can still override or opt out.`
-
- Save `workflow["agents"] = "auto"` only when the user picks auto;
- otherwise leave it `None` (the §6 render omits it, matching pre-roster
- shape).
-
- ### 3.3. Pre-flight pins (optional)
-
- Every workflow goes through three pre-flight questions at run
- start: control-mode (wave-sync / synchronous / auto-advance),
- worktree (current tree vs new worktree), rename_session (rename the
- Claude Code session for /resume). A workflow author can **pin** any or
- all of those answers when one of them doesn't make sense for the
- workflow — e.g. a workflow with `ask` steps and interactive prompts
- needs wave-sync or auto-advance, because synchronous mode would
- auto-approve gates and skip the asks; pin `auto-advance` instead of
- `wave-sync` when those prompts should fire but the runner should NOT
- be asked to start each wave. Pinned answers skip the corresponding
- AskUserQuestion at run start and are logged for the user.
-
- For each of the three keys below, default to `Leave it to the
- runner (prompt)` — that's the current behaviour and the right
- answer when the workflow works fine in either mode.
-
- **3.3a. Control mode.** `AskUserQuestion`:
- - Question: `Should the runner pick the control mode at pre-flight, or pin one for this workflow?`
- - Header: `Control mode`
- - Options:
- - `Leave it to the runner (prompt)` — `Ask the runner at pre-flight (default).`
- - `Pin wave-sync` — `Force wave-sync. Pick this when the workflow needs human input (ask steps, AskUserQuestion inside prompt/interactive steps, approval gates) AND the runner should review progress between waves.`
- - `Pin auto-advance` — `Force auto-advance. Like wave-sync (in-step asks/approvals/interactive prompts still fire) but with no between-wave menu — the run flows wave-to-wave and stops only where a step needs input. Pick this when the workflow has its own questions but the runner should NOT be asked to start each wave.`
- - `Pin synchronous` — `Force synchronous. Pick this when the workflow is end-to-end automated and has no steps that need human input.`
-
- If the user picks pin wave-sync, pin auto-advance, or pin
- synchronous, save to `workflow["preflight"]["control-mode"]`.
-
- **3.3b. Worktree.** `AskUserQuestion`:
- - Question: `Should the runner be asked to pick a worktree, or pin one choice for this workflow?`
- - Header: `Worktree`
- - Options:
- - `Leave it to the runner (prompt)` — `Ask the runner at pre-flight (default).`
- - `Pin current tree` — `Force in-place execution. Pick this for workflows that don't modify files (status checks, read-only reports).`
- - `Pin new worktree` — `Force a dedicated worktree on every run. Pick this for workflows that make destructive-ish edits and the user should always be able to throw the tree away.`
-
- Save to `workflow["preflight"]["worktree"]` when pinned.
-
- **3.3c. Session rename.** `AskUserQuestion`:
- - Question: `Should the runner be asked to rename the Claude Code session for /resume, or skip that prompt?`
- - Header: `Session rename`
- - Options:
- - `Leave it to the runner (prompt)` — `Ask the runner at pre-flight (default).`
- - `Pin skip` — `Don't ask. Pick this for short-running workflows where the rename prompt is more friction than the /resume label is worth.`
-
- Save to `workflow["preflight"]["rename_session"]` when pinned.
-
- If all three came back as `prompt`, leave `workflow["preflight"]`
- empty — the YAML render in §6 omits empty blocks so the produced
- file matches pre-0.42 shape exactly.
-
- The wizard does not walk the opt-in questionaries or unit caps
- interactively — but when it renders the YAML in §6, it appends a
- commented example of the three related blocks (`preflight.tuning` /
- `preflight.step-select` set to `prompt`, plus skeleton `tuning:`,
- `step-select:`, and `profiles.medium.caps` stanzas copied from
- `docs/wise/workflows.md`'s schema comment) so an author who wants
- them can uncomment and adapt instead of hunting the docs.
-
- ### 3.5. Inputs loop (optional)
-
- Inputs are values the user must supply at run start — `workflow-run`
- asks for each via `AskUserQuestion` during pre-flight, validates
- the answer against the declared regexes, and exposes it to every
- step as a `{{<name>}}` template variable. Use inputs whenever a
- workflow's first step would otherwise try to extract a value from
- invocation prose (ticket ids, branch names, target environments,
- etc.) — the TUI prompt is a better UX than a subagent asking in
- chat.
-
- **3.5a. Continue?** `AskUserQuestion`:
- - Question: `Does this workflow need any user-supplied inputs before the DAG launches? (<N> so far)`
- - Header: `Inputs`
- - Options: `Add input`, `Done — move to steps`.
-
- On Done, go to [§4](#4-step-loop).
-
- **3.5b. Name.** Ask for a kebab/snake-case identifier matching
- `^[a-z][a-z0-9_]*$`. This is the variable name used in `{{…}}`
- templates. Re-ask on collision with already-added inputs.
-
- **3.5c. Prompt text.** Free-text question the user will see in the
- AskUserQuestion call (e.g. `Which Jira ticket? (PROJ-18572 or a
- browse URL)`).
-
- **3.5d. Validate regex (optional).** Full-match regex the cleaned
- value must satisfy. If the user skips, accept any non-empty string.
-
- **3.5e. Extract regex (optional).** `re.search` regex applied
- *before* validation — useful when the user might paste a full URL
- and you want the id out of it. If the regex has a capture group,
- group(1) is the result; otherwise group(0). Skip if the value is
- already bare.
-
- Store each finished input as
- `{"name": …, "prompt": …, "validate": …, "extract": …}` (omitting
- the optional keys when the user skipped them) and append to
- `workflow["inputs"]`. Loop back to 3.5a.
-
- ### 4. Step loop
-
- Repeat until the user chooses Done:
-
- **4a. Continue?** `AskUserQuestion`:
- - Question: `Add another step? (<N> so far)`
- - Header: `Steps`
- - Options: `Add step`, `Done — preview workflow`.
-
- On Done, go to [§5](#5-external-requires).
-
- **4b. Step id.** Ask for a kebab-case id. Validate against the regex
- above and against the set of already-added ids. On collision, re-ask.
-
- **4c. Step type.** The valid types are `skill`, `prompt`,
- `interactive`, `bash`, `approval`, `ask`. `AskUserQuestion` caps at
- four options, so present the four most relevant for this workflow and
- let the user name any other via the `Other` free-text field (or ask in
- two passes). Type meanings:
-
- - `skill` — invoke a registered skill (`wise:…` or 3rd-party).
- - `prompt` — free-form prompt to an isolated subagent.
- - `interactive` — free-form prompt run inline in the conductor's main
- thread (full tools + `AskUserQuestion`); use when the step must
- prompt the user mid-flow or drive a per-item wizard.
- - `bash` — run a shell command.
- - `approval` — pause for user approval.
- - `ask` — capture a free-text/binary value into an output.
-
- **4d. Type-specific fields.**
-
- Build `step = {"id": <id>, "type": <type>, "depends_on": []}` and
- extend per type:
-
- - **skill:**
- - Ask for the namespaced skill id (`wise:wise-workflow-list`,
- `skill-creator:skill-creator`, …). Validate format
- `^[a-z][a-z0-9-]*:[a-z][a-z0-9-]*$`.
- - Ask whether the skill takes a payload. If yes, ask for the payload
- as multi-line `key: value` pairs via a free-text `AskUserQuestion`
- with "Other" — parse each line at `:`. Store as
- `step["payload"]`. Empty → `{}`.
-
- - **prompt:**
- - Ask for the prompt body (free text, multi-line). Templates
- (`{{project.path}}`, `{{var}}`) allowed. Store as `step["prompt"]`.
- - Ask whether there's an `until:` regex. If yes, ask for the regex
- and for a `max_iterations` integer (default 3). Store both.
- - Ask whether the step captures named outputs. If yes, ask for a
- comma-separated list of names. Store as `step["outputs"]`.
- - **Agent (optional).** `AskUserQuestion`: `Which subagent runs this
- prompt step?` Header `Agent`. Options:
- - `Inherit workflow policy (default)` — omit `step["agent"]`; the
- step follows the workflow-level `agents:` policy (§3.2).
- - `Auto-select a role` — store `step["agent"] = "auto"`.
- - `Force a specific role` — list the roster (run
- `python3 "${CLAUDE_PLUGIN_ROOT}/scripts/workflows.py" list-agents`
- and offer the `name`s) and store the picked role as
- `step["agent"]`.
- - `Build a team (multiple roles)` — the step is worked by several
- roster roles at once and the conductor synthesizes one result. Run
- the **team builder** below and store the resulting list as
- `step["agent"]`.
- - `general-purpose (no persona)` — store `step["agent"] = "off"`.
-
- **Team builder** (only when `Build a team` is picked). Roster from
- `list-agents`.
- 1. `AskUserQuestion` (multiSelect): `Which roles are on this step's
- team?` — offer the roster `name`s; require ≥2.
- 2. `AskUserQuestion`: `Which role leads (integrates the others before
- the conductor's synthesis)?` — the chosen roles **plus** `No lead
- (equal peers)`.
- 3. `AskUserQuestion`: `Per-member model/effort, or shared step-level?`
- Options: `Shared (set once for the whole step)` → ask the Model and
- Effort questions below **once** and store them as the step-level
- `step["model"]`/`step["effort"]`, and write each team member as a
- bare role-name string; `Per member` → for each role ask its own
- Model + Effort and write that member as
- `{role: <name>, model?: …, effort?: …}` (omit a knob when left at
- default). Either way, mark the lead with `lead: true` (this forces
- the object form for the lead).
- Store the assembled list (bare strings and/or
- `{role, lead?, model?, effort?}` objects) as `step["agent"]`. When the
- team uses shared knobs, **skip** the standalone Model/Effort questions
- below (already collected); otherwise still ask them as the step-level
- fallback for any bare-string member.
- - **Model (optional).** `AskUserQuestion`: `Pin a model for this step?`
- Header `Model`. Options: `Inherit session (default)` (omit
- `step["model"]`), `opus`, `sonnet`, `haiku` — store the alias as
- `step["model"]` when not default. (`fable`/`inherit` accepted too
- via Other.)
- - **Effort (optional).** `AskUserQuestion`: `Pin reasoning effort for
- this step?` Header `Effort`. Options: `Inherit (default)` (omit
- `step["effort"]`), `low`, `high` — and `medium`/`xhigh`/`max` via
- Other. Store as `step["effort"]` when not default. (Conveyed as a
- prompt directive only — best-effort, may be ignored by the model
- today; the real per-step knob is `model:`. Note `xhigh`/`max` are
- capped at resolve time by the model's policy ceiling — Opus 5 tops
- out at `high`. See `docs/wise/workflows.md`.)
-
- - **interactive:** same `prompt` body + optional `until:` +
- `max_iterations` + `outputs:` fields. The difference is execution — an
- interactive step runs inline in the conductor instead of an isolated
- subagent, so it can call `AskUserQuestion`. Collect those fields, but
- **do not** ask the Agent / Model questions: an interactive step is the
- conductor itself, so it can't become a subagent or switch model
- mid-conversation. (`agent:` / `model:` are `prompt`-only.)
-
- - **bash:**
- - Ask for the command (free text). Templates allowed. Store as
- `step["command"]`.
- - Ask for `cwd`. Default suggestion: `{{project.path}}`. Store.
- - Ask for expected `exit_code` (default 0). Store as
- `step["success"]["exit_code"]`.
- - Ask whether there's an expected `stdout_matches` regex. If yes,
- store under `step["success"]["stdout_matches"]`.
- - Ask for a timeout in seconds (default 120). Store as
- `step["timeout"]`.
-
- - **approval:**
- - Ask for the message text (free text, multi-line). Templates
- allowed. Store as `step["message"]`.
-
- - **ask:**
- - Ask for the question text the user will see (free text).
- Store as `step["question"]`.
- - Ask for the `output` variable name — kebab/snake-case, matches
- `^[a-z][a-z0-9_]*$`. The captured answer is stored in
- `state.outputs[<output>]`, referenceable as `{{<output>}}` in
- later step definitions. Store as `step["output"]`.
- - Ask for an optional header (≤12 chars, chip label). Store as
- `step["header"]` only when provided.
- - `AskUserQuestion`: `How should this step present its options to
- the user?`
- - `Free-text (default)` — `The user picks a skip label or types a value via the Other affordance. Use for "what's your comment?" / "which ticket?" / similar open answers.`
- - `Binary choice (yes/no-ish)` — `Two explicit options — a skip label and a confirm label. Use for yes/no / "opt-in to this extra stage".`
- Store the pick as a working variable `ask_shape`.
- - Ask for an optional skip-option label (default `Skip`). Store
- as `step["skip_label"]` only when non-default.
- - **If `ask_shape == "Binary choice"`:** also ask for
- - `confirm_label` (required) — the label for the "yes" option
- (e.g. `Yes — watch pipelines`). Store as
- `step["confirm_label"]`.
- - `confirm_value` (optional, defaults to the confirm label
- verbatim) — the string recorded to the output when the user
- picks confirm. Shorter values (`yes`, `enabled`) make later
- `when:` clauses like `when: "<output> == 'yes'"` cleaner.
- Store as `step["confirm_value"]` only when different from
- the label.
-
- **4e. Dependencies.** If at least one prior step exists,
- `AskUserQuestion` with `multiSelect: true`, options = each prior
- step's id (as a label) plus an explicit `None (runs first)` option.
- On `None`, `step["depends_on"] = []`. Otherwise the selected ids go
- into `step["depends_on"]`. If multiple selected AND ≥2 prior steps
- already share these deps, mention that they will run in parallel —
- one follow-up question (`OK?` / `Let me change`); on change, loop
- 4e.
-
- **4f. Trigger rule (only if depends_on has ≥2 entries).**
- `AskUserQuestion` for `trigger-rule`: `all-success`, `one-success`,
- `all-done`, `none-failed-min-one-success`. Default `all-success`.
- Store as `step["trigger-rule"]` only if not default.
-
- Append `step` to `workflow["steps"]` and loop to 4a.
-
- ### 5. External requires
-
- `AskUserQuestion`: `Does this workflow depend on plugins or skills
- that wise doesn't already provide?` Header: `Requires`. Options: `No`,
- `Yes, list them`.
-
- On `Yes`: ask for a comma-separated list of entries of the form
- `plugin:<name>` or `skill:<plugin>:<skill-name>`. Parse and validate;
- store as:
-
- ```
- workflow["requires"] = [
- {"plugin": "...",} or {"skill": "plugin:skill"},
- ...
- ]
+ "$HOME/.local/share/wise/bin/wise-engine" --wise-host "$WISE_HOST" definition-roots
+ "$HOME/.local/share/wise/bin/wise-engine" --wise-host "$WISE_HOST" list-defs
```
- ### 6. Preview and confirm
-
- Render the YAML in your working memory as a string — make sure:
-
- - Top-level keys appear in the order:
- `version, name, description, author, requires, project-selection, agents, preflight, inputs, steps`.
- - Keys that are `None` / empty are omitted (don't emit
- `author: null`, `requires: []`, `agents: null`, or `preflight: {}`
- when empty — the `agents:` line is dropped unless §3.2 set `auto`, and
- the `preflight:` block is skipped entirely when no key was pinned in
- §3.3, so the produced YAML matches pre-roster / pre-0.42 shape exactly
- for the common "leave everything to the runner" case).
- - Step keys appear in the order:
- `id, type, <type-specific>, agent, model, effort, depends_on, trigger-rule`
- (`agent` / `model` / `effort` appear only on `prompt` steps that set
- them).
-
- Show the rendered YAML to the user in a code block and
- `AskUserQuestion`:
-
- - Options: `Save`, `Edit a step (re-enter loop at [§4](#4-step-loop))`,
- `Cancel (discard)`.
-
- On `Edit`, jump back to [§4](#4-step-loop) (re-using the existing list).
-
- ### 7. Write
-
- On `Save`, write to the `TARGET` computed in [§2.5](#25-detect-write-destination).
- `TARGET` always ends in `<name>/workflow.yaml`, so the immediate
- parent of `TARGET` is the workflow folder (which does NOT exist yet
- and must be created).
-
- - **User-authored mode.** Ensure the workflow folder exists:
-
- ```bash
- mkdir -p "${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>"
- ```
-
- Write the YAML via the `Write` tool to `TARGET` (i.e.
- `${CLAUDE_PLUGIN_DATA}/workflows/definitions/<name>/workflow.yaml`).
+ The first argument is the workflow name. Ask for it if absent; require
+ `^[a-z][a-z0-9]*(-[a-z0-9]+)*$`. Reject an existing name in either root,
+ including flat `<name>.yaml` and folder `<name>/workflow.yaml` forms.
+ Never overwrite an existing definition.
- - **Bundled mode.** `<REPO_ROOT>/plugins/wise/workflows/` always exists
- in a valid clone, but the `<name>/` subfolder does not. Create it:
+ Default destination: `<user_root>/<name>/workflow.yaml`. When cwd is
+ inside a marketplace clone containing both `.claude-plugin/marketplace.json`
+ and `plugins/wise/.claude-plugin/plugin.json`, offer User (private) or
+ Bundled (tracked in that clone). Use `<repo>/plugins/wise/workflows/<name>/`
+ only after the user chooses Bundled. A plugin cache is not a repository
+ authoring destination. Recheck the chosen target before writing.
- ```bash
- mkdir -p "<REPO_ROOT>/plugins/wise/workflows/<name>"
- ```
+ ## 2. Collect workflow settings
- Write the YAML via the `Write` tool to `TARGET` (i.e.
- `<REPO_ROOT>/plugins/wise/workflows/<name>/workflow.yaml`).
+ Ask for a short description, then control mode: leave the runner to
+ choose, pin `interactive`, or pin `synchronous`. Interactive workflows
+ pause at approval/question gates. Synchronous workflows auto-approve
+ approval steps; child questions use supplied decisions or report that
+ human input is needed. Do not describe synchronous mode as permission
+ bypass. Provider permissions are separate preflight answers.
- Mention to the user that they can drop workflow-owned artifacts
- (templates, prompt fragments, fixtures) as siblings of the
- `workflow.yaml` and reference them from steps with
- `{{workflow.dir}}/<subdir>/<file>`. Common layout:
+ Ask whether the workflow needs inputs. For each input collect `name`,
+ `prompt`, optional `default`, optional `from-context`, and optional
+ `validate`/`extract` regexes. Read the canonical schema reference in
+ `docs/wise/workflows.md` before using additional fields. Inputs become
+ `{{name}}` template values. A missing required answer must remain a
+ preflight question, not an invented value.
- ```
- <name>/
- ├── workflow.yaml
- ├── README.md # generated alongside — see §7.5
- ├── templates/ # optional; e.g. pr-template.md
- └── prompts/ # optional; e.g. ensure-pr.md, watch-pipelines.md
- ```
+ ## 3. Collect steps and dependencies
- ### 7.5. Generate the README.md
+ Repeat until the user selects Done. Every step has a unique lowercase
+ `id`, a description when useful, and one supported type:
- Every workflow ships a README.md beside its `workflow.yaml`. Compose it
- from the in-memory `workflow` dict and `Write` it to
- `<TARGET_FOLDER>/README.md` — the folder already exists from §7, so this
- is the wizard's second `Write` (first was the YAML).
+ - `agent`: prompt or a referenced prompt file, provider/model/effort or
+ a tuning group, optional timeout and resume policy. For outputs,
+ collect a JSON schema and an explicit `outputs` list of properties.
+ `skill:` is a Claude-specific convenience and must not be offered as
+ portable execution on other providers. Use a plain prompt for a
+ workflow intended to run across providers.
+ - `bash`: command, timeout, optional outputs. The first output receives
+ trimmed stdout. Explain the exact command in the final preview.
+ - `approval`: message and dependencies. Runtime answers approve/reject.
+ - `ask`: message, choices, whether free text is allowed, and output name.
+ - `units`: choose the supported `ticket` or `plan` pipeline, items input,
+ parallelism, model-phase tuning groups and caps. Read the current
+ bundled `ticket-auto` or `impl-plan-auto` definition for the exact
+ pipeline shape; do not invent phase fields.
- Produce these sections (drop whole sections when empty):
+ Offer prior step IDs as `depends_on` choices. Keep independent work
+ parallel by leaving unrelated dependencies absent. Choose a trigger
+ rule only where needed: `all-success` (default), `one-success`,
+ `all-done`, `none-failed`, or `none-failed-min-one-success`. `when` is
+ an expression or supported list of expressions evaluated by the engine.
+ Never write a cycle or a dependency on an unknown step.
- - **Title + description** — `# <name>` and the verbatim
- `workflow["description"]`, preceded by an HTML comment noting the
- README must stay in sync with `workflow.yaml` + `prompts/*.md` (the
- CLAUDE.md invariant).
- - **When to use / When not to use** — one placeholder bullet each for
- the author to refine.
- - **Prerequisites** — `/wise-init` completed; one bullet per
- `workflow["requires"]` entry; a "run from inside the project repo"
- bullet unless `project-selection: any`.
- - **Flow** — a mermaid `flowchart TD` (rules below).
- - **Steps** — table `Step | Type | Purpose` (purpose derived in one
- line from prompt / command / message / question).
- - **Inputs** — table `Name | Required | Description` if the workflow
- has `inputs:`, else `None.`.
- - **Outputs** — table `Name | Source | Used for`, from prompt steps'
- `outputs:` and ask/interactive steps' `output:`.
- - **Examples** — `/wise-workflow-run <name>`.
- - **Related** — link to `./workflow.yaml` (and any templates/prompts
- added later).
+ For model steps, ask whether shared tuning groups are useful. Read
+ `"$HOME/.local/share/wise/bin/wise-engine" --wise-host "$WISE_HOST" models` for catalogs.
+ Groups use mapping defaults such as
+ `{harness: codex, model: inherit, effort: medium}`. Keep harness/model
+ choices available at run preflight unless the author explicitly pins
+ them. Provider permission choices remain explicit runtime questions.
+ Read `engine/engine.sh list-agents` for role names when composing role
+ instructions; do not copy the retired v1 `agents` roster syntax.
- **Mermaid rules:** one node per step labelled `<id><br/><type>` (append
- `→ <outputs>` when declared); one edge per `depends_on` entry
- (`<dep> --> <id>`); a `when:`-gated parent renders as a decision diamond
- with edges labelled by the when-value (a plain arrow + edge label is a
- fine fallback); sort topologically (entry nodes top, terminal bottom).
- Keep it a flat DAG — no nested subgraphs.
+ Optional steps use the canonical `step-select` block. Resource limits
+ use `profiles.<profile>.caps` and referenced cap names. Inspect bundled
+ examples and compile rather than copying v1 profile or tuning syntax.
- Then print:
+ ## 4. Preview and validate
- ```
- Saved /wise-workflow-<name> to:
- <TARGET>
- <TARGET_FOLDER>/README.md (overview + mermaid flow diagram)
- ```
+ Render complete YAML beginning with `version: 2`, plus a README with
+ the purpose, inputs, step table, provider requirements and run command.
+ A small Mermaid DAG may accompany the preview. Omit empty optional
+ blocks. Do not make unrelated files or invoke skill-creator.
- In bundled mode, also print a pointer about the release workflow:
+ Compile a temporary candidate through the same public engine:
- ```
- Heads up — this is a bundled workflow. Commit the new file plus a
- CHANGELOG entry + plugin.json version bump in the same PR per the
- wise plugin's versioning rules (see CLAUDE.md / CONTRIBUTING.md §9).
+ ```bash
+ "$HOME/.local/share/wise/bin/wise-engine" --wise-host "$WISE_HOST" compile-check <candidate.yaml>
```
- ### 8. Point at the next command
-
- Do NOT invoke `wise:wise-workflow-run` from this skill — the invariant
- that only `wise-workflow-run` and `wise-workflow-resume` may call wise
- action skills still holds here. Instead, end with a clear pointer:
+ Fix every error, relay relevant warnings, and remove the temporary
+ candidate after the preview. Unsupported Unicode case-insensitive
+ backreferences must be reported as validation errors; do not silently
+ rewrite the input rule.
- ```
- Ready to run it:
- /wise-workflow-run <name>
- ```
+ Show the exact destination and files, then ask Create or Keep editing.
+ On Create, recheck collisions, make the folder, write `workflow.yaml`
+ and `README.md`, and compile the final path. If validation fails, fix
+ only the generated files and rerun it. Do not report success while the
+ final definition is invalid.
- ## Guardrails
+ ## 5. Finish
- - Only two write destinations are valid: the user-authored path
- (`${CLAUDE_PLUGIN_DATA}/workflows/definitions/`) and — only when
- the detection in [§2.5](#25-detect-write-destination) matches and
- the user opts in — the bundled path
- (`<REPO_ROOT>/plugins/wise/workflows/`). Never write anywhere else.
- - Never overwrite an existing workflow file (bundled or
- user-authored). Collision = stop with a clear message; the user
- must `remove` first or pick a new name.
- - Never invoke another action skill. Per CLAUDE.md, only
- `workflow-run` and `workflow-resume` may call wise action skills via
- the `Skill` tool; `workflow-create` authors definitions and nothing
- more. After saving, point the user at `/wise-workflow-run <name>`.
- - If the user cancels at any point, discard the in-memory workflow
- and stop. Do not leave partial files behind.
+ Show the saved paths and `/wise-workflow-run <name>`. A bundled workflow
+ requires a repository version bump when committed, per CONTRIBUTING;
+ do not commit or publish it unless the user requested that action.
+ Never launch the workflow merely because authoring succeeded.