Skip to content
27 changes: 27 additions & 0 deletions .agents/skills/writing-sdk-specs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: writing-sdk-specs
description: Write, edit, or review SDK specs. Use when changing or reviewing any page under develop-docs/sdk/ that has spec_id frontmatter (except process specs with spec_kind: process), or when creating a new SDK spec.
---

# Writing SDK Specs

The rules live in [`develop-docs/sdk/getting-started/standards/writing-specs.mdx`](../../../develop-docs/sdk/getting-started/standards/writing-specs.mdx). That page is the source of truth. This skill only says when and how to apply it.

## Steps

1. **Read the guidelines.** Read `writing-specs.mdx` in full before changing a spec. Don't work from memory or from this file.
2. **Check what kind of spec it is.** If its frontmatter has `spec_kind: process` (playbooks and engineering standards), the guidelines don't apply: skip the remaining steps. Otherwise, the spec is legacy if its frontmatter has no `spec_guidelines` field.
3. **Write to the guidelines.**
- **New spec:** follow the guidelines for the whole page and set `spec_guidelines: writing-specs@<major.minor>` to the current version of `writing-specs.mdx`.
- **Legacy spec:** make every requirement you add or change follow the guidelines. Leave the rest of the page as it is unless the user asks you to migrate it. Don't add `spec_guidelines` unless the whole page now conforms.
4. **Check your own work.** Re-read every requirement you added or changed against `writing-specs.mdx`, and fix any violations before you finish.
5. **Report existing violations.** List violations you noticed in content you didn't change, but don't fix them unless the user asks. Give the section and quote the text.

## What to Report

When you finish, briefly report:

- Which guidelines version you followed.
- Whether the page is legacy or conforming, and whether you set `spec_guidelines`.
- Any pre-existing violations you found (or "none found").
- For a migration: every requirement you added, removed, or whose level or meaning changed, so a reviewer can check each one.
1 change: 1 addition & 0 deletions .claude/skills/writing-sdk-specs
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ To bypass the hook once without marking the file, use `SKIP=trailing-slashes git

Managed skills in `.agents/skills/` are not checked in. Run `make develop` (or `npx -y @sentry/dotagents install`) to install them before relying on skills like `/brand-guidelines` or `/commit`.

Repo-specific skills live in `.agents/skills/<name>/`, are checked in, and are declared in `agents.toml` with a `path:` source (for example `writing-sdk-specs`).

## Developer Documentation (develop-docs/)

When writing requirements in `develop-docs/`:
Expand All @@ -98,6 +100,7 @@ When writing requirements in `develop-docs/`:
- **ALWAYS** run `/brand-guidelines` to audit any user-facing content before committing. See `.agents/skills/brand-guidelines/SKILL.md`
- Use `docs-review` skill for Sentry style and voice review. See `.claude/skills/docs-review/SKILL.md`
- Use `technical-docs` skill when writing or reviewing SDK documentation. See `.claude/skills/technical-docs/SKILL.md`
- Use `writing-sdk-specs` skill when writing, editing, or reviewing SDK specs (pages in `develop-docs/sdk/` with `spec_id` frontmatter, except those with `spec_kind: process`). See `.agents/skills/writing-sdk-specs/SKILL.md`

## LLM-Friendly MD Exports

Expand Down
4 changes: 4 additions & 0 deletions agents.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ source = "getsentry/skills"
[[skills]]
name = "create-branch"
source = "getsentry/skills"

[[skills]]
name = "writing-sdk-specs"
source = "path:.agents/skills/writing-sdk-specs"
80 changes: 23 additions & 57 deletions develop-docs/sdk/foundations/client/integrations/modules.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
title: Modules
description: Integration for attaching loaded libraries and their versions to events, populating the event modules field.
spec_id: sdk/foundations/client/integrations/modules
spec_version: 1.0.0
spec_version: 2.0.0
spec_status: stable
spec_guidelines: writing-specs@0.1
spec_depends_on:
- id: sdk/foundations/client/integrations
version: ">=1.0.0"
spec_changelog:
- version: 2.0.0
date: 2026-10-19
summary: 'Migrated to Writing SDK Specs. Requirements now describe only externally observable behavior. Using the `processEvent` hook (was "MUST"), caching the module list, and choosing or combining discovery mechanisms are no longer required. The reported modules "SHOULD" instead list every installed or loaded module with the version in use. Attaching modules to events is "SHOULD" instead of "MUST"; their format stays "MUST". The "MAY" for omitting modules now covers only events that are not error events, instead of any event type where modules are less useful.'
- version: 1.0.0
date: 2026-03-04
summary: Initial spec, extracted from expected features
Expand All @@ -18,89 +22,51 @@ sidebar_order: 4

<SpecMeta />

## Overview
The Modules integration attaches the libraries an application uses, and their versions, to events. Sentry shows them in the event details, so users can spot dependency-related issues.

The Modules integration attaches a list of loaded libraries (packages, modules) and their versions to events. This populates the [`modules` field](/sdk/foundations/envelopes/event-payloads/#optional-attributes) on the event payload, which Sentry displays in the event detail view to help users identify dependency-related issues.
## Scope

This integration **SHOULD** be a default integration.
This spec applies to SDKs that implement the Modules integration.

---

## Behavior
## Definitions

<SpecSection id="event-enrichment" status="stable" since="1.0.0">
- **Module**: a library or package the application can use, such as a Python distribution or an npm package.

### Event Enrichment
## Requirements

The integration **MUST** use the `processEvent` lifecycle hook to attach module information to events.
<SpecSection id="event-enrichment" status="stable" since="2.0.0">

The integration **MUST** populate `event.modules` as a map of module name to version string:
### Event Enrichment

```json
{
"modules": {
"flask": "2.3.1",
"requests": "2.31.0",
"sqlalchemy": "2.0.19"
}
}
```
SDKs **SHOULD** enable the integration by default.

The integration **SHOULD** cache the module list, since installed packages rarely change during a process lifetime.
The integration **SHOULD** attach modules to every event, except where [Event Type Filtering](#event-type-filtering) allows it to omit them. Attached modules **MUST** be in the event's [`modules` field](/sdk/foundations/envelopes/event-payloads/#optional-attributes), as a map from module name to version string.

</SpecSection>

<SpecSection id="module-sources" status="stable" since="1.0.0">
<SpecSection id="module-sources" status="stable" since="2.0.0">

### Module Sources

How modules are discovered is platform-specific. SDKs **SHOULD** use the most reliable mechanism available on their platform. Common strategies include:

- **Package manager metadata** — reading installed package registries (e.g., `pkg_resources` or `importlib.metadata` in Python, `package.json` dependencies in Node.js)
- **Runtime module cache** — inspecting loaded modules from the runtime (e.g., `require.cache` in Node.js CJS)
- **Build-time injection** — embedding module information at build time when runtime discovery is unavailable or incomplete (e.g., bundled environments)

SDKs **MAY** combine multiple sources to produce the most complete list. When the same module appears in multiple sources, the more specific version (e.g., from a lockfile or runtime cache) **SHOULD** take precedence.
The `modules` field **SHOULD** list every module installed in the application's environment or loaded by the application, each with the version the application uses.

</SpecSection>

<SpecSection id="event-type-filtering" status="stable" since="1.0.0">
<SpecSection id="event-type-filtering" status="stable" since="2.0.0">

### Event Type Filtering

SDKs **MAY** skip attaching modules to certain event types (e.g., transactions) where the information is less useful, to reduce payload size.
SDKs **MAY** omit modules from events that are not error events, such as transactions, to reduce payload size.

</SpecSection>

---

## Examples

### JavaScript (Node.js)

```javascript
// modulesIntegration is a default integration in @sentry/node
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
});

// Modules are automatically attached to error events.
// The integration reads from package.json and require.cache (CJS).
```
## Implementation Guidance

### Python
_This section is non-normative._

```python
import sentry_sdk
How to discover modules depends on the platform. Common sources are package manager metadata (such as `importlib.metadata` in Python or `package.json` in Node.js), the runtime's module cache (such as `require.cache` in Node.js CJS), and module lists injected at build time, for bundled environments where runtime discovery is incomplete. When SDKs combine sources, the version from the more specific source, such as a lockfile or the runtime cache, is usually the one in use.

# ModulesIntegration is a default integration
sentry_sdk.init(dsn="https://examplePublicKey@o0.ingest.sentry.io/0")

# Modules are automatically attached to error events.
# The integration reads from importlib.metadata / pkg_resources.
```

---
Installed packages rarely change while a process runs, so SDKs typically collect the module list once and cache it, rather than collecting it for every event.

## Changelog

Expand Down
Loading