Unblock PR
One-line summary: Investigate a failing PR CI pipeline β attribute each failure as flaky, infra, or regression and propose a targeted action.
Requires: dd-pup skill (pup CLI installed and authenticated), triage-flaky-test skill (for flaky failure deep investigation).
Backend
Detection β At the start of every invocation, before taking any action, determine which backend to use:
- If the user passed
--backend pupanywhere β use pup mode immediately. Skip steps 2β4. - Check whether
search_datadog_ci_pipeline_eventsappears in your available tools. - If present β use MCP mode throughout. Call tools exactly as named in this skill's workflow sections.
- If absent β check whether
pupis executable: runpup --versionvia Bash. If the command exits successfully (exit code 0), pup is available. - If pup responds β use pup mode throughout. Translate every tool call using the Tool Reference appendix at the bottom of this file.
- If neither is available β stop and tell the user:
"Neither the Datadog MCP server nor the pup CLI is available. Connect the MCP server or install pup (
brew install datadog-labs/pack/pup)."
pup invocation rules:
- Invoke via Bash. pup always outputs JSON β parse directly.
- Repository IDs passed to pup must be fully lowercase (the API rejects mixed-case):
github.com/datadog/my-repo, notgithub.com/DataDog/my-repo. - If pup returns a 401/403, tell the user to run
pup auth refreshorpup auth login.
Input
| Parameter | Description |
|---|---|
| PR branch | The branch under investigation (e.g. my-feature-branch) |
| Repository | Lowercase, no-schema URL (e.g. github.com/org/repo). Derive from git remote get-url origin if not provided. |
Workflow
STEP 0 β Parse Input
Derive repository ID and default branch from git if not provided:
# Repository ID: fully lowercase, no-schema URL (the API rejects mixed-case)
git remote get-url origin
# Strip protocol and trailing .git, then lowercase the result
# e.g. https://github.com/DataDog/my-repo.git β github.com/datadog/my-repo
# Default branch
git symbolic-ref refs/remotes/origin/HEAD
# Strip refs/remotes/origin/ prefix β fall back to main if unsetSTEP 1 β Get PR CI Summary (run in parallel)
Pipeline failures:
Tool: search_datadog_ci_pipeline_events
query: @ci.status:error @git.branch:<branch> @git.repository.id_v2:"<repo>"
ci_level: job
from: now-24hTest failures (only if pipeline results include test-runner jobs):
Tool: search_datadog_test_events
query: @test.status:fail @git.branch:<branch> @git.repository.id_v2:"<repo>"
from: now-24h
test_level: testRun both in parallel. Collect all distinct @test.service values from test event results. If more than one distinct service is found, note each separately in the triage brief β do not collapse them into a single service filter. If pipeline results contain only infrastructure job types (build, lint, deploy) with no test-runner output, discard test results and skip to STEP 3.
STEP 1.5 β Fetch PR Health (run in parallel with STEP 1)
This step runs unconditionally β PR health context is valuable whether CI is red or green.
Code coverage (both modes):
Tool: get_datadog_code_coverage_branch_summary
repository_id: <repo>
branch: <branch>PR number resolution (MCP mode only β skip if PR number already provided as input):
Tool: get_prs_by_head_branch
repo_url: https://<repo>
head_branch: <branch>Use the first open PR returned. If no open PR is found, skip the quality/security fetch and report "No data available" for Quality and Security.
Code quality and security (MCP mode only β only if PR number is available):
Tool: search_pr_insights
repo_url: https://<repo>
pr_number: <pr_number>Extract only code_quality and code_security from products_status. Ignore failed_tests, flaky_tests, and failed_jobs β CI data comes from STEP 1β3.
pup mode note: PR number resolution and
search_pr_insightsare not available in pup. Quality and Security always show "No data available" in pup mode.
STEP 2 β Blame Guard per Failing Job
First check whether @error_classification.domain / @error_classification.type are present on job events from STEP 1 β if populated, use them as primary classification signals.
For each failing job where classification is still needed, run both checks in parallel:
Default branch check β was this job already failing before this PR?
Tool: aggregate_datadog_ci_pipeline_events
query: @ci.status:error @ci.job.name:"<job>" @git.branch:<default-branch> @git.repository.id_v2:"<repo>"
ci_level: job
aggregation: count
from: now-24hBlast radius check β is this job failing on other branches too?
Tool: aggregate_datadog_ci_pipeline_events
query: @ci.status:error @ci.job.name:"<job>" @git.repository.id_v2:"<repo>"
ci_level: job
aggregation: count
group_by: ["@git.branch"]
from: now-24hPerformance fallback: if the blast radius query is slow or times out, skip it and rely on the default branch check alone.
STEP 3 β Classify Each Failure
Priority order:
- If
@error_classification.domain/@error_classification.typepresent β use as primary signal - If test failure AND test in
get_datadog_flaky_testswithflaky_test_state:activeβ flaky - Use blame guard results:
| Failing on default branch? | Failing on β₯3 other branches? | Classification |
|---|---|---|
| Yes | Yes | infra (pre-existing, widespread) |
| Yes | No | infra (pre-existing on default branch) |
| No | No | regression (introduced by this PR) |
| No | Yes | flaky (intermittent, cross-branch) |
| Insufficient data | β | unknown |
STEP 4 β Produce Triage Brief
One entry per failing job:
PR CI Triage Brief
==================
Branch: <branch>
Repo: <repo>
Job: <job-name>
Classification: <flaky | infra | regression | unknown>
Evidence: <1 key data point β error message, pipeline count, or test result>
Confidence: <high | medium | low>
Recommended: <action>
[repeat for each failing job]
Overall: <N> failures β <e.g. "1 regression, 1 flaky, 1 infra">
PR Health
=========
Coverage: <X>% on <branch> | No data available
Quality: <N violations (X high, Y medium)> | No violations | No data available
Security: <N violations> | No violations | No data availableAll three lines always appear. Use "No data available" when a tool returned no data or is unavailable (pup mode for Quality/Security).
STEP 5 β Propose Actions
regression β Prompt user to investigate their code changes. No write action available.
flaky β Load triage-flaky-test skill for deep investigation. Invoke it once per distinct failing test name classified as flaky, passing the test name (from @test.name in STEP 1 results) and the derived repository as inputs. That skill will:
- Attempt an agent-native fix using
flaky_category+ stack trace - Propose quarantine via
update_datadog_flaky_test_statesif a quick fix isn't possible
infra β Before proposing a retry, assess whether the failure is transient:
- Check
@error_classification.typeand error message for signals liketimeout,runner unavailable,network error,quota exceededβ transient failures where a retry is likely to help - If the error is deterministic (build misconfiguration, missing secret, explicit test assertion failure), a retry is unlikely to help β suggest investigating the root cause
- If the failure is pre-existing on the default branch, inform the user β a retry will likely fail again; await the upstream fix instead
If transient:
MCP mode β GitHub Actions: use retry_datadog_ci_job. From the failing job event, collect:
@ci.provider.nameβ ci_provider ("github")@git.repository.id_v2β repository_id@ci.job.idβ job_id- event
idfield β event_uuid (optional)
For pipeline_id: use @ci.pipeline.id directly if it matches ^\d+-[1-9]\d*$ (e.g. 26027867390-1). If it is a bare numeric run ID, combine it with @github.run_attempt from the same event: "{@ci.pipeline.id}-{@github.run_attempt}". Fallback: parse @ci.pipeline.url β extract {run_id} and {attempt} from runs/{run_id}/attempts/{attempt}.
After retry returns, confirm via search_datadog_ci_pipeline_events (query: @ci.job.name:"<job>" @git.branch:<branch>, from: now-5m) that a new run appears.
Fallback / pup mode β GitHub Actions: extract the run ID from @ci.pipeline.url:
gh run rerun <run_id> --failedGitLab / other providers (both modes): share @ci.pipeline.url and direct to the provider UI.
unknown β Suggest checking raw job logs via the CI provider UI or @ci.pipeline.url from the pipeline event.
Tool Reference
This appendix applies only in pup mode. In MCP mode, use the tool names in the workflow sections directly.
| MCP Tool | pup Command |
|---|---|
search_datadog_ci_pipeline_events (ci_level: job) |
pup cicd events search --query "..." --level job --from 24h --limit 50 |
aggregate_datadog_ci_pipeline_events (count, group_by branch) |
pup cicd events aggregate --query "..." --compute count --group-by "@git.branch" --from 24h |
aggregate_datadog_ci_pipeline_events (count, no group_by) |
pup cicd events aggregate --query "..." --compute count --from 24h |
search_datadog_test_events |
pup cicd tests search --query "..." --from 24h --limit 50 |
get_datadog_flaky_tests |
pup cicd flaky-tests search --query "flaky_test_state:active ..." |
update_datadog_flaky_test_states |
Write body to /tmp/flaky-update.json, then pup test-optimization flaky-tests update --file /tmp/flaky-update.json |
get_datadog_code_coverage_branch_summary |
repo_lower=$(echo "<repo>" | tr '[:upper:]' '[:lower:]') && pup code-coverage branch-summary --repo "$repo_lower" --branch "<branch>" |
get_prs_by_head_branch |
Not available in pup β skip; report "No data available" for Quality/Security |
search_pr_insights |
Not available in pup β skip; report "No data available" for Quality/Security |
retry_datadog_ci_job |
Not available in pup β use gh run rerun <run_id> --failed instead |