Alerting Squad Guidelines
public/app/features/alerting/unified/AGENTS.mdAlerting-specific patterns and conventions for Grafana
AGENTS.md
Quality
76/100
Scores the file, not the repository.Length
2,505 words
57 headings · 21 code blocksRepository
76k
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.12345678# Alerting Squad - Agent Configuration910This file provides context for AI agents when working on the Grafana Alerting codebase. It contains alerting-specific patterns and references to Grafana's coding standards.1112## Project Context1314**Location**: `public/app/features/alerting/unified/`15**Squad**: Alerting16**Focus**: Frontend development for Grafana's unified alerting system17**Tech Stack**: React, TypeScript, Redux Toolkit, RTK Query, Emotion, Jest, React Testing Library, MSW1819## Grafana Coding Standards2021**IMPORTANT**: Always follow Grafana's official style guides. Do not duplicate standards here - reference the source files:2223### Required Reading24251. **Frontend Style Guide**: [../../../../../contribute/style-guides/frontend.md](../../../../../contribute/style-guides/frontend.md)26 - Naming conventions, component patterns, TypeScript, exports27 - Function declarations for components, callback props with "on" prefix28292. **Testing Guidelines**: [../../../../../contribute/style-guides/testing.md](../../../../../contribute/style-guides/testing.md)30 - React Testing Library, query priorities, user event setup31323. **Styling Guide**: [../../../../../contribute/style-guides/styling.md](../../../../../contribute/style-guides/styling.md)33 - Emotion usage, `useStyles2` hook patterns34354. **Redux Framework**: [../../../../../contribute/style-guides/redux.md](../../../../../contribute/style-guides/redux.md)36 - Redux Toolkit patterns, reducer testing37385. **Alerting Testing Guide**: [./TESTING.md](./TESTING.md)39 - MSW API mocking, permission mocking, data source setup4041### Alerting-Specific Conventions4243**Use @grafana/alerting Package**:4445- **Always check @grafana/alerting for shared components/hooks** before creating new ones:4647```typescript48 // Good - Use exported components/hooks from @grafana/alerting49 import { AlertLabel, alertingMatchers } from '@grafana/alerting';5051 // Check what's available before reimplementing52```5354**Layout Components**:5556- **Prefer @grafana/ui layout components** over styled divs:5758```typescript59 // Good - Use Box for simple layout/spacing60 import { Box } from '@grafana/ui';61 <Box marginLeft={1}>Content</Box>6263 // Good - Use Stack for flex layouts64 import { Stack } from '@grafana/ui';65 <Stack direction="column" gap={2}>66 <div>Item 1</div>67 <div>Item 2</div>68 </Stack>6970 // Avoid - Custom styled divs when layout components exist71 <div className={styles.wrapper}>Content</div>72```7374## Alerting Codebase Structure7576### Key Directories7778- `api/` - RTK Query API slices for data fetching79- `components/` - Feature-specific React components organized by domain80- `hooks/` - Reusable custom hooks for logic and data fetching81- `rule-editor/` - Alert rule creation and editing forms82- `rule-list/` - Alert rules list views (v1 and v2)83- `state/` - Redux state management and context providers84- `utils/` - Utility functions and helpers85- `types/` - TypeScript type definitions86- `mocks/` - MSW mock server setup for testing87- `testSetup/` - Test utilities and configuration8889### Component Domains9091- `alert-groups/` - Alert grouping and filtering92- `contact-points/` - Contact point configuration93- `notification-policies/` - Notification routing policies94- `mute-timings/` - Mute timing windows95- `silences/` - Silence management96- `receivers/` - Receiver configuration97- `templates/` - Notification templates98- `permissions/` - Permission management99- `settings/` - Alertmanager settings100101## State Management Patterns102103### RTK Query (Primary - Preferred)104105**IMPORTANT**: Our direction is to use RTK Query for data fetching, NOT Redux.106107- API slices in `api/` directory108- Custom base query in `api/alertingApi.ts`109- Automatic caching with 2-minute polling: `RULE_LIST_POLL_INTERVAL_MS`110- Key APIs: `alertRuleApi`, `alertmanagerApi`, `prometheusApi`, `receiversApi`111112**For new features**: Always use RTK Query hooks for data fetching:113114```typescript115import { useGetAlertRulesQuery } from '../api/alertRuleApi';116117const { data, isLoading, error } = useGetAlertRulesQuery(params);118```119120### Using Auto-Generated API Clients (`@grafana/api-clients`)121122**IMPORTANT**: When consuming an API endpoint, always prefer the auto-generated clients from `@grafana/api-clients` over creating custom RTK Query endpoints manually. Do not create new RTKQ endpoints by hand — use the generated ones instead.123124The auto-generated clients are available under `@grafana/api-clients/rtkq/<api-group>/<version>` (e.g., `@grafana/api-clients/rtkq/notifications.alerting/v0alpha1`).125126**When the auto-generated client works as-is** — just import and use it directly:127128```typescript129import { generatedAPI } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';130131const { data } = generatedAPI.useListReceiversQuery(params);132```133134**When the auto-generated client is incomplete** (e.g., missing request body types), use `enhanceEndpoints` to override the endpoint while still using the generated client as base. This avoids creating a fully manual RTKQ endpoint:135136```typescript137import { CreateReceiverTestApiArg, generatedAPI } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';138139// Define the missing body type140interface TestReceiverIntegrationBody {141 integration: { type: string; settings: Record<string, unknown> };142 alert: { labels: Record<string, string>; annotations: Record<string, string> };143}144145// Extend the generated arg with the correct body type146export interface CreateReceiverTestOverrideArg extends CreateReceiverTestApiArg {147 body: TestReceiverIntegrationBody;148}149150// TODO: Remove this override once the auto-generated client includes the request body type151const enhancedApi = generatedAPI.enhanceEndpoints({152 endpoints: {153 createReceiverTest: (endpoint) => {154 endpoint.query = (queryArg: CreateReceiverTestOverrideArg) => ({155 url: `/receivers/${queryArg.name}/test`,156 method: 'POST' as const,157 body: queryArg.body,158 });159 },160 },161});162163// Re-export with correct types164export function useCreateReceiverTestMutation() {165 const [originalTrigger, state] = enhancedApi.useCreateReceiverTestMutation();166 const trigger = (arg: CreateReceiverTestOverrideArg) => originalTrigger(arg);167 return [trigger, state] as const;168}169```170171**Key rules**:1721731. Always start from `@grafana/api-clients` — never skip it to write a manual RTKQ endpoint1742. If the generated client has gaps (missing body, wrong types), use `enhanceEndpoints` to patch it1753. Mark overrides with a `TODO` comment so they can be removed when the generated client is fixed1764. Place enhanced API wrappers in the `api/` directory (e.g., `api/testReceiversApi.ts`)177178### Redux Toolkit (Legacy)179180**Avoid for new features** - Use RTK Query instead181182- Legacy reducers exist in `state/reducers/`183- Use state selectors: `useUnifiedAlertingSelector`184- Only modify if maintaining existing Redux code185186### Context Providers187188- `AlertmanagerContext` - Alertmanager selection state, for managing Alertmanager entities for a specific Alertmanager data source.189- `SettingsContext` - Settings state – used in `public/app/features/alerting/unified/components/settings`190- `WorkbenchContext` - Workbench state used in the alert triage feature `public/app/features/alerting/unified/triage`191192### Forms193194- Use `react-hook-form` (v7) for all forms195- See `rule-editor/alert-rule-form/` for patterns196197## Alerting-Specific Testing Patterns198199See [./TESTING.md](./TESTING.md) for comprehensive testing guide. Key points:200201### API Mocking with MSW202203**REQUIRED**: Use MSW for all API mocking (not `jest.fn()`) – though it's fine to use this function for unit testing.204205```typescript206import { mockApi } from '../mockApi';207208// Mock common endpoints209mockApi.eval(); // for AlertingQueryRunner210// If helper doesn't exist, add it to mockApi.ts211```212213**Why MSW?** Forces proper loading state handling, discovers UI issues early214215### Permission Mocking216217**Default: RBAC enabled** (most common user scenario)218219```typescript220import { enableRBAC, grantUserPermissions } from '../mocks';221222enableRBAC(); // Usually not needed, enabled by default223grantUserPermissions([AccessControlAction.AlertingRuleRead]);224```225226### Mock Data Factories227228Located in `mocks.ts`:229230```typescript231mockDataSource();232mockPromAlert();233mockRulerGrafanaRule();234mockAlertmanagerAlert();235mockSilence();236```237238### Data Source Setup239240Located in `testSetup/datasources.ts` for data source mocking patterns241242### Test Data Factories243244**Use factories for creating test data** - Don't manually create objects.245246For Kubernetes APIs and new schemas – use the `@grafana/alerting` package.247248Mock factories are defined in `packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/fakes`249MSW handlers in `packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers`250251And there are "scenarios" that combine the two above. An example of such is `packages/grafana-alerting/src/grafana/contactPoints/components/ContactPointSelector/ContactPointSelector.test.scenario.ts` and is used for integration tests.252253Additionally alerting uses **`alertingFactory`** from `mocks/server/db` for building test data:254255```typescript256import { alertingFactory } from './mocks/server/db';257import { mockFolder } from './mocks';258259// Build a single alerting rule260const alertingRuleBuilder = alertingFactory.ruler.grafana.alertingRule;261const rule = alertingRuleBuilder.build();262263// Build multiple rules264const rules = alertingRuleBuilder.buildList(6);265266// Override specific fields267const customRule = alertingRuleBuilder.build({268 grafana_alert: { title: 'CPU Alert' },269 labels: { severity: 'critical' },270});271```272273**Common patterns**:274275```typescript276// Alerting rules277alertingFactory.ruler.grafana.alertingRule.build();278alertingFactory.ruler.grafana.alertingRule.buildList(n);279280// Folders281mockFolder(); // Simple mock function282283// Override fields when building284alertingRuleBuilder.build({285 grafana_alert: { title: 'Custom Title' },286 labels: { key: 'value' },287});288```289290**Benefits**:291292- Consistent test data across tests293- Easy to generate multiple instances with `buildList(n)`294- Override only the fields you care about295- Automatic sequencing (e.g., "Alerting rule 1", "Alerting rule 2")296297**Other mock functions** (from `mocks.ts`):298299```typescript300mockDataSource();301mockPromAlert();302mockRulerGrafanaRule();303mockAlertmanagerAlert();304mockSilence();305mockFolder();306```307308## Alerting-Specific Patterns309310### Feature Toggles & settings311312A full list of features can be found in `pkg/services/featuremgmt/toggles_gen.csv` – focus on feature toggles owned by `@grafana/alerting-squad`.313314```typescript315import { config } from '@grafana/runtime';316317if (config.featureToggles.alertingTriage) {318 // Render triage view319}320```321322A common configuration setting would be `unifiedAlertingEnabled` which allows a user to configure Grafana without any alerting UI or backend enabled at all.323324### Date/Time Formatting325326Use `dateTimeFormat()` / `dateTimeFormatTimeAgo()` from `@grafana/data` instead of `dateTime().format()` — they respect the user's configured timezone.327328```typescript329// Good - respects user timezone330import { dateTimeFormat, dateTimeFormatTimeAgo } from '@grafana/data';331dateTimeFormat(timestamp);332dateTimeFormatTimeAgo(timestamp);333334// Bad - ignores user timezone setting335import { dateTime } from '@grafana/data';336dateTime(timestamp).format('YYYY-MM-DD HH:mm:ss');337```338339### Data Source Abstractions340341```typescript342import { isGrafanaRulerRule } from '../utils/rules';343344if (isGrafanaRulerRule(rule)) {345 // Grafana-managed346} else {347 // External alertmanager348}349```350351### Access Control (RBAC)352353```typescript354import { useAbilities } from '../hooks/useAbilities';355356function Component() {357 const [_, { can }] = useAbilities();358 const canCreate = can(AccessControlAction.AlertingRuleCreate);359360 return canCreate ? <CreateButton /> : null;361}362```363364### Key Routes365366Defined in `routes.tsx`:367368- `/alerting` - Home369- `/alerting/list` - Rules list (v1/v2)370- `/alerting/new/:type?` - Create rule371- `/alerting/:id/edit` - Edit rule372- `/alerting/notifications` - Contact points373- `/alerting/routes` - Notification policies374375### Common Hooks376377```typescript378useCombinedRuleNamespaces(); // Combines Prometheus + Ruler rules379useAlertmanagerConfig(); // Fetch alertmanager config380useFolder(); // Folder operations381useUnifiedAlertingSelector(); // Redux state – avoid using382useAbilities(); // Permission checking383```384385### Link URLs and Navigation386387**IMPORTANT**: Different navigation components require different URL formats.388389#### When to use `createRelativeUrl`390391Use `createRelativeUrl` **only with LinkButton** (and other components that render HTML `<a>` elements):392393```typescript394import { createRelativeUrl } from '@grafana/data';395import { LinkButton } from '@grafana/ui';396397// LinkButton renders <a> tag - needs manual subpath prefix398<LinkButton href={createRelativeUrl('/alerting/list')}>399 View Rules400</LinkButton>401```402403**Why?** LinkButton renders a native HTML anchor element, so it doesn't use React Router. You must manually add the subpath prefix using `createRelativeUrl`.404405#### When NOT to use `createRelativeUrl`406407Do **NOT** use `createRelativeUrl` with:4084091. **locationService** - Automatically adds prefix:410411```typescript412import { locationService } from '@grafana/runtime';413414// locationService uses react-router history - prefix added automatically415locationService.push('/alerting/list'); // ✅ Correct - no createRelativeUrl416locationService.push(createRelativeUrl('/alerting/list')); // ❌ Wrong - double prefix!417```4184192. **TextLink component** - Automatically adds prefix:420421```typescript422import { TextLink } from '@grafana/ui';423424// TextLink uses react-router Link - prefix added automatically425<TextLink href="/alerting/list">View Rules</TextLink> // ✅ Correct426<TextLink href={createRelativeUrl('/alerting/list')}>View Rules</TextLink> // ❌ Wrong427```428429#### Summary430431| Component/Service | Use `createRelativeUrl`? | Reason |432| -------------------- | ------------------------ | --------------------------------------- |433| `LinkButton` | ✅ YES | Renders `<a>` tag (native HTML) |434| `Button` with `href` | ✅ YES | Renders `<a>` tag when href provided |435| `locationService` | ❌ NO | Uses react-router history (auto-prefix) |436| `TextLink` | ❌ NO | Uses react-router Link (auto-prefix) |437| React Router `Link` | ❌ NO | React Router component (auto-prefix) |438439**Rule of thumb**: If it renders a native HTML `<a>` tag, use `createRelativeUrl`. If it uses React Router, don't.440441## Key Libraries442443### Grafana Internal444445- `@grafana/ui` - UI components (Button, Select, Input, etc.)446- `@grafana/data` - Data models and utilities447- `@grafana/runtime` - Runtime services (config, backendSrv, locationService)448- `@grafana/scenes` - Scene framework (Insights/Triage views)449- `@grafana/e2e-selectors` - Test selectors450- `@grafana/alerting` - Grafana managed alerting specific package (utility functions, API endpoints, mocks, React components, etc)451452### External453454- `react-hook-form` (v7) - Form state455- `@reduxjs/toolkit` - Redux + RTK Query456- `@emotion/css` - Styling457- `lodash` - Utilities458- `msw` - API mocking for tests459460## Quick Reference Checklists461462### Creating a New Component4634641. ✅ Create in appropriate `components/` subdirectory4652. ✅ Use function declaration (not arrow function)4663. ✅ Add TypeScript props interface (no "I" prefix)4674. ✅ Use `useStyles2` for styling (Emotion)4685. ✅ Create colocated test file4696. ✅ Use MSW for API mocking in tests4707. ✅ Query with `*ByRole` queries471472### Adding a New API Endpoint4734741. ✅ Check if the endpoint exists in `@grafana/api-clients` — always prefer auto-generated clients4752. ✅ If the generated client is incomplete, use `enhanceEndpoints` to patch it (see [Using Auto-Generated API Clients](#using-auto-generated-api-clients-grafanaapi-clients))4763. ✅ Place the wrapper in the `api/` directory4774. ✅ Add helper to `mockApi.ts` for testing4785. ✅ Handle loading/error states in UI4796. ✅ Test with MSW480481### Creating a New Form4824831. ✅ Use `react-hook-form` (v7)4842. ✅ See `rule-editor/alert-rule-form/` for patterns4853. ✅ Add validation (schema if needed)4864. ✅ Handle API submission errors4875. ✅ Test user interactions with `userEvent`488489### Writing Tests490491Check https://testing-library.com/docs/queries/about/ for what selectors to prefer when using React Testing Library492493- [ ] RBAC enabled by default494- [ ] MSW for API mocking (not `jest.fn()`)495- [ ] Loading states tested496- [ ] Error states tested497- [ ] User interactions use `userEvent.setup()`498- [ ] Queries prefer `*ByRole`499- [ ] Async operations use `await` and `findBy*`500- [ ] Permissions tested with `grantUserPermissions`501502## Using GitHub CLI for Context503504When working on issues, PRs, or needing repository context, use the GitHub CLI (`gh`) to fetch information directly:505506### Common Commands507508```bash509# View issue details510gh issue view <issue-number>511512# View PR details and diff513gh pr view <pr-number>514gh pr diff <pr-number>515516# List recent issues517gh issue list --limit 10518519# List PRs with specific labels520gh pr list --label "alerting"521522# Search issues523gh issue list --search "keyword"524525# View PR reviews and comments526gh pr view <pr-number> --comments527528# Check CI status529gh pr checks <pr-number>530531# View repository info532gh repo view533```534535### When to Use536537- **Understanding issue context**: Fetch issue descriptions, comments, and linked PRs538- **Reviewing PR changes**: Get diffs, review comments, and CI status539- **Finding related work**: Search for similar issues or existing implementations540- **Checking project status**: List open issues/PRs for the alerting team541542### Example Workflow543544```bash545# Working on issue #12345546gh issue view 12345547548# Check if there's an existing PR549gh pr list --search "fixes #12345"550551# Review a related PR552gh pr view 67890553gh pr diff 67890554```555556## Learning from Corrections557558When the user corrects a mistake you made (wrong API, wrong pattern, wrong approach), assess whether the correction represents a recurring pattern worth documenting. If so, propose a concise addition to this AGENTS.md — but do **NOT** apply it without explicit approval.559560Skip proposing an update if the correction is:561562- A one-off or highly context-specific fix563- Already documented in this file564- A personal preference rather than a project convention565566## Dependency Security567568- **No new dependencies without explicit approval**: Do NOT run `yarn add` or otherwise introduce new packages. If a task would benefit from a new dependency, stop and ask the user for approval first — explain what package you want, why, and its publish date.569- **7-day quarantine**: Even with approval, never add a dependency whose latest version was published less than 7 days ago. Check publish date with `npm view <package> time --json` before proposing.570- **Prefer established packages**: Favor well-known, actively maintained packages. Avoid packages with very few downloads or no recent maintenance.571- **No postinstall script overrides**: The repo has `enableScripts: false`. Do not add per-package script overrides without approval from @grafana/frontend-ops.572- **Lock file integrity**: Always use `yarn install --immutable`. Never manually edit `yarn.lock`.573- **Report suspicious packages**: If a dependency shows signs of compromise (unexpected scripts, obfuscated code, ownership transfer), flag it in the PR and tag @grafana/frontend-ops.574575## Getting Help576577- Check patterns in existing `components/` code578- Review test examples in `*.test.tsx` files579- Consult `mockApi.ts` for API mocking580- See `mocks.ts` for data factories581- Read [./TESTING.md](./TESTING.md) for testing details582- Review Grafana style guides (linked at top)583- Use `gh` CLI to fetch issue/PR context from GitHub584585---586587**Last Updated**: 2026-03-31588**Maintained By**: Alerting Squad589
Also in grafana/grafana
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| grafana/grafanaAGENTS.md · 76k | AGENTS.md | setupbuildtestlint-format+6 | 89/100 | 3 days ago | |
| grafana/grafanae2e-playwright/alerting-suite/AGENTS.md · 76k | AGENTS.md | teststylearchtesting-strategy+3 | 81/100 | 3 days ago | |
| grafana/grafanae2e-playwright/dashboard-new-layouts/AGENTS.md · 76k | AGENTS.md | teststyletesting-strategydatabase+1 | 62/100 | today | |
| grafana/grafanae2e-playwright/plugin-e2e/plugin-e2e-api-tests/AGENTS.md · 76k | AGENTS.md | teststyletesting-strategygit+4 | 70/100 | 3 days ago | |
| grafana/grafanapackages/grafana-ui/AGENTS.md · 76k | AGENTS.md | uiagent-behaviour | 16/100 | 3 days ago | |
| grafana/grafanapkg/storage/unified/AGENTS.md · 76k | AGENTS.md | do-not | 46/100 | 3 days ago | |
| grafana/grafanapublic/app/core/journeys/AGENTS.md · 76k | AGENTS.md | testtesting-strategygitagent-behaviour | 73/100 | 3 days ago | |
| grafana/grafanapublic/app/features/AGENTS.md · 76k | AGENTS.md | agent-behaviour | 16/100 | 3 days ago | |
| grafana/grafanapublic/app/features/expressions/components/SqlExpressions/SqlEditor/AGENTS.md · 76k | AGENTS.md | styleagent-behaviour | 43/100 | 3 days ago | |
| grafana/grafanapublic/app/plugins/panel/AGENTS.md · 76k | AGENTS.md | agent-behaviour | 16/100 | 3 days ago |
Diff against AGENTS.md Diff against e2e-playwright/alerting-suite/AGENTS.md Diff against e2e-playwright/dashboard-new-layouts/AGENTS.md Diff against e2e-playwright/plugin-e2e/plugin-e2e-api-tests/AGENTS.md Diff against packages/grafana-ui/AGENTS.md Diff against pkg/storage/unified/AGENTS.md Diff against public/app/core/journeys/AGENTS.md Diff against public/app/features/AGENTS.md Diff against public/app/features/expressions/components/SqlExpressions/SqlEditor/AGENTS.md Diff against public/app/plugins/panel/AGENTS.md
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| code-yeongyu/oh-my-openagentpackages/web/AGENTS.md · 67k | AGENTS.md | setupbuildtestlint-format+6 | 100/100 | 2 days ago | |
| TryGhost/Ghoste2e/AGENTS.md · 55k | AGENTS.md | setupteststylearch+2 | 100/100 | 3 days ago | |
| mui/material-uiAGENTS.md · 99k | AGENTS.md | setupbuildtestlint-format+9 | 100/100 | 3 days ago | |
| n8n-io/n8npackages/@n8n/agents/AGENTS.md · 199k | AGENTS.md | buildteststylearch+3 | 100/100 | 3 days ago | |
| duckduckgo/content-scope-scriptsspecial-pages/AGENTS.md · 70 | AGENTS.md | buildteststylearch+3 | 100/100 | 3 days ago | |
| aaif-goose/gooseAGENTS.md · 52k | AGENTS.md | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| trick77/agents-md-syncAGENTS.md · 2 | AGENTS.md | setupbuildteststyle+5 | 100/100 | 3 days ago | |
| ethereum/go-ethereumAGENTS.md · 51k | AGENTS.md | buildtestlint-formatgit+1 | 100/100 | 3 days ago |
