/workflows): a list, a canvas editor
(/workflows/new, /workflows/:workflowId/canvas), a run history per workflow
(/workflows/:workflowId/history) and a run detail page
(/workflows/:workflowId/executions/:executionId).
What it does
Composes automations from 15 node types in four categories. The registry (workflowNodeTypes query) is the single source of truth; the canvas draws from it.
Templates everywhere. Any
*_template field uses {{key.subkey}} against the data
flowing through the edge. Missing keys are left as the literal placeholder, dicts and
lists are JSON-serialised. A node may also declare an output_transform to reshape its
output before the next node.
Five ways a run starts.
- A Jira or GitHub webhook arrives for a connection; the trigger matcher finds active
workflows whose trigger node has that node type and
connection_id. - An external system posts to the generic webhook URL
POST /api/webhooks/workflow/{token}(no login; the token routes and, by default, authenticates). Optional HMAC signature verification and a header token can be turned on per webhook. Responses:202triggered or skipped by a guardrail,400bad JSON,401failed auth,413payload over the cap,404unknown or disabled token. - A schedule with target
workflowlaunches it on a cadence, passing the stored parameters plus a_sourceenvelope (see Schedules). - A user clicks run, which calls
executeWorkflowwith an optional trigger event. - An agent calls the built-in tools
olyros_list_workflow_capabilitiesandolyros_trigger_workflowagainst a workflow whoseapi_triggernode is discoverable.
auto_pause_after_failures consecutive failures, when max_concurrent runs are already
active, or when the cooldown_seconds since its last trigger have not elapsed. The skip
is recorded (webhook deliveries show skipped_guardrail).
Runs are first-class records. Each run is a WorkflowExecution with status
running, suspended (waiting on a dispatched task), completed or failed, plus
cost and token totals, the actor that started it (olyros_user, slack_user,
webhook, schedule), the trigger event, and one node execution per node with input,
output and error. Runs can carry cost tags (setWorkflowTags, workflowCostTags) and
can be cancelled (cancelWorkflowExecution).
Webhook deliveries are logged and replayable. Every inbound call to a generic
webhook leaves a delivery row with outcome (accepted, rejected_too_large,
rejected_bad_json, rejected_auth, skipped_guardrail, error), a payload preview,
content type and source IP (webhookDeliveries); an editor can replay one
(replayWebhookDelivery).
Who can use it
- Creating, editing, saving the graph, filing in a folder, cancelling and deleting
workflows: editor or admin (ability
workflow.manage). Reading workflows, their runs and node types: any company member. - Running a workflow: any company member who holds Run access on it (see Access); with no Run or View grants at all, that is everyone.
- Changing a workflow’s Access lists (
setWorkflowAccess): editor or admin (workflow.manage); each change writes aworkflow.access_updatedaudit event. - Reading or rotating a generic webhook’s secret and token, changing its settings and replaying deliveries: editor or admin.
- Listing node types (
workflowNodeTypes) has no company gate; it is static registry data for any authenticated user. - No plan or tier gate exists for workflows.
How to configure it
- Create the workflow (Workflows -> New):
createWorkflow(name, description, sourceSystem, connectionId, trustLevel). AconnectionIdrequiressourceSystem(jiraorgithub). It starts asdraft. - Draw the graph on the canvas and save:
saveWorkflowGraph(workflowId, nodes, edges). Each node has anode_type, label, position and aconfigvalidated against the node’s schema; aslack_messagenode must haveworkspace_id,agent_idandmessage_template. - Connect the trigger. Jira and GitHub triggers need the connection from
Integrations. A
webhooknode mints its URL on save; read it withwebhookForNode, harden it withupdateWebhookSettings(enabled, verifySignature, headerToken, maxPayloadKb), and rotate withregenerateWebhookToken/regenerateWebhookSecret(revealWebhookSecretshows the current secret once). - Set the guardrails and budget with
updateWorkflow(status, trustLevel, monthlyBudgetUsd, maxExecutionsPerTrigger, cooldownSeconds, maxConcurrent, autoPauseAfterFailures); setstatustoactiveto let triggers fire. - Test from the canvas Test tab: an
event_testnode emits a fixed payload, and for Jira the tab can fetch a real issue as a synthetic webhook (POST /api/jira/connections/{connection_id}/fetch-issue). - Watch runs in History and the execution detail page (
workflowExecutions,workflowExecution,recentWorkflowExecutions).
Access
Each saved workflow carries two abilities, Run (workflow.execute) and View
(workflow.view), granted to Olyros users, Slack users and Slack groups. The Access
section lives in the canvas under Workflow Settings, above Delete Workflow; a new,
unsaved workflow shows “Save the workflow to manage access.” instead.
- Who may grant: editors and admins (
workflow.manage), through the Access table (setWorkflowAccess(workflowId, ability, userIds, slackUserIds, slackGroupIds); anulllist leaves that kind unchanged). Viewers see the same table read-only. Admins and editors are subject to the lists like everyone else: there is no role bypass, and an admin who removes their own Run access loses the Run button until they add themselves back. - Run lets a person start the workflow from the web Run button (
executeWorkflow) and from agent chat (olyros_trigger_workflow). Run includes View. - View lets a person see the workflow listed as a capability
(
olyros_list_workflow_capabilities) without being able to run it. View-only subjects appear in the View row; subjects who hold Run appear there as muted “via Run” chips. - No grants at all means everyone; any grant means only the listed people and groups, in chat and on the web. A workflow with no Run and no View grant is open to every company member and to anyone the agent’s Slack bot can reach: the table reads “Everyone”. As soon as one person or group is granted anything, the workflow is closed to everyone else on every channel. Granting Run to the Slack group Sales closes the workflow to Slack users outside Sales and to company members on the web, except members whose linked Slack account is in Sales. Agents read their Chat grants with the same rule.
- View-only closes Run. Once a workflow has only View grants, nobody can run it; the
Run row then reads “No one”. The status line above the table summarises both rows
(
Run: Sales · View: Sales, Support, orRun: everyone). - What the agent tools show. A Slack or web user asking an agent what it can do sees
only the discoverable workflows they may View; with none, the tool answers “No workflow
capabilities are currently available.” Triggering a workflow the person may not View
answers as if it did not exist (
Error: workflow '<id>' not found.); triggering one they may View but not Run answers “Error: you don’t have access to run this workflow. Ask a workspace admin to grant it.” The web Run button is disabled with “You don’t have access to run this workflow”, and the server refusesexecuteWorkflowwith the same sentence. - Not affected: schedules, generic webhooks, Jira and GitHub triggers and workflow chains (a run started by another workflow) are system actors and always pass. A permitted person’s run of workflow A that triggers restricted workflow B runs B.
- Deleting a workflow removes its grants. A Slack group that any workflow or agent still lists cannot be deleted until it is removed from their Access settings.
- Slack users in the lists are keyed by workspace and user id, so the same Slack user id in a second workspace does not match. Picking a Slack user who is not yet in the workspace cache is allowed with a warning; the cache fills on their first message.
Folders
Folders organise a company’s workflows. Each folder belongs to one area: the folders created under Workflows hold workflows only and never appear under Schedules, which has its own folders (see Schedules). A workflow is in at most one folder, and a workflow in no folder is Unfiled. Filing a workflow changes nothing about how it runs, who may run it, or its triggers. Access grants stay on the workflow.- Who manages folders. Creating, editing (name, description, colour) and deleting a
folder needs the Editor role or higher (ability
folder.manage). Any member can see the folder list (folders(context: WORKFLOWS)). Folders are listed alphabetically, ignoring case;createFolder(context: WORKFLOWS, ...)creates one. - Who files a workflow. Editors and admins (
workflow.manage), like every other workflow edit:folderIdoncreateWorkflowandupdateWorkflow(omitted on update leaves it unchanged;nullmeans Unfiled), ormoveWorkflowsToFolder(workflowIds, folderId)for one or many workflows at once. A move is all or nothing. A Viewer is refused. Duplicating a workflow in the client keeps its folder: the copy is created with the original’sfolderId. - Deleting a folder never deletes workflows or schedules:
deleteFoldermoves both to Unfiled and deletes the folder in one step. A move into the folder that races the delete fails with “Folder not found”. - Listing.
workflowsPagefilters byfolderIdor byunfiledOnly(not both), andworkflowFolderCounts(statuses)returns the total, the Unfiled count and a count per folder for the same status filter. - Agents.
olyros_list_workflow_capabilitiesshows each listed workflow’s folder on its ownFolder:line. The display name is unchanged. - A Schedules folder, or a folder from another company, answers “Folder not found” when used to file, move or filter workflows, like an unknown id. The database also refuses filing a workflow in another company’s folder.
- Name, description and colour limits are those of schedule folders; names are unique per area, so a Workflows folder may share a name with a Schedules folder.
- Existing folders (November 2026). Before areas existed, one folder could hold both. On upgrade, a folder holding only workflows moved to Workflows. A folder holding both stayed under Schedules, and a copy with the same name, colour and description was created under Workflows, holding its workflows.
Limits and defaults
What it emits
WorkflowExecutionandWorkflowNodeExecutionrows with cost, tokens, actor and tags, visible in History and in usage reporting.- Cloud tasks created by
create_task, linked back so the run resumes when the task finishes. - Side effects in connected systems: Jira issues, transitions, comments and labels; GitHub issues, labels and comments; Slack messages posted as an agent.
- Webhook delivery rows for generic webhooks (replayable).
- For scheduled runs, the outcome feeds the schedule’s failure counter.
workflow.access_updatedaudit events (ability, before and after lists) for every change to the Access table;access_deniedlog lines (ids only) for refused runs.
Known gaps
- No schedule trigger node: cadence comes from a
TaskScheduleoutside the graph, and the graph still needs its own trigger node for the editor. - No approval or question node: a human gate has to be modelled through Jira (a status
change or label fires
jira_event). Workflow-run human-in-the-loop is designed but not built. - No for-each, HTTP request, code or email node;
create_jira_ticketcreates exactly one issue per run, so fan-out needs several nodes. trust_level,monthly_budget_usdandmax_executions_per_triggerare stored and validated but no code reads them at run time.github_actioncannot open a pull request; a task can push a branch but the PR is manual.- Jira has no issue search, so a workflow cannot ask “is there already a ticket for
this?” before
create_jira_ticket. - A suspended run resumes only when its dispatched task reaches a terminal state; there is no per-node timeout.