Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .craft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ targets:
- name: npm
id: "@sentry/junior-octolens"
includeNames: /^sentry-junior-octolens-\d.*\.tgz$/
- name: npm
id: "@sentry/junior-pagerduty"
includeNames: /^sentry-junior-pagerduty-\d.*\.tgz$/
- name: npm
id: "@sentry/junior-sentry"
includeNames: /^sentry-junior-sentry-\d.*\.tgz$/
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ jobs:
- packages/junior-memory/**
- packages/junior-notion/**
- packages/junior-octolens/**
- packages/junior-pagerduty/**
- packages/junior-sentry/**
- packages/junior-vercel/**
repo:
Expand Down Expand Up @@ -501,6 +502,7 @@ jobs:
pnpm --filter @sentry/junior-memory pack --pack-destination artifacts
pnpm --filter @sentry/junior-notion pack --pack-destination artifacts
pnpm --filter @sentry/junior-octolens pack --pack-destination artifacts
pnpm --filter @sentry/junior-pagerduty pack --pack-destination artifacts
pnpm --filter @sentry/junior-maintenance pack --pack-destination artifacts
pnpm --filter @sentry/junior-sentry pack --pack-destination artifacts
pnpm --filter @sentry/junior-vercel pack --pack-destination artifacts
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ This repo uses Craft for manual lockstep npm releases of:
- `@sentry/junior-memory`
- `@sentry/junior-notion`
- `@sentry/junior-octolens`
- `@sentry/junior-pagerduty`
- `@sentry/junior-sentry`
- `@sentry/junior-vercel`

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Start here:
| `@sentry/junior-memory` | Memory plugin package for long-term Junior memory storage |
| `@sentry/junior-notion` | Notion plugin package for page search workflows |
| `@sentry/junior-octolens` | Octolens plugin package for social-listening workflows |
| `@sentry/junior-pagerduty` | Read-only PagerDuty on-call, schedule, and incident lookups |
| `@sentry/junior-maintenance` | Maintenance plugin package for updating and improving Junior apps |
| `@sentry/junior-sentry` | Sentry investigations and issue events |
| `@sentry/junior-vercel` | Vercel plugin package for deployment monitoring and log investigations |
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"docs:dev": "pnpm --filter @sentry/junior-docs dev",
"docs:build": "pnpm --filter @sentry/junior-docs build",
"docs:check": "pnpm --filter @sentry/junior-docs check",
"package:lint": "for pkg in packages/junior packages/junior-plugin-api packages/junior-memory packages/junior-dashboard packages/junior-github packages/junior-google packages/junior-agent-browser packages/junior-amplitude packages/junior-cloudflare packages/junior-datadog packages/junior-tts packages/junior-hex packages/junior-linear packages/junior-maintenance packages/junior-notion packages/junior-octolens packages/junior-sentry packages/junior-vercel; do pnpm exec publint \"$pkg\" || exit $?; done",
"package:lint": "for pkg in packages/junior packages/junior-plugin-api packages/junior-memory packages/junior-dashboard packages/junior-github packages/junior-google packages/junior-agent-browser packages/junior-amplitude packages/junior-cloudflare packages/junior-datadog packages/junior-tts packages/junior-hex packages/junior-linear packages/junior-maintenance packages/junior-notion packages/junior-octolens packages/junior-pagerduty packages/junior-sentry packages/junior-vercel; do pnpm exec publint \"$pkg\" || exit $?; done",
"package-types:check": "sh scripts/check-package-types.sh",
"release:check": "node scripts/check-release-config.mjs",
"start": "pnpm --filter @sentry/junior-example dev",
Expand Down
5 changes: 5 additions & 0 deletions packages/docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineConfig({
"/extend/cloudflare": "/extend/cloudflare-plugin",
"/extend/datadog": "/extend/datadog-plugin",
"/extend/hex": "/extend/hex-plugin",
"/extend/pagerduty": "/extend/pagerduty-plugin",
"/plugins/overview": "/extend",
"/plugins/agent-browser": "/extend/agent-browser-plugin",
"/plugins/amplitude": "/extend/amplitude-plugin",
Expand Down Expand Up @@ -136,6 +137,10 @@ export default defineConfig({
},
{ label: "Memory Plugin", link: "/extend/memory-plugin/" },
{ label: "Notion Plugin", link: "/extend/notion-plugin/" },
{
label: "PagerDuty Plugin",
link: "/extend/pagerduty-plugin/",
},
{ label: "Sentry Plugin", link: "/extend/sentry-plugin/" },
{ label: "Vercel Plugin", link: "/extend/vercel-plugin/" },
],
Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/content/docs/contribute/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Junior uses lockstep package releases for:
- `@sentry/junior-memory`
- `@sentry/junior-notion`
- `@sentry/junior-octolens`
- `@sentry/junior-pagerduty`
- `@sentry/junior-sentry`
- `@sentry/junior-vercel`

Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/content/docs/extend/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ fixed behavior that code must control.
| [Maintenance](/extend/maintenance-plugin/) | Repository maintenance workflows |
| [Memory](/extend/memory-plugin/) | Long-term scoped memory |
| [Notion](/extend/notion-plugin/) | Notion content |
| [PagerDuty](/extend/pagerduty-plugin/) | On-call, schedules, and incidents (read-only) |
| [Scheduler](/extend/scheduler-plugin/) | Durable scheduled automations |
| [Sentry](/extend/sentry-plugin/) | Sentry issues, telemetry, and issue webhooks |
| [Vercel](/extend/vercel-plugin/) | Vercel projects and deployments |
Expand Down
85 changes: 85 additions & 0 deletions packages/docs/src/content/docs/extend/pagerduty-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: PagerDuty Plugin
description: Configure read-only PagerDuty lookups for on-call, handoffs, schedules, escalation policies, services, and incidents.
type: tutorial
prerequisites:
- /extend/
related:
- /concepts/credentials-and-oauth/
- /operate/security-hardening/
---

The PagerDuty plugin lets Slack users ask Junior who is on call, who rotates in or out next, and what is open in PagerDuty. Junior calls the PagerDuty REST API from the sandbox.

The plugin is read-only. It uses one deployment-level API key, and the bundled skill uses only `GET` requests.

## Install

Install the plugin package alongside `@sentry/junior`:

```bash
pnpm add @sentry/junior @sentry/junior-pagerduty
```

## Runtime setup

Add the package name to the plugin set exported from `plugins.ts`:

```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";

export const plugins = defineJuniorPlugins(["@sentry/junior-pagerduty"]);
```

## Config

Set deployment variables in the Junior environment, then redeploy.

### Environment variables

<details class="plugin-config">
<summary><code>PAGERDUTY_API_KEY</code></summary>

PagerDuty REST API key for read-only requests.

- **Define:** Set `PAGERDUTY_API_KEY` in the deployment environment
- **Required:** Yes
- **Environment override:** `PAGERDUTY_API_KEY`

Use an account-level General Access REST API key with **Read-only API Key** enabled. An admin or account owner creates it in **Integrations > Developer Tools > API Access Keys**.

</details>

## Auth model

- The plugin uses one deployment-level PagerDuty API key, not per-user OAuth.
- Junior keeps the real `PAGERDUTY_API_KEY` value on the host.
- Sandbox requests to `api.pagerduty.com` receive a host-managed `Authorization: Token token=<key>` header.
- The sandbox never receives the key in env, files, or command arguments.
- Users do not connect or disconnect individual PagerDuty accounts from Junior App Home for this plugin.

## What users can do

- Ask who is on call now for a schedule, escalation policy, or service.
- Ask who rotates in or out next and when the handoff happens.
- Inspect schedule members, escalation paths, and team members.
- List open incidents and read incident details, timelines, and notes.

## Verify

1. Set `PAGERDUTY_API_KEY` and redeploy.
2. Ask Junior in a channel: `Who is on call for <schedule name> right now, and who is next?`
3. Confirm the reply names the current and next responders, the handoff time, and a PagerDuty link.

## Failure modes

- `PAGERDUTY_API_KEY` missing: Junior cannot add the credential. Set the env var and redeploy.
- `401 Unauthorized`: the key is invalid or revoked.
- `403 Forbidden`: the key cannot read the requested resource.
- `429 Too Many Requests`: PagerDuty is throttling. Retry later or narrow the request.
- EU-region account: the manifest covers only `api.pagerduty.com`. EU accounts need a manifest change for `api.eu.pagerduty.com`.
- Mutation requests (acknowledge, resolve, override): the plugin is read-only, and the skill declines these.

## Next step

Review [Credentials & OAuth](/concepts/credentials-and-oauth/) and [Security Hardening](/operate/security-hardening/).
37 changes: 37 additions & 0 deletions packages/junior-pagerduty/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# @sentry/junior-pagerduty

`@sentry/junior-pagerduty` adds read-only PagerDuty lookups to Junior through the PagerDuty REST API. Use it to answer on-call, handoff, schedule, escalation policy, service, team, and incident questions.

## Install

```bash
pnpm add @sentry/junior @sentry/junior-pagerduty
```

## Configure

Add the package name to the plugin set exported from `plugins.ts`:

```ts
import { defineJuniorPlugins } from "@sentry/junior";

export const plugins = defineJuniorPlugins(["@sentry/junior-pagerduty"]);
```

Set a PagerDuty REST API key in the Junior deployment environment:

```bash
PAGERDUTY_API_KEY=...
```

Use an account-level General Access REST API key with **Read-only API Key** enabled. An admin or account owner creates it in **Integrations > Developer Tools > API Access Keys**.

## Auth model

- The plugin uses one deployment-level PagerDuty API key. Users do not connect individual PagerDuty accounts.
- The real key stays on the host. Junior adds `Authorization: Token token=<key>` to sandbox requests to `api.pagerduty.com`.
- The key is the read-only boundary. The bundled skill also uses only `GET` requests.

The manifest covers the US service region only. EU-region accounts (`api.eu.pagerduty.com`) need a manifest change.

Full setup guide: https://junior.sentry.dev/extend/pagerduty-plugin/
18 changes: 18 additions & 0 deletions packages/junior-pagerduty/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@sentry/junior-pagerduty",
"version": "0.257.0",
"private": false,
"publishConfig": {
"access": "public"
},
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/getsentry/junior.git",
"directory": "packages/junior-pagerduty"
},
"files": [
"plugin.yaml",
"skills"
]
}
14 changes: 14 additions & 0 deletions packages/junior-pagerduty/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: pagerduty
display-name: PagerDuty
description: Read-only PagerDuty on-call, schedule, escalation, service, and incident lookups through the PagerDuty REST API

# Junior injects a deployment-level PagerDuty REST API key on sandbox requests
# to the US API host. Use a read-only key. The sandbox never sees the real key.
env-vars:
PAGERDUTY_API_KEY:

domains:
- api.pagerduty.com

api-headers:
Authorization: Token token=${PAGERDUTY_API_KEY}
62 changes: 62 additions & 0 deletions packages/junior-pagerduty/skills/pagerduty/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
name: pagerduty
description: Look up PagerDuty on-call state through the read-only PagerDuty REST API. Use when users ask who is on call, who is rotating in or out, when the next on-call handoff is, what a schedule or escalation policy looks like, which team or service owns paging, or for PagerDuty incident status and timelines. Do not use it to acknowledge, resolve, reassign, or create incidents, to create schedule overrides, or for Sentry issues, Datadog telemetry, or Linear tickets.
---

# PagerDuty

Use this skill for read-only PagerDuty lookups: on-call, handoffs, schedules, escalation policies, services, teams, users, and incidents.

## Call the API

- Call `https://api.pagerduty.com` with `curl` from the sandbox.
- Do not send an `Authorization` header. Junior adds the PagerDuty credential to requests for this host.
- Send `-H 'Accept: application/vnd.pagerduty+json;version=2'`.
- Use only `GET`. The deployment key is read-only.
- Pipe responses through `jq` and keep only the fields you need.
- Lists page with `limit` (max `100`) and `offset`. Follow `more: true` only when the answer needs more rows.
- Array filters use bracket syntax, for example `schedule_ids[]=PABC123`. Pass them with `curl -G --data-urlencode`.
- Times are ISO 8601. Pass `time_zone=<IANA zone>` when the user names a zone.

## Workflow

1. Resolve the target.

- Use IDs or PagerDuty URLs from the request or the thread first. A URL such as `https://<subdomain>.pagerduty.com/schedules/PABC123` contains the ID.
- Otherwise resolve names with one search: `GET /schedules?query=<name>`, `GET /escalation_policies?query=<name>`, `GET /services?query=<name>`, `GET /teams?query=<name>`, or `GET /users?query=<name>`.
- If a search returns several plausible matches, list them and ask which one the user means.

2. Pick the most direct endpoint.

| Question | Endpoint |
| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Who is on call now for a schedule or policy | `GET /oncalls?schedule_ids[]=<id>` or `escalation_policy_ids[]=<id>`; add `earliest=true` |
| Who is rotating in or out, next handoff | `GET /schedules/<id>?since=<now>&until=<now+7d>`; read `final_schedule.rendered_schedule_entries` |
| What is a user's on-call coverage | `GET /oncalls?user_ids[]=<id>&since=<start>&until=<end>` |
| Who is on a schedule | `GET /schedules/<id>/users` |
| What is the escalation path | `GET /escalation_policies/<id>` |
| Which policy pages for a service | `GET /services/<id>?include[]=escalation_policies` |
| Team members | `GET /teams/<id>/members?include[]=users` |
| Open incidents | `GET /incidents?statuses[]=triggered&statuses[]=acknowledged`; filter with `service_ids[]` or `team_ids[]` |
| Incident detail, timeline, or notes | `GET /incidents/<id>`, `GET /incidents/<id>/log_entries`, `GET /incidents/<id>/notes` |

3. Bound every query.

- Default "now" questions to the current time. Get it with `date -u +%Y-%m-%dT%H:%M:%SZ`.
- Default handoff questions to the next 7 days. Default incident history to the last 24 hours.
- In `/oncalls` results, `escalation_level` `1` is the primary responder. Say which level you report.

4. Report the result.

- Lead with the answer: names, levels, and shift start and end times in the user's zone when known.
- For handoffs, name who is on call now, who is next, and the handoff time.
- Link to the object with its `html_url` when the response contains one. Do not build links from partial IDs.
- Do not dump raw JSON.

## Guardrails

- This skill is read-only. Decline requests to acknowledge, resolve, reassign, snooze, or create incidents, to add notes or responders, or to create overrides. Tell the user to do it in PagerDuty.
- Share only the contact details that the question needs. Do not list phone numbers or email addresses unless the user asks for them.
- `401 Unauthorized`: report that the PagerDuty credential is missing or invalid for this Junior deployment. Do not retry.
- `403 Forbidden`: report that the PagerDuty credential cannot read the resource. Do not guess at missing permissions.
- `429 Too Many Requests`: wait briefly and retry the same request once. If it fails again, report the throttle.
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions scripts/bump-release-versions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const files = [
"packages/junior-memory/package.json",
"packages/junior-notion/package.json",
"packages/junior-octolens/package.json",
"packages/junior-pagerduty/package.json",
"packages/junior-maintenance/package.json",
"packages/junior-sentry/package.json",
"packages/junior-vercel/package.json",
Expand Down
Loading