Skip to content

steerium

steerium is an open-source, local-first TypeScript workflow orchestrator for deterministic code, AI calls, and coding agents, with typed, inspectable, replayable runs.

v0.6.0 · open source (MIT) · runs on your machine

Write the workflow.Not the runner.

steerium gives you the primitives — triggers, steps, providers — and a local daemon that keeps them live, records a typed event timeline and execution provenance for every run, and can replay it. What goes inside the function is entirely yours: deterministic code, a coding agent, or both in the same run.

npm install -g steerium

Needs Node 22.13+

.steerium/workflows/review.tsproject workflow
import { defineWorkflow, github } from "steerium";
export default defineWorkflow({
name: "review",
on: github.prOpened({ repo: "acme/app" }),
async run(ctx) {
const { pr } = ctx.event;
const review = await ctx.step("review", () =>
ctx.agent.run({
provider: "claude", // the CLI you already log into
allowedTools: ["Read", "Grep", "Bash"],
prompt: `Review PR #${pr.number} against ${pr.baseBranch}.
Correctness bugs only — skip style nits.`,
}),
);
const { token } = ctx.connector<{ token: string }>("github");
await github.comment(token, pr.repo, pr.number, review.text);
},
});
typed timeline·provenance captured·inspectable and replayable

01 Ideas

Nine ideas, to show the shape

None of these are features — they’re just workflows, each a single file someone wrote in .steerium/workflows/. Some call an agent, some are only git and a schedule. Yours will be different, and that’s the point.

github.prOpened()

Review every PR as it opens

An agent reads the diff inside the real checkout — not a pasted patch — and posts a review comment.

linear.ticketMoved()

Turn a ticket into a branch

Plan with a cheap API call, then let a coding agent take a first pass and push it for you to judge.

schedule.cron("0 16 * * 5")

Write Friday’s changelog

Read the week’s commits, draft release notes, and save them as an artifact you can actually diff.

schedule.every(6h)

Prune merged branches

No AI anywhere in this one. It’s git fetch --prune and a loop — automation doesn’t have to mean agent.

github.issueOpened()

Triage new issues

Ask for schema-checked structured output, then route on typed fields like label, priority, and missing repro steps.

approvals.responded()

Draft it, but ask me first

The agent drafts and stops. Choose a structured action or leave feedback; stale replies cannot answer a newer round.

schedule.cron("0 9 * * 1")

Bump deps, but only if green

Update, run the suite, open a PR when it passes and a note to yourself when it doesn’t.

github.prOpened()

Keep the docs honest

When a PR touches the public API, have an agent check whether the docs still describe reality.

schedule.cron("0 8 * * *")

Yesterday, summarized

Commits landed, tickets closed, and PRs still waiting on you — as a digest before you open your laptop.

defineTrigger() · defineProvider() · defineConnector()

…and whatever yours actually is

If the trigger you need isn’t in the box, write it — a queue, a file watcher, an internal webhook, a device on your network. Same for providers and connectors: the built-ins are written against the public API you get, so there’s nothing to fork and nothing to wait for.

See how the built-ins are built

02 The code

Four real workflows, start to finish

No DSL, no YAML, no visual builder. These are copy-pasteable files from the examples directory. For typed agent results, see the structured-output guide and structured-triage.ts.

03 Mix

Deterministic and agentic, in one function

There is no “AI workflow” mode. ctx.step() wraps a shell command and a coding agent exactly the same way, so a workflow can be plain code, entirely agent-driven, or move between the two as many times as it needs.

Start deterministic. Most automations begin as git, fs, and an npm package. Nothing about steerium asks you to add a model.

Reach for an agent at the step that needs judgement. Summarizing, drafting, deciding, writing code — a call, not a rewrite.

Both land in the same typed timeline. Step status, logs, artifacts, agent provenance, and the final outcome remain inspectable whichever kind of step produced them.

release-notes.tsschedule.cron("0 16 * * 5")
  1. codecollectgit log --since=1.week --oneline
  2. agentdraftanthropic · group 42 commits into notes
  3. codewriteprepend CHANGELOG.md, commit
  4. agentopen-prclaude · push the branch, summarize it

one workflow · one run record · one replay

04 Scope

Global or in the repo. Same runner.

Some automation belongs to you, some belongs to a codebase. steerium runs both from one daemon, with one API and one run history — the only difference is where the file lives and what cwd it runs with.

Global

~/.steerium/workflows/

  • runs with cwd = ~/.steerium

  • automation that isn’t about one repo
  • digests, drafting, cross-repo chores
  • travels with steerium config export

Project

<repo>/.steerium/workflows/

  • runs with cwd = the repo root

  • committed alongside the code it automates
  • arrives with git clone, reviewed in PRs

  • what makes agent workflows natural

one steerium daemon

the same defineWorkflowone SQLite run historyone CLIone control APIone browser UI

Project config merges over global, and project wins. Run steerium start inside a repo that has a .steerium/ and the daemon scopes itself to that project automatically — no registration, works in a fresh clone.

05 Model

Three primitives — and you can replace all of them

The built-ins hold no privileged access. Every one of them is written against the same public API you get, so anything shipped is a worked example rather than a wall.

Trigger

Emits events.

  • cron & intervals
  • GitHub, Linear, Jira
  • webhooks (HMAC-verified)
  • approval replies
  • manual fires

defineTrigger — implement start(ctx, emit) and you get persistent state for dedup cursors and webhook registration for free.

Workflow

Handles one event.

  • an async function
  • typed events and outcomes
  • steps, logs, artifacts
  • any npm package
  • shell, git, fs

defineWorkflow — there is nothing to extend here, because there was never a DSL in the way.

Provider

Runs an AI or agent call.

  • openai, anthropic

  • claude, codex

  • mock (the default)

  • typed structured output
  • chosen per call

defineProvider — a local model, an internal inference service, a different agent. Register it in config; workflows just name it.

  1. 1 an event arrives

  2. 2 deduped and persisted

  3. 3 your function runs, step by step

  4. 4 it ends succeeded, failed, cancelled, or timed_out

  5. 5 replay the same event, with both runs’ provenance recorded

No automatic retries, deliberately: agents commit code, push branches, and leave comments, so a blind retry duplicates all of it. steerium replay <runId> is the explicit re-run. Replay keeps the original event, but uses the code and provider configuration loaded now; compare the two provenance records when exact reproducibility matters.

And you don’t have to write any of it by hand.

A workflow is a plain TypeScript file with a typed API and no DSL to learn, which makes it the kind of thing a coding agent is genuinely good at producing. Point Claude Code or Codex at your repo, describe the automation in a sentence, and let it write the file, fire it once against the mock provider, and read the run record to check its own work.

06 Start

Running in four commands

The default provider is mock — deterministic, offline, no key. You can watch the whole loop work before pointing it at a real model.

Once the daemon is up, 127.0.0.1:4319 serves a small browser UI: live typed timelines, per-step logs, artifacts, provenance, explicit outcomes, cancel and replay, plus an approval inbox with structured actions.

Follow the browser UI guide, or build a durable human-in-the-loop flow with the approvals guide.

Read the getting started guide
$ steerium init # scaffold ~/.steerium
$ steerium workflow run hello # fire one workflow, right now
$ steerium logs # every run is on the record
$ steerium start # daemon: triggers, API, browser UI

Build something that runs itself.

Install it, scaffold a workflow, and have something of your own running in the next five minutes.