Saltar al contenido

Docs / Escalaciones

Escalations

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

Some situations require a human decision. developerz.ai 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. 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.

A closed vocabulary of four, and all four are the default set for human-authored PRs. AI-managed PRs (this App's, Dependabot's, Renovate's) are graded against only the categories the repo wrote, askBeforeActingFor(managed=true, {list, written}) returns written, never the schema default, so without an explicit escalate.ask_before_acting, a Dependabot major bump merges once the gates pass. The ruling (2026-10-09) is the one source of truth on this; the askBeforeActingFor helper on the policy module is its seam.

Category Default (human) 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. AI-managed PRs are graded against written, not the schema default: without an explicit major_dep_bump in escalate.ask_before_acting, a Dependabot major bump merges once the gates pass.
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 (additions plus deletions) exceed pr.large_threshold_lines (default 500). The merge gate enforces it: re-reading the live PR before every merge, it holds an over-threshold PR for your decision, and holds it too when GitHub reports no line count. Approve the head, or merge it yourself. AI-managed PRs are graded against written: the schema large_pr is held only when the repo wrote large_pr in escalate.ask_before_acting.

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, the first time a condition escalates, every owner and admin on the account is emailed at their own address: the email names what is waiting and links into the dashboard. The same condition raised again on the same pull request or issue while the first is still standing is a repeat: it is recorded and audited, and emails nobody. For a security, license or cla escalation this email cannot be switched off, not by a notification preference and not by an unsubscribe link; for any other category an owner or admin can switch it off in their notification preferences. Not everyone is reached. By default members and viewers get the bell and push notification, not the email (a member can switch it on, and when no owner or admin can be emailed the account's members are), and an owner or admin with no address on file, or whose address bounced, is not emailed. Where the escalation's category has an email route, that email goes to the route's one address instead, and for security, license and hostile_tone that address also gets the category's own escalation email. Either way the escalation is recorded, audited, and waiting on the dashboard.
  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. Today the decision happens on the dashboard or over MCP, with the API for automation:

  • The dashboard. Approvals are listed under the PR, with approve and skip buttons. The escalation email names what is waiting and links into the dashboard.
  • MCP, from your own agent: pr approvals lists the pull requests waiting on you, and pr approve_pending or pr skip_pending decides one (MCP verbs).
  • The API, for automation:
curl -X POST https://api.developerz.ai/v1/prs/$PR_ID/approve-pending \
  -H "Authorization: Bearer dev_pat_…" \
  -H 'content-type: application/json' \
  -d '{"head_sha":"<the head from GET /v1/prs/:id>"}'
# or …/skip-pending to decline it

The body names the commit you decided on. If someone pushed since you looked, the call answers 409 with head_moved and the current head: read the PR again and decide on what is there now.

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.