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
51 changes: 48 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# AGENTS.md

Sentry React Native SDK โ€” monorepo using yarn workspaces with a single package at `packages/core`.
Sentry React Native SDK โ€” a **hybrid SDK**: a TypeScript/JS layer on top that wraps the native **sentry-cocoa** (iOS) and **sentry-android/java** SDKs through a JSโ†”native bridge. Monorepo using yarn workspaces; the SDK itself is the `packages/core` package.

## Stack

- **Published packages:** `@sentry/react-native` (`packages/core`, the SDK) + companion `@sentry/expo-upload-sourcemaps`; yarn 4 workspaces.
- **Wraps native SDKs:** sentry-cocoa (iOS) + sentry-android/java (Android) through the JSโ†”native bridge.
- **Hosts:** React Native on **both** the New (TurboModule/Fabric) and Old (bridge) Architecture, plus Expo and React.
- **Exact versions** (don't copy them here โ€” they rot): JS deps and host peer ranges in [`packages/core/package.json`](packages/core/package.json); the bundled native SDK versions per release in [`SDK-VERSIONS.md`](SDK-VERSIONS.md) (regenerated each release by `craft-pre-release.sh`).

Changes to the wrapped native SDKs can ripple to them and to downstream hybrid SDKs (Flutter, .NET/MAUI, Unity) โ€” see *Cross-Platform Dependencies*.

## Agent Responsibilities

- **Continuous Learning**: Document new patterns in the appropriate nested `AGENTS.md` file.
- **Context Management**: After compaction, re-read `AGENTS.md` files relevant to your current task.
- **Reach for a skill first.** For anything beyond a trivial edit, load the matching skill (see *Skills*) โ€” it carries the deep, current guidance this file only indexes.
- **Continuous Learning:** when you discover a durable pattern, record it in the nearest nested `AGENTS.md` (or the relevant skill), not inline in a PR.
- **Context Management:** after compaction, re-read the `AGENTS.md` for the surface you're touching before continuing.

## Setup

Expand All @@ -32,6 +42,26 @@ yarn build
| ObjC/C++ lint | `yarn lint:clang` |
| Swift lint | `yarn lint:swift` |

## Boundaries

**โœ… Always**
- Run `yarn lint`, `yarn test`, and `yarn circularDepCheck` before calling a change done; regenerate the API report (`yarn api-report`) when the public surface moved.
- Make a change work on **both** architectures (New + Old) and **both** platforms (iOS + Android) โ€” a fix that only covers one is not done.
- Gate any user data placed in events/breadcrumbs/spans/logs on `options.sendDefaultPii`.
- Catch native errors at the bridge boundary and degrade โ€” reject/log, never let them propagate.

**โš ๏ธ Ask first**
- Adding or changing any dependency, `.vscode` extension, GitHub Action, or native dependency โ€” verify provenance first (load `code-guidelines` โ†’ *Adding dependencies*).
- Changing the public API (`packages/core/src/js/index.ts` barrel, exported options) or a codegen/bridge spec (`NativeRNSentry.ts`, `*NativeComponent.ts`) โ€” these are breaking and need a deprecation path.
- Changing CI workflows, release config, or anything under `scripts/`.

**๐Ÿšซ Never**
- Crash the host app โ€” a native exception that reaches the app is the highest-severity failure this SDK can cause.
- Break the public API or bridge ABI without a `@deprecated` migration path (an app can ship new JS against an older cached native binary).
- Hand-edit generated files: `packages/core/etc/sentry-react-native.api.md` (regenerate it) or New-Architecture codegen output โ€” regenerate, never edit by hand.
- Add `CHANGELOG.md` noise for routine internal/CI/test/chore changes โ€” the user-facing sections (`### Features`, `### Fixes`) are for user-visible changes. A genuinely notable internal change goes under the `### Internal` section instead, not among the user-facing entries.
- Commit secrets, tokens, or DSNs.

## Commit Conventions

Follow conventional commit format: `<type>(<scope>): <subject>`
Expand Down Expand Up @@ -99,6 +129,21 @@ Changes may impact downstream SDKs. Coordinate with other teams when modifying n
- **Inline comments** for complex logic only
- Update `CHANGELOG.md` for user-visible changes

## Skills โ€” load on demand

The deep, task-specific guidance lives in `.agents/skills/` (registered in `agents.toml`) and is loaded when you need it โ€” this file is the always-on operating manual, the skills are the specialists. Reach for one **before** doing the matching work:

| Skill | Load it when |
|-------|--------------|
| `spec` | The *what* isn't pinned down yet โ€” a fuzzy issue or idea to scope into acceptance criteria. Hands off to `design-first`. |
| `design-first` | Starting a feature/integration, changing the public barrel, crossing the bridge, or changing a codegen spec โ€” shape modules and seams before coding. |
| `code-guidelines` | Implementing, refactoring, designing APIs, writing integrations, handling breaking changes, or adding dependencies. |
| `test-guidelines` | Writing, modifying, or reviewing Jest tests, fixtures, and mocks. |
| `review` | A three-axis (Standards / Spec / Correctness) pass on a branch or PR before opening or merging. |
| `diagnosing-bugs` | A hard bug, flaky test, CI hang, native crash, or perf regression โ€” builds a red-capable loop before hypothesizing. |

Warden's automated PR review and `agents.toml` also pull **remote** specialists (`security-review`, `gha-security-review`, `span-convention-review`, and more) โ€” invoke those for depth beyond the local pass.

## Nested AGENTS.md Files

- [`packages/core/AGENTS.md`](packages/core/AGENTS.md) โ€” TypeScript/JavaScript code style, testing, patterns
Expand Down
12 changes: 9 additions & 3 deletions packages/core/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# packages/core โ€” TypeScript/JavaScript SDK

> **Depth lives in the skills.** The `code-guidelines` and `test-guidelines` skills (`.agents/skills/`) hold the authoritative, current guidance on code style, API/integration design, the bridge, and tests โ€” load them before non-trivial work. This file covers the package's build/test commands, quick-reference conventions, and the **TurboModule subsystem**, which is documented nowhere else. Where a convention here overlaps a skill, the skill wins.

## Build & Test

```bash
Expand Down Expand Up @@ -95,14 +97,18 @@ describe('MyComponent', () => {

## Common Patterns

> Diagnostics use **`debug`** from `@sentry/core`, not `logger` โ€” `logger` is the Logs API and emits log *events* (and recurses in the bridge hot path). See *TurboModule Instrumentation* below.

### Error Handling

```typescript
import { debug } from '@sentry/core';

try {
const result = await riskyOperation();
return result;
} catch (error) {
logger.error('Operation failed', error);
debug.error('Operation failed', error);
// Don't throw - log and return fallback
return fallbackValue;
}
Expand All @@ -117,14 +123,14 @@ const { RNSentry } = NativeModules;

export async function nativeOperation(param: string): Promise<boolean> {
if (!RNSentry) {
logger.warn('Native module not available');
debug.warn('Native module not available');
return false;
}

try {
return await RNSentry.nativeOperation(param);
} catch (error) {
logger.error('Native operation failed', error);
debug.error('Native operation failed', error);
return false;
}
}
Expand Down
24 changes: 20 additions & 4 deletions packages/core/android/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# packages/core/android โ€” Java & Kotlin

> **Depth lives in the skills.** `code-guidelines` (`.agents/skills/`, esp. `references/native-bridge.md`) is authoritative for bridge and native conventions โ€” load it before non-trivial work. This file is the quick reference for the Android surface; where a convention here overlaps a skill, the skill wins.

## Formatting & Linting

| Task | Command |
Expand All @@ -25,25 +27,39 @@

## Architecture Variants

Android native code supports both old and new React Native architectures:
Android native code supports both React Native architectures โ€” a bridge-method change usually has to land in **both**:

- `src/oldarch/` โ€” Legacy bridge implementation
- `src/newarch/` โ€” TurboModule / Fabric implementation
- `src/main/` โ€” Shared code
- `src/main/` โ€” Shared code (`io.sentry.react`)

## Native Bridge Pattern (Java)

Catch `Throwable` at the boundary โ€” not just `Exception`, so an `Error` can't crash the app either (the module code catches `Throwable` throughout) โ€” and reject with the shared `"SentryReactNative"` code, not a per-method one:

```java
@ReactMethod
public void nativeOperation(String param, Promise promise) {
try {
boolean result = performOperation(param);
promise.resolve(result);
} catch (Exception e) {
promise.reject("OPERATION_FAILED", "Operation failed: " + e.getMessage(), e);
} catch (Throwable e) {
promise.reject("SentryReactNative", e.getMessage(), e);
Comment thread
antonis marked this conversation as resolved.
}
}
```

## Boundaries

**โœ… Always**
- Land a bridge-method change in **both** `src/oldarch/` and `src/newarch/` โ€” one arch is not done.
- Catch `Throwable` at every `@ReactMethod` and `promise.reject(...)` โ€” an uncaught throwable crashes the host app.
- Gate any user data added to events/breadcrumbs/spans on `sendDefaultPii`.

**๐Ÿšซ Never**
- Change the codegen bridge ABI without mirroring it in JS + iOS and keeping it backward-compatible with an older cached native binary.
- Bump the bundled `io.sentry:sentry-android` version by hand โ€” go through `scripts/update-android.sh`.

## Working with Local sentry-java

1. Build sentry-java: `cd sentry-java && make dryRelease`
Expand Down
29 changes: 16 additions & 13 deletions packages/core/ios/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# packages/core/ios โ€” Objective-C & Swift

> **Depth lives in the skills.** `code-guidelines` (`.agents/skills/`, esp. `references/native-bridge.md`) is authoritative for bridge and native conventions โ€” load it before non-trivial work. This file is the quick reference for the iOS surface; where a convention here overlaps a skill, the skill wins.

## Formatting & Linting

| Task | Command |
Expand All @@ -22,20 +24,10 @@
- Use **swiftlint** (enforced by CI)
- Follow Swift API design guidelines

## Error Handling Pattern

```objc
NSError *error = nil;
BOOL success = [self performOperation:&error];
if (!success) {
[SentryLog logWithMessage:[NSString stringWithFormat:@"Operation failed: %@", error]
andLevel:kSentryLevelError];
return fallback;
}
```

## Native Bridge Pattern (Objective-C)

Catch everything at the boundary and reject โ€” never let an exception reach the app. The reject error code is the shared `@"SentryReactNative"`, not a per-method code:

```objc
RCT_EXPORT_METHOD(nativeOperation:(NSString *)param
resolver:(RCTPromiseResolveBlock)resolve
Expand All @@ -45,11 +37,22 @@ RCT_EXPORT_METHOD(nativeOperation:(NSString *)param
BOOL result = [self performOperation:param];
resolve(@(result));
} @catch (NSException *exception) {
reject(@"OPERATION_FAILED", exception.reason, nil);
reject(@"SentryReactNative", exception.reason, nil);
}
}
```

## Boundaries

**โœ… Always**
- Resolve or reject every exported method โ€” a `Promise` left neither resolved nor rejected hangs the JS caller.
- Catch native exceptions at the bridge โ€” an exception that reaches the app crashes it.
- Gate any user data added to events/breadcrumbs/spans on `sendDefaultPii`.

**๐Ÿšซ Never**
- Reach for `PrivateSentrySDKOnly` from new code โ€” route hybrid-SDK access through `RNSentryInternal` (see below).
- Bump the bundled sentry-cocoa version by hand โ€” go through `scripts/update-cocoa.sh`.

## Working with Local sentry-cocoa

1. Build sentry-cocoa: `cd sentry-cocoa && make init`
Expand Down
8 changes: 6 additions & 2 deletions samples/expo/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# samples/expo โ€” Expo Sample App

The test bed for the SDK under Expo (config plugin, Metro integration, EAS). Use it to verify a change behaves in an Expo-managed app, not just a bare RN one.

## Running

```bash
yarn start
yarn start # Start the dev server (expo start)
yarn ios # Build & run the iOS dev client (expo run:ios)
yarn android # Build & run the Android dev client (expo run:android)
```

Follow the Expo CLI prompts to open on iOS simulator, Android emulator, or a physical device.
`yarn start` then follows the Expo CLI prompts to open on an iOS simulator, Android emulator, or a physical device. Because the SDK ships native code, plain Expo Go isn't enough โ€” the `run:*` scripts build a dev client that includes it.
20 changes: 20 additions & 0 deletions samples/react-native/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# samples/react-native โ€” React Native Sample App

The end-to-end test bed for the SDK on a bare RN app. Use it to reproduce and verify a change on real devices/simulators, on **both** architectures.

## Running

```bash
Expand All @@ -8,6 +10,24 @@ yarn ios # Run iOS app (separate terminal)
yarn android # Run Android app (separate terminal)
```

## iOS: pod install build matrix

The iOS build varies on three axes, and there's a `yarn` script per combination. Install pods through one of these rather than a bare `pod install` โ€” each exports the env the Podfile and `pod update` read (`USE_FRAMEWORKS`, `ENABLE_PROD`, `ENABLE_NEW_ARCH`):

```
yarn pod-install-<debug|release>-<static|dynamic>[-legacy]
```

- **debug / release** โ†’ `ENABLE_PROD` (0/1)
- **static / dynamic** โ†’ `USE_FRAMEWORKS` framework linkage
- **New Arch (default) / `-legacy`** โ†’ `ENABLE_NEW_ARCH` (1/0)

e.g. `yarn pod-install-debug-static` (New Arch, static frameworks) or `yarn pod-install-release-dynamic-legacy` (Old Arch, dynamic frameworks). A native change is only verified once it runs across the arch and linkage combinations it can affect.

## Android: architecture toggle

Set `newArchEnabled` (`true`/`false`) in `android/gradle.properties`, then rebuild.

## Troubleshooting

**General build failures:**
Expand Down
Loading