Skip to content

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Repository files navigation

smol-workflows

Minimal agentic workflow runtime for orchestrating your agents at scale.

smol-workflows runs ES-module workflow scripts inside a self-contained Rust/QuickJS engine. Workflows use injected workflow primitives such as agent, parallel, pipeline, workflow, budget, phase, and log; agent calls are checkpointed in SQLite so interrupted runs can be resumed without re-running completed provider steps.

Getting Started

Installing

Install the latest official release to ~/.local/bin:

curl -fsSL https://raw.githubusercontent.com/b4fun/smol-workflows/main/install.sh | bash

Override the destination with INSTALL_DIR, BIN_DIR, or --dir:

curl -fsSL https://raw.githubusercontent.com/b4fun/smol-workflows/main/install.sh \
  | bash -s -- --dir "$HOME/bin"

Install a specific release tag:

curl -fsSL https://raw.githubusercontent.com/b4fun/smol-workflows/main/install.sh \
  | bash -s -- --version v0.3.0-alpha.4

From a source checkout, ./install.sh also installs the latest official release by default. Use --from-source when you explicitly want to build and install local checkout binaries:

./install.sh --from-source
./install.sh --from-source --dir "$HOME/.local/bin"

The installer requests these binaries:

  • smol-wf
  • smol-sandbox-exe-dev

Release archives are packaged with both binaries.

You can also download release archives manually:

# Linux x86_64
curl -fsSL https://github.com/b4fun/smol-workflows/releases/latest/download/smol-wf-linux-x86_64.tar.gz | tar -xz

# macOS Apple Silicon
curl -fsSL https://github.com/b4fun/smol-workflows/releases/latest/download/smol-wf-macos-aarch64.tar.gz | tar -xz

Using smol-wf in GitHub Actions

The smol-workflows GitHub Action installs smol-wf and runs a workflow script from your repository. Check out your repository first, then provide workflow arguments as a YAML mapping:

steps:
  - uses: actions/checkout@v6

  # Install and authenticate the provider CLI before this step.
  - name: Run workflow
    id: smol-wf
    uses: b4fun/smol-workflows-action@v1.0.0
    with:
      workflow: ./workflows/review.mjs
      provider: pi
      smol-wf-version: latest
      args: |
        target: ${{ github.event.pull_request.title }}

  - name: Read the workflow report
    run: cat "${{ steps.smol-wf.outputs.result-file }}"

The action's default provider is debug. For real agent calls, install and authenticate the chosen provider CLI in an earlier step and pass credentials through GitHub Actions secrets. The action also exposes the run ID and SQLite database path. See the action README for all inputs, outputs, and retention details.

Running your first workflow

Here is a workflow that uses agent, parallel, and pipeline to diagnose Kubernetes pod status. This example is also available at examples/pod-diagnostics.mjs:

export const meta = {
  name: 'pod-diagnostics',
  description: 'Diagnose Kubernetes pod status with agent, parallel, and pipeline primitives',
  phases: [
    { title: 'Discover', detail: 'Find the target pods', model: 'github-copilot/gpt-5.4-mini' },
    { title: 'Inspect', detail: 'Gather metrics and logs for each pod', model: 'github-copilot/gpt-5.4-mini' },
    { title: 'Summarize', detail: 'Generate diagnostic guidance', model: 'github-copilot/gpt-5.5' },
  ],
}

const target = typeof args.target === 'string'
  ? args.target
  : 'pods that look unhealthy in the current Kubernetes context'

const POD_LIST_SCHEMA = {
  type: 'object',
  properties: {
    pods: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          namespace: { type: 'string' },
          name: { type: 'string' },
          reason: { type: 'string' },
        },
        required: ['namespace', 'name', 'reason'],
        additionalProperties: false,
      },
    },
  },
  required: ['pods'],
  additionalProperties: false,
}

phase('Discover')
const { pods } = await agent(
  `List Kubernetes pods to inspect for this request: ${target}. Use kubectl if needed.`,
  { schema: POD_LIST_SCHEMA },
)

phase('Inspect')
const inspections = await parallel(pods.map((pod) => async () => {
  const [inspection] = await pipeline(
    [pod],
    (currentPod) => agent(
      `Get recent metrics and status for pod ${currentPod.namespace}/${currentPod.name}.
Include restarts, readiness, CPU/memory, events, and current phase.`,
      { phase: 'Inspect' },
    ),
    (metrics, currentPod) => agent(
      `Get relevant recent logs for pod ${currentPod.namespace}/${currentPod.name}.
Focus on errors, crashes, probes, and startup failures.
Metrics/status context:
${metrics}`,
      { phase: 'Inspect' },
    ),
  )

  return { pod, inspection }
}))

phase('Summarize')
const diagnostics = await agent(
  `Summarize Kubernetes pod diagnostics for: ${target}
For each pod, identify likely status, evidence, severity, and next actions.
${JSON.stringify(inspections, null, 2)}`,
)

export default { target, pods, inspections, diagnostics }

Save the code above to pod-diagnostics.mjs, then run it with your preferred provider and a natural-language target:

smol-wf run ./pod-diagnostics.mjs \
  --agent-provider pi \
  --args-target "coredns pods under kube-system" \
  | tee pod-diagnostics.json \
  | jq -r '.results.diagnostics'

Example diagnostic output:

[phase] Discover
[phase] Inspect
[phase] Summarize
## Kubernetes Pod Diagnostics Summary: CoreDNS pods in `kube-system`

### Overall assessment

Both CoreDNS pods appear healthy and operational.

The only recurring log messages are warnings about missing optional CoreDNS customization files:

- `No files matching import glob pattern: custom/*.override`
- `No files matching import glob pattern: custom/*.server`

These are typically benign when no custom CoreDNS override/server files are configured.

### Pod: `kube-system/coredns-...-2ngp4`

- Status: Running
- Readiness: 1/1 Ready
- Restarts: 0
- Events: none
- Severity: Low / Informational

### Pod: `kube-system/coredns-...-vck6j`

- Status: Running
- Readiness: 1/1 Ready
- Restarts: 0
- Events: none
- Severity: Low / Informational

### Final conclusion

Both requested CoreDNS pods are Running, Ready, and not restarting. There is no evidence of operational failure from the provided diagnostics.

smol-wf run writes progress such as [phase] ... and [log] ... to stderr, and writes the final JSON report to stdout. The JSON report includes:

  • runID — workflow run identifier;
  • tokenUsage — aggregate inputTokens, outputTokens, and totalTokens;
  • results — the workflow's returned data.

Explore more workflows under the examples folder.

You can inspect persisted run records later with smol-wf history:

# List recent workflow runs from the default platform app-state workflows.db
smol-wf history

# Show details for a specific run, including attempts, steps, usage, sessions,
# model metadata, and isolation metadata when present
smol-wf history run_01kt...

# Machine-readable detail output
smol-wf history run_01kt... --output json | jq '.steps'

Clean up old runs to reclaim disk space with smol-wf history delete:

# Preview, then delete all failed runs and vacuum the database
smol-wf history delete --state failed --dry-run
smol-wf history delete --state failed

Installing in Code Agents

Ask your code agent to read the harness installation instructions and install the smol-workflows harness integration for itself.

These integrations add smol-workflows skills/tools to the host agent. They do not install the smol-wf binary itself; the bundled helper resolves an existing binary, builds from a nearby checkout when possible, or downloads a release archive.

Workflow shape and primitives

Workflows are ES modules. The Rust runner injects workflow primitives before evaluating the script. A primitive is a small built-in capability the workflow can call directly, such as running an agent, fanning work out in parallel, or marking progress. The TypeScript definitions for these globals live in ts/sdk/src/index.ts and ts/sdk/src/pipeline.ts.

A workflow script should export:

export const meta: WorkflowMetadata
export default resultOrWorkflowFunction

args -- Workflow input values supplied by the CLI or parent workflow

args: Record<string, unknown>
Details

Input arguments passed by smol-wf run --args-* or --args-from-file. Treat values as untrusted JSON and narrow them before use.

agent(prompt, options?) -- Send a prompt to a provider and get text or structured JSON back

agent(prompt: string, options?: AgentRunOptions): Promise<string | null>
agent(prompt: string, { schema, ...options }): Promise<FromSchema<typeof schema> | null>
Details

Runs one agent/provider call. By default it returns text. With schema, it requests structured JSON and the engine validates the result against that JSON Schema. Useful options include:

  • phase — associate the call with a phase for tracing and token usage grouping;
  • schema — JSON Schema for structured output;
  • model — provider-specific model override;
  • provider — provider override such as pi, opencode, codex, or claude-code;
  • isolation: "worktree" — run the agent in an engine-managed temporary git worktree;
  • agentType — provider-specific subagent/agent selection.

If an agent call fails inside parallel or pipeline, that item/task resolves to null; otherwise errors reject the workflow.

parallel(tasks) -- Run independent async tasks concurrently and collect their results

parallel(tasks: Array<() => Awaitable<T>>): Promise<Array<T | null>>
Details

Runs independent tasks concurrently and returns results in input order. If one task throws, only that task becomes null; sibling tasks can still complete. Use this when there is a real barrier before the next workflow step.

pipeline(items, ...stages) -- Move each item through ordered stages as soon as it is ready

pipeline(
  items: readonly Item[],
  ...stages: Array<(previous, item, index) => Awaitable<Next>>
): Promise<Array<Final | null>>
Details

Runs each item through sequential stages without a global barrier between stages. Each stage receives:

  • previous — the previous stage result, or the original item for the first stage;
  • item — the original input item;
  • index — the item index.

If a stage throws for one item, that item becomes null and later stages for that item are skipped.

workflow(nameOrRef, args?) -- Invoke another workflow as a child step

workflow(nameOrRef: string | { scriptPath: string }, args?: unknown): Promise<unknown>
Details

Runs another workflow as a child workflow. Relative scriptPath values resolve from the current workflow file. The current engine supports one level of child workflow nesting.

budget -- Inspect the shared token-budget view for budget-aware prompts and decisions

budget: {
  total: number | null
  spent(): number
  remaining(): number
}
Details

Exposes the soft output-token budget. total is set by --budget-allowance; spent() is accumulated from provider-reported output tokens; remaining() is Infinity when no allowance is configured.

phase(name, options?) -- Mark the current workflow phase for logs, tracing, and phase defaults

phase(name: string, options?: unknown): void
Details

Marks workflow progress. Phases are printed to stderr, included in run history, and used to apply phase-level metadata defaults such as model and provider.

log(...values) -- Write progress/debug messages without changing workflow results

log(...values: unknown[]): void
Details

Writes workflow progress/debug information to stderr without changing the workflow result.

Usage

CLI

Command group Purpose Reference
smol-wf run Run a workflow script. docs/usages/run.md
smol-wf tui Interactively stream or replay workflow events in a terminal UI. docs/usages/tui.md
smol-wf history Get workflow runs history. docs/usages/history.md
smol-wf llm LLM-facing helper commands, such as workflow discovery. docs/usages/llm.md

Terminal UI

Use the TUI to observe workflows live or replay a saved event stream.

smol-wf TUI live workflow demo

# Run a workflow with live event visibility.
smol-wf tui run ./workflow.mjs --agent-provider pi --args-target "coredns pods under kube-system"

# Save an event stream from a normal run, then replay it.
smol-wf run ./workflow.mjs --events > events.jsonl
smol-wf tui replay events.jsonl

# Validate/summarize an event stream without opening the interactive UI.
smol-wf tui replay events.jsonl --check

The live TUI shows workflow scopes, provider events, token usage, an event-rate graph, selected-event details, and raw/pretty views. Live event logs start unsaved; after the workflow stops, press s or choose save & quit to write $PWD/<run-id>.jsonl. Replay starts paused with zero revealed events and advances according to elapsedNanos, with long gaps capped by --max-delay (50ms by default).

See docs/usages/tui.md for keybindings and replay options.

Agent providers

The engine includes built-in agent providers for debug, codex, claude-code, pi, and opencode. Providers can be selected globally with --agent-provider or per call with agent(prompt, { provider }).

Structured output schemas are validated by the Rust engine, with one retry using a schema-validation prompt when a provider result does not match. Agent calls can also opt into per-call provider retries with agent(prompt, { retry: { maxAttempts, backoffMs } }). See docs/workflow/retry.md and docs/harness-capabilities for provider capability notes, including provider-specific structured-output behavior, input/environment capability expectations, and budget/usage tracking behavior.

Durable backends

Durable workflow runs use the Rust SQLite backend. The CLI uses this backend by default and stores run/task/step state, completed agent checkpoints, provider results, and budget ledger entries in the platform app-state workflows.db unless --db is provided. Runs are not retried globally; use per-agent retry settings for transient provider failures and --resume-run <run-id> to explicitly continue an existing run. See docs/usages/config.md for default database locations.

What is in this repo

  • rust/engine — Rust workflow engine with a sandboxed QuickJS runtime, metadata extraction, schema validation, budget accounting, built-in agent providers, and a SQLite durable backend.
  • rust/cli — smol-wf command-line interface for running and discovering workflows.
  • ts/sdk — TypeScript types for workflow authors (@smol-workflows/sdk).
  • harness — integrations and skills for code-agent hosts.
  • examples — runnable workflow scripts.
  • docs — design notes, workflow API reference, and harness capability notes.

TODOs

  • improve context passing between agents; provide primitives for propagated context and workflow/pre-defined memory data
  • human in the loop / steering support
  • cross-run aggregate budget reporting

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages