---
name: workflower-authoring
description: Creates or modifies Pi Workflower workflow packages, workflow definitions, and companion step skills. Use when a user asks Pi to create, scaffold, or update a Workflower workflow.
allowed-tools: read write edit bash
---

# Workflower Authoring

Use this skill when the user wants a Workflower workflow created or changed.

This is a standalone authoring skill. The user does not need to install or run `@supierior/workflower` just to use this skill. Generated workflow packages should depend on `@supierior/workflower` internally and initialize it from their extension entrypoint, so workflow users can install the generated workflow package rather than manually installing Workflower first.

Workflower runs garden-scoped multi-step workflows. Start the first flower with `/wf:<workflow-id> <garden-name>`, hand off to another workflow while active with `/wf:<next-workflow-id>`, and advance steps with `/next`. A workflow package usually registers a `WorkflowDefinition` from a Pi extension entrypoint and may ship companion skills used by each step.

## First, clarify the workflow

Ask only for missing information. Gather:

1. Workflow id, for example `feature`, `github_issue`, or `release-notes`.
2. Initial garden name example for README smoke tests, such as `demo-garden`.
3. What the workflow should accomplish.
4. Step list, including each step's purpose.
5. Command for each step. Prefer `/skill:<skill-name>` when the step should be implemented by a bundled skill.
6. Expected output files for each step, if any.
7. Pollen behavior:
   - pass the latest completed step outputs by default when handing off to another workflow;
   - set workflow-level `pollen` when only specific output path(s) should be pinned and handed off;
   - set workflow-level `acceptPollen: false` when a workflow should ignore incoming pollen paths from a previous flower.
8. Lifecycle preferences. `clearOnStart`, `clearOnCompletion`, and `cleanupOnCompletion` all default to `true`; only set them when turning that default _off_ (`false`), and only leave a field unset when the default is what you want:
   - preserve artifacts after final garden completion instead of cleaning them up? Set `cleanupOnCompletion: false` — only when the workflow's outputs are a real user-facing deliverable (a final report, a doc meant for later review, screenshots), not as a standing habit and never just to make inspection easier while iterating on the workflow itself.
   - continue the visible session that was already active instead of starting cold? Set `clearOnStart: false` — typical for a shortcut entry workflow chained into mid-conversation, not typical for a private loop workflow reached only by handoff.
   - keep the visible session instead of clearing it when the workflow completes? Set `clearOnCompletion: false`.
   - keep context between specific steps? Set that step's `clearOnNext: false`.
   - immediately advance after a step finishes? Set that step's `autoNext: true`.
9. Composability: does this workflow need more than one public entry point? A shortcut entry workflow (skips an early question-gathering step, `clearOnStart: false`, jumps straight into a shared step) can hand off into the same private loop chain as the full entry workflow. Design the shared private chain once; add thin entry workflows around it as needed.

## Validate the design

Before writing files:

- Workflow ids must be folder-safe and match `^[a-z0-9_-]+$`: lowercase ASCII letters, digits, underscores, and hyphens only. Do not use colon-separated, uppercase, whitespace, slash, dot-segment, or quoted ids.
- The initial garden name is provided by the user at runtime with `/wf:<workflow-id> <garden-name>` and becomes `.workflower/workflows/<garden-name>/`.
- The first workflow execution creates a flower workdir like `.workflower/workflows/<garden-name>/0001-<workflow-id>/` and a flower index at `.workflower/workflows/<garden-name>/0001-<workflow-id>/index.json`.
- While a workflow is active, hand off to another workflow with `/wf:<next-workflow-id>` and no garden name; Workflower creates the next flower in the same garden, such as `.workflower/workflows/<garden-name>/0002-<next-workflow-id>/`.
- Step ids should be short, stable, lowercase kebab-case.
- Step commands should exist or be created as bundled skills/commands.
- Output paths should be relative file paths under the workflow workdir.
- If a skill writes an output, its instructions must mention the exact output filename declared in the workflow definition.
- If a skill reads a previous output, its instructions must read from the previous-step output path provided by the kickoff prompt.

## Minimal workflow package shape

For a new package, create this structure. In a monorepo it may live under `packages/<package-name>/`; in a standalone repo it can live at the repository root.

```text
<package-root>/
├── src/
│   ├── index.ts                        # registers every workflow + calls setupWorkflower(pi)
│   ├── routing/
│   │   └── <package-id>-router.ts      # one shared router command for all deterministic branching, if any
│   ├── <shared-context-folder>/        # markdown context shared by skills across workflows, if any
│   └── my-workflow/                    # folder name matches the workflow id
│       ├── my-workflow-workflow.ts     # WorkflowDefinition
│       ├── skills/
│       │   └── my-first-step/SKILL.md  # when using skill-backed steps
│       └── scripts/
│           └── helper.js               # workflow-scoped scripts, if any
├── docs/                                # optional: standards multiple skills/scripts enforce
├── package.json
├── README.md
├── tsconfig.json
├── tsup.config.ts
└── vitest.config.ts
```

One folder per workflow id, even for a single-workflow package: everything that workflow needs (definition, its skills, its scripts) stays together directly under `src/<workflow-id>/`. Default to this flat shape; only nest an extra `src/workflows/<workflow-id>/` layer when the package also has other non-workflow top-level `src/` concerns that a flat `src/<workflow-id>/` would otherwise crowd. Use an existing small workflow package as a scaffold when available, but prefer the architecture above for new packages.

## Architecture guidance

Generated TypeScript workflow packages should follow the suPIerior package architecture direction:

- Keep `src/index.ts` small and stable: import each `WorkflowDefinition`, call `registerWorkflows([...])` once with all of them, then call `setupWorkflower(pi)`, and export the result as the default extension entrypoint. This is the one file that shows the whole package's workflow registration at a glance. Do not hand-roll a module-level "already registered" boolean guard: `registerWorkflows` already dedupes idempotently (re-registering the same definition is a no-op; a conflicting redefinition under the same id throws), so the extension entrypoint can call it unconditionally on every load.
- Group everything one workflow needs under its own `src/<workflow-id>/` folder: the `WorkflowDefinition`, its bundled step skills (`skills/`), and any helper scripts (`scripts/`). Add other folders local to that workflow (for example its own `internals/`) only when that workflow's own logic grows past a few files.
- If multiple workflows share deterministic routing logic, put it in one `src/routing/<package-id>-router.ts` that registers a single `registerWorkflowerCommand` named `<package-id>-route`, whose handler switches on a route-name argument (see "Step archetypes" below), rather than one command per branch.
- If multiple skills across different workflows share instructional context (methodology docs, contracts, quality bars), put that markdown under a domain-named shared folder, for example `src/global-skill-context/`, and reference it by relative path from each skill's own instructions.
- If multiple workflows share non-Pi logic that is neither routing nor skill context, put it under `src/internals/<domain-capability>/` using workflow domain language, not generic names like `utils` or `helpers`. Workflows may import shared `src/internals/`; shared internals should not import from a specific workflow or from `src/index.ts`.
- `scripts/` inside a workflow folder may hold either TypeScript helpers imported by that workflow's definition, or standalone executable scripts (plain `.js`, run as `node path/to/script.js --flag`) that a bundled skill's instructions shell out to via bash. When a skill relies on the latter, its `SKILL.md` should show the exact copy-paste invocation.
- An optional `docs/` folder at the package root can hold standards documents that multiple skills or scripts enforce (for example a required output file-layout convention) — distinct from the README (user-facing smoke test) and from shared skill-context markdown (instructional content meant to be injected into a skill's own prompt).
- Do not create empty architecture folders for tiny packages; add seams when they clarify navigation.
- Reserve "flower" for the runtime run-instance concept (`.workflower/workflows/<garden-name>/0001-<workflow-id>/`). A `src/<workflow-id>/` folder holds a workflow's source — its definition, skills, and scripts — not a flower; a flower only exists once that workflow starts running in a garden.

Markdown-only companion skill packages can stay simple. If a skill grows beyond one `SKILL.md` plus a few directly referenced files, use an analogous split with `SKILL.md`, `skill-api/`, and `internals/`.

## Extension entrypoint templates

`src/index.ts`:

```ts
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import setupWorkflower, { registerWorkflows } from "@supierior/workflower";

import { myWorkflow } from "./my-workflow/my-workflow-workflow";

export { myWorkflow };

export default function myWorkflowPackageExtension(pi: ExtensionAPI): void {
  registerWorkflows([myWorkflow]);
  setupWorkflower(pi);
}
```

`src/my-workflow/my-workflow-workflow.ts`:

```ts
import type { WorkflowDefinition } from "@supierior/workflower";

export const myWorkflow: WorkflowDefinition = {
  id: "my-workflow",
  userInvocable: true,
  modelInvocable: true,
  // cleanupOnCompletion defaults to true (artifacts are cleaned up); only set it to
  // false when the workflow's outputs are a real user-facing deliverable meant to
  // survive after the garden finishes, e.g. this workflow's second-step.md report.
  cleanupOnCompletion: false,
  model: "medium",
  thinkingLevel: "low",
  autoNext: false,
  pollen: "second-step.md",
  acceptPollen: true,
  steps: [
    {
      id: "first-step",
      command: "/skill:my-first-step",
      outputs: ["first-step.md"],
      // Override the workflow default for the one step doing real authoring work.
      model: "large",
      thinkingLevel: "high",
      clearOnNext: false,
    },
    {
      id: "second-step",
      command: "/skill:my-second-step",
      outputs: ["second-step.md"],
    },
  ],
};
```

For a package with several workflows, `src/index.ts` imports each `WorkflowDefinition` and registers all of them before calling `setupWorkflower(pi)` once:

```ts
import { firstWorkflow } from "./first-workflow/first-workflow-workflow";
import { secondWorkflow } from "./second-workflow/second-workflow-workflow";

export default function myWorkflowPackageExtension(pi: ExtensionAPI): void {
  registerWorkflows([firstWorkflow, secondWorkflow]);
  setupWorkflower(pi);
}
```

Use `setupWorkflower(pi)` in workflow packages so installing the workflow package also initializes Workflower's `/wf`, `/wf:<id>`, and `/next` commands.

Set `model` and `thinkingLevel` deliberately — do not leave every workflow on Workflower's start-of-garden defaults. Set workflow-level `model`/`thinkingLevel` as the default for every step, then override per step to match that step's actual cost: a cheap router-only step (see "Step archetypes" below) can drop to a low/minimal thinking level, while the one step doing real authoring or review work should get the workflow's best model and a higher thinking level. Step-level `model` and `thinkingLevel` override the workflow default for only that step; the next step falls back to the workflow settings, then the model and thinking level that were active when the garden started. `model` accepts a level name (`tiny`, `small`, `medium`, `large`, `xl`), a `provider/model-id` string, or an ordered fallback array of `provider/model-id` strings. Level names resolve against the user's `/wf config` model-level mapping (`.workflower/config.json`); do not assume a level name resolves to a specific model.

`WorkflowDefinition` and `WorkflowStep` are fully documented in `@supierior/workflower`'s type declarations, including which fields are optional and each field's default — treat the installed package's `.d.ts` as the source of truth for current optional/required fields and defaults, and re-check it if this skill's guidance and the type declarations ever disagree.

Workflow-level `autoNext?: boolean` sets the default for steps that omit their own `autoNext`; it defaults to `false`. Step-level `autoNext` overrides it for that step only.

Workflow-level `userInvocable?: boolean` (default `true`) controls whether Workflower registers `/wf:<id>` for users to start the workflow directly. Set `userInvocable: false` for workflows that should only be reached by handoff. Workflow-level `modelInvocable?: boolean` (default `true`) controls whether `workflower_handoff` may start this workflow; set `modelInvocable: false` to keep a workflow user-started only.

Workflow-level `pollen?: string | string[]` pins the output path or paths that should be referenced when another workflow is started in the same garden. If omitted, completed step outputs become unpinned pollen as `/next` advances. Workflow-level `acceptPollen?: boolean` defaults to `true`; set `acceptPollen: false` when a workflow should not receive previous flower pollen paths in its kickoff prompt. Pollen paths are referenced from the previous flower's `index.json`; files are not copied into the new flower.

## Garden state and deterministic routing

Use Workflower garden state for small structured facts that must survive context-clearing boundaries or drive deterministic routing. State lives at `.workflower/workflows/<garden-name>/state.json`, is shared by all flowers in the garden, and is deleted on final garden completion. Use output files for large artifacts: do not use state for large reports, logs, diffs, or plans; write those as declared output files instead.

When authoring workflows and companion skills:

- Declare expected state keys in README and skill instructions, for example `review.rating`, `review.summary`, and `review.required_changes`.
- Tell agents exactly when to call `workflower_state_set` and which JSON value shape to write.
- Tell agents to use `workflower_state_get` when a later step depends on previously saved state.
- Use `workflower_state_list` when an agent needs to discover which state keys are already set without guessing key names.
- Use code/router commands or model-callable tools for deterministic branching, then call `createWorkflowerRuntime(pi, ctx).handoff(...)` or the `workflower_handoff` tool.
- For autonomous branching, prefer a model-callable router tool. Do not rely on assistant text to invoke `/wf:<id>` or `/review-route`; printed slash commands are not executed by Pi.

Example reviewer instruction:

```markdown
After writing `implementation-review.md`, call `workflower_state_set` three times:

1. `{ "key": "review.rating", "value": <integer 1-5> }`
2. `{ "key": "review.summary", "value": "<one-sentence summary>" }`
3. `{ "key": "review.required_changes", "value": ["<change>"] }`
```

Example deterministic router:

```ts
const rating = await wf.state.getValue("review.rating");
const nextWorkflow =
  typeof rating === "number" && rating >= 4 ? "feature-next-steps" : "implementation-review-loop";
await wf.handoff(nextWorkflow);
```

## Custom private step commands

Use `registerWorkflowerCommand` when a step's `command` should expand to generated, per-invocation prompt content instead of a static skill body, for example injecting the current garden state or a computed file list into the kickoff prompt. Register once at extension startup, next to `registerWorkflows`:

```ts
import { registerWorkflowerCommand } from "@supierior/workflower";

registerWorkflowerCommand({
  name: "my-workflow-review-brief",
  description: "Builds the review-step prompt from current garden state.",
  handler: async (args, ctx) => {
    return { kind: "prompt", content: `Review garden ${ctx.gardenName}, step ${ctx.stepId}.` };
  },
});
```

Reference it from a step as `command: "/my-workflow-review-brief"`. Prefer a bundled skill (`/skill:<name>`) for static, hand-written step instructions; reach for `registerWorkflowerCommand` only when the prompt content must be computed at step-start time.

## Step archetypes

Most steps are one of three shapes. Recognizing which one a step is decides whether it needs a skill, `outputs`, `autoNext`, or none of those:

- **Skill step** — does the actual work. `command: "/skill:<name>"`, declares `outputs` when it writes files, usually `autoNext: true` unless a human should review the result before continuing.
- **Router step** — pure deterministic branching, no skill. `command: "/<package-id>-route <route-name>"` hitting the single shared router command (see "Architecture guidance" above), never declares `outputs`, always `autoNext: true` and `clearOnNext: true` since it only reads/writes garden state and hands off. Give it a step id starting with `route-`.
- **Human-pause step** — waits for a person to reply before continuing, no skill required if the prompt is simple. No `autoNext`, and usually `clearOnNext: false` so the question and the eventual answer stay in the same visible context. This differs from a router step's missing `autoNext`: a router step still moves on its own by calling `workflower_handoff`, a human-pause step genuinely stops until the user responds.

A bounded review loop composes a skill step (implement/improve), another skill step (review, writes a `review.score` state key), and a router step (reads the score, either hands off forward on pass or hands back to the first skill step with an incremented attempt counter). Cap the attempt counter with a constant; once exceeded, the router step's prompt should tell the model to stop and ask the user to intervene rather than handing off again.

## Compact kickoff prompt display

Current Workflower shows generated workflow kickoff prompts compactly in chat. A user may see only a label such as `Workflow: my-workflow — demo-garden` or `Step: first-step` instead of the whole generated prompt.

Teach junior workflow authors these rules:

- The model still receives the full kickoff prompt, including workflow id, garden name, workdir, previous pollen paths, previous outputs, expected output paths, and expanded private skill instructions.
- Private Workflower skills may be injected into model context even when their Markdown body is not visible in the transcript. Do not rely on visible transcript content to verify full private skill injection.
- This is not a token-saving feature. Keep workflow prompts and private skills concise because the full prompt still uses context.
- Assistant text that prints `/wf:<id>`, `/next`, or a router command does not execute that slash command. Autonomous workflow movement should call `workflower_handoff` or a deterministic model-callable router tool instead.

## Step skill template

`src/my-workflow/skills/my-first-step/SKILL.md`:

```markdown
---
name: my-first-step
description: Performs the first step of the my-workflow Workflower workflow and writes first-step.md.
allowed-tools: read write edit bash
---

# My First Step

You are step 1 of the `my-workflow` Workflower workflow.

## Goal

Describe the concrete outcome of this step.

## Instructions

1. Use the workflow kickoff prompt for the workflow id, garden name, active flower workdir, previous pollen paths, previous outputs, and expected output paths.
2. Create the declared output file: `first-step.md`.
3. Write the file at the absolute expected output path shown in the kickoff prompt. If no absolute path is visible, write it relative to the current working directory.
4. If this step is expected to write garden state, call `workflower_state_set` with the exact documented key names and JSON-compatible values.
5. Tell the user what was written and, unless this step has `autoNext: true`, tell them to inspect the output and run `/next` when ready.
```

## Minimal workflow example

Not every workflow needs `outputs` or `pollen`. A workflow with no file artifacts at all is valid — for example a two-step counter that only reads and writes garden state:

```ts
export const counterWorkflow: WorkflowDefinition = {
  id: "counter",
  model: "medium",
  thinkingLevel: "low",
  steps: [
    { id: "initialize-counter", command: "/skill:counter-init", clearOnNext: true },
    {
      id: "start-counter-loop",
      command: "/skill:counter-start-loop",
      autoNext: true,
      clearOnNext: true,
    },
  ],
};
```

Don't add `outputs`, `pollen`, or lifecycle overrides a workflow doesn't need just to match a bigger template.

## package.json requirements

A workflow package should include:

```json
{
  "keywords": ["pi-package", "pi", "workflow", "workflower"],
  "dependencies": {
    "@supierior/workflower": "workspace:^"
  },
  "peerDependencies": {
    "@mariozechner/pi-coding-agent": "*"
  },
  "pi": {
    "extensions": ["./dist/index.mjs"],
    "skills": ["./src/*/skills"]
  }
}
```

`pi.skills` is a glob (Pi's array fields support glob patterns and `!exclusions`), so it picks up every workflow's `skills/` directory without listing each workflow by name. Skills are plain Markdown and load directly from `src/`; they do not need a build step or a `dist/` copy. Update the glob (or list workflow folders explicitly) only if a workflow intentionally ships no skills and an author wants tighter filtering.

Use `workspace:^` for monorepo workflow packages so pnpm links the local workspace package during development and publishes the dependency as a compatible semver range such as `^0.1.0`. For published packages outside this monorepo, use a real `@supierior/workflower` version/range. Follow current Pi package dependency rules for the target distribution method; if publishing an npm Pi package that depends on another Pi package, consider adding `@supierior/workflower` to `bundledDependencies` so the generated package is self-contained for users.

## README smoke test

Document how to run the workflow from a fresh session:

```text
/wf:<workflow-id> <garden-name>
```

Then after each non-auto step:

```text
/next
```

If the README demonstrates chaining to another workflow while active, use the handoff form with no garden name:

```text
/wf:<next-workflow-id>
```

Also mention the built-in `/wf` management subcommands:

```text
/wf status
/wf stop
/wf list
/wf clean <garden-name>
/wf state list | get <key> | set <key> <json-value>
/wf resume [garden-name]
/wf config
```

`/wf clean` removes a garden's artifacts by hand (refuses while a workflow is still active in it). `/wf state` lets a user inspect or edit garden state without a running step. `/wf resume` restarts an interrupted garden from its durable resume metadata. `/wf config` opens an interactive editor for the model-level mapping (`tiny`/`small`/`medium`/`large`/`xl`), default model, and fallback strategy used to resolve level-name `model` settings.

and where artifacts are written:

```text
.workflower/workflows/<garden-name>/0001-<workflow-id>/
.workflower/workflows/<garden-name>/0001-<workflow-id>/index.json
```

Cleanup waits until the whole garden completes. Handoffs preserve earlier flowers so their pollen can be referenced by later workflows; final `/next` cleanup applies each flower's producing workflow `cleanupOnCompletion` setting.

## Final checklist

Before finishing:

- Each workflow lives in its own `src/<workflow-id>/` folder alongside its bundled skills and scripts (nested under `src/workflows/<workflow-id>/` only if the package needs that extra layer — see "Minimal workflow package shape").
- Every workflow is registered in one `registerWorkflows([...])` call in `src/index.ts`, during extension startup, with no hand-rolled "already registered" guard.
- The package initializes Workflower with `setupWorkflower(pi)`.
- Every `/skill:<name>` command has a matching bundled skill under its workflow's `skills/` folder.
- Skill instructions and workflow `outputs` agree; steps that don't write files (router steps, state-only review steps) correctly omit `outputs` rather than declaring an empty or fake one.
- The package manifest loads both extension and skills.
- Every workflow-level and step-level field set on a `WorkflowDefinition` differs from that field's documented default; fields left at their default are omitted rather than restated (check `@supierior/workflower`'s type declarations for current defaults).
- `model` and `thinkingLevel` are set deliberately at the workflow level and tuned per step (higher for the step doing real authoring/review work, lower for router-only steps), not left unset by default.
- `cleanupOnCompletion: false` is only used when the workflow's outputs are a genuine user-facing deliverable meant to survive after the garden completes — not left over from debugging, and not set merely to make artifacts easier to inspect while iterating.
- A package with more than one loop-back branch shares a single `registerWorkflowerCommand` router named `<package-id>-route`, rather than one command per branch; router steps have no skill, no `outputs`, and always `autoNext: true` + `clearOnNext: true`.
- If several public workflows share a private loop chain (a full entry and a shortcut entry, for example), that composability is intentional and documented, not accidental duplication.
- The README includes a copy-paste smoke test using `/wf:<workflow-id> <garden-name>`.
- The README and bundled skills explain active handoff with `/wf:<next-workflow-id>` when relevant.
- The README or workflow usage notes explain compact prompt display and warn authors not to verify private skill injection by visible transcript content alone.
- Artifact examples use `.workflower/workflows/<garden-name>/0001-<workflow-id>/` flower paths and mention `index.json`.
- Workflow-level `pollen` and `acceptPollen` choices are documented when handoff behavior matters.
- Expected garden state keys and `workflower_state_set` calls are documented when state drives later steps or routing.
- Deterministic routers are implemented as commands/tools or extension code, not as printed slash-command text.
- Cleanup timing is clear: flower artifacts are cleaned only after final garden completion, not during handoff; garden state is also deleted on final completion.
- `userInvocable` / `modelInvocable` are set explicitly whenever a workflow should not be both user-startable and handoff-startable.
- Level-name `model` settings (`tiny`/`small`/`medium`/`large`/`xl`) are only used when the README tells users they must configure `/wf config` first.
- Any `registerWorkflowerCommand` step commands are registered once at extension startup and documented alongside the bundled skills.
- Run package-local validation when practical: `pnpm test`, `pnpm typecheck`, `pnpm lint`, `pnpm build`.
