# Workflows

Workflows are node graphs (automations) in a Space. A workflow has a draft
definition and, once published, an immutable active version. workflows.get
returns draft, published version, webhooks, trigger status and shares.

Build flow: workflows.create (starts with one manual trigger node) ->
workflows.node_kinds with detail=summary (keys, descriptions and ports of every
kind) -> workflows.node_kinds with kinds=[...] and detail=full for each kind you
add (its JSON config schema, default config and output schema; take config
fields and port names only from there, never guess them) -> workflows.draft.save
with the full definition and the current expected_revision (409 on stale
revision; the response lists non-blocking validation issues) ->
workflows.validate to check without saving -> workflows.publish (validates,
creates the active version, registers schedule and event triggers, creates
webhooks). Node kinds: trigger.manual, trigger.schedule, trigger.event, trigger.webhook, skill, wait, approval. Every node has an id, a kind, config and
connections between ports; items flow between nodes as JSON lists. A skill node
needs only skill_id: the items of its predecessor reach the Skill run as
input/items.jsonl in the run's working directory (plus their document
references in the scope), and the Skill's declared outputs come back as items
(an items output as one item per element, a sheet as one item per row, a doc as
one item with its text). Chain skills instead of mapping fields; input_mapping
and instruction stay available for explicit values.
workflows.rename changes the name at once; workflows.draft.discard drops the
draft of a published workflow and keeps the active version (an unpublished
workflow is archived instead).

Schedules (trigger.schedule config, also skills.automation.set and import
sources): prefer kind=rule, a structured rule with unit (minute, hour, day,
week, month, year), every, times (HH:MM in the schedule timezone) and for
months a list of `on` selectors. Every 14th: on=[{type: month_day, day: 14}];
last day of the month: day=-1; first Monday: {type: nth_weekday, nth: 1,
weekday: 1}; last workday: {type: nth_weekday, nth: -1, weekday: workday};
last day of week 4 of the month: {type: month_week, week: 4, day: last}; ISO
week 3 of the year: unit=year with {type: year_week, week: 3, day: first};
every second week needs every=2 plus start_date. kind=cron stays available
for five-field expressions (L = last day of month, 1#1 = first Monday, L5 =
last Friday; day-of-month and day-of-week together match either one),
kind=once runs a single time. Call workflows.schedule.preview with the
schedule to validate it and to tell the user the next run times before
publishing.

Running: workflows.runs.start runs a published workflow from its manual
trigger; workflows.runs.get, workflows.runs.events (cursor) and
workflows.runs.node_items show progress and data. workflows.runs.resume decides
an open approval node; workflows.approvals.list shows open approvals.
workflows.runs.retry starts a new run from a finished one.

Lifecycle: workflows.set_enabled pauses or resumes the triggers,
workflows.archive removes triggers and keeps history, workflows.delete only
works on archived workflows without runs. workflows.restore copies an earlier
version into the draft (publish afterwards). workflows.share manages access for
other users of the Space. workflows.webhooks.rotate issues a new webhook URL
and secret (the old URL stops working).
