cl-dataflow is a small Common Lisp library for composable computation graphs, pipelines, event-driven workflows, state machines, and effect boundaries.
- Core graph, pipeline, event, effect, and state-machine primitives are implemented.
- Runnable examples live under
examples/. - The canonical test system is
cl-dataflow/test, andasdf:test-system :cl-dataflowdispatches to it. - The repository verifies cleanly on SBCL with all tests and example scripts passing.
| Area | Status | Notes |
|---|---|---|
| Graphs and nodes | Done | Node creation, edge construction, graph validation, and topological sort are implemented. |
| Pipelines | Done | Sequential pipelines and simple branching pipelines run against graph-ordered stages. |
| Iterative pipelines | Done | Feedback execution: run-pipeline-times, run-pipeline-until-fixpoint, and run-pipeline-while feed a result back as the next input for recurrent/settling computations. |
| Events | Done | Event creation, emission, and trace capture are implemented. |
| Effects | Done | Effect creation, handler lookup, and test-friendly execution are implemented. |
| State machines | Done | States, transitions, guards, history, reset/copy helpers, step-based execution, context propagation, and pipeline-stage embedding are implemented. |
| Event workflows | Done | Pipeline stages can emit events, run effects, and advance a state machine in one workflow. |
| Graph algorithms | Done | Strongly/weakly connected components, topological generations, transpose, acyclicity, shortest-hop distance, degrees, and immediate neighbors, all over the bulk-query adjacency snapshot. |
| Graph export | Done | Deterministic Graphviz DOT and Mermaid rendering, plus a graph-to-plist/plist-to-graph structural round trip. |
| Graph mutation | Done | remove-node, remove-edge, induced graph-subgraph, disjoint graph-merge, and graph-relabel-node for editing and composing graphs. |
| Graph paths | Done | Transitive closure/reduction, topological rank, longest (critical) path, all simple paths, an ordered cycle witness, and weighted (Dijkstra) shortest distance and path. |
| Equality predicates | Done | pipeline-equal-p, state-machine-equal-p, context-equal-p (structural equality via plist serialization), and state-machine-reachable-p. |
| Graph metrics | Done | Edge density, degree histogram, bipartiteness, structural graph-equal-p, and weak (undirected) reachability. |
| Graph connectivity | Done | Weak/strong connectivity predicates, self-loop nodes, the SCC condensation DAG, single-source distances, eccentricity, and diameter. |
| Graph algebra | Done | Set operations graph-union, graph-intersection, graph-difference, plus graph-filter-nodes (predicate-induced subgraph) and graph-map-nodes (injective relabel). |
| Graph criticality | Done | graph-articulation-points (cut vertices / critical stages), graph-bridges (critical connections / single points of failure), graph-dominators (the immediate-dominator tree of mandatory waypoints), and graph-post-dominators (its dual toward a sink), recursion-free. |
| State-machine analysis | Done | State/event enumeration, reachability, unreachable/terminal-state detection, structural determinism check, and DOT/Mermaid rendering. |
| State-machine execution | Done | state-machine-run-states (visited-state trace), state-machine-accepts-p (acceptance), and state-machine-event-path (shortest driving event sequence between two states). |
| State-machine builders | Done | Serialization (to-plist/plist-to), state-machine-complete-p, state-machine-transition-for, add-transition/remove-transition, and state-machine-relabel-state. |
| Combinators | Done | Handler wrappers (retry, fallback, memoize, tap, map, compose), node wrappers, and result-threading pipeline sequencing. |
| Streams (pull) | Done | A lazy transducer layer (map/filter/scan/take/drop/distinct/flat-map/concat/zip/tap) with collect/reduce/for-each/count/first consumers. |
| Reactive subjects (push) | Done | Synchronous push-based subjects with subscribe/emit/unsubscribe and derived subject-map/subject-filter/subject-merge -- the producer-driven dual of pull streams for event-driven workflows. |
| Reactive operators | Done | Stateful/combining subject operators scan, distinct, tap, take, drop, take-while, drop-while, count, zip, combine-latest, buffer -- push-side parity with the pull-stream vocabulary. |
| Stream extras | Done | Generators (iterate/repeat/cycle/enumerate/unfold), windowing (chunk/window/partition-by), and aggregate consumers (sum/min/max/find/some/every/last/nth). |
| Stream ops | Done | zip-with, interleave, take-nth, dedupe-consecutive, interpose, plus collectors group-by, frequencies, index-by, partition, split-at, average. |
| Stream statistics | Done | flatten, scan1, count-if, and statistical aggregates variance, stddev, median. |
| Stream search | Done | find-index, none-p, mode, and the lazy Cartesian product stream-cartesian. |
| Context serialization | Done | context-to-plist/plist-to-context plus event/effect plist round trips, completing the serialization story (handlers excluded). |
| Observability | Done | Pipeline rendering (pipeline->dot/->mermaid) and role enumeration, plus format-trace, trace-summary, and context-summary over a run's recorded trace. |
| Effect ergonomics | Done | register-effect-handler, context-effect-handler, effect-handled-p, context-effect-handler-types, and the with-effect-handler-scope macro for scoped handler registration. |
| Protocols | Done | flow-name, flow-metadata, and flow-kind provide consistent introspection across flow objects. |
| Testing helpers | Done | Dedicated helpers assert emitted events, effects, final state, state-machine state, and pipeline results. |
| Runnable examples | Done | Scripts cover a simple pipeline, event workflow, state machine, graph analysis, the graph toolkit, state-machine visualization, resilient pipelines, and streams. |
| Public API | Stable | cl-dataflow is the single exported package. |
Place this checkout and cl-prolog in locations ASDF can see, then load the
system. The test system additionally requires cl-weave.
(asdf:load-system :cl-dataflow)For a Quicklisp-style local checkout:
~/quicklisp/local-projects/cl-dataflow/
Then load it from Quicklisp:
(ql:quickload :cl-dataflow)Or register the repository directory in asdf:*central-registry* before loading.
The flake pins all dependencies and provides the reproducible development environment:
nix develop
nix run
nix flake check(defparameter *pipeline*
(cl-dataflow:define-pipeline ()
(:node "start"
:handler (lambda (input context)
(declare (ignore context))
(1+ input)))
(:node "finish"
:handler (lambda (input context)
(declare (ignore context))
(* input 2)))
(:edge "start" "finish")))
(cl-dataflow:run-pipeline *pipeline* :input 10)
;; => 22Node: a named computation with input ports, output ports, and a handler.Edge: a connection from one node output port to another node input port.Graph: a collection of nodes and edges with validation and topological ordering.Context: runtime state for events, effects, trace data, and workflow metadata.Pipeline: an executable graph or ordered stage list.Event: a recorded workflow occurrence with payload and trace position.Effect: a tracked side effect with handler lookup and result capture.State Machine: a small transition model with guards and actions.Workflow: a pipeline can emit events, trigger effects, and drive a state machine.
cl-dataflow exports a single package, cl-dataflow, with these public entry points:
- Errors:
cl-dataflow-error,graph-error,graph-error-graph,graph-error-detail,node-not-found-error,node-not-found-designator,graph-cycle-error,graph-cycle-nodes,effect-handler-missing-error,missing-effect-type,effect-handler-missing-effect,effect-handler-missing-detail,invalid-input-error,invalid-input-expected,invalid-input-value,invalid-input-detail,invalid-transition-error,invalid-transition-state,invalid-transition-event-type,invalid-transition-detail,guard-failed-error,guard-failed-state,guard-failed-event-type,guard-failed-transition,guard-failed-detail - Core data types:
node,edge,graph,context,event,effect,state-transition,state-machine,pipeline - Predicates:
node-p,edge-p,graph-p,context-p,event-p,effect-p,state-transition-p,state-machine-p,pipeline-p - Node APIs:
node-name,node-inputs,node-outputs,node-handler,node-metadata,make-node - Edge APIs:
edge-from,edge-from-port,edge-to,edge-to-port,edge-metadata,make-edge - Graph APIs:
graph-nodes,graph-edges,graph-metadata,make-graph,copy-graph,add-node,add-edge,find-node,graph-source-nodes,graph-sink-nodes,graph-reachable-p,graph-descendants,graph-ancestors,graph-path,validate-graph,topological-sort - Context APIs:
make-context,copy-context,context-values,context-value,context-node-values,context-events,context-events-in-order,context-event-types,context-events-of-type,context-effects,context-effects-in-order,context-effect-types,context-effects-of-type,context-trace,context-trace-in-order,context-last-event,context-last-effect,context-metadata,context-effect-handlers,context-result,context-state - Event APIs:
make-event,copy-event,emit-event,event-type,event-payload,event-metadata,event-trace-index - Effect APIs:
make-effect,copy-effect,perform-effect,effect-type,effect-payload,effect-metadata,effect-trace-index,effect-result - State machine APIs:
make-transition,define-state-machine,step-state-machine,run-state-machine,run-state-machine-with-context,make-state-machine-node,make-state-machine,copy-state-machine,state-machine-last-transition,state-machine-available-transitions,state-machine-can-step-p,reset-state-machine,transition-from,transition-event-type,transition-to,transition-guard,transition-action,transition-metadata,state-machine-state,state-machine-initial-state,state-machine-transitions,state-machine-history,state-machine-history-limit,state-machine-metadata - Pipeline APIs:
make-pipeline,define-pipeline,define-workflow,copy-pipeline,run-pipeline,run-pipeline-with-context,run-pipeline-sequence,pipeline-graph,pipeline-stages,pipeline-metadata - Observability APIs:
pipeline->dot,pipeline->mermaid,pipeline-node-names,pipeline-stage-names,pipeline-source-names,pipeline-sink-names,format-trace,trace-summary,context-summary - Pipeline extension APIs:
pipeline-to-plist,plist-to-pipeline,pipeline-validate,pipeline-stage-count,map-pipeline,pipeline->node - Iterative pipeline APIs:
run-pipeline-times,run-pipeline-until-fixpoint,run-pipeline-while - Batch event/effect APIs:
emit-events,perform-effects,event-of-type-p,effect-of-type-p,context-effect-results,context-effect-results-of-type - Context & introspection APIs:
context-merge,context-trace-of-kind,flow-describe,flow-children - Serialization APIs:
context-to-plist,plist-to-context,event-to-plist,plist-to-event,effect-to-plist,plist-to-effect - Stream search APIs:
stream-find-index,stream-none-p,stream-mode,stream-cartesian - Reactive subject APIs:
make-subject,subject-p,subject-subscribe,subject-unsubscribe,subject-emit,subject-subscriber-count,subject-map,subject-filter,subject-merge,subject-collect - Reactive operator APIs:
subject-scan,subject-distinct,subject-tap,subject-take,subject-drop,subject-take-while,subject-drop-while,subject-count,subject-flat-map,subject-partition,subject-zip,subject-combine-latest,subject-buffer - Effect ergonomics APIs:
register-effect-handler,context-effect-handler,effect-handled-p,context-effect-handler-types,with-effect-handler-scope - Graph analysis APIs:
graph-node-names,graph-order,graph-size,graph-empty-p,graph-successors,graph-predecessors,graph-out-degree,graph-in-degree,graph-transpose,graph-acyclic-p,graph-strongly-connected-components,graph-connected-components,graph-topological-generations,graph-distance - Graph export APIs:
graph->dot,graph->mermaid,graph-layout,graph-to-plist,plist-to-graph - Graph mutation APIs:
remove-node,remove-edge,graph-subgraph,graph-merge,graph-relabel-node,graph-contract-edge - Graph path APIs:
graph-transitive-closure,graph-transitive-reduction,graph-topological-rank,graph-longest-path,graph-all-paths,graph-find-cycle,graph-eulerian-path,graph-weighted-distance,graph-weighted-path,graph-weighted-distances-from,graph-max-flow,graph-min-cut - Equality/reachability predicate APIs:
pipeline-equal-p,state-machine-equal-p,context-equal-p,state-machine-reachable-p - Graph metric APIs:
graph-density,graph-degree-histogram,graph-clustering-coefficient,graph-average-clustering,graph-reciprocity,graph-bipartite-p,graph-greedy-coloring,graph-equal-p,graph-undirected-reachable-p - Graph connectivity APIs:
graph-connected-p,graph-strongly-connected-p,graph-self-loop-nodes,graph-condensation,graph-distances-from,graph-bfs-order,graph-dfs-order,graph-eccentricity,graph-diameter,graph-radius,graph-center,graph-periphery,graph-wiener-index,graph-average-path-length,graph-closeness-centrality,graph-betweenness-centrality - Graph algebra APIs:
graph-union,graph-intersection,graph-difference,graph-diff,graph-filter-nodes,graph-map-nodes - Graph criticality APIs:
graph-articulation-points,graph-bridges,graph-dominators,graph-post-dominators - State-machine analysis APIs:
state-machine-states,state-machine-event-types,state-machine-reachable-states,state-machine-unreachable-states,state-machine-terminal-states,state-machine-deterministic-p,write-state-machine-dot,write-state-machine-mermaid,state-machine->dot,state-machine->mermaid - State-machine execution APIs:
state-machine-run-states,state-machine-accepts-p,state-machine-event-path - State-machine builder APIs:
state-machine-to-plist,plist-to-state-machine,state-machine-complete-p,state-machine-transition-for,add-transition,remove-transition,state-machine-relabel-state,state-machine->graph - Combinator APIs:
mapping-handler,compose-handlers,retrying-handler,fallback-handler,memoizing-handler,tapping-handler,wrap-node,node-with-retry,node-with-fallback,node-with-memoization,node-with-tap,contract-handler,node-with-contract - Stream APIs:
flow-stream-p,empty-stream,list->stream,stream-of,stream-range,stream-map,stream-filter,stream-scan,stream-take,stream-drop,stream-take-while,stream-drop-while,stream-distinct,stream-flat-map,stream-concat,stream-zip,stream-tap,stream-collect,stream-reduce,stream-for-each,stream-count,stream-first,stream-empty-p - Stream generator/window/aggregate APIs:
stream-iterate,stream-repeat,stream-cycle,stream-enumerate,stream-unfold,stream-chunk,stream-window,stream-partition-by,stream-sum,stream-min,stream-max,stream-find,stream-some,stream-every,stream-last,stream-nth - Stream op/collector APIs:
stream-zip-with,stream-interleave,stream-take-nth,stream-dedupe-consecutive,stream-interpose,stream-distinct-by,stream-group-by,stream-frequencies,stream-index-by,stream-partition,stream-split-at,stream-average - Stream statistics APIs:
stream-flatten,stream-scan1,stream-count-if,stream-variance,stream-stddev,stream-median - Protocols:
flow-name,flow-metadata,flow-kindacross nodes, edges, graphs, contexts, events, effects, transitions, state machines, and pipelines - Testing helpers:
run-pipeline-with-test-context,assert-emitted-events,assert-performed-effects,assert-final-state,assert-state-machine-state,assert-pipeline-result
Collection-oriented readers such as graph-nodes, graph-edges, graph-source-nodes,
graph-sink-nodes, context-values, context-events, context-effects,
context-trace, event-payload, event-metadata, effect-payload,
effect-metadata, effect-result, transition-metadata,
state-machine-transitions, and pipeline-stages return independent snapshots.
Their setters replace the entire live collection.
context-effect-handlers is intentionally mutable and returns the live handler
table so callers can register handlers directly.
pipeline-graph returns the live, validated graph owned by the pipeline, so
mutating it intentionally affects the pipeline. Use copy-pipeline when you
need an isolated graph clone.
node-not-found-error exposes the missing designator so callers can inspect
whether the failure came from a node name or an edge reference.
graph-cycle-error exposes the remaining cyclic nodes so callers can inspect
the exact cycle component that blocked ordering.
effect-handler-missing-error includes the missing effect type and a copied
effect snapshot so callers can inspect the payload that triggered the failure.
The library is organized around a small set of composable primitives:
- Graphs and nodes model the structure of a flow.
- Contexts capture runtime values, trace data, events, effects, and final result state.
copy-context,copy-event, andcopy-effectprovide explicit clone helpers for the main runtime value types.copy-contextclones the effect-handler table as well, so derived contexts can register different handlers without cross-talk.context-resultreturns an independent snapshot on read, so callers can inspect pipeline output without mutating the stored result.- Graph node names are unique within a graph;
add-noderejects duplicate names so edges do not silently retarget to a replacement node. - Graph edges are unique by source node, source port, destination node, and destination port;
add-edgerejects duplicate connections instead of counting them twice. copy-pipelineprovides an explicit clone helper that preserves the pipeline graph, stage order, and metadata, while remapping stages onto the copied graph.copy-state-machineclones transitions, history, and metadata so derived machines can evolve independently from the original instance.- Pipelines execute graphs and stage lists against a context.
define-pipeline,define-state-machine, anddefine-workflowprovide declarative entry points, so graph structure and transition data can stay separate from handler logic.- Node handlers receive structured inputs normalized from hash tables, alists, plists, or scalars, and structured outputs are normalized back into the pipeline context and sink result data.
- Events, effects, and state machines let one pipeline drive another workflow boundary.
make-state-machine-nodeturns a state machine into a pipeline stage without handwritten glue, and itsevent-fnandresult-fnhooks let callers adapt pipeline input and emitted output without wrapping the machine manually.event-fnmay return an event designator or a full event object.define-workflowunifies graph edges, state-machine transitions, and embedded machine nodes in one macro expansion while still returning ordinarypipelineandstate-machinevalues.step-state-machineandrun-state-machinereturn transition records so the state machine can behave like a reducer in pipeline and workflow code.- When
step-state-machinereceives acontext, it updatescontext-stateand appends the transition record tocontext-trace. copy-state-machine,reset-state-machine, andstate-machine-historymake the mutable state machine reusable and observable across runs.- State machine transitions are copied on construction and assignment, so caller-owned transition objects do not leak into the machine.
- State-machine transition failures surface structured condition data, including the current state, event type, and the transition snapshot for guard failures.
- Graph cycle failures surface the remaining cyclic nodes so callers can inspect the exact component that prevented ordering.
graph-reachable-p,graph-descendants,graph-ancestors, andgraph-pathanswer reachability questions over the Prolog edge relation:graph-reachable-pis the boolean predicate,graph-descendantsreturns every node reachable from a node andgraph-ancestorsreturns every node that reaches it (both as name-ordered node snapshots), andgraph-pathreturns the node names of a shortest witnessing path (FROMfirst,TOlast) orNIL. All follow the same one-or-more-edges rule and terminate on cyclic graphs.- Pipeline stage lists are copied on construction and assignment, so caller-owned stage lists do not leak into the pipeline object.
- Pipelines copy supplied graphs on construction and assignment, so caller-owned graph mutations do not leak into the pipeline object. When a pipeline is built from a graph, its stage list is remapped onto that copied graph so the pipeline stays internally coherent.
- Collection readers return snapshots, so callers can inspect state without mutating the live object by accident.
- Effect handlers are stored on the context with normalized lowercase string keys, so symbols and strings both resolve consistently through
make-contextandperform-effect. state-machine-available-transitionsandstate-machine-can-step-pexpose the active control surface for orchestration;state-machine-can-step-paccepts:contextso callers can preflight guarded transitions with the same runtime data they will use for stepping.run-state-machine-with-contextreturns the machine, transition records, and context for workflow embedding. If you omit:context, it creates a fresh context seeded with the machine's current state.- Protocols provide uniform introspection across the major flow objects.
cl-dataflow keeps the implementation deliberately small:
src/package.lispdefines the public package and exported API surface.src/core.lispholds the shared graph, node, and context primitives.src/protocols.lispdefines the shared introspection and printing protocols.src/pipeline.lisp,src/events.lisp,src/effects.lisp, andsrc/state-machine.lispsplit the runtime behavior into focused files.src/testing.lispcontains deterministic test helpers, including state-machine assertions.- The graph runtime models edges as a
cl-prologfact base.topological-sortandgraph-reachable-pread the edge relation with a single bulkcl-prolog:query-prolog, then run linear, stack-safe traversals (Kahn's algorithm and a work-list search) over the materialized adjacency. This uses Prolog as the relational store while deliberately keeping the bounded graph algorithms in Lisp, so cyclic or adversarially deep graphs cannot trigger the non-termination or exponential-path blow-ups that a naive recursivereachable/2rule would. cl-dataflow.asdloads the library system and routesasdf:test-system :cl-dataflowtocl-dataflow/test.examples/contains runnable scripts that bootstrap the ASDF system for zero-setup demonstrations.
Runnable examples are provided as plain scripts:
examples/simple-pipeline.lispexamples/event-workflow.lisp- a pipeline that emits events and advances a state machineexamples/state-machine.lisp- a standalone state machine transition flowexamples/graph-analysis.lisp- reachability analysis (descendants, ancestors, shortest path, boundaries) over a dataflow graphexamples/graph-toolkit.lisp- strongly connected components, topological generations, transpose, distance, and DOT/Mermaid renderingexamples/state-machine-visualization.lisp- state/event enumeration, reachability, terminal and unreachable states, and DOT/Mermaid renderingexamples/resilient-pipeline.lisp- retrying and fallback node wrappers plus result-threading pipeline sequencingexamples/streams.lisp- lazy stream pipelines (map/filter/take/scan/flat-map/distinct) over an unbounded rangeexamples/graph-analysis-advanced.lisp- critical path, topological rank, transitive reduction, weighted distance, density/bipartiteness, and a serialization round tripexamples/stream-analytics.lisp- frequencies, group-by, partition, sliding-window averages, and whole-stream meanexamples/integration.lisp- an end-to-end scenario composing pipelines, graph analysis, pull streams, reactive subjects, a state machine, and context serialization
Run them with SBCL:
sbcl --script examples/simple-pipeline.lisp
sbcl --script examples/event-workflow.lisp
sbcl --script examples/state-machine.lisp
sbcl --script examples/graph-analysis.lisp
sbcl --script examples/graph-toolkit.lisp
sbcl --script examples/state-machine-visualization.lisp
sbcl --script examples/resilient-pipeline.lisp
sbcl --script examples/streams.lisp
sbcl --script examples/graph-analysis-advanced.lisp
sbcl --script examples/stream-analytics.lisp
sbcl --script examples/integration.lispExpected outputs:
examples/simple-pipeline.lispprintsSimple pipeline result: rendered: 70examples/event-workflow.lispprints the final workflow state and event traceexamples/state-machine.lispprintsFinal state: completed, the transition count, and the last transition recordexamples/graph-analysis.lispprints the downstream/upstream node sets, the shortestingest -> loadpath, and the graph's source and sink nodesexamples/graph-toolkit.lispprints the graph order/size, topological generations,a -> ddistance, strongly connected components, and DOT/Mermaid diagramsexamples/state-machine-visualization.lispprints the state and event sets, reachable/unreachable/terminal states, the determinism verdict, and DOT/Mermaid diagramsexamples/resilient-pipeline.lispprintsRetry result: 70 (after 3 attempts), the fallback results, and the sequenced pipeline resultexamples/streams.lispprintsFirst 3 even squares: (4 16 36), the running totals, the flat-mapped list, and the distinct sumexamples/graph-analysis-advanced.lispprints the critical path, topological rank, transitive-reduction edge count, weighted distance, density/bipartiteness, and the serialization round-trip checkexamples/stream-analytics.lispprints the event frequencies, parity grouping, partition, sliding-window averages, and the mean of 1..100examples/integration.lispprints the priced orders, high-value reactive alerts, the state-machine driving events, and a confirmed context serialization round trip
The test ASDF system is cl-dataflow/test. asdf:test-system :cl-dataflow
dispatches to the cl-weave suite. The suite dogfoods advanced cl-weave usage:
property-based generators (gen-tuple, gen-list, gen-integer), custom
matchers (:to-have-valid-topological-order, :to-be-acyclic, :to-reach),
differential property tests that cross-check graph-reachable-p against an
independent reference transitive closure over random DAGs, and a
:to-run-under-ms performance guard that keeps deep-graph topological sort and
reachability from regressing into superlinear behavior.
GitHub Actions runs the CI workflow on a matrix of ubuntu-latest
(x86_64-linux) and macos-latest (aarch64-darwin), so the documented
cross-platform support is verified on every push and pull request. Each job runs
the same nix flake check and coverage build as local verification and uploads
the generated per-system coverage report as an artifact. Pushing a vX.Y.Z tag
additionally triggers the release workflow, which publishes a GitHub release
using the matching CHANGELOG.md section.
nix run
nix flake checkCoverage is measured only for source files owned by the cl-dataflow ASDF
system. The coverage check requires at least 84% expression coverage and 100%
branch coverage; falling below either threshold fails the command. Run the same
gate locally with ./scripts/coverage.sh. The output paths and thresholds can
be overridden with COVERAGE_OUTPUT, COVERAGE_REPORT_DIR,
COVERAGE_MIN_EXPRESSION, and COVERAGE_MIN_BRANCH.
The current verification commands are:
./scripts/verify.sh
nix build .#checks.$(nix eval --impure --raw --expr builtins.currentSystem).coverage
sbcl --script examples/simple-pipeline.lisp
sbcl --script examples/event-workflow.lisp
sbcl --script examples/state-machine.lispThe test suite currently covers branching pipeline behavior, event emission,
state-machine transitions, effect handling, and the pipeline/state-machine
workflow integration used by the examples. It also covers the exported testing
helpers, including singleton expectations for event/effect assertions and
runtime-context seeding via run-pipeline-with-test-context.
See CONTRIBUTING.md for the local workflow and verification commands.
See CHANGELOG.md for the current project history.
See SECURITY.md for vulnerability reporting guidance.
See CODE_OF_CONDUCT.md for discussion expectations and project norms.
- The repository is verified with SBCL and the commands above. Other Common Lisp implementations may work, but they are not currently part of the documented verification surface.
- Collection readers return snapshots for safe inspection. Use the documented setters when you want to replace the live collection.
context-effect-handlersis the one intentionally mutable collection reader because it is the registration surface for effect handlers.copy-contextcopies the handler table, so you can fork a context and mutate handler registration independently from the original.run-pipeline-with-test-contextseedsstate,metadata, and effect handlers onto a fresh context and returns that live context after execution.assert-emitted-eventsandassert-performed-effectsaccept either a single expected type or a list of expected types.topological-sortis deterministic for independent nodes, which keeps graph execution order stable across implementations.- The example scripts double as smoke tests for the core execution paths, so keep them green when changing runtime behavior.
cl-dataflow is intentionally not:
- a CLI framework
- parser combinators
- terminal or TTY handling
- a Prolog engine
- an HTTP server
- a database adapter
- a distributed execution runtime
- an async runtime
- a large dependency injection framework
- a generic utility package
cl-dataflow/
README.md
LICENSE
cl-dataflow.asd
src/
tests/
examples/
MIT