Skip to main content
A workflow is a small graph a company draws on a canvas: one trigger node starts a run, logic nodes filter and route the event, AI nodes hand work to an agent, and action nodes write back to Jira, GitHub or Slack. Workflows live in the client app under the Tasks sidebar group as Workflows (/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.
  1. 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.
  2. 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: 202 triggered or skipped by a guardrail, 400 bad JSON, 401 failed auth, 413 payload over the cap, 404 unknown or disabled token.
  3. A schedule with target workflow launches it on a cadence, passing the stored parameters plus a _source envelope (see Schedules).
  4. A user clicks run, which calls executeWorkflow with an optional trigger event.
  5. An agent calls the built-in tools olyros_list_workflow_capabilities and olyros_trigger_workflow against a workflow whose api_trigger node is discoverable.
Guardrails before every start. A workflow is skipped when it has reached 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 a workflow.access_updated audit 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

  1. Create the workflow (Workflows -> New): createWorkflow(name, description, sourceSystem, connectionId, trustLevel). A connectionId requires sourceSystem (jira or github). It starts as draft.
  2. Draw the graph on the canvas and save: saveWorkflowGraph(workflowId, nodes, edges). Each node has a node_type, label, position and a config validated against the node’s schema; a slack_message node must have workspace_id, agent_id and message_template.
  3. Connect the trigger. Jira and GitHub triggers need the connection from Integrations. A webhook node mints its URL on save; read it with webhookForNode, harden it with updateWebhookSettings(enabled, verifySignature, headerToken, maxPayloadKb), and rotate with regenerateWebhookToken / regenerateWebhookSecret (revealWebhookSecret shows the current secret once).
  4. Set the guardrails and budget with updateWorkflow(status, trustLevel, monthlyBudgetUsd, maxExecutionsPerTrigger, cooldownSeconds, maxConcurrent, autoPauseAfterFailures); set status to active to let triggers fire.
  5. Test from the canvas Test tab: an event_test node 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).
  6. 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); a null list 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, or Run: 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 refuses executeWorkflow with 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.
Agents use the same model with one ability, Chat; see Agents. The roles and their abilities are listed on Company settings.

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: folderId on createWorkflow and updateWorkflow (omitted on update leaves it unchanged; null means Unfiled), or moveWorkflowsToFolder(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’s folderId.
  • Deleting a folder never deletes workflows or schedules: deleteFolder moves 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. workflowsPage filters by folderId or by unfiledOnly (not both), and workflowFolderCounts(statuses) returns the total, the Unfiled count and a count per folder for the same status filter.
  • Agents. olyros_list_workflow_capabilities shows each listed workflow’s folder on its own Folder: 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

  • WorkflowExecution and WorkflowNodeExecution rows 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_updated audit events (ability, before and after lists) for every change to the Access table; access_denied log lines (ids only) for refused runs.

Known gaps

  • No schedule trigger node: cadence comes from a TaskSchedule outside 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_ticket creates exactly one issue per run, so fan-out needs several nodes.
  • trust_level, monthly_budget_usd and max_executions_per_trigger are stored and validated but no code reads them at run time.
  • github_action cannot 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.

Customer-safe summary

Workflows let your team automate what happens around your agents without writing code. You draw a small flow: it starts from a Jira or GitHub event, an incoming webhook, a schedule, a button, or a request from one of your agents; it can filter and branch on the event; it can hand the work to an agent and wait for the result; and it can update Jira, comment on GitHub or post to Slack when done. Every run is recorded with its cost, who or what started it, and what each step produced, and you can replay an incoming webhook or cancel a run. Safety limits pause a workflow that keeps failing, cap how many runs happen at once, and space out repeated triggers. You choose who may run each workflow and who may merely see it offered in chat, by person or by Slack group, on the web and in Slack separately.