Workflows Guide

Workflows are multi-step operations that chain tools, connector actions and agent steps together with durable state persistence. They are the preferred way to run multi-step automation programmatically because a run survives restarts and can be started, watched, paused and cancelled by ID.

Workflows are started two ways:

  • Manual — launch via the REST API or MCP
  • In chat — the workspace agent assembles and runs a workflow from a natural-language request

Why Use Workflows?

A workflow runs on a durable executor, not inside a single request or a single sandbox, and it does not hold your one tracked-execution slot. (Each user can have only one skill execution running at a time; a second returns EXECUTION_RUNNING.)

  • Durability — workflow state is persisted server-side. If the server restarts, the run continues from where it left off.
  • Multi-step operations — chain tool calls, connector operations and agent steps into pipelines.
  • Error recovery — a single step failing doesn’t lose previous step results.
  • Human in the loop — a run can suspend to wait for input and resume when you answer.

Launching a Workflow

Each workflow has a kebab-case workflowId (e.g. deep-research, pr-review, analyse-csv) and an inputs schema. List the available workflows first (GET /api/v1/workflows) to discover valid IDs and their inputs.

Via the Chat Agent

The easiest path is chat. The agent assembles and runs a workflow for you:

You: "Research the current state of solid-state batteries"
Agent: [proposes the deep-research workflow]
You: [confirm]
Agent: [workflow runs, shows results inline]

Via MCP

{
  "tool": "start-workflow",
  "arguments": {
    "workflow_id": "deep-research",
    "inputs": { "topic": "the current state of solid-state batteries" }
  }
}

Via REST API

curl -X POST https://next.clanker.engineer/api/v1/workflows/deep-research/launch \
  -H "x-api-key: ck_live_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": { "topic": "the current state of solid-state batteries" }
  }'

Response:

{
  "runId": "wf_abc123",
  "workflowId": "deep-research",
  "status": "started",
  "conversationId": null
}

Multi-Step Workflow Examples

Example 1: Deep Research

deep-research searches several angles of a topic and synthesizes the findings into a structured report:

{
  "tool": "start-workflow",
  "arguments": {
    "workflow_id": "deep-research",
    "inputs": { "topic": "the current state of solid-state batteries" }
  }
}

This workflow:

  1. Gathers sources on the topic
  2. Follows up on recent developments
  3. Synthesizes the results into a report artifact

Example 2: Pull Request Review

pr-review fetches a GitHub pull request and produces a structured summary (requires the GitHub connector):

{
  "tool": "start-workflow",
  "arguments": {
    "workflow_id": "pr-review",
    "inputs": { "owner": "my-org", "repo": "my-repo", "pullNumber": 42 }
  }
}

Retrieving Results

A launched run is asynchronous. Get its outcome one of these ways:

  1. Poll the run — GET /api/v1/workflows/runs/:runId until the status is terminal (completed / failed / cancelled).
  2. Stream it — GET /api/v1/workflows/runs/:runId/events streams a run’s live step events over SSE (use the runId from launch).
  3. In chat — a workflow started from a conversation reports completion back into that thread automatically.

Workflow States

StatusDescription
runningActively executing steps
suspendedPaused awaiting human input (resume to continue)
completedAll steps finished successfully
failedExecution failed
cancelledCancelled by the user

Suspended for input

A suspended run is waiting for something only you can give, such as approval of a step. Resume it with POST /api/v1/workflows/runs/:runId/resume.

Monitoring Workflow Runs

List your runs

GET /api/v1/workflows/runs

Get run details

GET /api/v1/workflows/runs/:runId
{
  "run": {
    "runId": "wf_abc123",
    "workflowId": "deep-research",
    "status": "completed"
  },
  "steps": [
    {
      "stepId": "initial-search",
      "status": "completed",
      "output": {
        "executionId": "exec_456",
        "artifactId": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
      },
      "completedAt": "2026-02-12T10:00:30.000Z"
    }
  ]
}

Cancel a run

POST /api/v1/workflows/runs/:runId/cancel

Workflows vs Direct Skill Execution

FeatureDirect ExecutionWorkflow
TriggerAPI/MCP callAPI / MCP / chat
Concurrent runs1 per user (fails if busy)Durable runs, not counted against the execution slot
Multi-stepNoYes
State persistenceIn-memoryDurable, server-persisted
Crash recoveryLostResumes

When to use direct execution: one tracked skill run you want to stream, poll and cancel. In chat, asking the agent to use a skill is a third path: it carries the skill out in its own sandbox and creates no execution.

When to use workflows: bot integrations, CI/CD pipelines, and any automation that needs reliability, multi-step chaining or schedules.

MCP Tools Reference

start-workflow launches a workflow over MCP; search-workflows finds the ID, and list-schedules, set-schedule and unset-schedule manage schedules. Run management (list, inspect, cancel, resume) is done through the REST API. See Workflow MCP Tools for full details.

start-workflow

Start a workflow by ID.

{
  "tool": "start-workflow",
  "arguments": {
    "workflow_id": "deep-research",
    "inputs": { "topic": "solid-state batteries" }
  }
}

Response:

{
  "success": true,
  "data": {
    "runId": "wf_abc123",
    "workflowId": "deep-research",
    "conversationId": null
  }
}

To check on a run afterward, poll GET /api/v1/workflows/runs/:runId.

Node.js Bot Example

A minimal bot that starts a workflow and polls for the result:

import express from "express";

const app = express();
app.use(express.json());

const CLANKER_API_KEY = process.env.CLANKER_API_KEY;
const BASE_URL = "https://next.clanker.engineer/api";

async function pollRun(runId) {
  while (true) {
    const res = await fetch(`${BASE_URL}/v1/workflows/runs/${runId}`, {
      headers: { "x-api-key": CLANKER_API_KEY },
    });
    const { run } = await res.json();
    if (["completed", "failed", "cancelled"].includes(run.status)) return run;
    await new Promise((r) => setTimeout(r, 2000));
  }
}

app.post("/webhook", async (req, res) => {
  res.sendStatus(200);
  const { input } = req.body;

  const launch = await fetch(`${BASE_URL}/v1/workflows/deep-research/launch`, {
    method: "POST",
    headers: {
      "x-api-key": CLANKER_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ inputs: { topic: input } }),
  });

  const { runId } = await launch.json();
  const run = await pollRun(runId);
  console.log(`Workflow ${runId} finished: ${run.status}`);
});

app.listen(3000);

Best Practices

  1. Store run IDs — track runs in your database for audit trails.
  2. Poll or stream for results — use GET /workflows/runs/:runId, or the GET /workflows/runs/:runId/events SSE endpoint; don’t assume synchronous completion.
  3. Handle long runs — workflows with several LLM steps can take many minutes.
  4. Watch for suspended — it means the run is waiting for input; resume it when you have answered.
  5. Always handle failure — a run can end failed; check the terminal status.

Next Steps