Skip to main content

Flowlit

A lightweight, event-driven workflow execution engine. Hand it a YAML plan — a set of steps, their dependencies, and per-step instructions — and Flowlit validates it as a DAG, runs it, and hands each step to whichever executor is registered for that step's type, running every step the DAG allows to run at once genuinely concurrently, not one at a time.

pip install -e ".[dev]"
flowlit examples/hello_workflow.yaml
  -> greet (noop): submitted
       step greet (noop): Hello from Flowlit!
  <- greet: completed
  -> build (noop): submitted
       step build (noop): Pretending to build the project...
  <- build: completed
  -> test (noop): submitted
       step test (noop): Pretending to run tests...
  <- test: completed
  -> report (noop): submitted
       step report (noop): Build and test both finished.
  <- report: completed
Workflow hello-workflow: completed

Why Flowlit

  • The DAG alone decides concurrency. Two steps that share nothing but a parent run genuinely at once, as independent asyncio.Tasks — not serialized because they happen to share a step type, and not artificially parallelized either. See Concurrency model.
  • Data flow is explicit and auditable. A step reads a prior step's output only via a small, closed ${{ steps.<id>.output.<path> }} placeholder syntax — no expressions, no filters, nothing a semi-trusted plan author (an AI agent proposing a workflow, say) could use to smuggle in arbitrary logic. See Plan format.
  • Failure handling is a first-class, per-step decision. optional, blocking, silent_failures, and per-edge blocking_overrides let two different dependents of the same step disagree about whether they're blocked by its failure — expressive enough for "best-effort logging that should never stop a required deploy step." See Plan format.
  • Branching without an expression language. when/when_not/else gate a step on a prior step's output or outcome, reusing the same closed placeholder syntax — no new DSL to audit. A branch step is implicitly optional, so picking one path over another can't itself abort the workflow. See Branching.
  • Clean, layered architecture, built to extend. Four layers (domain → application → infrastructure → interfaces), each only depending on the ones below it, with ports (Protocols) separating contracts from implementations. Add a step type without forking the repo via one call to register_executor(). See Architecture.
  • Built for both a blocking CLI and a future async server. run_to_completion() blocks until done (right for a CLI); start_workflow()
    • polling get_status() doesn't (right for an MCP server or any poll-driven client) — same DAG, same engine, no separate code path. See API reference.

Everything runs in memory — nothing survives a process restart. That's a deliberate v1 choice, not an oversight: the goal is to get the architecture right first, with the WorkflowRepository/EventBus ports already shaped so a persistent implementation can be dropped in later without touching orchestration logic. The eventual goal is to run this as an MCP server so agent tools (e.g. VS Code GitHub Copilot) can submit and drive plans.

Key features

Real concurrency Independent steps run as genuinely parallel asyncio.Tasks, driven purely by the dependency graph.
Four built-in executors noop, sleep, shell (with timeout), http (with retry/backoff) — see Executors.
Typed, defaulted specs Any executor can declare a pydantic spec_model and get validation for free, at the earliest honest point.
Pluggable executors register_executor("my_type", MyExecutor()) — no fork required.
Rich failure semantics Required vs. optional steps, blocking vs. non-blocking dependents (with per-edge overrides), silent vs. visible failures, cascading skips.
Clean cancellation A required failure — or an explicit cancel_workflow() — stops every in-flight step promptly and deterministically.
Output passing ${{ steps.<id>.output.<path> }} placeholders, resolved just before dispatch.
Two execution modes run_to_completion() (blocking) and start_workflow() + poll (non-blocking), from the exact same engine.
JSON-ready DTOs WorkflowService returns primitives-only dataclasses — no domain leakage across the API boundary.

Quickstart

python -m venv .venv
source .venv/bin/activate   # or `.venv\Scripts\activate` on Windows
pip install -e ".[dev]"

flowlit examples/hello_workflow.yaml
pytest              # run the test suite
ruff check src tests # lint
mypy src             # type-check

See Getting started for a full walkthrough, including using flowlit as a library and reading its CLI output.

Documentation

Detailed, modular guides live under doc/:

Guide Covers
Getting started Install, quickstart, CLI flags, using flowlit as a library.
Plan format The YAML plan schema: steps, dependencies, output-passing placeholders, failure-handling fields.
Architecture The four-layer design, execution flow, event bus, composition root — with diagrams.
Concurrency model How the DAG drives real concurrency, cancellation semantics, max_concurrent_steps.
Executors The noop/sleep/shell/http executors, adding your own, registering one from outside the repo.
API reference WorkflowService, ports, DTOs, events, and the full exception hierarchy.
Configuration CLI flags, build_app_context() parameters, per-step configuration.
Observability Logging setup and live progress via the event bus.
Testing Test suite layout and what each part covers.
Examples A guided tour of every plan in examples/.
Changelog What changed in each release, including any breaking changes.

A minimal plan

id: build-and-deploy
name: Build and Deploy
steps:
  - id: fetch_source
    type: shell
    spec:
      command: "echo '{\"commit_sha\": \"abc123\"}'"
    depends_on: []

  - id: notify
    type: noop
    spec:
      message: "deployed commit ${{ steps.fetch_source.output.commit_sha }}"
    depends_on: [fetch_source]

type selects the executor; spec is whatever that executor needs; depends_on must form a DAG. See Plan format for the complete schema, including optional/blocking/silent_failures and blocking_overrides.

Project layout

src/flowlit/
├── domain/          Step/Workflow entities, DAG validation -- stdlib only
├── application/      use cases, ports (Protocols), orchestration
├── infrastructure/   YAML loading, in-memory event bus/repository, executors
├── interfaces/        CLI today; a future MCP server; the composition root
└── plugins.py         register_executor() -- the public extension seam
examples/              runnable YAML plans
tests/                 unit + integration test suite

See Architecture for the reasoning behind this layering.

License

MIT — see pyproject.toml.

Release files for flowlit 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flowlit 0.5.0
File Size Uploaded
flowlit-0.5.0.tar.gz 206.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flowlit 0.5.0
File Interpreter ABI Platform
flowlit-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 320.6 kB

Release files / flowlit-0.5.0.tar.gz

Download URL flowlit-0.5.0.tar.gz
Size 206.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ff529f267b4936e9bba9079d5f3d4c0c88a21b78c7c8eef56fbf0d933ccdc628
BLAKE2b-256 checksum
How to use checksums
43d37419fa640e7d569f6bd5e2fd7e54b1d3671c350ca3cd44752d8243dadce9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / flowlit-0.5.0-py3-none-any.whl

Download URL flowlit-0.5.0-py3-none-any.whl
Size 113.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e37074d78f1549986d2bce370445ddc3264d546923e45396c510f2fdab360663
BLAKE2b-256 checksum
How to use checksums
c5d0ff81f71b57f872f14ad5f4ef6fd9f7e9c41e89abc90b9af9676187352e8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page