Skip to content

Visual Workflows ​

Build complex automation flows with a drag-and-drop workflow editor.

Overview ​

The workflow editor provides:

  • 30+ node types for various operations
  • Drag-and-drop interface
  • Real-time preview of workflow structure
  • Execution tracking and history
  • Error handling and retries

Creating Workflows ​

Via Dashboard ​

  1. Navigate to Workflows in the sidebar
  2. Click New Workflow
  3. Drag nodes from the palette
  4. Connect nodes by dragging from output to input handles
  5. Configure each node's properties
  6. Save and activate the workflow

Workflow Canvas ​

The canvas provides:

  • Zoom and pan controls
  • Mini-map for navigation
  • Grid snapping
  • Undo/redo
  • Copy/paste nodes

Node Categories ​

Triggers ​

NodeDescription
triggerStart point for workflow
webhookHTTP webhook trigger
scheduleTime-based trigger

Logic ​

NodeDescription
if-elseConditional branching
switchMulti-way branching on a value
decisionModel-judged branching — see Decision node
approvalApproval Gate: ask a human over a gateway, wait durably, route approved / rejected — see Approval Gate
await-eventPause until an external event arrives (or time out) — see Await Event
loopIterate over arrays
waitDelay execution
parallelRun branches concurrently

HTTP & API ​

NodeDescription
http-requestMake HTTP requests
webhook-responseRespond to webhooks
graphqlGraphQL queries

Communication ​

NodeDescription
emailSend emails
telegramTelegram messages
slackSlack messages
discordDiscord messages
whatsappWhatsApp messages
smsSMS messages

Social Media ​

NodeDescription
post-linkedinPost to LinkedIn via UGC Posts API
post-xPost to X (Twitter)
post-instagramPost to Instagram
post-youtubeUpload to YouTube
post-tiktokUpload to TikTok

Browser Automation ​

NodeDescription
navigateGo to URL
clickClick element
typeEnter text
extractExtract content
screenshotCapture screenshot
scrollScroll page

AI & LLM ​

NodeDescription
chatAI conversation
promptSingle prompt completion
tool-callInvoke agent tools
embeddingsGenerate embeddings
ai-agentDelegate a task to an agent and get a typed result back — see AI Agent node

Data Operations ​

NodeDescription
database-querySQL queries
transformData transformation
filterFilter arrays
aggregateAggregate data

Utilities ​

NodeDescription
codeExecute JavaScript
variableSet/get variables
logLog messages
errorThrow errors

Decision node ​

The Decision logic node branches on a judgement rather than a value. Its outputs are the node's outflow labels; each label gets a short description, and the Jev typed-decision model picks one of them from the node's state (the trigger payload or a template).

Acceptance rules (resolveDecision() in agent/jev.ts, emitted verbatim into generated Worker code so interpreter and deployed workflows agree):

  • the chosen option must reach the threshold (default 0.6), and
  • it must beat the runner-up by the margin (default 0.15).

Otherwise the node takes its default output — the one labelled default (or *); when none is, the last output is the silent fallback and the node panel warns which one that is. Any error or timeout also routes to the default. Inside a Workflow the Jev call runs within step.do with two retries, so a cold start is retried before falling back; the timeout is 10 s there (4 s in the interpreter).

Approval Gate ​

The Approval Gate logic node pauses a workflow until a human says yes or no. Configuration: the question, the gateway to send it on, the recipient, a timeout in seconds (default 3600), and what to do on timeout (reject by default).

How it runs:

  1. The step calls POST /api/agents/{agentId}/workflows/approvals/request on the agent (AGENT_BASE_URL + AGENT_API_KEY), which sends the question with approve / reject links over the chosen gateway. The links are public workflow.uranus.im/{slug}/events/{name}?executionId=… URLs, so a tap in WhatsApp or Telegram answers.
  2. The generated step waits durably with step.waitForEvent (after a D1 pre-check for an answer that already arrived); the interpreter polls for up to 45 s.
  3. The answer routes to the approved or rejected output; a timeout follows the configured policy.

Await Event ​

Await Event pauses until a named event is delivered for this execution, or times out. Deployed workflows wait on step.waitForEvent(type, timeout) with a D1 pre-check before and a final check on timeout, so an event that arrives while the Worker was between steps is not lost. Nodes wired to the received output only run when the event arrived, not on timeout.

Events reach a running instance two ways, both of which also write the workflow_events row that older deployments poll:

RouteWho calls it
POST /api/agents/{agentId}/workflows/events/{eventName} { executionId, data } (or GET …?executionId=…&k=v for clickable links)external systems, the agent's add_workflow_event tool
POST https://<workflow-worker>/events/{instanceId} { type, payload }the agent, forwarding to the instance's sendEvent

AI Agent node ​

AI Agent delegates a task to an agent — the workflow's own agent or another one — and returns its reply. It takes a task template, a context object, and an optional output schema (JSON Schema). With a schema the agent returns data.structured, the step checks the required keys are present, and a mismatch fails the step so Workflows retries it; the result then carries both response and structured. In the interpreter the node really runs (the agent's own LLM for self-delegation, the Durable Object binding for other agents) rather than returning a placeholder.

Deployed workflows call back into the agent with AGENT_BASE_URL and AGENT_API_KEY, which the deployer injects (see Supporting Services).

Node Configuration ​

Each node has configurable properties accessed in the side panel.

Example: HTTP Request ​

json
{
  "type": "http-request",
  "data": {
    "method": "POST",
    "url": "https://api.example.com/data",
    "headers": {
      "Authorization": "Bearer {{secrets.api_key}}"
    },
    "body": {
      "message": "{{previous.output}}"
    }
  }
}

Variables & Expressions ​

Syntax ​

Use double curly braces for dynamic values:

{{variable.path}}
{{previous.output}}
{{context.user.email}}
{{secrets.api_key}}

Available Contexts ​

ContextDescription
previousOutput from previous node
triggerTrigger node data
contextWorkflow context
secretsStored secrets
envEnvironment variables

Execution ​

Manual Trigger ​

Click the Run button to execute immediately.

Scheduled Trigger ​

Link to a schedule for automatic execution.

Webhook Trigger ​

Create a webhook URL for external triggers.

Execution Status ​

StatusDescription
queuedWaiting to start
runningCurrently executing
completeFinished successfully
erroredFailed with error
terminatedManually stopped

Error Handling ​

Retry Configuration ​

json
{
  "retry": {
    "attempts": 3,
    "delay": 60,
    "backoff": "exponential"
  }
}

Error Handlers ​

Add error handler nodes to catch and handle failures.

Best Practices ​

1. Start Simple ​

Begin with 2-3 nodes and add complexity gradually.

2. Use Descriptive Names ​

Name nodes clearly: fetch-user-data not node-1.

3. Handle Errors ​

Always include error handling nodes.

4. Test Thoroughly ​

Test each execution path before going live.

5. Monitor Executions ​

Review execution history regularly.

Agent integration ​

Workflows aren't just user-built artifacts that the agent invokes. They participate in the agent's reasoning loop: linked to goals, recalled from memory, proposed by reflection, discovered semantically.

Goal linkage ​

A workflow can be attributed to one or more agent goals via the goal_workflows table. When execute_workflow(workflow_id, ..., goal_id=...) runs, two things happen:

  1. The link is auto-created on first run (INSERT OR IGNORE INTO goal_workflows).
  2. On completion the goal's progress_notes get a new line ([YYYY-MM-DD] workflow_name: completed|failed).

list_goals returns linked workflow names per goal; list_workflows returns linked goal descriptions per workflow. The system prompt's "Active Goals" section shows linked workflows inline so the agent doesn't re-derive the mapping each turn.

Role values in goal_workflows:

RoleMeaning
achievesCompleting this workflow completes the goal
advancesEach run pushes the goal forward (default)
evaluatesWorkflow checks goal status or produces evidence

Outcomes → memory ​

Every workflow execution (success or failure) gets summarized via summarizeWorkflowOutcome (background, glm-4.7-flash) and written to a memory key:

memory:workflow:{YYYY-MM-DD}:{slug}:{success|failure}

The summary is embedded into Vectorize so the next time the agent considers running a similar workflow, prior outcomes surface via semantic recall. Failures are stored at higher confidence (0.7) than successes (0.5) — failure modes outrank successes when the model is deciding what to try.

Throttled to one summary per workflow per 60s to prevent spam from rapidly-cycling workflows.

Reflection proposals ​

Reflection can propose new workflows when it notices recurring patterns. Output schema:

json
{
  "proposed_workflows": [
    {
      "description": "Auto-tag incoming receipts",
      "trigger_kind": "gateway_event",
      "outline": "Step 1: detect attachment...\nStep 2: ..."
    }
  ]
}

These insert as rows with status='draft' and source='reflection'. They appear in the existing Workflows UI tab (filterable by status). The agent never auto-activates — activate_draft_workflow requires user approval.

Semantic discovery ​

find_workflow_for_goal(goal) queries Vectorize over workflow embeddings instead of doing an LLM match. Each workflow is embedded with its description + node-type summary into the shared vector index (tagged metadata.type = "workflow"). On a goal query:

  1. Embed the goal text.
  2. Vectorize query, top-5, score ≥ 0.55.
  3. Return the best match with confidence (high ≥ 0.75, medium ≥ 0.65, otherwise low) plus up to two alternates.
  4. Fall back to the prior LLM matcher if no semantic hits.

When workflows get embedded:

  • createWorkflow LLM tool — embeds on create (ctx.waitUntil)
  • activateDraftWorkflow — embeds when draft → active
  • Editor save (PUT /workflows/{id}) — re-embeds when name/description/nodes change
  • Daily reindex-workflows cron at 05:00 UTC — catches any drift; hash-gated so unchanged workflows are skipped

Goal context in workflow execution ​

When a run is attributed to a goal, the workflow trigger payload includes a goal object:

js
{
  trigger: "chat",
  input: {
    ...conversationContext,
    goal: {
      id: "abc-123",
      description: "Send weekly summary to Acme",
      progress_notes: "..."
    },
    ...userInputs
  }
}

Workflow nodes can reference this via the existing interpolation syntax:

{{trigger.goal.description}}    →  "Send weekly summary to Acme"
{{trigger.goal.progress_notes}} →  "...accumulating log..."

No codegen change was needed — the interpolation engine resolves dotted paths against ctx.input.

Run stats ​

list_workflows returns 30-day rollup stats per workflow so the LLM picking between candidates sees reliability data:

json
{
  "id": "...",
  "name": "Daily standup",
  "stats_30d": {
    "runs_total": 30,
    "runs_failed": 2,
    "failure_rate": 0.07,
    "avg_duration_ms": 8421,
    "last_run_at": "2026-05-14T08:00:00Z"
  }
}

Reflection's gatherSignals also surfaces a per-workflow rollup so the LLM can say "workflow X failed 12/15 times this week" instead of just "12 failures."

Callbacks from workflows to the agent ​

Deployed workflows can call back into the agent for memory, messaging, contact lookup, and event emission. See Workflow → Agent RPC for the HMAC envelope, whitelisted methods, and rate limits.

Schema ​

TablePurpose
workflowsWorkflow definitions (nodes/edges JSON), now with source and callback_secret columns
workflow_executionsPer-run state + outputs + duration
workflow_eventsAsync event stream for await-event nodes
goal_workflowsMany-to-many linkage to agent_goals
workflow_embeddingsVectorize ID registry with content hash

API Reference ​

See Workflows API for complete endpoint documentation.