Metadata-Version: 2.5
Name: flowlit
Version: 0.5.0
Summary: A lightweight, event-driven workflow execution engine.
Project-URL: Homepage, https://github.com/shadiwazir/flowlit
Project-URL: Repository, https://github.com/shadiwazir/flowlit
Project-URL: Issues, https://github.com/shadiwazir/flowlit/issues
Author: shadiwazir
License: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: aiohttp>=3.9
Requires-Dist: pydantic>=2.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
Description-Content-Type: text/markdown

# 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.

```bash
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.Task`s — not
  serialized because they happen to share a step type, and not
  artificially parallelized either. See
  [Concurrency model](doc/concurrency.md).
- **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](doc/plan-format.md).
- **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](doc/plan-format.md#failure-handling-optional-blocking-silent_failures).
- **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](doc/plan-format.md#branching-when-when_not-else).
- **Clean, layered architecture, built to extend.** Four layers
  (`domain` → `application` → `infrastructure` → `interfaces`), each only
  depending on the ones below it, with ports (`Protocol`s) separating
  contracts from implementations. Add a step type without forking the
  repo via one call to `register_executor()`. See
  [Architecture](doc/architecture.md).
- **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](doc/api-reference.md).

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.Task`s, driven purely by the dependency graph. |
| **Four built-in executors** | `noop`, `sleep`, `shell` (with timeout), `http` (with retry/backoff) — see [Executors](doc/executors.md). |
| **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

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

flowlit examples/hello_workflow.yaml
```

```bash
pytest              # run the test suite
ruff check src tests # lint
mypy src             # type-check
```

See [Getting started](doc/getting-started.md) for a full walkthrough,
including using flowlit as a library and reading its CLI output.

## Documentation

Detailed, modular guides live under [`doc/`](doc/):

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

## A minimal plan

```yaml
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](doc/plan-format.md) 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](doc/architecture.md) for the reasoning behind this
layering.

## License

MIT — see [`pyproject.toml`](pyproject.toml).
