Skip to main content
If you want a copy-paste cookbook after reading this reference, also see: If you are trying to answer any of these questions, start here:
  • Where do workflow files live?
  • What node types are available?
  • What do triggers do?
  • What is a run?
  • How do edges work?
  • How do I run one manually?
  • What does the runner do?
  • What does the worker do?
  • How do approvals work?
  • Why did a run fail or stop?
  • Why is posting still off after install?

Mental model

ClawRecipes workflows are file-first. That means:
  • workflow definitions live on disk
  • workflow runs live on disk
  • approvals live on disk
  • node outputs live on disk
  • debugging usually starts by reading files, not opening a database
This is intentional.

Where workflow files live

Workflow definitions live here inside a team workspace:
Example:

What a workflow file looks like

At a high level, a workflow file contains:
  • workflow metadata (id, optional name)
  • optional triggers
  • nodes
  • optional edges
Minimal example:

Available workflow node types

These are the current first-class node kinds supported by the runner.

Quick chooser

Use this when you are deciding what kind of node to add:
  • use start when you want a visible graph entry point
  • use end when you want a visible graph exit point
  • use llm when you want the workflow to generate or transform content with an LLM
  • use tool when you want the workflow to call a tool or side-effecting action
  • use human_approval when a person must approve before the workflow continues
  • use writeback when you want to append workflow breadcrumbs/results into team files
  • use media-image when you want to generate images as part of the workflow
  • use media-video when you want to generate video content as part of the workflow
  • use media-audio when you want to generate audio content as part of the workflow

start

Purpose:
  • visual or structural start node
  • useful in UI-authored workflows
  • treated as a no-op by the runner
What it does at runtime:
  • marks itself successful
  • does not perform work
Example:

end

Purpose:
  • visual or structural end node
  • used to make the workflow graph readable
  • treated as a no-op by the runner
What it does at runtime:
  • marks itself successful
  • does not perform work
Example:

llm

Purpose:
  • run an LLM step in the workflow
  • generate structured or text-like content and store it as node output JSON
Use it when:
  • you want to draft content
  • you want to transform or summarize earlier node output
  • you want a workflow step to reason over previous results before the next action
Required pieces:
  • assignedTo.agentId
  • either action.promptTemplatePath or action.promptTemplate
What it does:
  • builds a task prompt
  • calls llm-task-fixed if present, otherwise falls back to llm-task
  • passes upstream node output when available
  • writes result JSON into the run’s node-outputs/
Example using an inline prompt:
Example using a prompt template file:
Optional output path override:

tool

Purpose:
  • run a tool action during the workflow
Use it when:
  • you want to write a file
  • send a message
  • publish content
  • call another tool after an LLM step
Current behavior:
  • supports runner-native special handling for some tools
  • otherwise falls back to normal tool invocation by tool name
  • stores result/error artifacts in artifacts/
Currently important built-in / special-cased tools:

fs.append

Use when you want to append text into a file in the team workspace. Required args:
  • path
  • content
Example:
Notes:
  • path must stay within the team workspace
  • simple template vars are supported in args like {{date}}, {{run.id}}, {{workflow.id}}

outbound.post

Use when you want a workflow to publish externally through the supported outbound posting service. Required args:
  • platform
  • text
  • idempotencyKey
Required plugin config:
  • outbound.baseUrl
  • outbound.apiKey
Example:
For full posting details, see OUTBOUND_POSTING.md.

Other tool names

If a tool node references some other tool name, the runner will try to invoke that tool by name. Example:
Whether that works depends on your actual runtime/tool exposure.

human_approval

Purpose:
  • pause a workflow until a human approves or rejects
Use it when:
  • the workflow might publish externally
  • a human needs to review copy or generated content
  • the next step is risky enough that you do not want it to happen automatically
Required pieces:
  • assignedTo.agentId
  • action.approvalBindingId (or workflow-level fallback metadata that resolves to one)
What it does:
  • writes approvals/approval.json
  • sends an approval request message through the bound messaging target
  • changes run status to awaiting_approval
  • waits until you record a decision
Example:

writeback

Purpose:
  • append workflow run information back into one or more workspace files
Use it when:
  • you want a durable audit note in notes/ or shared-context/
  • you want workflow output to leave a breadcrumb for humans
  • you want the run to update a team file after the main work finishes
Required pieces:
  • assignedTo.agentId
  • action.writebackPaths[]
What it does:
  • appends a stamped workflow note with run/ticket context into the target file(s)
Example:

media-image

Purpose:
  • generate images using available media generation skills
Use it when:
  • you want to create visual content as part of a workflow
  • you need to generate images from text prompts
  • you want to create marketing visuals or illustrations
Required pieces:
  • assignedTo.agentId
  • either action.image_prompt or upstream node output with image prompt
What it does:
  • scans available skills for image generation capabilities
  • executes image generation via skill auto-discovery
  • writes generated image data to node outputs
Example:

media-video

Purpose:
  • generate video content using available media generation skills
Use it when:
  • you want to create video content as part of a workflow
  • you need to generate promotional or educational videos
  • you want to create dynamic visual content
Required pieces:
  • assignedTo.agentId
  • either action.video_prompt or upstream node output with video prompt
What it does:
  • scans available skills for video generation capabilities
  • executes video generation via skill auto-discovery
  • writes generated video data to node outputs
Example:

media-audio

Purpose:
  • generate audio content using available media generation skills
Use it when:
  • you want to create audio content as part of a workflow
  • you need to generate voiceovers or music
  • you want to create podcast content or audio narration
Required pieces:
  • assignedTo.agentId
  • either action.audio_prompt or upstream node output with audio prompt
What it does:
  • scans available skills for audio generation capabilities
  • executes audio generation via skill auto-discovery
  • writes generated audio data to node outputs
Example:

What is not currently a first-class built-in node type?

People often expect nodes like:
  • if
  • delay
  • switch
  • loop
Those are not currently first-class built-in node kinds in the runner code. So if you want branching today, use:
  • edges (success, error, always)
  • multiple nodes
  • approval or tool-mediated control flow
If you want waiting/delay behavior today, do it outside the runner with:
  • cron triggers
  • scheduled reruns
  • approval pause/resume
I’m calling this out explicitly so we don’t imply features that do not yet exist as first-class nodes.

Triggers

Triggers answer the question: “What causes a workflow run to be created?” In the current schema, a workflow may include triggers[]. Current workflow type shape:

What is currently supported in the type layer?

  • cron is the clearly documented trigger kind in the current workflow types
  • manual runs are also supported operationally via CLI, even though that is a run-time invocation mode rather than a trigger stored in the workflow file

Example trigger block

Human translation of that example:
  • run on weekdays
  • at 2:00 PM
  • in New York time

Manual trigger example

You can always create a run manually:

Runs

A run is one concrete execution of a workflow. If your workflow is the recipe, the run is the actual cooking session.

What a run records

A run stores:
  • workflow id/name/file
  • team id
  • run id
  • trigger information
  • current run status
  • node states
  • event history
  • node results
  • ticket/lane context when used

Common run statuses you will see

Examples include:
  • queued — the run exists and is waiting to be claimed
  • running — the runner/worker is actively moving it forward
  • awaiting_approval — the run is paused for human review
  • completed — the run finished successfully
  • rejected — approval was rejected and the run stopped there
  • needs_revision — a rejection pushed the run back into a revise-and-try-again path

Where a run lives

What else is inside the run folder?

  • node-outputs/ — output from nodes
  • artifacts/ — tool result payloads
  • approvals/approval.json — approval state when needed

Where workflow runs live

Every workflow run gets its own folder under:
Layout:
Important files:
  • run.json — the canonical run record
  • node-outputs/*.json — structured output from executed nodes
  • artifacts/ — tool output, payloads, or generated files
  • approvals/approval.json — approval record when the run is waiting on a human

Edges

Edges define how the workflow graph moves from one node to another. Current edge shape:

Supported on values

  • success
  • error
  • always

What they mean

success

Move to the target node if the source node completed successfully.

error

Move to the target node if the source node failed.

always

Move to the target node whether the source node succeeded or failed.

Important current semantics

The current runner behavior is intentionally simple:
  • if a node has explicit input.from, those dependencies behave like AND
  • if a node has incoming edges, edge satisfaction behaves like OR
    • meaning: if any incoming edge condition is satisfied, the node can run
Human translation:
  • input.from is “wait for all of these upstream node outputs”
  • incoming edges are “if any of these paths became valid, go ahead”
That is important. Do not assume complex boolean graph semantics unless you have built them explicitly.

Example: success path + failure path


The two moving parts: runner and worker

ClawRecipes splits workflow execution into two roles.

Runner

The runner is the scheduler. It:
  • claims queued runs
  • reads the workflow graph
  • decides what node can run next
  • enqueues node work for workers
  • records state transitions
Useful commands:

Worker

The worker is the executor. It:
  • pulls queued node tasks for one agent
  • runs the node
  • writes node output
  • updates run state
Useful command:

Run a workflow manually

If you want to trigger one run yourself:
This reads the workflow file from:
Then you usually follow with runner / worker execution:

Approval flows

Approval is a first-class workflow state. When a workflow reaches a human-approval node:
  • the run moves to awaiting_approval
  • ClawRecipes writes approvals/approval.json
  • the run stops until a decision is recorded

Approve a run

Reject a run

Resume a run after approval

Auto-resume recorded approvals


What run.json tells you

run.json is where you should look first when a workflow behaves strangely. It records:
  • workflow metadata
  • current run status
  • node state by node id
  • timestamps
  • append-only event history
  • error details when something fails
If you are debugging, read this before guessing.

Common debugging commands

Inspect recent runs on disk

Inspect one run

Inspect node outputs

Inspect approval record


Posting / publish behavior after install

This matters. A successful install gives you workflow support, but it does not guarantee that workflow publishing side effects are enabled in your environment. Use the runner-native outbound.post tool with a configured outbound posting service. See: OUTBOUND_POSTING.md

Local patched path

If you rely on a controller-local custom posting patch:
  • you may need to reapply that patch after install/update
  • you may need to tell your assistant to turn workflow posting back on
  • RJ’s current public gist for the marketing.post_all patch is: https://gist.github.com/rjdjohnston/2440a776529829e7d1c0d5d949f6e631
    • Note: Updated for current file structure (workflow-worker.ts vs old workflow-runner.ts)
So if a workflow runs but does not actually post, check your posting path before blaming the runner.

Typical end-to-end example

This is the operational sequence most people mean when they say, “run the workflow”:

End-to-end example: draft → approve → publish

Use this pattern when you want:
  • an LLM to draft content
  • a human to approve it
  • a tool step to publish it only after approval