Deterministic LLM workflow engine
Project description
llmflow-core
Deterministic LLM workflow engine for file-defined, schema-validated pipelines.
Overview
llmflow-core executes explicit workflow DAGs from YAML and prompt files.
It is designed for predictable execution, strict output contracts, and replayable
artifacts.
Core guarantees:
- Stable topological execution order
- Fail-fast behavior on first step error
- JSON-schema validation for LLM outputs
- Run artifacts for audit and replay
Why this exists
Production LLM pipelines often fail on three basics:
- Step order is implicit and hard to reason about
- Outputs drift from expected structure
- Runs are difficult to reproduce and debug
llmflow-core addresses this with file-defined workflows, strict validation,
and deterministic run traces.
Installation
python -m pip install -e .
Install with test dependencies:
python -m pip install -e .[dev]
Quickstart
1) Run with Python API
from llmflow import MockProvider, RunConfig, Runner, Workflow
workflow = Workflow.load("examples/blog_pipeline/workflow.yaml")
runner = Runner(
provider=MockProvider(default_output="{}", strict=False),
config=RunConfig(artifacts_dir=".runs", provider_name="mock"),
)
result = runner.run(
workflow,
inputs={"topic": "Deterministic AI", "audience": "Engineering managers"},
)
print(result.outputs)
print(result.run_dir)
Note:
MockProvider(default_output=...)returns the same JSON for every LLM step.- If your workflow has different per-step schemas, use per-prompt mock responses (see Example Workflow below).
2) Run with CLI
llmflow run examples/blog_pipeline/workflow.yaml \
--input topic="Deterministic AI" \
--input audience="Engineering managers" \
--mock-output '{"title":"Draft","summary":"S","body":"B"}'
3) Inspect and replay
llmflow graph examples/blog_pipeline/workflow.yaml
llmflow replay .runs/run_YYYYMMDD_HHMMSS_<shortid>
CLI
The CLI is a thin wrapper over the library API.
Commands:
llmflow run <workflow.yaml> --input key=value ...llmflow graph <workflow.yaml>llmflow replay <run_dir>
Example:
llmflow run examples/blog_pipeline/workflow.yaml \
--input topic="Deterministic AI" \
--input audience="Engineering managers" \
--mock-output '{"title":"Draft","summary":"S","body":"B"}'
llmflow graph examples/blog_pipeline/workflow.yaml
llmflow replay .runs/run_YYYYMMDD_HHMMSS_<shortid>
CLI mock behavior:
--mock-outputand--mock-output-fileare applied to all LLM steps in the run.- For workflows with heterogeneous per-step schemas, prefer Python API tests with prompt-specific mock responses.
Example workflow
Repository example: examples/blog_pipeline
Contents:
examples/blog_pipeline/workflow.yamlexamples/blog_pipeline/prompts/outline.mdexamples/blog_pipeline/prompts/critique.mdexamples/blog_pipeline/prompts/revise.mdexamples/blog_pipeline/schemas/outline.jsonexamples/blog_pipeline/schemas/critique.jsonexamples/blog_pipeline/schemas/final_article.jsonexamples/blog_pipeline/tools.py
The end-to-end deterministic example run is validated by:
tests/test_examples_blog_pipeline.py
Workflow YAML format
Minimal shape:
workflow:
name: blog_post_pipeline
version: "1.0"
inputs:
topic:
type: string
audience:
type: string
steps:
- id: outline
type: llm
prompt: prompts/outline.md
output_schema: schemas/outline.json
llm:
model: mock-model
temperature: 0
- id: critique
type: llm
depends_on: [outline]
prompt: prompts/critique.md
output_schema: schemas/critique.json
llm:
model: mock-model
temperature: 0
outputs:
article: critique
Rules:
workflow.nameandworkflow.versionare required.inputsis a mapping of input names to type declarations.- Each step needs a unique
idandtype. depends_onmust reference existing step ids.outputsmaps final output names to step ids.- For
llmsteps,prompt,output_schema, andllm.modelare required.
Replay
Replay reconstructs outputs from recorded artifacts and verifies they match the
recorded outputs.json exactly.
from llmflow import replay
result = replay(".runs/run_YYYYMMDD_HHMMSS_<shortid>")
print(result.outputs)
Optional workflow override:
result = replay(
".runs/run_YYYYMMDD_HHMMSS_<shortid>",
workflow_path="examples/blog_pipeline/workflow.yaml",
)
Artifacts
Each run writes a folder under .runs/:
.runs/
run_YYYYMMDD_HHMMSS_<shortid>/
metadata.json
inputs.json
outputs.json
steps/
<step_id>/
output.json
rendered_prompt.md
llm_call.json
logs.txt
metadata.json includes:
artifacts_version- engine version
- workflow name, version, and hash
- provider name
- execution order
- prompt hashes and step output hashes
- timestamps
Typical step artifacts:
steps/<step_id>/output.json: Validated step output payloadsteps/<step_id>/rendered_prompt.md: Rendered prompt text for LLM stepssteps/<step_id>/llm_call.json: Provider request/response metadata for LLM steps
Extending the engine
Providers
Implement Provider.call(request) -> ProviderResponse and pass the provider to
Runner.
from llmflow.providers import Provider, ProviderRequest, ProviderResponse
class StaticProvider(Provider):
def call(self, request: ProviderRequest) -> ProviderResponse:
return ProviderResponse(
model=request.model,
output_text='{"title":"Draft","summary":"S","body":"B"}',
raw={"provider": "static"},
)
Tools
Register Python functions in ToolRegistry. Tool functions accept merged step
inputs and must return a dict.
from llmflow.registry import ToolRegistry
tools = ToolRegistry()
tools.register("summarize_topic", lambda inputs: {"topic_slug": inputs["topic"].lower()})
Validators
Register custom validators in ValidatorRegistry. Validator functions accept
merged step inputs and should return True/None on success, or False on
failure.
from llmflow.registry import ValidatorRegistry
validators = ValidatorRegistry()
validators.register("has_summary", lambda inputs: bool(inputs.get("summary")))
Custom steps
Register custom step classes in StepRegistry when you need a new execution
primitive beyond llm, tool, and validate.
Testing
Run all tests:
pytest
Run tests with coverage for core modules:
pytest --cov=llmflow --cov-report=term-missing
Determinism and replay checks:
pytest tests/test_replay.py tests/test_examples_blog_pipeline.py
Run a local command equivalent to CI:
python -m pip install -e .[dev]
pytest --cov=llmflow --cov-report=term-missing
Current status
Implemented through Phase 11:
- Core workflow loading and validation
- Graph ordering and cycle detection
- LLM/tool/validate steps
- Artifacts and metadata
- Runner and replay
- CLI (
run,graph,replay) - Example workflow (
examples/blog_pipeline) - CI workflow and coverage command (
pytest --cov=llmflow)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llmflow_core-0.0.2.tar.gz.
File metadata
- Download URL: llmflow_core-0.0.2.tar.gz
- Upload date:
- Size: 20.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65f1010616c54b12e5ce09dff4b2c2a0111ce62629d4ec0be6c98858c3e927c9
|
|
| MD5 |
9a59569ea0432586a78bac90a5af021a
|
|
| BLAKE2b-256 |
ee431cbd8321255399d2077fc1ee583cf624b5ca241e257e1193acbcf6cd353a
|
Provenance
The following attestation bundles were made for llmflow_core-0.0.2.tar.gz:
Publisher:
publish-pypi.yml on ibrahim1023/llmflow-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llmflow_core-0.0.2.tar.gz -
Subject digest:
65f1010616c54b12e5ce09dff4b2c2a0111ce62629d4ec0be6c98858c3e927c9 - Sigstore transparency entry: 954836724
- Sigstore integration time:
-
Permalink:
ibrahim1023/llmflow-core@0dea63fb8a25ed0122b89590ee2bd5889fdd31b6 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ibrahim1023
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@0dea63fb8a25ed0122b89590ee2bd5889fdd31b6 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file llmflow_core-0.0.2-py3-none-any.whl.
File metadata
- Download URL: llmflow_core-0.0.2-py3-none-any.whl
- Upload date:
- Size: 21.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f48e24bb5bfbb84bbfbfa0f9fccb5bd8aebd143bc447518a35e2a1c9af81453
|
|
| MD5 |
3ae648e50326f1a84d6bca451e10d4c3
|
|
| BLAKE2b-256 |
e5f5e99a3ec559a006b95188eb31be05ea05b05c737351c924f7d2a7110024b5
|
Provenance
The following attestation bundles were made for llmflow_core-0.0.2-py3-none-any.whl:
Publisher:
publish-pypi.yml on ibrahim1023/llmflow-core
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llmflow_core-0.0.2-py3-none-any.whl -
Subject digest:
6f48e24bb5bfbb84bbfbfa0f9fccb5bd8aebd143bc447518a35e2a1c9af81453 - Sigstore transparency entry: 954836727
- Sigstore integration time:
-
Permalink:
ibrahim1023/llmflow-core@0dea63fb8a25ed0122b89590ee2bd5889fdd31b6 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ibrahim1023
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@0dea63fb8a25ed0122b89590ee2bd5889fdd31b6 -
Trigger Event:
workflow_dispatch
-
Statement type: