Skip to content
/

saflib-workflows

saflib-workflows · sderickson/saflib-workflows-playground · ★ 0 · last commit 2025-11-16

TypeScript-typed, composable workflow step machines that guide AI agents through structured multi-step development procedures with resume capability and optional per-step git commits.

Best whenDevelopment procedures should be code (TypeScript), not prose — typed, composable, testable, and version-controlled like any other software.
vs seeds
spec-driverin sequential workflow approach, but saflib-workflows is a standalone CLI library (not a Claude Code plugin) with TypeSc…
Primitive shape
No installable primitives
00

Summary

saflib-workflows — Summary

saflib-workflows is a TypeScript workflow orchestration library (@saflib/workflows) that structures AI-assisted software development into sequential, resumable step sequences — providing a CLI (saf-workflow) that agents follow as a series of prompts, automated scripts, and file templates, with optional git commits and agent CLI invocation between steps.

Problem it solves: AI coding agents lack a structured way to perform multi-step development workflows (database schema updates, API route additions, service initialization) that require a specific sequence of automation + agent judgment steps; saflib-workflows defines these sequences as TypeScript workflow definitions with steps that mix automated scripts, template file copies, and agent prompt invocations.

Distinctive trait: Workflows are defined as TypeScript type-safe step sequences (using defineWorkflow + step primitives) that can be nested (a workflow calls sub-workflows via makeWorkflowMachine), producing a CLI that guides both humans and AI agents through the sequence with status tracking and resume capability.

Target audience: Full-stack TypeScript developers building SAF (Scalable Application Framework) applications who want to encode complex, multi-service development sequences as reusable, versioned, and resumable workflow definitions.

Production-readiness: Playground repository is 0-star, unlicensed, last pushed November 2025; the parent saflib library has 6 stars and is actively maintained (last pushed May 2026). This is a narrowly-scoped framework for the SAF ecosystem.

Differs from seeds: Most similar to spec-driver in its sequential workflow approach with discrete phases, but saflib-workflows is not a Claude Code plugin — it's a standalone TypeScript library with its own CLI that can be integrated with any agent CLI (including Cursor via -- -r cursor). Unlike taskmaster-ai which manages a task backlog, saflib-workflows defines structured development procedures (add schema, add route, init service) as composable, resumable step machines. No CLAUDE.md injection, no hooks, no spec files — pure TypeScript workflow definitions.

01

Overview

saflib-workflows — Origin and Philosophy

Origin

Created by Scott Derickson (sderickson on GitHub). Part of the SAF (Scalable Application Framework) library ecosystem at sderickson/saflib. The workflows playground (saflib-workflows-playground) demonstrates the workflow library with concrete examples.

Website: saf-demo.online

Philosophy

From the README:

"Please run the following command: npm exec saf-workflow kickoff ./workflows/demo.ts. Follow its instructions until the workflow is entirely finished."

The framework is designed so an AI agent can receive a single instruction — run the workflow CLI — and follow prompts to completion. The workflow CLI is the authoritative guide; the agent executes each step as instructed.

From the CLI source:

"Tool for agents to be given a series of prompts. For a list of available workflows, run: npm exec saf-workflow help kickoff"

Design principles

  1. Workflow as code — workflows are TypeScript classes with typed inputs and explicit step sequences, not YAML or Markdown
  2. Composability — workflows call sub-workflows via makeWorkflowMachine; complex sequences are built from simpler ones
  3. Resumabilitysaf-workflow status shows current step; interrupted workflows can be continued from the last checkpoint
  4. Dual-mode — workflows support both agent-driven and CLI-driven (-- -r cursor) execution; the same workflow definition works for both
  5. Optional version control-- -v git flag makes the workflow commit after each step, creating an atomic history of the development sequence

Integration with SAF ecosystem

saflib-workflows is a module within saflib, which also provides:

  • Drizzle ORM workflows (@saflib/drizzle/workflows)
  • OpenAPI workflows (@saflib/openapi/workflows)
  • Service initialization workflows (@saflib/service/workflows)
  • Vue frontend workflows
02

Architecture

saflib-workflows — Architecture

Distribution

  • Type: npm package (@saflib/workflows within sderickson/saflib)
  • Playground: sderickson/saflib-workflows-playground
  • CLI binary: saf-workflow (via npm exec saf-workflow)
  • Version analyzed: playground repo (0 semver; saflib library at unknown version)
  • License: none (playground); MIT (saflib library)

Install (playground)

git clone https://github.com/sderickson/saflib-workflows-playground.git
git submodule update --init   # set up saflib/ submodule
npm install
npm exec saf-workflow          # verify workflows are working

Required runtime

  • Node.js >= v22.19.0
  • TypeScript (via @saflib/monorepo dev dependency)

Target AI tools

Any agent CLI that can run shell commands. Explicitly tested:

  • Agent-driven (Claude Code, any MCP-compatible)
  • Cursor CLI (-- -r cursor)

Directory structure

saflib-workflows-playground/
├── saflib/                    # Git submodule: the saflib library
│   └── workflows/             # The @saflib/workflows package source
│       ├── core/              # Types, makeWorkflow, step primitives
│       │   ├── types.ts       # WorkflowDefinition, WorkflowStep, etc.
│       │   ├── make.ts        # defineWorkflow(), step()
│       │   └── steps/        # CwdStepMachine, CopyTemplateMachine, etc.
│       ├── bin/saf-workflow/  # CLI binary source
│       │   ├── kickoff.ts     # kickoff subcommand
│       │   ├── checklist.ts   # checklist subcommand
│       │   ├── status.ts      # status subcommand
│       │   └── ...
│       └── workflows/         # Built-in workflows (add-workflow.ts, etc.)
├── workflows/
│   ├── demo.ts               # Demo composite workflow
│   └── index.ts              # Workflow registry
├── package.json              # @saflib/playground workspace
└── vitest.config.ts          # Test config

Workflow definition structure

export const MyWorkflowDefinition = defineWorkflow<typeof input, MyContext>({
  id: "namespace/workflow-name",
  description: "What this workflow does",
  input,                      // typed argument definitions
  context: () => ({}),        // workflow-level state
  templateFiles: {},          // files to copy into project
  versionControl: {
    allowPaths: ["./output/**"]  // paths that git commit should include
  },
  steps: [
    step(SomeStepMachine, () => ({ /* step inputs */ })),
    step(makeWorkflowMachine(SubWorkflowDefinition), () => ({})),
  ],
});
03

Components

saflib-workflows — Components

CLI binary: saf-workflow

Subcommand Purpose
kickoff <workflow> Start a workflow (agent-driven or CLI-driven with -- -r cursor)
checklist <workflow> Show what the workflow will do without running anything
status <workflow> Show current step and completion state
next <workflow> Show the next step to execute
goto <workflow> <step> Jump to a specific step
run-scripts <workflow> Run only the automated scripts (no agent prompts)
dry-run <workflow> Preview changes without executing
list List available workflows
source <workflow> Show the workflow source file
info <workflow> Show workflow metadata

Core step primitives (@saflib/workflows)

Primitive Purpose
defineWorkflow() Define a workflow with id, description, input schema, context, steps
step() Add a step to a workflow sequence
makeWorkflowMachine() Wrap a workflow definition as a step (sub-workflow composition)
CwdStepMachine Change working directory for subsequent steps
CopyTemplateMachine Copy template files into the project
UpdateTemplateMachine Update template files with new values
PromptStep Emit a prompt message for the agent to follow
CommandStep Run a shell command
TransformFileStep Transform a file with a function

Domain workflows (from saflib sub-packages)

Workflow Package Purpose
InitServiceWorkflowDefinition @saflib/service/workflows Initialize a new service with standard structure
UpdateSchemaWorkflowDefinition @saflib/drizzle/workflows Update a Drizzle ORM database schema
AddDrizzleQueryWorkflowDefinition @saflib/drizzle/workflows Add a typed database query
AddSchemaWorkflowDefinition @saflib/openapi/workflows Add an OpenAPI schema definition
AddRouteWorkflowDefinition @saflib/openapi/workflows Add an API route with spec

Playground demo workflow

The PlaygroundDemoWorkflowDefinition composes 6 sub-workflows:

  1. InitServiceWorkflowDefinition — initialize example-service
  2. CwdStepMachine — cd to example-db
  3. UpdateSchemaWorkflowDefinition — add user schema
  4. AddDrizzleQueryWorkflowDefinition — add list users query
  5. CwdStepMachine — cd to example-spec
  6. AddSchemaWorkflowDefinition — add user API schema
  7. AddRouteWorkflowDefinition — add users list route
05

Prompts

saflib-workflows — Prompt Files (Verbatim Excerpts)

Excerpt 1: Demo workflow definition (workflows/demo.ts)

Technique: TypeScript-typed workflow composition with sub-workflow nesting

import {
  defineWorkflow,
  step,
  makeWorkflowMachine,
  CwdStepMachine,
} from "@saflib/workflows";
import {
  AddDrizzleQueryWorkflowDefinition,
  UpdateSchemaWorkflowDefinition,
} from "@saflib/drizzle/workflows";
import {
  AddRouteWorkflowDefinition,
  AddSchemaWorkflowDefinition,
} from "@saflib/openapi/workflows";
import { InitServiceWorkflowDefinition } from "@saflib/service/workflows";

export const PlaygroundDemoWorkflowDefinition =
  defineWorkflow<typeof input, PlaygroundDemoWorkflowContext>({
    id: "playground/demo",

    description: "Create a demo workflow that runs init workflows and example workflows",

    checklistDescription: () =>
      `Create a demo workflow demonstrating the power of workflows by running init
       workflows and example workflows.`,

    input,
    context: () => { return {}; },
    templateFiles: {},
    versionControl: {
      allowPaths: ["./demo/**"],
    },
    docFiles: {},

    steps: [
      step(makeWorkflowMachine(InitServiceWorkflowDefinition), () => ({
        name: "example-service",
        path: "./example",
      })),

      step(CwdStepMachine, () => ({
        path: path.join("./example/example-db"),
      })),
      step(makeWorkflowMachine(UpdateSchemaWorkflowDefinition), () => ({
        path: "./schemas/user.ts",
      })),
      step(makeWorkflowMachine(AddDrizzleQueryWorkflowDefinition), () => ({
        path: "./queries/user/list.ts",
        promptMessage: "Add the query for a list of users.",
      })),

      step(CwdStepMachine, () => ({
        path: path.join("./example/example-spec"),
      })),
      step(makeWorkflowMachine(AddSchemaWorkflowDefinition), () => ({
        name: "user",
        promptMessage: "Add the API schema for the user resource that reflects
                        the database schema.",
      })),
      step(makeWorkflowMachine(AddRouteWorkflowDefinition), () => ({
        path: "./routes/users/list.yaml",
        promptMessage: "Add the spec for a list route that uses the user schema.",
      })),
    ],
  });

Excerpt 2: README agent instruction

Technique: Single-line agent handoff instruction pattern

### Agent-Driven

If you'd like the agent to do the implementation, prompt the agent:

Please run the following command: npm exec saf-workflow kickoff ./workflows/demo.ts

Follow its instructions until the workflow is entirely finished.


Odds are good the agent will do so. If it stops partway through, nudge it
to continue. You can check the status of the workflow with:

npm exec saf-workflow status ./workflows/demo.ts


Prompting techniques observed

  1. Single-line agent delegation — the entire agent interaction is one instruction: run this CLI command and follow its prompts. The workflow CLI is the prompt manager.
  2. Type-safe step inputsstep(AddRouteWorkflowDefinition, () => ({ path, promptMessage })) passes typed context from the parent workflow to each sub-workflow, preventing mismatched arguments at compile time.
  3. Embedded prompt messagespromptMessage: "Add the query for a list of users." passes a scoped prompt to the sub-workflow that the CLI surfaces to the agent; the agent only sees one step's prompt at a time.
  4. Sub-workflow compositionmakeWorkflowMachine(SubWorkflowDefinition) wraps existing workflows as steps; complex procedures are built by composing simpler ones, not by duplicating prompts.
09

Uniqueness

saflib-workflows — Uniqueness and Positioning

Differs from seeds

saflib-workflows is unlike any of the 11 seed frameworks in a key dimension: it defines development procedures as TypeScript-compiled step machines rather than Markdown prompt files or YAML. The closest seed is spec-driver in its sequential workflow approach with discrete phases, but spec-driver is a Claude Code plugin while saflib-workflows is a standalone CLI library. Unlike taskmaster-ai (flat task backlog with MCP), saflib-workflows defines structured procedures (add schema, add route, init service) as composable TypeScript step machines. Unlike agent-os (Markdown scaffold), saflib-workflows has no CLAUDE.md injection — the agent follows the CLI's prompts directly. The sub-workflow composition pattern (makeWorkflowMachine) is unique in the corpus: complex procedures are assembled from simpler ones at the TypeScript level, with type safety enforced at compile time.

Positioning

saflib-workflows targets developers building within the SAF (Scalable Application Framework) ecosystem who want to encode standard development patterns (new service, new schema, new API route) as reusable, versioned, type-safe procedures. The value proposition is highest for teams with many repetitive service development patterns that should always be executed in the same order.

Observable failure modes

  1. Ecosystem coupling — heavily tied to the SAF library ecosystem (drizzle, openapi, service packages); general-purpose use requires building custom workflow definitions from scratch
  2. TypeScript compilation barrier — workflow definitions require TypeScript toolchain; less accessible than YAML/Markdown-based frameworks
  3. Narrow community — 0-star playground, 6-star parent library; very small community
  4. No spec/requirement phase — workflows jump straight into implementation; no requirement-gathering, no approval gate before execution
  5. Agent reliability — the README notes "if it stops partway through, nudge it to continue" — implicit acknowledgment that agent compliance is imperfect

Explicit antipatterns

None stated explicitly in the repository. Implied: don't manually edit the files that a workflow manages (use the workflow instead); don't skip steps (use goto only for intentional resume).

04

Workflow

saflib-workflows — Workflow

Execution modes

Mode Command Who drives
Checklist npm exec saf-workflow checklist ./workflows/demo.ts Human reviews what will happen
Scripts only npm exec saf-workflow run-scripts ./workflows/demo.ts Automated (no agent)
Agent-driven npm exec saf-workflow kickoff ./workflows/demo.ts Agent follows step prompts
CLI-driven (Cursor) npm exec saf-workflow kickoff ./workflows/demo.ts -- -r cursor Cursor CLI drives automatically
With version control npm exec saf-workflow kickoff ./workflows/demo.ts -- -v git Agent-driven + commit per step

Step execution flow

For each step in the workflow:

  1. checklist shows what the step will do
  2. kickoff initializes the workflow, then:
    • Runs automated scripts for the current step (if any)
    • Emits the step's prompt to the agent
    • Agent executes the prompt (writes code, calls APIs, etc.)
    • Agent marks step complete or calls saf-workflow next
  3. Workflow advances to next step
  4. status can be called at any time to see progress

Phase-to-artifact map (demo workflow)

Phase Step Artifact
Service init InitServiceWorkflowDefinition ./example/ service directory
Schema update UpdateSchemaWorkflowDefinition ./example/example-db/schemas/user.ts
Query add AddDrizzleQueryWorkflowDefinition ./example/example-db/queries/user/list.ts
API schema AddSchemaWorkflowDefinition OpenAPI schema for user resource
Route add AddRouteWorkflowDefinition ./example/example-spec/routes/users/list.yaml

Approval gates

None — the framework has no explicit human approval gates. The [agent-driven mode] relies on the agent to complete each prompt and signal completion. Manual mode allows the human to act as the agent for any step.

Version control integration

With -- -v git:

  • Workflow auto-commits after each step's allowPaths files are modified
  • Creates a clean atomic commit per step in the development sequence
  • Useful for isolating each workflow step in git history
06

Memory Context

saflib-workflows — Memory and Context

State storage

Workflow progress state is stored by the CLI in a state file per workflow run.

State Location
Workflow progress Internal state tracked by saf-workflow CLI (exact path not documented in public README)
Generated files Per-workflow allowPaths directories (e.g., ./demo/**)
Template files templateFiles section of workflow definition

Persistence

  • Session-spanningsaf-workflow status can be called in a new session to check where a workflow was interrupted; the CLI supports resume via saf-workflow goto
  • Step-level commits — with -- -v git, each step is committed atomically, creating durable git history of the workflow execution

Context injection

Each workflow step receives typed context from the parent workflow definition:

step(AddDrizzleQueryWorkflowDefinition, () => ({
  path: "./queries/user/list.ts",
  promptMessage: "Add the query for a list of users.",
}))

The agent only sees the current step's prompt and context — not the full workflow definition.

Version control as memory

With -- -v git:

  • Each step creates a git commit with the step's changes
  • Git log serves as a sequential record of the entire workflow execution
  • Failed steps have no commit; successful steps have a clean commit

Cross-session continuity

saf-workflow status ./workflows/demo.ts shows current step and completion. saf-workflow goto ./workflows/demo.ts <step> allows resuming from any point.

No external state

No database, no MCP server, no external service. Workflow state is purely local file-based.

07

Orchestration

saflib-workflows — Orchestration

Multi-agent

No — single agent instance follows the workflow CLI's prompts sequentially.

Orchestration pattern

Sequential — steps execute in the order defined in the workflow definition. The CLI emits one step's prompt at a time.

Execution mode

Interactive-loop (agent-driven) or one-shot (scripts-only). The CLI drives sequencing; the agent responds to each prompt.

Subagent definition format

None — no sub-agents. Sub-workflows (makeWorkflowMachine) are not multi-agent — they are nested step sequences within the same agent session.

Isolation mechanism

None — the workflow operates in-place. The allowPaths field in versionControl scopes which files are committed, but there's no process isolation.

Multi-model

No — single agent/model configured by the user.

Consensus mechanism

None.

Prompt chaining

Yes — each step's output (generated files, code written by agent) becomes the context for the next step. Sub-workflows operate on the output of their predecessors.

Version control integration

-- -v git flag:

  • Commits each step's changes automatically
  • Uses versionControl.allowPaths to scope the commit
  • Creates atomic, reviewable history of the development sequence

CLI-driven mode

-- -r cursor flag enables Cursor CLI to drive the workflow automatically:

npm exec saf-workflow kickoff ./workflows/demo.ts -- -r cursor

The saf-workflow CLI calls the Cursor CLI for each agent-facing prompt step, fully automating the workflow.

Crash recovery

saf-workflow goto ./workflows/demo.ts <step> allows jumping to any step; workflow can be resumed after interruption.

08

Ui Cli Surface

saflib-workflows — UI and CLI Surface

CLI binary

saf-workflow — accessible via npm exec saf-workflow. Not a globally-installed binary; invoked through npm exec within the project.

Subcommands

Command Purpose
kickoff <workflow> Start or resume a workflow
checklist <workflow> Preview workflow steps (dry run checklist)
status <workflow> Show current step progress
next <workflow> Show what the next step is
goto <workflow> <step> Jump to a specific step
run-scripts <workflow> Execute only automated scripts (no agent prompts)
dry-run <workflow> Full dry run without execution
list List all available workflows
source <workflow> Show the TypeScript source of a workflow
info <workflow> Show workflow metadata

Flags

Flag Purpose
-- -v git Auto-commit after each step
-- -r cursor Use Cursor CLI to drive agent prompts automatically

Local UI

None — terminal CLI only. No web dashboard.

IDE integration

Cursor CLI integration via -- -r cursor. Works with any agent CLI that can run shell commands.

Observability

  • saf-workflow checklist — before execution: shows all steps
  • saf-workflow status — during execution: shows current step
  • git log — with -- -v git: atomic commit per step, full history of workflow execution
  • No dashboard, no metrics, no log streaming

Cross-platform

Node.js-based CLI; works on any platform with Node.js >= v22.19.0.

Related frameworks

same archetype · same primary tool · same memory type

Context-Engineering Handbook ★ 9.0k

Provides a first-principles, research-grounded vocabulary and learning path for context engineering — the discipline of designing…

walkinglabs/learn-harness-engineering ★ 6.6k

Teach harness engineering from first principles (12 lectures + 6 projects) and provide a scaffolding skill (harness-creator) that…

Awesome Harness Engineering (walkinglabs) ★ 2.7k

Curate the authoritative reference list of articles, benchmarks, and tools for harness engineering — the practice of shaping the…

cline-memory-bank (nickbaumann98) ★ 581

Custom instructions + 6-file hierarchical Markdown memory bank so Cline maintains full project context across sessions, with a…

FPF (First Principles Framework) ★ 372

Provides a formal pattern language for making reasoning explicit, traceable, and publishable in mixed human/AI engineering work —…

nexu-io/harness-engineering-guide ★ 134

Provide a practical, code-first reference guide to harness engineering — from first principles to production patterns —…