This document fixes the terms an Airflow Language SDK (Go, Java, TypeScript, …) uses for
its user-facing authoring interface, and how they fit together. Every SDK spells them in its
own language’s idiom; the terms and the flow are the same everywhere.
Spec version: 1.0.
There are two authoring features, and they differ in one thing: who owns the graph.
A TaskHandler supplies a body for a task Python already declared, so it names the
dagId/taskId pair it binds to and nothing else. A native Dag owns the schedule, the
tasks, and the edges, so dag.Task returns a TaskRef that edges attach to. Both features
land in the same bundle, and one bundle.serve() call serves both, so a single process can carry
native Dags and mixed-language task handlers at once.
The function callable itself: the task body a user writes.
TaskHandler
Callable interface factory over (dagId,taskId,fn); returns a TaskHandlerRef.
Dag
Callable interface factory over a Dag spec; returns a DagRef.
dag
The instance a Dag call returns.
dag.Task
Callable interface factory over (fn,options); returns a TaskRef.
bundle
Holds every Dag and TaskHandler. One register takes either kind, in any
mixture, and the bundle serves them.
serve
A method on the bundle: the task subprocess’s entrypoint calls bundle.serve(),
which serves it for the lifetime of the process. Nothing outside the bundle needs a
handle on the serving machinery.
Authoring is only half the contract. Every SDK runs the same sequence inside the task
subprocess, once per task instance:
Steps 2 through 5 and step 7 belong to the SDK; step 6 is the only one that runs code a user
wrote. How fn reaches Context and Client is each SDK’s own choice — parameters, or
getters that read the scope opened at step 6 — and all this spec asks is that fn receives the
same pair the SDK built at step 3. The terminal state at step 7 is one of SucceedTask,
RetryTask, or TaskState, and it is reported exactly once.