The language-neutral foundation for Airflow language SDKs — implement task logic in a non-Python language while the DAG stays in Python. Use when the user wants to run an Airflow task in another language (Java, Kotlin, Go, or other JVM/native languages), asks how the Python `@task.stub` pairs with native task code, how task/DAG IDs must match across the two sides, how data passes via XCom as JSON, or which language SDKs exist. This skill owns the shared Python-stub pattern and conceptual model; for a specific language's native API, build, and runtime, use that language's skill (e.g. authoring-java-sdk-tasks, authoring-go-sdk-tasks).
npx skills add https://github.com/astronomer/agents --skill authoring-language-sdk-tasks
Airflow language SDKs let you implement task logic in a language other than Python while the DAG and its scheduling stay in Python. This skill describes the parts that are identical across every language SDK. Each language has its own companion skill for the native API, build tooling, and runtime — see Per-language skills.
> Experimental. The language SDKs are in preview. APIs and artifact coordinates may change.
A DAG is authored in Python as usual. Tasks that should run in another language are declared as stubs routed to a dedicated queue. At runtime, Airflow hands a stub task to a coordinator that launches a short-lived native subprocess for that one task instance, runs your compiled/native code, and shuts the subprocess down.
Consequences that hold for every language SDK:
Every task has two halves that must agree:
The example below uses the Go SDK to be concrete, but the Python side is identical for every language SDK. The queue name ("golang" here) is an arbitrary label you choose — it just has to match a key in queue_to_coordinator (see configuring-airflow-language-sdks). Pick whatever name fits the SDK you're routing to.
from datetime import timedelta
from airflow.sdk import dag, task
@dag
def sales_pipeline():
@task.stub(queue="golang") # queue selects the coordinator (see configuring-airflow-language-sdks)
def extract(): ...
@task.stub(queue="golang")
def transform(extracted): ... # arg only declares the dependency
@task.stub(queue="golang", retries=1, retry_delay=timedelta(seconds=5))
def load(transformed): ...
@task() # an ordinary Python task can sit downstream
def report(loaded):
print(f"done: {loaded}")
report(load(transform(extract())))
sales_pipeline()
Rules that apply regardless of language:
@dag name (or dag_id=) is the DAG ID. The native side must use these exact IDs.transform(extracted)) exists only to declare the dependency in Python. The value itself is fetched on the native side via XCom — passing it in Python does not hand it to the native code.queue value is what routes the task to a coordinator; the same string must appear in queue_to_coordinator (see configuring-airflow-language-sdks).XCom values are stored as JSON in Airflow's metadata database, so the boundary between Python and any native language is JSON. The Python/JSON side is the same for every SDK:
| Python type | JSON |
|-------------|------|
| int | number (integer) |
| float | number (decimal) |
| str | string |
| bool | boolean |
| None | null |
| list | array |
| dict | object |
Each language SDK maps these JSON types onto its own native types (e.g. a JSON integer becomes a Java Long). The native-type mapping lives in that language's skill. The key portability rule: a value pushed by one task is read by another as JSON, so the consuming side must expect a type compatible with what was stored.
This skill deliberately stops at the shared concepts. The following differ per language and are documented in each language's companion skills:
The Airflow-side wiring (which coordinator runs which queue) is shared in structure but has per-coordinator options; it lives in configuring-airflow-language-sdks.
@dag/dag_id and the native DAG ID. Mismatches surface as "no DAGs" or missing-XCom errors.pass, ..., or a docstring is allowed in the body; any real logic is rejected.retry_policy is rejected on stubs (@task.stub raises ValueError). Use retries/retry_delay instead — a retry-policy callable runs Python in-process and would never fire for a task executing in a native subprocess.authoring-<lang>-sdk-tasks skill that builds on this one.)*Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling
Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification
Take astronomer/authoring-language-sdk-tasks from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.