Hamburger Cross Icon
Min Participants
+
PagerDuty Collector

Min Participants + PagerDuty Collector

✓ Guardrail ↓ Collector Beta Operational Readiness

Enforce Min Participants using data collected by PagerDuty Collector. Automatically check operational readiness standards on every PR.

Guardrail: Ensures the on-call rotation has at least a minimum number of participants to avoid single-person burnout. Checks .oncall.schedule.participants against the configurable min_participants threshold (default: 2).
Data Source: Query the PagerDuty API to collect on-call schedule, escalation policy, and current responder data. Normalizes results into the .oncall category for tool-agnostic policy evaluation. Can find each component's service in Backstage, including one declared on its System or Domain.

How PagerDuty Collector Powers This Guardrail

The PagerDuty Collector gathers metadata from your incident management systems. This data flows into Lunar's Component JSON, where the Min Participants guardrail evaluates it against your standards.

When enabled, this check runs automatically on every PR and in AI coding workflows, providing real-time enforcement with actionable feedback.

1
↓ PagerDuty Collector Gathers Data Collector
Extracts metadata from code, configs, and tool outputs
2
{ } Component JSON
Data centralized in structured format for evaluation
3
✓ Min Participants Checks Guardrail
Pass/fail result with actionable feedback in PRs

Quick Start Configuration

Add both the collector and policy to your lunar-config.yml to enable this guardrail.

📄 lunar-config.yml
# Step 1: Enable the PagerDuty Collector
collectors:
  - uses: github://earthly/lunar-lib/collectors/pagerduty@v1.0.5
    # with: ...

# Step 2: Enable the On-Call Guardrails
policies:
  - uses: github://earthly/lunar-lib/policies/oncall@v1.0.5
    include: [min-participants]
    # with: ...

What PagerDuty Collector Collects

This collector gathers the following data that the Min Participants guardrail evaluates.

Collector code

oncall

Queries the PagerDuty REST API for the component's service on a code hook — it runs when commits are pushed (PRs and the default branch). Resolves the service ID in order: the component's pagerduty/service-id meta annotation (set by a cataloger via lunar catalog component --meta pagerduty/service-id <id>), then the explicit service_id input, then — with backstage_discovery: "true" — the component's own catalog-info.yaml from the checkout. Records where the ID came from at .oncall.service.discovered_via. Fetches service details, on-call schedule participants, and escalation policy. Writes normalized data to .oncall.service, .oncall.schedule, .oncall.escalation, and .oncall.summary, and the raw API responses under .oncall.native.pagerduty. When none of those sources maps the component, writes .oncall.service_lookup with the places it looked instead, and the from-backstage-collector sub-collector, if included, looks in the live catalog.

Collector cron

oncall-cron

Same PagerDuty query as oncall, but on a daily cron instead of on push — it re-collects on a schedule so .oncall stays fresh as on-call schedules and escalation policies rotate between commits (they change on their own clock, independent of code). Resolves the service ID identically, then also reads the backstage collector's live lookup from the default branch's Component JSON when there is one. Writes the same normalized .oncall.service, .oncall.schedule, .oncall.escalation, and .oncall.summary (raw responses under .oncall.native.pagerduty). clone-code gives it the checkout so backstage_discovery: "true" can read catalog-info.yaml. Include oncall for on-push evaluation, oncall-cron for always-fresh scheduled refresh, or both.

Collector after-json

from-backstage-collector

Finds the component's PagerDuty service in what the backstage collector read from the live catalog: the component's own entity, else its System, else that System's Domain. Covers the components oncall can't map from meta, service_id or, with backstage_discovery: "true", the catalog file, and leaves those to oncall. Runs once the backstage collector's lookup (.catalog.native.backstage.refs.entity) lands in the Component JSON, retrying the read for up to backstage_wait_seconds while it catches up, then queries PagerDuty and writes .oncall like oncall. Only the backstage collector calls Backstage; it needs backstage_url set.

Example Data Flow

Here's an example of the data that PagerDuty Collector writes to the Component JSON, which Min Participants then evaluates.

{ } component.json From PagerDuty Collector
{
  "oncall": {
    "source": {
      "tool": "pagerduty",
      "integration": "api"
    },
    "service": {
      "id": "PXXXXXX",
      "name": "Payment API",
      "status": "active",
      "discovered_via": "system:default/payment-platform"
    },
    "schedule": {
      "exists": true,
      "participants": 4,
      "rotation": "weekly"
    },
    "escalation": {
      "exists": true,
      "levels": 3,
      "policy_name": "Payment API Escalation"
    },
    "summary": {
      "has_oncall": true,
      "has_escalation": true,
      "min_participants": 4
    },
    "native": {
      "pagerduty": { "...full PagerDuty API response..." }
    }
  }
}

Configuration Options

PagerDuty Collector Inputs

Input Required Default Description
service_id Required — PagerDuty service ID to query (e.g. PXXXXXX). Optional if the component has a `pagerduty/service-id` meta annotation set by a cataloger.
pagerduty_base_url Optional https://api.pagerduty.com PagerDuty API base URL
backstage_discovery Optional false When "true", and component meta and the service_id input don't give a service ID, read it from the annotations in the component's checked-out catalog-info.yaml. The live catalog, including an ID inherited from the component's System or Domain, is the `from-backstage-collector` sub-collector's job and needs no setting here.
backstage_annotations Optional pagerduty.com/service-id,pagerduty/service-id Comma-separated annotation keys to read the service ID from, tried in order (first non-empty value wins). Defaults to both conventional spellings — PagerDuty's Backstage integration guide uses `pagerduty.com/service-id`; Lunar's meta uses `pagerduty/service-id`. Used for the checked-out catalog-info.yaml and the live catalog alike.
backstage_catalog_paths Optional catalog-info.yaml,catalog-info.yml Comma-separated catalog-info file paths to try in the checked-out repo (first match wins). Only used when backstage_discovery is "true".
backstage_wait_seconds Optional 1800 How long the `from-backstage-collector` sub-collector keeps retrying the read of the backstage collector's lookup before it fails the run. The Component JSON it reads can lag the write that triggered it by several minutes.

On-Call Guardrails Inputs

Input Required Default Description
min_participants Optional 2 Minimum number of on-call rotation participants required

Ready to Automate Your Standards?

See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 300+ built-in guardrails.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Auto-ID My Guardrails
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo