Skip to content

Node catalog

Every node type a workflow can use, with its config fields, defaults and output branches.

These are the node types the workflow editor’s palette offers, with the fields its inspector shows and validates. This page is generated from the catalog itself when the docs are built, so it always matches what a workflow accepts. Each node’s anchor is its type, for example #control.approval.

A node’s outputs are the branches it can take. An edge leaves a node from one output (none means out); the edges on branches a node didn’t take are skipped, along with any node only they lead to. See Branches and edges.

Field kinds decide how a value is edited and checked:

  • duration is a string such as "2 days";
  • logic is a JSON Logic expression over the run;
  • list is a non-empty list of strings;
  • contentType, field and release are pickers for a content type, one of its fields, or a release;
  • text fields accept {{path}} templates. See Expressions and templates.

Every node also takes retries (0 to 10) and a timeout, outside its config. Nodes marked undo are reversed if the run later fails; nodes marked waits pause the run for a person or an event.

A workflow has exactly one trigger. It decides when a run starts and for which entry.

Submit for review

trigger.manual

Started by a person from the entry editor, POST …/entries/:id/workflow-runs, or the MCP server.

  • Outputsout

Entry created

trigger.entry_created

Started when an entry of the workflow’s content types is created.

  • Outputsout
FieldKindDefaultNotes
whenlogicOnly when. JSON Logic over the event (input) and entry; empty starts a run for every matching entry. The workflow’s content types already narrow it.

Entry saved

trigger.entry_saved

Started when a draft is saved. The event carries the new version and the changed fields (input.changedFields).

  • Outputsout
FieldKindDefaultNotes
whenlogicOnly when. JSON Logic over the event (input) and entry; empty starts a run for every matching entry. The workflow’s content types already narrow it.

Publish requested

trigger.publish_requested

Started when someone asks to publish an entry. The run decides whether, and when, it is published.

  • Outputsout
FieldKindDefaultNotes
whenlogicOnly when. JSON Logic over the event (input) and entry; empty starts a run for every matching entry. The workflow’s content types already narrow it.

Entry published

trigger.entry_published

Started after an entry is published.

  • Outputsout
FieldKindDefaultNotes
whenlogicOnly when. JSON Logic over the event (input) and entry; empty starts a run for every matching entry. The workflow’s content types already narrow it.

Entry unpublished

trigger.entry_unpublished

Started after an entry is unpublished.

  • Outputsout
FieldKindDefaultNotes
whenlogicOnly when. JSON Logic over the event (input) and entry; empty starts a run for every matching entry. The workflow’s content types already narrow it.

Release published

trigger.release_published

Started once for each entry in a release when the release is published.

  • Outputsout
FieldKindDefaultNotes
whenlogicOnly when. JSON Logic over the event (input) and entry; empty starts a run for every matching entry. The workflow’s content types already narrow it.
maxEntriesnumber100At most. Runs started per release; the rest are skipped and reported

Schedule

trigger.schedule

Started on a cadence for every entry the query matches (freshness reviews, periodic audits).

  • Outputsout
FieldKindDefaultNotes
cron (required)text0 9 * * 1Cron. Five fields, UTC
contentTypecontentTypeContent type. Empty uses the workflow’s content types
filterjson{}Filter. An entries query filter, e.g. { "fields.section": "news" }
maxEntriesnumber100At most

Content nodes act on the entry through the same operations as the admin and the API, with the same validation and events.

Validate entry

content.validate

Runs the content type’s field validation, the same checks publishing applies. Failures are in the output.

  • Outputsvalidinvalid

Policy check

content.policy

Checks editorial rules: required fields, word counts, forbidden terms, image alt text, references, publishing hours.

  • Outputspassfail
FieldKindDefaultNotes
rules (required)json[{"rule":"required_fields","fields":["title"]},{"rule":"has_alt_text"}]Rules. required_fields, min_words, max_words, forbidden_terms, has_alt_text, min_references, business_hours
localetextLocale. Empty checks whichever locale has a value

Publish

content.publishundo

Publishes the entry’s current version. Unpublished again if the run later fails, unless it has been republished since.

  • Outputsout
  • Undoreversed if the run later fails

Unpublish

content.unpublish

Takes the entry off delivery. Not undone if the run later fails.

  • Outputsout

Schedule

content.scheduleundo

Schedules the entry to publish or unpublish later. The schedule is cancelled if the run fails.

  • Outputsout
  • Undoreversed if the run later fails
FieldKindDefaultNotes
actionselectpublishAction. One of publish, unpublish
afterduration1 dayAfter
atlogicAt (expression). Epoch ms or an ISO date; overrides After

Add to release

content.add_to_releaseundo

Adds the entry to a release. Removed again if the run fails.

  • Outputsout
  • Undoreversed if the run later fails
FieldKindDefaultNotes
releaseId (required)releaseRelease

Publish release

content.publish_release

Publishes every entry in a release together.

  • Outputsout
FieldKindDefaultNotes
releaseId (required)release{{vars.releaseId}}Release

Set fields

content.set_fieldsundo

Writes field values (text interpolates {{paths}}). The prior values are restored if the run fails and nobody has edited the entry since.

  • Outputsout
  • Undoreversed if the run later fails
FieldKindDefaultNotes
values (required)json{}Values. { fieldApiId: value }
localetextLocale. Empty uses the default locale

Set tags

content.set_tagsundo

Adds, removes or replaces the entry’s tags. The prior tags return if the run fails.

  • Outputsout
  • Undoreversed if the run later fails
FieldKindDefaultNotes
tags (required)list["reviewed"]Tags
modeselectaddMode. One of add, remove, replace

Set stage

content.stage

Records the entry’s workflow stage (shown in the editor and returned by GET …/entries/:id/workflow).

  • Outputsout
FieldKindDefaultNotes
stepId (required)textin_reviewStage id
nametextIn reviewStage name
requiredScopeselectcontent:writeMove here needs. One of content:write, content:publish, content:manage, delivery:read, preview:read, search:read, space:admin, workflow:approve. The scope the legacy transition API requires to move an entry into this stage

Assign task

content.assignundo

Creates a task on the entry for a person. Resolved if the run fails.

  • Outputsout
  • Undoreversed if the run later fails
FieldKindDefaultNotes
assignee (required)texteditorAssignee
titletextReview “{{ref}}”Title
duedurationDue in

Comment

content.comment

Adds a comment to the entry (text interpolates {{paths}}).

  • Outputsout
FieldKindDefaultNotes
body (required)textareaPlease take a look at “{{ref}}”.Comment

Notify

content.notify

Emails people about the entry. Subject and message interpolate {{paths}}; each step sends once.

  • Outputsout
FieldKindDefaultNotes
to (required)listTo. Email addresses ({{paths}} allowed)
subjecttext“{{ref}}” needs attentionSubject
messagetextarea“{{ref}}” needs attention.Message

Webhook

content.webhook

Posts a JSON payload to a URL. String values interpolate {{paths}}.

  • Outputsout
FieldKindDefaultNotes
url (required)textURL
payloadjson{"entryId":"{{entry.id}}","title":"{{ref}}"}Payload

Condition

control.condition

Branches on a JSON Logic expression over the run context.

  • Outputstruefalse
FieldKindDefaultNotes
expression (required)logic{"in":["legal",{"var":"entry.tags"}]}Expression

Approval

control.approvalwaits

Waits for a person holding the required scope to approve or reject. Escalates when the timeout passes.

  • Outputsapprovedrejectedescalated
  • Waitsfor a person or an event
FieldKindDefaultNotes
titletextReview “{{ref}}”Title
assigneetexteditorAssignee
timeoutduration2 daysEscalate after
requiredScopeselectworkflow:approveWho may decide. One of content:write, content:publish, content:manage, delivery:read, preview:read, search:read, space:admin, workflow:approve. workflow:approve lets Approvers and up decide; content:publish keeps it to publishers
separateDutiesbooleanSeparate duties. Whoever started the run can’t decide. Unset follows the space default
instructionstextarea""Instructions. Shown in the approvals inbox

Wait for event

control.wait_eventwaits

Waits for an event: one delivered through the API or MCP, or one contentworker emits (entry.saved when the author revises).

  • Outputsreceivedtimeout
  • Waitsfor a person or an event
FieldKindDefaultNotes
event (required)textentry.savedEvent
timeoutduration7 daysTimeout

Wait

control.wait

Sleeps for a duration, or until a timestamp computed from the context.

  • Outputsout
FieldKindDefaultNotes
durationduration1 dayDuration
untillogicUntil (expression). Epoch ms; overrides duration

Set variables

control.set

Assigns run variables from JSON Logic expressions.

  • Outputsout
FieldKindDefaultNotes
assignjson{"cycle":{"+":[{"var":"vars.cycle"},1]}}Assignments. { name: expression }

Loop

control.loop

Repeats its body while the condition holds, up to a limit. Connect the end of the body back to the “next” input.

  • Outputsbodydone
  • Loopaccepts a next back-edge
FieldKindDefaultNotes
whilelogictrueWhile
maxIterationsnumber12Max iterations

Continue as new

control.continue_as_new

Ends this run and starts a fresh one on the same workflow, carrying the variables forward.

  • Outputsnone: ends the run

End

control.end

Finishes the run. “declined” is a policy or approval no; “failed” undoes every compensable step.

  • Outputsnone: ends the run
FieldKindDefaultNotes
outcomeselectcompletedOutcome. One of completed, declined, cancelled, failed
reasontext""Reason

AI nodes call the same AI features editors use, with the same validation; their results are proposals unless the node is set to apply them.

Classify

ai.classify

Assigns one label from a list (section, audience, intent) into a variable.

  • Outputsout
FieldKindDefaultNotes
labelslist["news","opinion","feature","how_to"]Labels
intotextcategoryStore as var

Agent router

ai.router

An LLM reads the entry and context, then chooses exactly one route. Each route is an output. Without a model answer it takes the last route.

  • Outputsone per configured route
FieldKindDefaultNotes
instructionstextareaDecide how this entry should be reviewed.Instructions
routeslist["publish","needs_review","ask_author"]Routes
guardsjson{}Guards. { route: JSON Logic } checked in code before the model’s choice is taken: a route whose guard fails can’t be chosen

Summarize

ai.summarize

Writes a short summary of the entry into a variable.

  • Outputsout
FieldKindDefaultNotes
intotextsummaryStore as var

Assess

ai.assess

A decision model reads the entry and returns a probability for every option of every question. Branches on one question.

  • Outputsone per configured route
FieldKindDefaultNotes
questionsjson{"stale":{"type":"noul","instructions":"Is this entry out of date: facts, dates, prices or links that no longer hold?"},"audience":{"type":"choice","instructions":"Who is this entry written for?","criteria":{"beginner":"New to the subject","practitioner":"Works with it day to day","expert":"Deep specialist knowledge assumed"}}}Questions. Question id → { type: noul | choice | score, instructions, criteria }. 1 to 64.
branchOntextstaleBranch on. A yes/no or choice question id. Empty: one output.
minConfidencenumber0Unsure below. Confidence 0–1. Above 0 adds an “unsure” output.
stateselectentry_and_contextState. One of entry, entry_and_context
intotextassessmentStore as var

Translate

ai.translate

Translates the entry’s localized fields into another locale and saves them.

  • Outputsout
FieldKindDefaultNotes
targetLocale (required)text{{vars.locale}}Into locale
sourceLocaletextFrom locale. Empty uses the default locale

Autofill field

ai.autofill

Drafts one field’s value from the rest of the entry (an excerpt, an SEO title).

  • Outputsout
FieldKindDefaultNotes
field (required)fieldField
localetextLocale. Empty uses the default locale
overwritebooleanfalseOverwrite. Off leaves a field that already has a value alone

Suggest tags

ai.suggest_tags

Suggests tags from the space’s taxonomy, into a variable or applied to the entry.

  • Outputsout
FieldKindDefaultNotes
intotextsuggestedTagsStore as var
applybooleanfalseApply

Enrich

ai.enrichwaits

Runs the enrich agent (SEO fields, summaries, tags). With review, its proposal waits in the approvals inbox.

  • Outputsone per configured route
  • Waitsfor a person or an event
FieldKindDefaultNotes
awaitReviewbooleantrueWait for review. Off applies the proposal at once
timeoutduration7 daysReview within

Moderate

ai.moderate

Runs the moderation agent. Anything it can’t check (no model answer) goes to “flagged”, never “clean”.

  • Outputscleanflagged
FieldKindDefaultNotes
instructionstextarea""House rules. Added to the moderation prompt
intotextmoderationStore as var