skills/airflow-dag-orchestrator/SKILL.md
Apache Airflow DAGs, operators, SLA monitoring, and workflow orchestration. Activate on: Airflow, DAG, operator, sensor, scheduler, task dependency, SLA, backfill, XCom. NOT for: dbt transformations (use dbt-analytics-engineer), streaming pipelines (use streaming-pipeline-architect).
npx skillsauth add curiositech/windags-skills airflow-dag-orchestratorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Design and operate Apache Airflow DAGs for reliable data pipeline orchestration with proper dependency management, SLAs, and monitoring.
Activate on: "Airflow", "DAG", "operator", "sensor", "scheduler", "task dependency", "SLA", "backfill", "XCom", "TaskFlow API", "MWAA", "Cloud Composer"
NOT for: dbt model execution → dbt-analytics-engineer (though Airflow can trigger dbt) | Stream processing → streaming-pipeline-architect | Workflow engine (Temporal) → distributed-transaction-manager
@dag, @task decorators) for Python-native DAGscatchup=False unless backfill is intentionalretries=2, retry_delay=timedelta(minutes=5) on every tasksla=timedelta(hours=2) on critical path tasksairflow dags test my_dag 2026-01-01 before deploying| Domain | Technologies | |--------|-------------| | Airflow | Apache Airflow 2.10+, MWAA, Cloud Composer 3 | | Operators | BashOperator, PythonOperator, KubernetesPodOperator | | Providers | apache-airflow-providers-{snowflake, google, aws, dbt-cloud} | | Executors | CeleryExecutor, KubernetesExecutor, LocalExecutor | | Monitoring | SLA misses, task duration, Airflow metrics → Prometheus |
from airflow.decorators import dag, task
from datetime import datetime, timedelta
@dag(
schedule="0 6 * * *", # daily at 6am UTC
start_date=datetime(2026, 1, 1),
catchup=False,
default_args={
"retries": 2,
"retry_delay": timedelta(minutes=5),
"sla": timedelta(hours=2),
},
tags=["finance", "daily"],
)
def daily_revenue_pipeline():
@task()
def extract_payments() -> dict:
"""Extract from Stripe API"""
data = stripe_client.list_payments(date=today())
return {"count": len(data), "path": "s3://raw/payments/"}
@task()
def extract_orders() -> dict:
"""Extract from Shopify API"""
data = shopify_client.list_orders(date=today())
return {"count": len(data), "path": "s3://raw/orders/"}
@task()
def transform(payments: dict, orders: dict) -> str:
"""Join and transform in DuckDB"""
result_path = run_duckdb_transform(payments["path"], orders["path"])
return result_path
@task()
def load(path: str):
"""Load to Snowflake"""
snowflake_copy_into("fct_revenue", path)
# Define dependencies via function calls
payments = extract_payments()
orders = extract_orders()
transformed = transform(payments, orders)
load(transformed)
daily_revenue_pipeline()
@task()
def get_partitions() -> list[str]:
return ["2026-01-01", "2026-01-02", "2026-01-03"]
@task()
def process_partition(partition_date: str) -> dict:
"""Runs in parallel for each partition"""
return {"date": partition_date, "rows": process(partition_date)}
@task()
def aggregate(results: list[dict]):
"""Fan-in: receives all partition results"""
total = sum(r["rows"] for r in results)
log.info(f"Processed {total} total rows")
# Dynamically maps process_partition across all partitions
partitions = get_partitions()
results = process_partition.expand(partition_date=partitions)
aggregate(results)
from airflow.operators.bash import BashOperator
from cosmos import DbtDag, ProjectConfig, ProfileConfig
# Option 1: cosmos (recommended)
dbt_dag = DbtDag(
project_config=ProjectConfig("/opt/airflow/dbt/"),
profile_config=ProfileConfig(
profile_name="default",
target_name="prod",
),
schedule="@daily",
dag_id="dbt_daily",
)
# Option 2: BashOperator (simple)
dbt_run = BashOperator(
task_id="dbt_run",
bash_command="cd /opt/airflow/dbt && dbt build --select tag:daily",
)
catchup=False; otherwise Airflow runs every missed intervalretries >= 1 with a delaycatchup=False unless backfill is intentionalairflow dags test before deploymentdata-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.