Skip to content

Docs / Escalations

Escalations

When the agent pages a human: security, breaking changes, and stuck threads.

Some situations require a human decision. The maintainer agent recognises these automatically and pauses until a maintainer responds, it never acts unilaterally on sensitive work.

Built-in escalation categories

These categories always escalate, regardless of your .maintainer.yml policy. They cannot be disabled:

Category Trigger
security Any issue or PR with a CVE, CWE, security label, or keywords like "vulnerability", "RCE", "SSRF", "injection".
license A PR adds a dependency with an incompatible or unknown SPDX licence.
cla A contributor raises a CLA or contribution-agreement question.

The triggers are what the agent recognises while reading the thread, not a regex over your issue text. The routing is not a judgment call: these three are hardcoded, and a .maintainer.yml that tries to drop them is ignored.

Configurable always escalations

The category set is closed. escalate.always selects from a fixed vocabulary, it does not define new triggers, and a name outside the set is a validation error on your .maintainer.yml rather than a category that quietly never fires. Beyond the three above, these are the values it accepts:

Category Trigger
hostile_tone The issue, or the comment that woke the bot, is hostile or abusive.
direct_mention Someone @-mentions the human maintainer rather than the bot.
paid_customer Reserved for the reporter-identity signal; no loop emits it yet.

hostile_tone and direct_mention are the default, so a repo with no escalate: block still pages you for both. Writing the key REPLACES that default, it does not add to it:

escalate:
  # Keep the defaults and page on nothing else. Dropping either one is opting out.
  always: [hostile_tone, direct_mention]

ask_before_acting escalations

These pause the bot and ask the maintainer for explicit approval before continuing. They email immediately too, the same as always. The difference is what the bot does next: an always category stops the session outright, an ask_before_acting category leaves a drafted action waiting for your yes or no.

Same closed vocabulary. The first four are the default set:

Category Default Trigger
breaking_change yes The diff classifies as a major semver impact, or the PR title/body says BREAKING CHANGE.
major_dep_bump yes A package.json / Cargo.toml / pyproject.toml / lockfile dependency crosses a major boundary.
first_time_contributor yes The author has never had a PR merged in this repo. Never fires for a dependency bot.
large_pr yes Changed lines exceed pr.large_threshold_lines (default 500).
release_publish no Accepted by validation; no loop emits it yet.
auto_merge no Accepted by validation; no loop emits it yet.

As with always, writing the key replaces the default set:

escalate:
  # Ask about breaking changes and big diffs, and nothing else.
  ask_before_acting: [breaking_change, large_pr]

How escalation works

  1. Detect, the agent matches the issue, PR, or event against the escalation rules.
  2. Comment, the bot posts a disclosure comment explaining exactly why it paused and what it needs from the maintainer.
  3. Email, an escalation email is sent immediately. Every category on this page routes email-immediate; only routine informational events fall through to the weekly digest.
  4. Wait, the agent parks the thread and does nothing until you decide.
  5. Resume, once approved, the agent continues the loop from the paused step.
  6. Audit, every escalation event (trigger, pause, approval, resume) is written to the audit log with actor and timestamp.

Bot-on-bot safety

The agent detects comments from CodeRabbit, Copilot, Dependabot, and Renovate and defers to them rather than creating conflicting threads. Configure the list via pr.wait_for_other_bots.

The agent never responds to itself. A comment from developerz-ai[bot], the login GitHub gives our App, does not trigger another loop iteration.

Resolving an escalation

There are no comment commands. A pending ask_before_acting action is resolved on the control plane, never by typing something on the thread, so the decision carries an authenticated actor rather than whoever could post:

  • The escalation email. It carries signed approve and skip links; one click each.
  • The dashboard. Approvals are listed under the PR, with approve and skip buttons.
  • The API, for automation:
curl -X POST https://api.developerz.ai/v1/prs/$PR_ID/approve-pending \
  -H "Authorization: Bearer dev_pat_…"
# or …/skip-pending to decline it

Scope: write:prs. Every decision is written to the audit log with the actor and a timestamp. The bot may also suggest you apply a needs-maintainer-ack label, but that is a human-readable marker for your own triage, it is not what resolves the escalation.