.stencila/skills/workflow-creation/SKILL.md
Create a new Stencila workflow. Use when asked to create, write, scaffold, or set up a workflow directory or WORKFLOW.md file. Covers workflow discovery, duplicate-name checks, ephemeral workflows, WORKFLOW.md frontmatter, DOT pipeline authoring, goals, agents, branching, composition, and validation.
npx skillsauth add stencila/stencila workflow-creationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create a new workflow directory and WORKFLOW.md file for Stencila. A workflow is a directory under .stencila/workflows/ containing a WORKFLOW.md file with YAML frontmatter and a Markdown body. The body should begin with a short human-readable explanation of what the workflow does and how it works, followed by a dot fenced code block that defines the pipeline, and then any additional documentation or referenced content blocks.
Use this skill when the user wants to define a multi-stage AI workflow, orchestrate several agent or human steps, or scaffold a reusable pipeline that can be validated and run with Stencila.
.stencila/ directory; if none exists, use the repository root or current working directory and create .stencila/workflows/<name>/.gitignore sentinel file containing *<closest-workspace>/.stencila/workflows/<name>/WORKFLOW.md with:
name and descriptiongoal-hint when the workflow expects user-supplied goals (see Optional frontmatter fields below); use goal only when the workflow has a stable, fixed objectivekeywords with domain-relevant terms and when-to-use/when-not-to-use entries to improve discoverability and delegation accuracydot fenced code block containing the workflow pipeline, and then any additional referenced content blocks or documentation.gitignore sentinel file with exactly * on its own line; if permanent, do not add that sentinellist_agents and list_workflows when agent selection or workflow composition matters, so you can choose from real available resources instead of guessing names:
description to the task and keywords to domain termswhen-to-use for positive signals and when-not-to-use to avoid poor matchesagent="name" and child workflows with workflow="name":
TODO before considering the workflow completestencila workflows validate <name>, the workflow directory path, or the WORKFLOW.md path, and report the result to the user when possibleWhen working from a nested directory in a repository, create the workflow in the closest workspace's .stencila/workflows/ directory rather than creating a new .stencila/ tree under the current subdirectory.
Workflow names must be lowercase kebab-case:
a-z, 0-9, -)--)^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$By convention, workflow names should describe the end-to-end process the workflow accomplishes, not the exact sequence of steps in the graph.
Use these naming patterns:
thing-process for the default casething-process-approach when you need to distinguish multiple workflows for the same processWhere:
thing is the artifact or domain the workflow acts on, such as code, blog, agent, or schemaprocess is the broad lifecycle stage or end-to-end goal, such as generation, refinement, publication, review, or creationapproach is an optional qualifier for strategy or tradeoffs, such as quick, iterative, consensus, thorough, or guidedPrefer names that communicate purpose rather than pipeline shape. Avoid brittle names that list every step, such as create-review-refine-test-deploy or plan-implement-validate, because they become outdated as the workflow evolves.
Good examples:
code-reviewcode-generation-iterativeblog-generation-quickarchitecture-design-consensusagent-creation-guidedCommon corrections: workflowBuilder → workflow-builder, test_deploy → test-deploy, Code-Review → code-review.
The file has two parts:
--- delimiters — metadata such as name, description, and optional goaldot fenced code block, then optional additional documentation and referenced content blocksname — the workflow name (must match directory name)description — what the workflow does and when to use it; keep it concise and specificgoal-hint — hint text displayed across user interfaces (TUI, web, email, Slack, etc.) when the workflow is activated, guiding the user to provide a specific goal (e.g., "What kind of analysis do you want to perform?"). Most workflows should include this because most workflows expect the user to supply their own objective at run time. The user's response becomes $goal at runtime. This field is a UI hint and is never substituted into prompts directlygoal — a fixed high-level objective for the workflow; use only when the workflow has a stable, predetermined intent that prompts interpolate as $goal. Omit generic goals that merely restate the workflow's purpose (e.g., "Produce an acceptable X for the requested purpose") — they add no value and clutter the user interface with unhelpful pre-filled textkeywords — list of keywords or tags for discovery and routing; use terms that reflect the workflow's domain and purposewhen-to-use — list of positive selection signals describing when this workflow should be used; helps managers choose the right workflowwhen-not-to-use — list of negative selection signals describing when this workflow should not be usedlicense — SPDX identifier or reference to a license file if neededcompatibility — environment requirements (max 500 characters)metadata — arbitrary key-value pairs if the workflow needs extra structured metadataEphemeral status is not stored in frontmatter. It is determined by whether the workflow directory has a .gitignore sentinel file containing exactly *.
dot fenced code blockdigraph code_review { ... }graph [...] only when required by execution semantics or to match an existing project styleprompt, agent, and ask where neededpersist shorthand when a node should retain its own conversational context but that thread does not need to be shared with other nodes; this is the simplest and preferred sugar for per-node persistencepersist alone because it auto-generates a distinct thread-id per node. Instead, set an explicit shared thread-id with fidelity="full", or use graph-level defaults default-fidelity="full" and default-thread-id="..." for a whole shared threadthread-id across different agents or across parallel branches; shared threads should usually stay within one agent and one sequential pathprompt-ref, shell-ref, ask-ref, or interview-ref instead of embedding long strings in DOT. Do not use refs for short single-line valuesinterview-ref (pointing to a YAML block with preamble, typed questions, and store keys) when a human review step collects multiple pieces of information; use ask or ask-ref for single-question gatesshow-if on interview questions to conditionally display them based on a previous answer (e.g., show-if: "decision == Revise" to ask for revision notes only when the reviewer chose to revise); use finish-if on yes-no, confirm, or single-select questions to end the interview early when the answer matches a value (e.g., finish-if: "no" to skip remaining questions when the user declines to continue)agent node has multiple outgoing edges with labels, the engine provides routing instructions (via workflow_set_route tool or XML tag fallback). Give each outgoing edge a descriptive label (e.g., Accept, Revise, Pass, Fail) and the agent will signal its choice. Edge conditions take priority over preferred labels, so both mechanisms can coexistworkflow_get_output, workflow_get_context) over $last_output / $human.feedback interpolation — this avoids bloating prompts with long prior outputs. Write prompts that say "check for reviewer feedback" instead of embedding variables inline. Reserve $-variable interpolation for short values ($goal, $last_stage) and for shell commands and edge conditions where tools are unavailableFanOut… node ID prefix for parallel fan-out — all outgoing edges from the fan-out node execute concurrently and reconverge at a downstream fan-in point. Set join_policy (wait_all or first_success), error_policy (fail_fast, continue, or ignore), and max_parallel (default 4) as needed. The fan-in node is detected automatically by structural convergence or can be made explicit with a FanIn… node ID prefix or shape=tripleoctagon. Static fan-out has a fixed number of branches defined by the outgoing edges in the DOT graph. For dynamic fan-out where the number of branches is determined at runtime, use fan-out="key" on a node to fan out over a list stored in the pipeline context under that key; the node must have exactly one outgoing edge pointing to the template entry node, and a fan-in node (explicit FanIn… prefix or shape=tripleoctagon) must follow the template subgraph to collect the resultsstore="key" to write their stdout into the pipeline context, with optional store-as="json" or store-as="string" to control parsing (default: try JSON, fall back to string). This is the typical way to produce the list that a dynamic fan-out consumes — a shell node outputs a JSON array and stores it with store="items" store-as="json", then a downstream fan-out node references fan-out="items". Alternatively, an agent node with context-writable=true can produce a list by calling workflow_set_context with a JSON array value (e.g., fan-out="items")workflow="child-name" on a node to run another workflow as a composed subprocess. Use goal="..." to pass an explicit child objective; if omitted, the child goal defaults to the node's resolved input (prompt, then label). Keep the parent focused on orchestration and the child on detailed execution; avoid composing trivial one-step tasks unless reuse is likelypersist="full" (or another persist mode) over spelling out fidelity and thread-id when you only want per-node carryover sugar and do not need multiple nodes to share the same threadagent attribute, the engine uses a default agent — note this to the user when it mattersask property for explicit human approval or review stepsgoal-hint over goal for most workflows; see Optional frontmatter fields for the distinctionThe recommended body structure is: a short human-readable explanation of the workflow before the first DOT block, then the DOT pipeline, then any additional referenced content blocks or documentation. Only the first DOT block is extracted as the pipeline definition.
Reusable content references resolve against code blocks or code chunks with ids in the same WORKFLOW.md. Use them mainly for longer content, for example:
```dot
digraph example {
Create [agent="writer", prompt-ref="#creator-prompt"]
Check [shell-ref="#run-checks"]
Ask [ask-ref="#human-question", question-type="freeform"]
Review [interview-ref="#review-interview"]
}
```
```markdown #creator-prompt
Create or revise the draft for this goal: $goal
Check for reviewer feedback from a previous iteration and revise rather than restart.
```
```sh #run-checks
cargo fmt -p workflows && cargo test -p workflows
```
```markdown #human-question
What should change before the next revision?
```
```yaml #review-interview
preamble: |
Please review the draft and provide structured feedback.
questions:
- header: Decision
question: Is the draft ready to publish?
type: single-select
options:
- label: Approve
- label: Revise
store: review.decision
- header: Feedback
question: What specific changes should be made?
store: review.feedback
```
Ids must be unique within the document.
An ephemeral workflow is a temporary workflow directory under .stencila/workflows/ that includes a .gitignore file containing exactly:
*
This sentinel marks the workflow as temporary without adding any special frontmatter or DOT attributes.
Use ephemeral workflows when:
Do not make a workflow ephemeral unless the user asks for temporary behavior or the surrounding flow clearly implies it.
When describing the result, explain whether the workflow is ephemeral or permanent. If ephemeral, mention stencila workflows save <name> to keep it and stencila workflows discard <name> to remove it.
---
name: lit-review
description: Search and summarize recent literature
goal: Review recent literature on CRISPR gene editing
---
This workflow searches for recent papers, summarizes the key findings, and drafts a literature review.
```dot
digraph lit_review {
Start -> Search
Search [prompt="Search for recent papers on: $goal"]
Search -> Summarize
Summarize [prompt="Summarize the key findings across the papers"]
Summarize -> Draft
Draft [prompt="Draft a literature review from the summaries"]
Draft -> End
}
```
---
name: code-review-guided
description: Automated code review with structured human feedback
goal: Implement and review the feature with detailed feedback
---
This workflow designs, builds, and reviews code changes using a structured human review interview that collects both a routing decision and detailed feedback.
```dot
digraph code_review_guided {
Start -> Design
Design [agent="code-planner", prompt="Design the solution for: $goal"]
Design -> Build
Build [agent="code-engineer", prompt="Implement the design"]
Build -> Review
Review [interview-ref="#review-interview"]
Review -> End [label="Approve"]
Review -> Design [label="Revise"]
}
```
```yaml #review-interview
preamble: |
Please review the implementation and provide structured feedback.
questions:
- header: Decision
question: Is the implementation ready to merge?
type: single-select
options:
- label: Approve
- label: Revise
store: review.decision
finish-if: Approve
- header: Revision Notes
question: What specific changes should be made?
show-if: "review.decision == Revise"
store: review.feedback
```
When an LLM agent decides the branch, use labeled edges without conditions.
---
name: draft-review-iterative
description: Draft and iteratively refine with agent-driven review
goal-hint: What would you like drafted and refined?
---
This workflow uses a writer agent to create or revise a draft, then a reviewer agent to evaluate it. The reviewer chooses between Accept and Revise branches via `workflow_set_route`. On acceptance, the draft enters a structured human review interview where the user can accept or request further revisions with feedback. The `Create` node retrieves reviewer feedback via `workflow_get_output` and human revision notes via `workflow_get_context` to keep prompts compact across iterations.
```dot
digraph draft_review_iterative {
Start -> Create
Create [agent="writer", prompt-ref="#creator-prompt"]
Create -> Review
Review [agent="reviewer", prompt-ref="#reviewer-prompt"]
Review -> HumanReview [label="Accept"]
Review -> Create [label="Revise"]
HumanReview [interview-ref="#human-review-interview"]
HumanReview -> End [label="Accept"]
HumanReview -> Create [label="Revise"]
}
```
```markdown #creator-prompt
Create or update the draft for: $goal
Before starting, check for reviewer feedback from a previous iteration. If feedback is present, use it to revise the existing draft instead of starting over. Also check for human revision notes and incorporate those as well.
```
```markdown #reviewer-prompt
Review the current draft for the goal '$goal'.
If the draft is acceptable, choose the Accept branch.
If the draft needs changes, choose the Revise branch and provide specific feedback in your response.
```
```yaml #human-review-interview
preamble: |
The reviewer agent has approved the current draft.
Please review and decide whether to accept or revise.
questions:
- header: Decision
question: Is the draft acceptable?
type: single-select
options:
- label: Accept
- label: Revise
store: human.decision
finish-if: Accept
- header: Revision Notes
question: What changes should be made?
store: human.feedback
show-if: "human.decision == Revise"
```
Use edge conditions for deterministic routing based on handler status. Unlike label routing above, condition-based branching evaluates structured outcome fields.
---
name: code-review
description: Automated code review with human approval gate
goal: Implement and review the feature
---
This workflow designs, builds, and tests a code change, then routes to human review on success or loops back on test failure. The human reviewer can approve or send the change back for revision.
```dot
digraph code_review {
Start -> Design
Design [agent="code-planner", prompt="Design the solution for: $goal"]
Design -> Build
Build [agent="code-engineer", prompt="Implement the design"]
Build -> Test
Test [agent="code-tester", prompt="Run tests and validate"]
Test -> Review [label="Pass", condition="outcome=success"]
Test -> Build [label="Fail", condition="outcome!=success"]
Review [ask="Review the code changes"]
Review -> End [label="Approve"]
Review -> Design [label="Revise"]
}
```
Use a FanOut… node ID prefix to execute independent branches concurrently. Branches reconverge at a shared downstream node (the fan-in point), which can be made explicit with a FanIn… node ID prefix or shape=tripleoctagon. Use this pattern when the workflow has multiple independent tasks that do not depend on each other's output — for example, searching different sources, running independent analyses, or generating alternative candidates.
Fan-out can be static or dynamic. Static fan-out has a fixed number of branches defined by the outgoing edges in the DOT graph. Dynamic fan-out uses fan-out="key" to iterate over a runtime list stored in the pipeline context, spawning one branch per item — use this when the number of items is not known until execution time.
---
name: literature-search-parallel
description: Search multiple sources in parallel and synthesize findings
goal-hint: What topic should the literature search cover?
---
This workflow fans out to three independent source searches in parallel, then synthesizes their combined results into a unified review.
```dot
digraph literature_search_parallel {
Start -> FanOut
FanOut [label="Search sources in parallel"]
FanOut -> Databases
FanOut -> Preprints
FanOut -> Reviews
Databases [prompt="Search published databases (PubMed, Scopus) for: $goal"]
Databases -> Synthesize
Preprints [prompt="Search preprint servers (bioRxiv, arXiv) for: $goal"]
Preprints -> Synthesize
Reviews [prompt="Search existing review articles for: $goal"]
Reviews -> Synthesize
Synthesize [prompt="Synthesize findings across all sources into a unified review"]
Synthesize -> End
}
```
Use a shell node with store and store-as to produce a runtime list, then a FanOut… node with fan-out="key" to iterate over it. The fan-out node must have exactly one outgoing edge pointing to the template entry node. A fan-in node collects the results after the template subgraph. Alternatively, an agent node with context-writable=true can populate the list by calling workflow_set_context with a JSON array value (e.g., key items), which the downstream fan-out node references with fan-out="items".
---
name: batch-analysis
description: Dynamically analyze items discovered at runtime
goal-hint: What kind of items should be discovered and analyzed?
---
This workflow discovers items with a shell command, fans out dynamically to process each one in parallel, then merges the results.
```dot
digraph batch_analysis {
Start -> Discover
Discover [shell="find src -name '*.rs' -printf '%f\\n' | head -20 | jq -R -s 'split(\"\\n\") | map(select(. != \"\"))'", store="items", store-as="json"]
Discover -> FanOutItems
FanOutItems [fan-out="items", label="Process each item"]
FanOutItems -> Analyze
Analyze [prompt="Analyze $fan_out.item and produce a summary"]
Analyze -> FanInResults
FanInResults [label="Merge results"]
FanInResults -> Report
Report [prompt="Compile all analysis summaries into a final report"]
Report -> End
}
```
Design the workflow so that each stage makes visible progress toward the goal instead of just adding more prompts. Start from the user's real objective, then map it to stages such as research, plan, build, test, review, and publish.
goal for the stable overall objectiveFanOut… node ID prefix) when the workflow has independent tasks that can run concurrently, such as searching multiple sources or generating alternative approaches. Ensure all branches are truly independent — if one branch needs another's output, use sequential edges instead. When the set of items is known at design time, use static fan-out with explicit branches; when items are determined at runtime (e.g., discovered by a shell command or produced by a prior agent), use dynamic fan-out with fan-out="key" over a stored listCommon shapes by objective type (simplify or extend to fit the request):
| Objective type | Typical shape | |---|---| | Research / literature review | clarify → search → extract → synthesize → critique → draft | | Coding / implementation | clarify → design → implement → test → review → approve | | Publishing / editorial | brief → draft → edit → fact-check → approve → publish | | Decision support | define criteria → gather options → evaluate → compare → recommend → approve | | Data analysis | define question → collect → clean → analyze → interpret → review |
Input: "Create a workflow that designs, implements, tests, and then asks for human approval before finishing"
Process: Derive name code-generation-iterative (process-oriented, not step-by-step like plan-implement-validate). Resolve workspace, check for duplicates, write the file, and validate.
Output:
---
name: code-generation-iterative
description: Generate and refine a requested software change through design, implementation, testing, and review
goal: Implement and validate the requested feature
---
This workflow designs an implementation plan, builds it, runs tests, and gates progression on test success. On failure, it loops back to rebuild. On success, a human reviewer can approve or send the change back to redesign.
```dot
digraph code_generation_iterative {
Start -> Design
Design [prompt="Design an implementation plan for: $goal"]
Design -> Build
Build [prompt="Implement the approved design"]
Build -> Test
Test [prompt="Run or describe validation steps and report the outcome"]
Test -> Review [label="Pass", condition="outcome=success"]
Test -> Build [label="Fail", condition="outcome!=success"]
Review [ask="Review the implementation"]
Review -> End [label="Approve"]
Review -> Design [label="Revise"]
}
```
Validated with: stencila workflows validate code-generation-iterative
Input: "Create a temporary workflow I can try once to summarize a set of notes"
Output structure:
.stencila/workflows/note-summary/
├── .gitignore # contains exactly: *
└── WORKFLOW.md
Example WORKFLOW.md:
---
name: note-summary
description: Summarize a temporary set of notes
goal: Summarize the provided notes into a concise brief
---
A simple one-step workflow that summarizes notes into a concise brief.
```dot
digraph note_summary {
Start -> Summarize -> End
Summarize [prompt="Summarize the notes for: $goal"]
}
```
Validated with: stencila workflows validate note-summary
.stencila/ directories exist in the ancestor chain, use the nearest one. Do not create a duplicate .stencila/workflows/ tree.TODO, <placeholder>, or empty description remains in the final WORKFLOW.md.dot block before reporting completion unless the user explicitly asks for documentation only.goal is optional — omit it if the user has not provided a stable objective. Use goal-hint when the workflow expects a user-supplied goal (the common case).agent.* attributes sparingly; prefer reusable agent definitions unless the user clearly needs a node-specific override.ephemeral: true; ephemeral workflows are identified solely by the .gitignore sentinel file containing *.Before finishing, validate the workflow:
# By workflow name
stencila workflows validate <workflow-name>
# By directory path
stencila workflows validate .stencila/workflows/<workflow-name>
# By WORKFLOW.md path
stencila workflows validate .stencila/workflows/<workflow-name>/WORKFLOW.md
Validation should pass before you report the workflow as complete.
documentation
An agent skill providing instructions for AI agents.
testing
Critically review a Stencila workflow and suggest improvements. Use when asked to review, audit, critique, evaluate, or improve a workflow directory or WORKFLOW.md file. Covers frontmatter validation, DOT pipeline quality, workflow structure, agent selection quality, discovery metadata, ephemeral workflow conventions, workflow composition, and adherence to Stencila workflow patterns.
development
Critically review an existing or proposed Stencila theme artifact for correctness, token usage, target coverage, cross-target portability, dark-mode handling, maintainability, and approval readiness. Use when asked to review, critique, assess, audit, or validate a theme.css file, theme patch, theme plan, site theme, document theme, plot theme, print or PDF theme, check design tokens, assess DOCX or email behavior, review dark mode support, or validate with stencila themes validate.
development
Create, update, or plan a Stencila theme for documents or published sites. Use when asked to choose a theme direction, write or patch theme.css, recommend semantic or module token families, customize site navigation or branding, tune PDF and print page tokens, align web, Python, and R plots with a Stencila design system, list available builtin tokens with `stencila themes tokens`, or validate a theme file with `stencila themes validate`.