Architecture Decision Records

The why behind Leoflow design decisions — one record per decision, immutable once accepted.

The why behind Leoflow’s design. ADRs are immutable once accepted.


ADR 0001: Why Leoflow and Not Apache Airflow's KubernetesExecutor

ADR 0001: Why Leoflow and Not Apache Airflow’s KubernetesExecutor

ADR 0002: Pod-per-Task Execution Model

ADR 0002: Pod-per-Task Execution Model

ADR 0003: DAG-as-Image with `leoflow.yaml` Abstraction Layer

ADR 0003: DAG-as-Image with leoflow.yaml Abstraction Layer

ADR 0004: Thin Static Go Agent in the Worker Container

ADR 0004: Thin Static Go Agent in the Worker Container

ADR 0005: Hybrid DAG Authoring with Compile-Time Parsing

ADR 0005: Hybrid DAG Authoring with Compile-Time Parsing

ADR 0006: XCom with Redis Backend

ADR 0006: XCom with Redis Backend

ADR 0007: Airflow UI Compatibility for the MVP

ADR 0007: Airflow UI Compatibility for the MVP

ADR 0008: JWT Authentication with OIDC-Ready Interface

ADR 0008: JWT Authentication with OIDC-Ready Interface

ADR 0009: Leader Election via Postgres Advisory Locks

ADR 0009: Leader Election via Postgres Advisory Locks

ADR 0010: Observability Stack from Day One

ADR 0010: Observability Stack from Day One

ADR 0011: Test-Driven Development (Strict)

ADR 0011: Test-Driven Development (Strict)

ADR 0012: Code Quality Standards (Go Report Card A+ as Floor)

ADR 0012: Code Quality Standards (Go Report Card A+ as Floor)

ADR 0013: API Documentation via Scalar, Embedded in the Server Binary

ADR 0013: API Documentation via Scalar, Embedded in the Server Binary

ADR 0014: Supply Chain Security Stack

ADR 0014: Supply Chain Security Stack

ADR 0015: Kubernetes as the Sole Container Execution Path (No Docker SDK)

ADR 0015: Kubernetes as the Sole Container Execution Path (No Docker SDK)

ADR 0016: Deferrable Tasks (Deferred to v0.3)

ADR 0016: Deferrable Tasks (Deferred to v0.3)

ADR 0017: UI Static Asset Serving Strategy

ADR 0017: UI Static Asset Serving Strategy

ADR 0018: UI Custom as Strategic North Star

ADR 0018: UI Custom as Strategic North Star

ADR 0019: Secret Encryption at Rest (Connections)

ADR 0019: Secret Encryption at Rest (Connections)

ADR 0020: "Delete DAG" Clears History; Deregister Is Separate

ADR 0020: “Delete DAG” Clears History; Deregister Is Separate

ADR 0021: Exposing Variables and Connections to Task Pods

ADR 0021: Exposing Variables and Connections to Task Pods

ADR 0022: Ephemeral Per-DAG-Run Staging Volume

ADR 0022: Ephemeral Per-DAG-Run Staging Volume

ADR 0023: DAG Authoring — Config Binding and Override Layers

ADR 0023: DAG Authoring — Config Binding and Override Layers

ADR 0024: DAG Parsing via a Structural Shim (No Airflow SDK Dependency)

ADR 0024: DAG Parsing via a Structural Shim (No Airflow SDK Dependency)

ADR 0025: Embedded Monaco Web Editor for Leoflow Lite

ADR 0025: Embedded Monaco Web Editor for Leoflow Lite

ADR 0026: Lite Datastore — XCom on Postgres, No Redis

ADR 0026: Lite Datastore — XCom on Postgres, No Redis

ADR 0027: Product Editions — Executors and Delivery

ADR 0027: Product Editions — Executors and Delivery

ADR 0028: Release & Versioning for the Two Editions (One Tag, Two Co-Versioned Artifacts)

ADR 0028: Release & Versioning for the Two Editions (One Tag, Two Co-Versioned Artifacts)

ADR 0029: Lite Datastore Default — Docker Postgres (Managed PG is the Opt-In)

ADR 0029: Lite Datastore Default — Docker Postgres (Managed PG is the Opt-In)

ADR 0030: Lite Datastore Auto-Selects — Docker Postgres, or a Managed PG When Docker Is Absent

ADR 0030: Lite Datastore Auto-Selects — Docker Postgres, or a Managed PG When Docker Is Absent

ADR 0031: Scheduler Architecture — Reconciliation Loop, Two-Phase Dispatch, Two-Layer Reaping

ADR 0031: Scheduler Architecture — Reconciliation Loop, Two-Phase Dispatch, Two-Layer Reaping

ADR 0032: Task Return Values Are Not Logged — Only Their Metadata Is

ADR 0032: Task Return Values Are Not Logged — Only Their Metadata Is

ADR 0033: Release Flow — RC Tags, E2E Gates, and Immutable Versions

ADR 0033: Release Flow — RC Tags, E2E Gates, and Immutable Versions

ADR 0034: Fan-in / map-reduce — list-of-upstream parameter binding

ADR 0034: Fan-in / map-reduce — list-of-upstream parameter binding

ADR 0035: Cloud connector auth — keyless-first; Leoflow is not a key manager

ADR 0035: Cloud connector auth — keyless-first; Leoflow is not a key manager

ADR 0036: Airflow 3.X runtime compatibility shim — one model, one policy seam

ADR 0036: Airflow 3.X runtime compatibility shim — one model, one policy seam

ADR 0037: Release version scheme — skip alpha/beta, RC discipline from `v0.0.1`

ADR 0037: Release version scheme — skip alpha/beta, RC discipline from v0.0.1

ADR 0038: Connector dependency ergonomics — `connectors:` sugar + `dependencies:` escape hatch

ADR 0038: Connector dependency ergonomics — connectors: sugar + dependencies: escape hatch

ADR 0039: Generated connector catalog with full form fidelity

ADR 0039: Generated connector catalog with full form fidelity

ADR 0040: Airflow operator + sensor execution — native fast path + generic executor

ADR 0040: Airflow operator + sensor execution — native fast path + generic executor

ADR 0041: `leoflow deploy` — pipeline-less promotion from Lite to Pro

ADR 0041: leoflow deploy — pipeline-less promotion from Lite to Pro

ADR 0042: dbt support via native-Go manifest rendering

ADR 0042: dbt support via native-Go manifest rendering

ADR 0043: TaskGroup as a first-class construct with split/fused execution

ADR 0043: TaskGroup as a first-class construct with split/fused execution

ADR 0044: dbt multi-project — one project per business domain

ADR 0044: dbt multi-project — one project per business domain

ADR 0045: Secrets reach a task because it declared them

ADR 0045: Secrets reach a task because it declared them

ADR 0046: Coverage — one rule, per package, counting the tests we already wrote

ADR 0046: Coverage — one rule, per package, counting the tests we already wrote

ADR 0047: Deprecate the native inline http_api; run HTTP through the generic pod executor

ADR 0047: Deprecate the native inline http_api; run HTTP through the generic pod executor

ADR 0048: The control plane executes no user-influenced code or network requests

ADR 0048: The control plane executes no user-influenced code or network requests

ADR 0049: Split the API/UI and scheduler into separate roles of one binary

ADR 0049: Split the API/UI and scheduler into separate roles of one binary

ADR 0050: Model Context Protocol (MCP) server

ADR 0050: Model Context Protocol (MCP) server

ADR 0051: Separate the orchestration and execution state machines

ADR 0051: Separate the orchestration and execution state machines

ADR 0052: Durable task outcome — decouple the task result from report delivery

ADR 0052: Durable task outcome — decouple the task result from report delivery

ADR 0053: Admission + placement — one scheduler-side layer for task concurrency and pod assignment

ADR 0053: Admission + placement — one scheduler-side layer for task concurrency and pod assignment

ADR 0054: Coexistence in a shared, multi-team Kubernetes cluster

ADR 0054: Coexistence in a shared, multi-team Kubernetes cluster

ADR 0055: Secret scoping and token liveness — scope by declaration, exchange the token, bind it to task liveness

ADR 0055: Secret scoping and token liveness — scope by declaration, exchange the token, bind it to task liveness

ADR 0056: Task-log object sink — native dual-SDK (S3 + GCS), keyless-first

ADR 0056: Task-log object sink — native dual-SDK (S3 + GCS), keyless-first

ADR 0057: OIDC/SSO authentication with fail-closed tenant pinning

ADR 0057: OIDC/SSO authentication with fail-closed tenant pinning

ADR 0058: Warm worker pools — pod-reuse semantics (N:1)

ADR 0058: Warm worker pools — pod-reuse semantics (N:1)

ADR 0059: OpenLineage emission from the Go control plane → OpenMetadata

ADR 0059: OpenLineage emission from the Go control plane → OpenMetadata