Skip to content

How it works

You saw a workflow in What Z.E.N. is. This page is the mechanical walkthrough: what Z.E.N. actually does between the moment a workflow fires and the moment the output lands somewhere you can read.

What happens when a workflow fires

You hit "run" in the Web UI, type zen workflow run morning-brief in the terminal, ask your agent to fire it, or a schedule wakes up. The trigger doesn't matter; the next sequence is the same.

  1. Z.E.N. looks up the workflow by name. It checks the project directory first (.zen/workflows/), then the global directory (~/.zen/workflows/), then bundled defaults. If two workflows share a name, the closer one wins.
  2. The run gets its own working directory. A separate folder so this run doesn't share files with whatever else is running. Each run is sandboxed.
  3. A run row goes into the local database. That's how the Dashboard knows about it, how zen run logs can find it, how a crashed run resumes from the right step.
  4. The DAG starts executing. Z.E.N. looks at the node list, finds nodes with no unresolved dependencies, fires them in parallel. As each node finishes, it unblocks whatever was waiting on it. The loop continues until every node is either done or the workflow is cancelled.

What a single node does

The exact behavior depends on the node type. The common case is a prompt node:

  1. The node's prompt text is rendered with variables. $BASE_BRANCH, $DOCS_DIR, anything the workflow defined under vars:, plus whatever previous nodes wrote to their outputs.
  2. Z.E.N. picks the provider for this node (Claude, Codex, Pi, set per-node or inherited from workflow defaults).
  3. The prompt goes to the provider. The response streams back.
  4. The response gets stored as that node's output, available to downstream nodes by node id.

Bash nodes run a shell command instead of a prompt. Subagent nodes hand off to a different model or a nested workflow. Approval nodes pause and wait for a human reply. Loop nodes run a body multiple times. Same general shape: input rendered, execution happens, output captured.

Where output lands

Two answers, depending on who fired the workflow.

You fired it directly (CLI, Web UI, schedule). The output goes wherever the last node writes it. A summary might land in your inbox via an email node. A draft might land in a Notion page. A research report might just print to your terminal. The workflow author decides; Z.E.N. just runs the steps.

Your agent fired it. The output goes back to the agent. Your Claude Code session, or OpenClaw, or Hermes, gets the final node's response and decides what to do with it. Usually that means quoting it back into the chat.

How the schedule loop works

The scheduler is a single in-process loop inside the daemon. It ticks every 60 seconds.

On each tick: query the database for schedules whose next_fires_at is in the past. For each one, check if the workflow is already running at the same working path (the lock). If yes, increment skip_count and move on. If no, fire it through the same dispatch path the CLI uses; the run goes into the database with scheduled_for: <next_fires_at>. Then compute the next fire time and update the schedule row.

Catch-up math handles missed fires. If your machine was asleep across three scheduled fires, the next wake either skips to now (the default) or replays the three missed windows back to back (catch_up: replay-missed-fires).

The scheduler is re-entrant safe. If a tick is still in flight when the next one is due, the second tick exits immediately.

When things crash

A node that throws marks the run as failed at that node. The run row stores the failure point and the inputs the failed node received. The next time you run the same workflow with resume: true, Z.E.N. picks up from the failed node instead of starting over.

A workflow that gets cancelled (via the Web UI, zen run cancel, or because a scheduled fire stepped on a running one) marks the run as cancelled, not failed. The two are distinct statuses everywhere they show up.

Next

AI that follows a recipe, not a conversation.