Installation¶
Leoflow ships in two editions โ pick the install path that matches the one you want:
| Edition | Where it runs | Who it's for | Install path |
|---|---|---|---|
| Lite | Your laptop or a single VM (no Kubernetes, no Docker required) | Local development, small teams, evaluation | Install Lite |
| Pro | A Kubernetes cluster (pod-per-task executor) | Team-scale and production workloads | Install Pro |
See Editions for the full feature-by-feature breakdown. The two editions share the same Go control plane and the same Airflow-compatible HTTP API โ Pro adds the K8s executor, HA scheduler, and external-datastore expectations; Lite bundles everything in one host process.
Install Lite¶
One command installs Leoflow Lite and bootstraps everything it needs โ no sudo, no system Python, no package manager:
That script downloads the release archive for your OS/architecture, verifies
its SHA-256 against the signed checksums, installs the binaries to
~/.leoflow/bin, and then runs leoflow setup.
What you need¶
Almost nothing. The control plane, CLI, and agent are static Go binaries,
and leoflow setup provisions a Python 3.11 itself if you don't have one.
There are two execution paths โ and no Docker executor, on purpose (ADR 0015): the Docker Go SDK carries an unfixable advisory (Moby AuthZ bypass, GO-2026-4887) that would reach the control-plane binary and fail the security gate. So:
| Executor | Needs | Isolation | For |
|---|---|---|---|
| subprocess | just the install (binaries + a managed Python) | none (dev-only) | fast local iteration, small projects |
| kubernetes | + Docker (to host a local k3d cluster; k3d/kubectl fetched on demand) | real pods | production parity, the staging volume, resource limits |
Docker, when present, is only the engine that hosts the local k3d cluster โ
it is never an executor itself. leoflow setup detects what's present and
picks the highest path available; without Docker it uses subprocess. Run
leoflow doctor anytime to see where you stand, and see
Choosing an executor for the trade-offs.
What leoflow setup does¶
setup is idempotent โ re-running is safe. It:
- Ensures Python 3.11. Uses a system
python3.11if one is onPATH; otherwise downloads a pinned, checksum-verified relocatable CPython into~/.leoflow/python. No sudo, no system install. - Extracts the DAG parser and task runtime (embedded in the binary) to
~/.leoflow/pysrc. - Points
parser_cmdat the parser in~/.leoflow/config.yaml. The parser is pure Python with its dependencies vendored (the Airflow shim and PyYAML โ ADR 0024), so there is no parser venv, no pip, and no Apache Airflow install โ it runs on the interpreter from step 1 directly. - Creates your workspace (default
~/leoflow, override with--workspace) for your DAG projects, and asks (on a terminal) for the workspace, executor (subprocessfor local use,k8sfor a dev mini-cluster โ changeable later), and UI port. Run non-interactively (e.g.curl | sh) it uses sensible defaults. - Creates the Lite admin (
admin@leoflow.local) with a generated, human-friendly password, shown once at the end (only its hash is stored). Recover it withleoflow lite reset-password.
Lite is for trusted networks
The admin password is short by design and there is no SSO/RBAC โ run Lite on localhost, an internal network, or a VPN, never exposed publicly. Production-grade deploys are Pro's job. See Editions.
Everything Leoflow manages lives under ~/.leoflow; your DAG source lives in
the workspace โ the two are kept separate.
leoflow setup # interactive on a terminal; defaults otherwise (safe to re-run)
leoflow setup --dry-run # show the plan, change nothing
leoflow setup --workspace ~/work # choose where your DAG projects live
There is no scanned dags/ folder
Unlike Airflow, Leoflow has no monolithic DAGs directory. Each DAG is its
own project (dag.py + leoflow.yaml); you point leoflow lite <path> at
it. The workspace is just a convenient home for those projects.
Platforms¶
Leoflow ships Linux and macOS binaries for amd64 and arm64. Because the install never touches your system package manager, the Linux distribution does not matter โ only the C library and CPU architecture do:
- glibc distros (Ubuntu, Debian, Fedora, RHEL/Rocky/Alma, Arch, openSUSE)
and musl (Alpine) are both supported;
setupdetects musl and fetches the matching CPython build. - Windows: use WSL2 (it's a glibc Linux). Keep your project in the WSL
native filesystem (
~/...), not under/mnt/cโleoflow lite's hot-reload uses inotify, which is unreliable on the Windows 9p mount.leoflow doctorwarns when your project is under/mnt.
Verifying the download¶
The release publishes checksums.txt (SHA-256), and the checksums file is
cosign-signed (keyless). install.sh verifies the archive checksum
automatically. To verify the signature yourself:
cosign verify-blob \
--certificate checksums.txt.pem \
--signature checksums.txt.sig \
--certificate-identity-regexp 'https://github.com/neochaotic/leoflow' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt
leoflow doctor¶
A read-only diagnostic โ it changes nothing:
$ leoflow doctor
leoflow doctor
platform linux/amd64 (glibc)
python 3.11 found (/usr/bin/python3.11)
docker found
k3d not found (fetched on demand for the k8s tier)
kubectl not found (fetched on demand for the k8s tier)
recommended executor: k8s
subprocess always available (dev-only, no isolation)
kubernetes available (Docker present; k3d/kubectl fetched on demand)
next: run `leoflow setup` to bootstrap the managed runtime.
Installer options¶
| Variable | Effect |
|---|---|
LEOFLOW_VERSION=v0.0.1-prealpha.1 |
install a specific release (default: newest, including pre-releases) |
LEOFLOW_NO_SETUP=1 |
install binaries only; run leoflow setup yourself later |
LEOFLOW_INSTALL_DIR=~/.leoflow/bin |
where to put the binaries |
Building Lite from source¶
If you have a Go toolchain and prefer to build it yourself:
go install github.com/neochaotic/leoflow/cmd/leoflow@latest
go install github.com/neochaotic/leoflow/cmd/leoflow-server@latest
go install github.com/neochaotic/leoflow/cmd/leoflow-agent@latest
# ensure $(go env GOPATH)/bin is on your PATH, then:
leoflow setup
The subsequent leoflow setup provisions the same managed runtime the
install-script path uses (managed CPython under ~/.leoflow/).
Uninstalling Lite¶
Use the built-in command โ it removes the install directory and (with
--purge) your workspace too:
leoflow uninstall # removes ~/.leoflow (binaries, managed Python, parser, config)
leoflow uninstall --purge # also removes ~/leoflow (your DAGs!)
If the leoflow binary is gone or broken, fall back to the same paths by
hand:
rm -rf ~/.leoflow # what `leoflow uninstall` would have removed
rm -rf ~/leoflow # what `--purge` adds (your workspace)
Install Pro¶
Pro installs the control plane into Kubernetes via the Leoflow Helm chart. Task pods are scheduled into the cluster by the same control plane โ no host-side process supervisor, no managed Python sidecar. DAGs ship as container images built in CI (CI/CD & deploy examples).
What you need¶
| Requirement | Why |
|---|---|
| A Kubernetes cluster (1.27+ recommended) | runs the control plane and task pods |
kubectl configured against that cluster |
applies the chart and lets the chart's pre-install Job run migrations |
| Helm 3.12+ | installs the chart |
| An external Postgres (PostgreSQL 13+) | Pro datastore โ the chart refuses to install without database.url (the embedded datastore is Lite-only) |
| An external Redis (Redis 6.0+) | XCom + advisory locks โ the chart refuses to install without redis.url |
Managed services are first-class โ RDS / Cloud SQL / Azure Database for
Postgres on the SQL side; ElastiCache / Memorystore / Azure Cache for Redis.
See the chart's Datastore compatibility
table for tested versions; managed providers that present a per-instance or
provider-specific CA expose a caConfigMap knob (Postgres and Redis sides
respectively) for verified TLS.
No managed datastore yet? There's a PoC path.
For a one-cluster evaluation (kind, minikube, k3d, scratch namespace), the
chart deliberately won't fall back to embedded datastores โ that's Lite's
job. The supported PoC path is to install plain Postgres + Redis
manifests alongside the chart, then point Leoflow at the in-cluster
Services. Recipe: helm/leoflow/examples/README.md.
Not for production.
Install with Helm¶
The chart is published per release (and built from helm/leoflow in the
repo). For pre-alpha cadence, the simplest path is to install directly from
the cloned repo at a checked-out tag:
git clone --depth 1 --branch v0.0.1-prealpha.27 https://github.com/neochaotic/leoflow
cd leoflow
kubectl create namespace leoflow
helm install lf ./helm/leoflow -n leoflow \
--set image.tag=v0.0.1-prealpha.27 \
--set migrations.image.tag=v0.0.1-prealpha.27 \
--set database.url='postgres://USER:PASS@HOST:5432/leoflow?sslmode=verify-full' \
--set redis.url='rediss://HOST:6380/0' \
--set auth.jwtSecret="$(openssl rand -base64 64)" \
--set secretKey="$(openssl rand -hex 16)" \
--set bootstrap.password='change-me'
What this installs (one Deployment, one Service, RBAC for the pod-per-task executor, a pre-install/upgrade migrations Job; optional Ingress, PDB, HPA, ServiceMonitor, NetworkPolicy):
leoflow-serverDeployment listening on HTTP8080, metrics9090, and agent gRPC9091.- A pre-install/pre-upgrade Job running
golang-migrateagainstdatabase.urlbefore the server starts. - A ServiceAccount + Role/RoleBinding letting the control plane create,
watch, and delete task pods (and read their logs) in
taskNamespace. - A chart-managed Secret holding the inline DB / Redis / JWT / bootstrap
credentials. Skipped when you bring your own via
*.existingSecret.
Open the UI by port-forwarding the Service, or enable ingress.enabled=true
with a controller of your choice โ see the chart's
ingress values for the field shape. Log in as the bootstrap
admin (admin@leoflow.local / the password you set above) and rotate it.
Bring-your-own Secrets¶
Inline --set values bake credentials into the chart-managed Secret.
Production deploys typically pre-create Secrets (sealed-secrets,
External Secrets, etc.) and point the chart at them:
--set database.existingSecret=my-db # key: databaseUrl
--set redis.existingSecret=my-redis # key: redisUrl
--set auth.existingSecret=my-jwt # key: jwtSecret
--set secretKeyExistingSecret=my-key # key: secretKey
--set bootstrap.existingSecret=my-boot # key: bootstrapPassword
When every credential comes from an existing Secret, the chart creates
no Secret of its own. The checksum/secret annotation on the pod template
only sees the chart-managed Secret, so rotation of an
existingSecret requires a manual kubectl rollout restart deploy/lf-leoflow.
Upgrades¶
helm upgrade runs the migrations Job, rolls the Deployment, and respects
PDB/replica settings. The full upgrade contract โ version skew, downtime
expectations, rollback โ lives in Upgrades.
Verifying the chart and images¶
Both the chart and the images (leoflow-server, leoflow-migrate,
plus leoflow and leoflow-agent binaries) are published by
.github/workflows/release.yaml and cosign-signed (keyless):
# Verify the server image at a release tag.
cosign verify ghcr.io/neochaotic/leoflow-server:v0.0.1-prealpha.27 \
--certificate-identity-regexp 'https://github.com/neochaotic/leoflow' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Full values reference¶
The chart README on this site is auto-generated from
values.yaml by helm-docs and documents every knob โ TLS, observability,
networking, autoscaling, secret wiring. Treat it as the source of truth.
Uninstalling Pro¶
This removes the chart-managed resources. PVCs (e.g. for control-plane logs
when logs.persistence.enabled=true) and any external Postgres / Redis
data outlive the chart โ drop them out of band when you're done.
Next¶
- Quickstart โ run your first DAG.
- The
leoflow liteworkflow โ the hot-reload inner loop (Lite). - Helm chart โ full Pro values reference.
- CI/CD & deploy examples โ packaging DAGs as images for Pro.
- Editions โ Lite vs Pro, feature by feature.