Use this skill when an Airflow DAG uses TriggerDagRunOperator, ExternalTaskSensor, or SubDagOperator to create cross-DAG dependencies or trigger downstream pipelines. Triggers: any DAG with external_dag_id=, trigger_dag_id=, SubDagOperator, or Airflow Datasets.
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Airflow cross-DAG patterns — TriggerDagRunOperator, ExternalTaskSensor, SubDagOperator, Datasets — all have Orchestra equivalents. Orchestra provides two mechanisms:
TRIGGER_PIPELINE task — an explicit pipeline step that triggers another pipeline and waits for it to complete. Equivalent to TriggerDagRunOperator(wait_for_completion=True).
trigger_events: block — event-driven triggering at the pipeline root. When an upstream pipeline completes, this pipeline starts automatically. Equivalent to ExternalTaskSensor + DAG scheduling, but cleaner.
# Airflow
trigger_downstream = TriggerDagRunOperator(
task_id="trigger_reporting",
trigger_dag_id="daily_reporting",
conf={"date": "{{ ds }}", "env": "prod"},
wait_for_completion=True,
execution_date="{{ execution_date }}",
)# Orchestra
task-001:
integration: ORCHESTRA
integration_job: TRIGGER_PIPELINE
name: trigger_reporting
parameters:
pipeline_id: "uuid-of-daily-reporting-pipeline" # UUID from Orchestra UI
run_inputs: # optional — equivalent to conf={}
date: "${{ ORCHESTRA.CURRENT_TIME }}"
env: prod
branch: null # optional — git branch override
depends_on: []
condition: null
tags: []TRIGGER_PIPELINE parameters:
| Parameter | Required | Notes |
|---|---|---|
pipeline_id | ✅ | UUID of the pipeline to trigger (find in Orchestra URL) |
run_inputs | ❌ | Key-value dict passed as inputs to the triggered pipeline |
branch | ❌ | Git branch to use for the triggered pipeline run |
Key difference from Airflow: TRIGGER_PIPELINE always waits for the triggered pipeline to complete before proceeding. There is no wait_for_completion=False equivalent.
trigger_events: (preferred)When an upstream pipeline is in Orchestra and you want to start a pipeline automatically on its completion, use trigger_events: at the pipeline root — no sensor polling needed.
# Airflow
wait_for_elt = ExternalTaskSensor(
task_id="wait_for_upstream_elt",
external_dag_id="nightly_elt",
external_task_id=None, # wait for whole DAG
poke_interval=60,
timeout=3600,
)# Orchestra — event-driven trigger
version: v1
name: daily-reporting
trigger_events:
- type: pipeline
pipeline_id: "uuid-of-nightly-elt-pipeline"
statuses: [SUCCEEDED, WARNING] # null defaults to SUCCEEDED + WARNING
run_inputs: # optional inputs to pass to this pipeline run
triggered_by: upstream_elt
pipeline:
...TriggerEventModel fields:
| Field | Required | Notes |
|---|---|---|
type | ✅ | Always pipeline |
pipeline_id | ✅ | UUID of the upstream pipeline, or "*" for any pipeline |
statuses | ❌ | Which completion statuses trigger this pipeline. Default: [SUCCEEDED, WARNING] |
run_inputs | ❌ | Input values to pass to the triggered run |
Multiple upstream triggers (OR logic):
trigger_events:
- type: pipeline
pipeline_id: "uuid-of-pipeline-a"
- type: pipeline
pipeline_id: "uuid-of-pipeline-b"
# fires when EITHER pipeline-a OR pipeline-b completesAirflow Sub-DAGs are mostly an anti-pattern — they create scheduling complexity and have known issues. In Orchestra:
Option A — Flatten into stages: If the sub-DAG is small and tightly coupled to the parent, convert its tasks into additional stages in the same Orchestra pipeline.
Option B — Separate pipeline: If the sub-DAG represents a reusable or independently schedulable unit, convert it to its own Orchestra pipeline and trigger it with TRIGGER_PIPELINE.
# Airflow
subdag_op = SubDagOperator(
task_id="process_subdag",
subdag=create_subdag(dag_id, "process_subdag", default_args),
)# Orchestra — Option B: separate pipeline + trigger
# In the parent pipeline:
task-trigger-subpipeline:
integration: ORCHESTRA
integration_job: TRIGGER_PIPELINE
name: process_subpipeline
parameters:
pipeline_id: "uuid-of-process-pipeline"
depends_on: []trigger_events: with any pipelineAirflow Datasets (2.4+) trigger DAGs when an upstream DAG updates a dataset. In Orchestra, use trigger_events: with the relevant upstream pipeline UUID.
# Airflow
my_dataset = Dataset("s3://my-bucket/orders/")
with DAG("producer", schedule=None) as producer_dag:
update_task = PythonOperator(..., outlets=[my_dataset])
with DAG("consumer", schedule=[my_dataset]) as consumer_dag:
...# Orchestra — consumer pipeline
trigger_events:
- type: pipeline
pipeline_id: "uuid-of-producer-pipeline"
statuses: [SUCCEEDED]from airflow.operators.trigger_dagrun import TriggerDagRunOperator
from airflow.sensors.external_task import ExternalTaskSensor
with DAG("orchestrator") as dag:
wait_for_elt = ExternalTaskSensor(
task_id="wait_for_elt",
external_dag_id="nightly_elt",
)
trigger_report = TriggerDagRunOperator(
task_id="trigger_report",
trigger_dag_id="daily_report",
conf={"env": "prod"},
wait_for_completion=True,
)
wait_for_elt >> trigger_report# nightly-elt pipeline (separate YAML)
version: v1
name: nightly-elt
pipeline:
... # existing ELT tasks
---
# orchestrator pipeline — triggered by nightly-elt completion
version: v1
name: orchestrator
trigger_events:
- type: pipeline
pipeline_id: "uuid-of-nightly-elt-pipeline"
statuses: [SUCCEEDED, WARNING]
pipeline:
stage-trigger-report:
tasks:
trigger-report:
integration: ORCHESTRA
integration_job: TRIGGER_PIPELINE
name: trigger_daily_report
parameters:
pipeline_id: "uuid-of-daily-report-pipeline"
run_inputs:
env: prod
depends_on: []
condition: null
tags: []
depends_on: []pipeline_id is a UUID — find it in the Orchestra UI pipeline URL (e.g. app.getorchestra.io/pipelines/xxxxxxxx-xxxx-...). It's not the pipeline name.TRIGGER_PIPELINE always waits — unlike Airflow's wait_for_completion=False option, Orchestra always waits for the triggered pipeline before proceeding.trigger_events: uses OR logic — any single entry firing starts the pipeline. For AND logic (wait for both pipeline A and pipeline B), chain: trigger_events fires pipeline B, and pipeline A is a TRIGGER_PIPELINE task at the start of pipeline B.statuses default — if omitted, trigger_events fires on SUCCEEDED and WARNING only. Explicitly set statuses: [SUCCEEDED] if you don't want WARNING runs to trigger downstream.alerts:
- name: on-failure
statuses: [FAILED]
destinations:
- integration: SLACK
destination: '#data-alerts'orchestra-hq/orchestra-skills
a200887
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.