Skip to main content
The incident commander is a DinoAI orchestrator that triages a data pipeline incident by spawning three specialist sub-agents in parallel (a log analyzer, a query profiler, and an owner notifier), then composing their findings into a single structured Slack post. It runs the moment a failure is detected, with no manual intervention required.
Prerequisites
  • Slack connected (the orchestrator and sub-agents post to #incidents).
  • Familiarity with programmable agents and agent-to-agent delegation (this recipe uses invoke_agent, notify_parent_session, and child_session_ids).
  • To trigger from Airflow or a script: a Paradime API endpoint, key, and secret with DinoAI agent API capabilities enabled (Workspace Settings, API; requires Admin access).
Estimated time: 30 minutes.

Steps

1

Create the agents

Build the four agents in the Agent UI: the three specialists first, then the commander (its Squad picker needs the sub-agents to exist). For each, fill the builder fields below, leave Model on Auto, then select Deploy and choose Just here (live in the workspace immediately) or Open a pull request (committed under .dinoai/agents/<name>.yml and governed as code, exactly the same definition the builder holds).Sub-agent 1, log-analyzer
  • Role: Bolt log specialist.
  • Goal:
  • Backstory:
  • Allowed tools: list_bolt_schedules, get_bolt_run_logs, notify_parent_session
Sub-agent 2, query-profiler
  • Role: Warehouse query specialist.
  • Goal:
  • Backstory:
  • Allowed tools: run_sql_query, list_all_snowflake_databases, notify_parent_session
Sub-agent 3, owner-notifier
  • Role: People-routing specialist.
  • Goal:
  • Backstory:
  • Allowed tools: read_file, search_files_and_directories, ripgrep_search, post_slack_message, notify_parent_session
Orchestrator, incident-commander
  • Role:
  • Goal:
  • Backstory:
  • Allowed tools: post_slack_message, invoke_agent
  • Squad: log-analyzer, query-profiler, owner-notifier
  • Output: Slack channel #incidents
None of the sub-agents have invoke_agent in their allowed tools. This keeps the delegation graph exactly two levels deep: the commander is the only delegator. Sub-agents cannot spawn further children, which makes incident response predictable and prevents runaway chains.
2

Trigger the commander

The simplest path is to run the agent with Bolt: trigger incident-commander on demand or on a schedule with the native Run Paradime DinoAI Agent command, passing an incident summary as the task, with no API keys to configure. Airflow is external to Paradime, though, so to fire triage automatically the moment a DAG task fails you need the API: wire one of the trigger paths below.Trigger from Airflow (on_failure_callback)The callback fires when any task in your DAG fails, extracts the task and DAG context from Airflow’s context dict, and hands it directly to the incident commander so the triage message is pre-populated with real incident details. Create dags/callbacks/incident_commander.py:
dags/callbacks/incident_commander.py
Then attach the callback to your DAG:
dags/hourly_marts.py
The callback runs in a daemon thread so it does not block Airflow’s task runner while the agent session runs (which can take several minutes). The original task failure is always surfaced normally in Airflow regardless of whether the triage agent succeeds or fails. To scope triage to a single high-priority model, set on_failure_callback=trigger_incident_commander on that operator instead of the whole DAG. Store the three PARADIME_* values as Airflow Variables or in an Airflow Connection rather than hardcoding them.
Trigger manually from a scriptFor teams not running Airflow, or for ad-hoc triage when a failure is spotted manually, create scripts/trigger_incident.py:
scripts/trigger_incident.py
Run it from your terminal:
Your Paradime API endpoint, key, and secret are available under Workspace Settings, API. Make sure the key has DinoAI agent API capabilities enabled. Set INCIDENT_SLACK_CHANNEL (defaults to #incidents) and, on the Airflow path, SUSPECT_MODEL (defaults to the failed task ID) to override the defaults.
3

Watch the triage

Both trigger paths block until the full triage is complete. Open the #incidents thread and watch the commander spawn its three specialists, each posting updates as it works, then post the unified summary once all three have reported.To stream sub-agent progress in real time instead of waiting, use the non-blocking trigger_run pattern and poll child_session_ids:
scripts/watch_incident.py
child_session_ids populates progressively as the orchestrator spawns each sub-agent. The first poll may return an empty list, which is expected. The three child sessions appear within the first 30 to 60 seconds as the commander issues its invoke_agent calls.
The commander posts a single structured message to #incidents with ROOT CAUSE, IMPACT, OWNER, and NEXT ACTION, each populated by the matching sub-agent. If the post never arrives, confirm all four agents are deployed and visible on the Agents page, and that the API key has DinoAI agent API capabilities. The full triage typically completes in 3 to 8 minutes depending on log volume and warehouse query history depth.

How it works

When the incident commander receives the trigger message, it calls invoke_agent three times in parallel (one per specialist), passing its own session ID as the callback target. Each sub-agent runs independently, posting updates to the #incidents Slack thread as it works, then calls notify_parent_session with its findings when complete. The commander resumes once all three callbacks have arrived, then composes and posts the unified triage report. The commander never investigates itself: it only delegates and composes, and because no sub-agent has invoke_agent, the graph stays exactly two levels deep.

Next steps

Run an agent with Bolt

Trigger this orchestrator on demand or on a schedule.

Self-healing Dagster pipelines

Dispatch failures to a healer from a Dagster hook.

Build an agent in the UI

Create these agents visually instead of by hand.

Agent-to-agent delegation

How invoke_agent and notify_parent_session work.