Workflows Guide

Workflows are multi-step operations that chain tools together with durable state persistence. They are the preferred way to run skills programmatically because they handle execution queueing automatically.

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?

The One-Execution-At-A-Time Rule

Each workspace can only have one skill execution running at a time. If you start a second execution while one is in progress, you get an EXECUTION_RUNNING error.

This ensures quality and resource management, but it makes running several skills in sequence awkward — you’d have to wait for each to finish before starting the next.

Workflows Solve This

Workflows handle the queueing for you. When a step needs to execute a skill but the slot is occupied:

  1. The workflow pauses automatically
  2. It waits for the current execution to finish
  3. When the slot frees up, it resumes and continues

This happens transparently — no manual intervention.

Additional Benefits

  • Durability — workflow state is persisted server-side. If the server restarts, the run continues from where it left off.
  • Multi-step operations — chain skills and connector operations into pipelines.
  • Error recovery — a single step failing doesn’t lose previous step results.

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]

If you’re already running another skill, the workflow suspends and resumes automatically — no error, no retry.

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://clanker.net/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 runGET /api/v1/workflows/runs/:runId until the status is terminal (completed / failed / cancelled).
  2. Stream itGET /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 a free execution slot or human input (resume to continue)
completedAll steps finished successfully
failedExecution failed
cancelledCancelled by the user

Suspended for an Execution Slot

This is the automatic queueing in action. When a run is suspended waiting on a slot:

  • Another skill execution is currently running
  • The workflow will resume automatically when the slot frees up
  • No action needed from you

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 (fails if busy)1 active, auto-queues
Multi-stepNoYes
State persistenceIn-memoryDurable, server-persisted
Crash recoveryLostResumes

When to use direct execution: simple interactive use from the dashboard or an MCP/IDE client. Not suited to bots or CI/CD.

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

MCP Tools Reference

One workflow tool is exposed over MCP: start-workflow. Workflow discovery and run management are 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": {
    "workflowId": "deep-research",
    "workflowName": "Deep Research Report",
    "inputs": { "topic": "solid-state batteries" }
  }
}

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://clanker.net/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 queued behind another execution and will auto-resume.
  5. Always handle failure — a run can end failed; check the terminal status.

Next Steps