KB LabsDocs

Workflow Engine

Last updated April 7, 2026


Jobs, steps, triggers, and artifacts.

The workflow engine orchestrates multi-step jobs across plugins. Workflows are declarative, have typed inputs and artifacts, and can run on schedules, webhooks, or be triggered manually. A workflow is the right tool when you need to chain several plugin operations together, run them with dependencies, or run them automatically in response to an event.

This page covers the mental model. For hands-on usage see Guides → Your First Workflow. For the full spec see Workflows → Spec Reference.

What a workflow is

A workflow is a YAML (or JSON) document that describes a graph of jobs, where each job contains an ordered list of steps. Each step calls a plugin handler, an inline shell command, or another workflow.

YAML
id: ai-review
name: AI Code Review
version: "1.0.0"
 
on:
  push:
    branches: ["main"]
 
jobs:
  review:
    steps:
      - id: diff
        uses: "@kb-labs/commit-plugin/git:diff"
        with:
          base: ${{ inputs.base }}
 
      - id: analyse
        uses: "@kb-labs/ai-review-plugin/review:run"
        with:
          diff: ${{ steps.diff.outputs.diff }}
 
      - id: comment
        uses: "@kb-labs/commit-plugin/github:comment"
        with:
          body: ${{ steps.analyse.outputs.summary }}

A workflow is not a script. You don't write imperative code — you declare what to run, what its inputs are, what its outputs are, and in what order. The workflow daemon resolves the dependency graph and schedules execution.

Workflows vs plugin commands

Both workflows and plugin CLI commands call plugin handler code. The difference is scope and lifecycle:

Plugin commandWorkflow
Invocationpnpm kb <cmd>kb workflow:run or trigger
CoordinationSingle handlerMultiple handlers across plugins
StateEphemeral (handler returns)Persisted (jobs, artifacts, logs)
TriggersManual onlyManual, push, schedule, webhook
Long-runningNo (CLI blocks)Yes (daemon manages lifecycle)

Use a plugin command for a single-purpose tool. Use a workflow when you need to compose commands, pass artifacts between steps, or run things on a schedule.

Jobs and steps

A workflow contains one or more jobs. Jobs run in parallel by default unless you declare dependencies:

YAML
jobs:
  build:
    steps:
      - uses: "@kb-labs/build-plugin/build:run"
 
  test:
    needs: [build]   # runs after build
    steps:
      - uses: "@kb-labs/qa-plugin/qa:run"
 
  deploy:
    needs: [build, test]
    steps:
      - uses: "@kb-labs/deploy-plugin/deploy:push"

Each step within a job runs sequentially. A step can be:

  • Plugin handleruses: "@package/group:command" with optional with: inputs.
  • Shell steprun: | with a multiline shell script (requires shell permission).
  • Workflow calluses: "workflow://other-workflow-id" to compose workflows.

Steps can reference outputs from previous steps via ${{ steps.<id>.outputs.<key> }} expressions. The engine evaluates expressions at runtime after the referenced step completes.

Triggers

Workflows can be triggered four ways:

Manual

Bash
pnpm kb workflow:run --workflow-id=ai-review --input='{"base":"main"}'

Or via the REST API: POST /api/v1/workflows/runs.

Push (git hook)

YAML
on:
  push:
    branches: ["main", "release/*"]
    paths: ["src/**"]  # optional filter

Triggered by the commit plugin's post-commit hook or via a repository webhook routed through the gateway.

Schedule (cron)

YAML
on:
  schedule:
    - cron: "0 9 * * 1-5"   # weekdays at 09:00

The workflow daemon maintains a cron scheduler. Cron expressions follow standard five-field syntax.

Webhook

YAML
on:
  webhook:
    source: github
    events: ["pull_request.opened", "pull_request.synchronize"]

Incoming webhooks hit the gateway, which routes them to the REST API's webhook handler. The handler matches the event against registered workflow triggers and enqueues runs.

Artifact passing

Artifacts are structured outputs that steps produce and subsequent steps consume. They're persisted by the workflow daemon so they survive step failures and retries.

YAML
steps:
  - id: generate
    uses: "@kb-labs/mind-plugin/mind:rag-query"
    with:
      text: "summarize recent changes"
    outputs:
      summary: ${{ result.answer }}
 
  - id: post
    uses: "@kb-labs/notify-plugin/slack:send"
    with:
      text: ${{ steps.generate.outputs.summary }}

Artifacts are stored in the platform's configured storage adapter (IStorage). They're automatically cleaned up after the run retention period (configurable per tenant tier).

Execution targets

By default, workflow steps run using the same execution backend as the invoking host. You can override per-job or per-step:

YAML
jobs:
  isolated-job:
    execution-target:
      mode: container        # run this job in a Docker container
      image: "node:22-slim"
    steps:
      - uses: "@kb-labs/untrusted-plugin/run:task"

This is the same execution model that plugin commands use — in-process, worker-pool, subprocess, or container. Workflows just expose it as a per-job configuration rather than a global platform setting.

See Execution Model for how the backends work.

Running and monitoring

Bash
# Start a run
pnpm kb workflow:run --workflow-id=ai-review
 
# List runs
pnpm kb workflow:list-runs --workflow-id=ai-review
 
# Tail logs for a run
pnpm kb workflow:logs --run-id=<id> --follow
 
# Cancel a run
pnpm kb workflow:cancel --run-id=<id>

Studio shows all runs in the Workflows section with live step status, artifact contents, and log output.

Workflow Engine — KB Labs Docs