# Alert Subscribe Copilot

> One-stop assistant for creating, editing, and troubleshooting Nightingale (n9e) alert subscription rules (alert_subscribe). Use when the user asks to "create a subscription rule / subscribe to alerts / forward alert events / CC another team / escalate alerts (notify someone else after N minutes unhandled) / receive alerts across business groups / troubleshoot a subscription not taking effect". A subscription is a "copy + secondary routing" of events at the notification stage; to configure "who an event directly notifies" use notification rules (→ notify-rule-copilot), and to stop receiving alerts use muting (→ alert-mute-copilot).

- Skill: `ccfos/alert-subscribe-copilot` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add ccfos/alert-subscribe-copilot`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ccfos/alert-subscribe-copilot/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ccfos (https://skillmd.com/u/ccfos)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ccfos/alert-subscribe-copilot

---


# Nightingale (n9e) Alert Subscription Rule Copilot

A subscription rule filters alert events by condition, **clones** a copy, and forwards it to the associated notification rule. Typical scenarios: cross-team CC, alert escalation (notify a supervisor only after N minutes of persistence), and aggregating events from scattered rules into a single outlet.

## Supporting materials (load on demand with read_file, set base to this skill name)

| File | Content | When to read |
|---|---|---|
| `reference.md` | Full config field table, new vs. old notification version differences, redefine fields, complete examples | When you're unsure about a field while assembling config |
| `troubleshooting.md` | Subscription-not-taking-effect troubleshooting chain (in engine matching order), behavioral semantics, gotcha table | When the user says "I subscribed but didn't receive anything" |
| `http-api.md` | HTTP API paths (for A2A / external agents), tryrun validation endpoint | Only for external A2A scenarios or when providing the user with curl commands |

---

## Prerequisites

You are the in-app AI assistant for n9e, running inside the n9e process and already authenticated as the current user. **Operate directly via the built-in tools — do not log in, do not call HTTP APIs, and do not use http_fetch against your own endpoints** (the HTTP flow in `http-api.md` is for external A2A agents).

---

## Mental model

- **Subscription happens at the notification stage** (`alert/dispatch/dispatch.go:handleSubs`): the original event still travels its own notification path as usual; each matching subscription **clones a copy** of the event, rewrites it per the subscription config, and then runs it through the notification chain again. A subscription is **additive** — it does not intercept and does not replace the original notification.
- **Match conditions are AND'd together** and checked in order: enabled → datasource → prod → cate → tags → business group name → duration → severity. Failing any single gate skips that subscription.
- **A subscription's `group_id` is the management ownership (permissions) and does not participate in event matching** — a subscription inherently receives events across business groups; to "subscribe only to a certain business group's events", use the `busi_groups` filter condition.
- New routing (`notify_version=1`): the cloned event's notification outlet is rewritten to the subscription's specified `notify_rule_ids`; the cloned event's callbacks are **cleared** by default, to prevent re-hitting the original rule's callbacks.
- Changes **take effect within 9 seconds at most** (the in-memory cache polling cycle).

## Core config structure

```json
{
  "name": "Subscription rule name",
  "note": "Notes",
  "disabled": 0,
  "prod": "",
  "cate": "",
  "datasource_ids": [],
  "cluster": "0",
  "rule_ids": [],
  "severities": [1, 2, 3],
  "for_duration": 0,
  "tags": [],
  "busi_groups": [],
  "extra_config": {},
  "notify_version": 1,
  "notify_rule_ids": []
}
```

Key points (full field table and new vs. old version differences are in `reference.md`):

- **`severities` is required** (validated in both new and old versions); `[1,2,3]` = all severities.
- **The new version uses `notify_version=1` + a non-empty `notify_rule_ids`** (use `list_notify_rules` to get the IDs; if there isn't a suitable notification rule yet, first create one with `create_notify_rule` and come back). Note: under version 1, the old-version redefine fields (redefine_severity/redefine_channels/webhooks, etc.) are **cleared** by validation.
- `rule_ids` empty = subscribe to events from all alert rules; when targeting only specific rules, use `list_alert_rules` to get the IDs.
- `for_duration` (seconds) = forward only when the alert **persists longer than** this duration; it is the switch for "alert escalation"; `0` = no limit.
- Multiple `tags` / `busi_groups` entries are all **AND**'d; `busi_groups` matches against the event's **business group name** (the key is written as `"groups"`; the actual match is driven by func/value).
- `prod` / `cate` participate in matching but with weak semantics: when `prod` is non-empty it is an exact match; `cate` **only has a real filtering effect when set to `"host"`**, other values are equivalent to no filtering. When in doubt, leave both as empty strings.
- `datasource_ids` empty array = all datasources; `cluster` is fixed at `"0"`.

---

## Workflow one: creating

1. **Determine the business group** (management ownership): use `list_busi_groups` to get the `group_id`. If the user named a business group, or the front end already popped up a business group form, use its ID directly without asking again.
2. **Determine the associated notification rule**: use `list_notify_rules` to get `notify_rule_ids` (the notification outlet for new routing).
3. **(Optional) Limit the subscription scope**: to subscribe to only certain alert rules, use `list_alert_rules` to get `rule_ids`; to narrow by tags/business group/severity/duration, fill in the corresponding filter fields.
4. **Call `create_alert_subscribe`**: pass the business group from step 1 as `group_id` (it can also go inside config), and pass `config` as a single JSON object string (not an array). If `group_id` is omitted, the tool will automatically pop up a business group selection form, and once the user finishes selecting it will resume this creation.
5. **Report the result**: the tool returns `{id, name, group_id, disabled, notify_rule_ids, url}`; just briefly report the subscription conditions and the notification outlet. **Display the rule name as an in-app link: `[<name>](<url>)`** (the url is the returned `/alert-subscribes/edit/<id>`), so the user can click straight to the config page to verify.

## Workflow two: editing / troubleshooting

1. Use `list_alert_subscribes` / `get_alert_subscribe_detail` to get the rule ID and current state, and confirm what to change.
2. Call `update_alert_subscribe` (**proposal-based**: calling it immediately shows the user a change list and pauses; after the user confirms, the system automatically persists it — the confirmation step does not go through you): `id` is required, and `config` only contains the fields to change (**incremental patch**: unspecified fields keep their original values; array fields such as tags/severities/rule_ids/notify_rule_ids/busi_groups/datasource_ids are **wholly replaced** when provided — first get the existing array from detail, build the complete modified array on top of it, then pass it). Common operations:
   - **Temporarily disable** = pass config `{"disabled":1}` (the cache layer filters it directly, taking it completely out of effect immediately); restore = `{"disabled":0}`
   - **Adjust the escalation threshold** = `{"for_duration":600}`; **switch the notification outlet** = `{"notify_rule_ids":[...]}` (first confirm the IDs with `list_notify_rules`)
   - The business group (management ownership) cannot be changed; **deletion** has no in-app tool — have the user do it in the UI (Alert Management → Subscription Rules)
3. When the user says "I subscribed but didn't receive anything", check each gate in order following the troubleshooting chain in `troubleshooting.md`, and **proactively point out** which gate is most likely failing (common ones: for_duration set too large, busi_groups name not matching, the notification rule that notify_rule_ids points to itself not being configured correctly); once you've confirmed it is a config problem at some gate, you can fix it directly with `update_alert_subscribe`.

## Output style

1. Creation goes straight to persistence via the tool; modification is proposal-based — after you call `update_alert_subscribe`, the system shows the user a change list and waits for confirmation, so **do not restate the changes yourself before calling** (to avoid double confirmation); calling completes your responsibility for this round, and do not pass proposal_id/confirmed. Provide HTTP API command templates per `http-api.md` only when the user explicitly asks for curl, and do not execute them.
2. A subscription's effect depends on the downstream notification rule — when giving a plan, clearly separate the "subscription conditions" from the "notification outlet (who notify_rule_ids points to)", and when necessary use `get_notify_rule_detail` to verify the outlet config.
3. A globally unfiltered subscription (rule_ids, tags, busi_groups all empty) copies all events; whether created or edited into this state, restate the blast radius to the user before persisting.
4. After a successful modification, likewise display the rule name in the link form from step 5 of workflow one (the `update_alert_subscribe` return value also includes `url`).

