The engine, in one section (answer first)
The workflow step engine is how anything gets set up on your box. An App Store listing declares typed workflows — install, status, uninstall, update — each a list of steps. The platform forwards those steps, unchanged, to a lightweight manager running on your box, which executes them in order: install a package, clone a repo, start a container, poll a health endpoint. The same engine that installs an app also runs your scheduled agent workers and stands up your AI staff. One delivery mechanism, every product.
A step is a small typed record — a type, a name, and
a config block — and that is the whole authoring surface:
{ "type": "git_clone", "name": "fetch_app",
"git_clone_config": { "repo": "https://github.com/acme/app.git", "ref": "v2.1.0", "dest": "/opt/app" } }The step-type philosophy: what earns a name
The design rule that keeps the engine small: a step type earns its place only
when the operation is both common and config-bearing. Common — it
recurs across many listings and workflows, not one. Config-bearing — authors
genuinely inject variables into it, so a named, typed block is more useful than an
ad-hoc shell line. Everything else is a script step: plain bash, the
workhorse that covers the long tail.
| Operation | Step type? | Why |
|---|---|---|
| Clone a repo with a ref, a destination, and an auth token | Yes: git_clone | Recurs everywhere; the token demands safe handling a bash line gets wrong |
| Install a working Docker on any distro | Yes: docker_install | Common, and painfully distro-specific — exactly what a curated block should absorb |
| Wait until a service is actually ready | Yes: health_check | Everyone needs it; typed config (http status, tcp port, log regex) beats sleep 30 |
| Bootstrap one specific tool's runtime image | No: script | One tool's one CLI call; wrapping it adds a name, not value |
| Run a coding agent headless | No: script (today) | A bash step calling the harness CLI — a first-class step is a candidate, not a given |
The vocabulary
The current building blocks, grouped by what they are for:
| Step | What it does |
|---|---|
script | Run bash. The workhorse — anything without its own block. |
package_install | Install packages; detects apt / apk / yum / dnf itself. |
git_clone | Clone a repo (ref, depth, dest); token via the secret env channel, never the command line. |
file_download / file_upload | Fetch a URL to a path; copy files into place. |
docker_install | A usable Docker (engine + compose v2) on any supported distro, with a pinned fallback. |
docker_run / build / compose / network / volume / login | The container family; registry passwords ride stdin, never argv. |
object_storage | Get / put / sync against any s3-compatible store, credentials off-band. |
health_check | Poll until genuinely ready: an HTTP status, a TCP port, or a log-line regex. |
environment_setup / wait / notification | Set variables for later steps; pause; POST a webhook (Slack and friends). |
Notice what is not here: no "install claws" step, no "set up Postgres" step, no per-product anything. Products compose the vocabulary; the vocabulary does not grow a word per product.
The blank-canvas rule
The box assumes nothing, and every workflow provisions its own
prerequisites. A fresh box is deliberately minimal — effectively an OS
and curl. A workflow that needs git runs a package_install for git
first. A workflow that needs Docker declares docker_install. Nothing is
pre-baked into the box image on the theory that some workflow might want it someday.
This sounds like a small discipline; it is actually what makes the fleet manageable. Because no listing depends on box-baked state, any workflow runs on any box — new, old, big, small — and two apps never fight over a shared, half-owned dependency. Your box stays yours: what is on it is exactly the sum of what you installed, each piece owned by the workflow that put it there and removed by the uninstall workflow that shreds it.
A worked install: an AI employee, step by step
The claw listing is the best
showcase because it mixes both kinds of step. The named blocks do the common,
config-bearing work; bash script steps call the product's own CLI for
the product-specific tail:
# The claw install workflow (abridged) — building blocks + bash tail script curl .../install.sh | bash # the tool's own installer docker_install engine + compose v2 # named block: distro-agnostic script claws image bootstrap --yes # one tool's CLI = bash, not a step type script claws apply --secrets-dir=/etc/claws/secrets script claws start default/ health_check claws agent ping, retry 5 x 10s # named block: typed readiness
The is a typed listing input, substituted at install
time. The same pattern delivers the
coordination daemon
(docker_install → docker_run →
health_check on its health endpoint) and every infra app in the store.
Once you can read one workflow, you can read them all — that is the point of a
vocabulary.
Secrets and safety, engine-enforced
The engine, not the author, carries the security invariants. Secret inputs are
delivered off-band to root-owned files created under a restrictive umask; steps
reference them as files or environment variables. A database password, a git token,
a model API key: none of them appear in a step's command line, the workflow record,
or a log — and an uninstall shreds them. Steps that take credentials
(git_clone, docker_login, object_storage) are
built to accept them only through that channel, which is precisely the kind of
correctness a named building block can guarantee and an ad-hoc bash line reliably
fumbles.
What earns a name next
The vocabulary is allowed to grow — through the same gate. The candidate on the
table now is an agent step: "run a coding agent with this task," with
typed config for the task, the harness, a budget, and autonomy limits. Today that is
a script step (cogs
run their harness exactly that way, with the task passed through the environment so
it cannot be injected), and it stays a script step until running agents is so common,
and its config surface so real, that the promotion pays for its permanent upkeep. If
it crosses that bar — and as agent workers multiply, it plausibly will —
it becomes the vocabulary's first agent-native word. If not, bash was already enough.
That is the philosophy working as intended, in both directions: for the harness side
of that question, see
why your worker should not be
locked to one brain.