code-guidelines
Skill878 starsChanged 32 days agoMITView on GitHub
Enforce Sentry Dart/Flutter SDK code guidelines for implementation, refactoring, and review. Use when implementing features, adding new functionality, refactoring code, reviewing code, designing APIs, modifying public API surface, handling breaking changes, deprecating APIs, writing integrations, or making architecture decisions in any package in this Melos monorepo.
4 other projects use a version of this.
Adopted by
Most recently taken up by
- lamprism/code-guidelines-skilltheir own version, first seen Nov 5, 2026
- jjenzz/agent-skillstheir own version, first seen Nov 1, 2026
- getsentry/sentry-react-nativetheir own version, first seen Sep 2, 2026
- mojianpo/skillstheir own version, first seen Aug 22, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- getsentry/sentry-react-native★ 1.8ksame name
- jjenzz/agent-skills★ 6same name
- mojianpo/skills★ 2same name
- lamprism/code-guidelines-skill★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- packages/dart/AGENTS.mdAGENTS.md
- packages/flutter/AGENTS.mdAGENTS.md
- design-firstSkill
- diagnosing-bugsSkill
- reviewSkill
- specSkill
- test-guidelinesSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. 0 are common, 4 are distinctive, and 9 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Use only language features available in the Dart/Flutter versions specified in AGENTS.md.
- Distinctive: line 18
Check feature flags and prerequisites early, log and return if disabled
- Very specific: line 30
Use named constants from SentryFeatures (packages/dart/lib/src/constants.dart, @internal) — never inline string literals — so the analytics …
- Very specific: line 36
Use internalLogger for all diagnostic logging.
- Very specific: line 69
Never collect Personally Identifiable Information (PII) without checking options.sendDefaultPii
- Distinctive: line 75
Prefer deprecation with migration path over immediate removal
- Very specific: line 95
Prefer modern Dart (3.5+) where it improves clarity — sealed classes for exhaustive matching, records for multi-value returns, pattern …
- Very specific: line 101
Private by default: Keep declarations private.
- Very specific: line 102
Control extension with class modifiers: Use final / base / interface / sealed to declare whether a public class may be extended or …
- Very specific: line 105
Keep imports inside
lib: Never let an import cross the lib boundary (../lib/..., or into another package's src/) — relative imports that … - Distinctive: line 112
Prefer self-documenting code — clear names and structure so comments become unnecessary.
- Very specific: line 126
Document a getter *or* its setter, never both — dart doc merges the pair and discards the setter's comment.
- Very specific: line 128
Put doc comments *before* annotations (@override, @internal).
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Apply these guidelines to all new and modified code across every package in this monorepo. Existing code may not follow these conventions — do not refactor it unless asked.
Use only language features available in the Dart/Flutter versions specified in AGENTS.md.
For non-trivial work — a new feature or integration, a public barrel-file change, or a cross-package/native-interop change — load the design-first skill to shape the modules and seams before writing code. When writing or modifying tests as part of implementation, also load the test-guidelines skill.
SDK Development Rules
Integrations
Encapsulate SDK features as Integration classes that implement call() and close():
- Check feature flags and prerequisites early, log and return if disabled
- Mark the integration as active for usage tracking — see Usage Tracking below
- Clean up resources in
close()if needed - See
packages/flutter/lib/src/replay/andview_hierarchy/for examples - Integrations should be order-independent; if yours requires running before/after another, reconsider the design
Usage Tracking
Record which integrations and features an app actually uses, so usage can be tracked internally. This metadata lives on options.sdk and is serialized onto events as sdk.integrations / sdk.features.
options.sdk.addIntegration('IntegrationName')— mark an integration as active. Call it from the integration'scall(). Do not confuse it withoptions.addIntegration(integration), which registers an integration to run —options.sdk.addIntegrationonly attaches the name as metadata.options.sdk.addFeature(SentryFeatures.x)— mark a feature as used, gated on whether it is actually configured (e.g. abeforeSend*callback is set, a privacy option is enabled).- Use named constants from
SentryFeatures(packages/dart/lib/src/constants.dart,@internal) — never inline string literals — so the analytics vocabulary stays consistent. Add a constant there when introducing a new feature. - Both calls dedupe, so calling them more than once is safe.
- Canonical example:
TrackBeforeSendUsageIntegration(packages/dart/lib/src/track_before_send_usage_integration.dart).
Logging
Use internalLogger for all diagnostic logging. options.log is deprecated — migrate any options.log calls you encounter to internalLogger.
Each package must have its own internalLogger instance. If one doesn't exist, create lib/src/internal_logger.dart:
import 'package:meta/meta.dart';
import 'package:sentry/sentry.dart';
/// Logger for the Sentry <Package> SDK.
@internal
const internalLogger = SentryInternalLogger('sentry_<package>');Log levels:
| Level | Use for |
debug | Routine lifecycle events, configuration confirmations, verbose tracing |
info | Notable but expected events (parsing results, fallback paths taken) |
warning | Recoverable problems (rate limits hit, missing optional config, degraded functionality) |
error | Failures that affect SDK behavior (transport errors, parsing failures) |
fatal | Unrecoverable errors requiring SDK shutdown |
Lazy evaluation — use a closure when the message involves expensive computation:
internalLogger.debug(() => 'Envelope size: ${envelope.computeSize()}');Logs are debug-only — all logging is tree-shaken in release builds via RuntimeChecker.kDebugMode.
Privacy
- Never collect Personally Identifiable Information (PII) without checking
options.sendDefaultPii - Flag any changes that could leak PII for review
Breaking Changes
- Signal breaking changes clearly (API removals, behavior changes, renamed options)
- Prefer deprecation with migration path over immediate removal
Native Code (JNI/FFI)
- Release all native memory (JNI local refs, malloc allocations)
- Handle native exceptions gracefully—don't crash the host app
File Organization
Group by feature, not by type. A processor or integration a feature owns lives in that feature's dir (a replay processor in replay/); a cross-cutting one earns its own top-level concept dir (exception/, enricher/). Cohesive subsystems already do this — transport/, telemetry/span/, and native/ (the binding boundary to the platform SDKs; features call it rather than embed native code). Native interop is special for testing and memory, not for placement — see design-first and the Native Code (JNI/FFI) rules above.
Two shapes are scatter — grow neither, and don't read the repo's current use of them as the target:
- Type-buckets (
event_processor/,integrations/) collect classes for sharing a base type. A bucket legitimately holds only its runner (run_event_processors.dart); the base contract belongs atsrc/root (event_processor.dart, besideintegration.dart). Keep enrichment, exceptions, and dedup in their feature homes, and keep screenshot/replay processors beside their features. - The loose
src/root. Core primitives (hub.dart,scope.dart,sentry_client.dart, thesentry.dartbarrel) belong there; feature code does not. Both transaction and streaming tracing implementations live undertelemetry/span/, alongside shared sampling, propagation, and instrumentation.
Where a given piece goes is a locality judgment — see design-first (Shape the modules).
Modern Dart
Prefer modern Dart (3.5+) where it improves clarity — sealed classes for exhaustive matching, records for multi-value returns, pattern matching and switch expressions, extension types for zero-cost wrappers, enhanced enums, and class modifiers (final / base / interface). Don't force them where plain code reads better.
API & Dart Style
Shape the public surface deliberately — see design-first for module shape. These habits matter more in an SDK than in app code, and several are easy to get wrong:
- Private by default. Keep declarations private; widen to public only when a type is genuinely part of the SDK's API. Every public symbol is a maintenance burden and a breaking-change liability — see
packages/dart/AGENTS.mdon the barrel-file cascade. - Control extension with class modifiers. Use
final/base/interface/sealedto declare whether a public class may be extended or implemented — without them every public class is implicitly both, and you can't evolve it without breaking consumers. - No public
late finalfield without an initializer. It silently defines a public setter, leaking API surface — use a normal field or an explicit getter instead. - Prefer a function to a one-member abstract class, and avoid classes of only static members.
- Keep imports inside
lib. Never let an import cross thelibboundary (../lib/..., or into another package'ssrc/) — relative imports that escapelibcreate duplicate library instances Dart treats as unrelated. - Re-raise with
rethrow, neverthrow e.throw eresets the stack trace to the rethrow site;rethrowpreserves the origin — and stack-trace fidelity is the product.
For everything else — naming, asynchrony, nullability, parameters, equality — follow Effective Dart; a frontier model and dart analyze already apply most of it, so it isn't restated here. The full checklist (and the standard the review skill cites) is in references/effective-dart.md.
Documentation Comments
Prefer self-documenting code — clear names and structure so comments become unnecessary.
Comment when:
- Public APIs — document for users who can't see the implementation.
- Non-obvious why — reasoning not clear from the code (workarounds, edge cases, constraints).
Don't comment when:
- Obvious behavior — don't describe what the code plainly does.
- Inline play-by-play — don't narrate every step of a method.
dart doc gotchas (tooling behavior, not taste):
- Document a getter or its setter, never both —
dart docmerges the pair and discards the setter's comment. - The first sentence becomes the summary in API listings — keep it standalone in its own paragraph.
- Put doc comments before annotations (
@override,@internal); placed after,dart docwon't associate them with the declaration.
Remaining doc-comment style (///, [bracket] references) is standard Effective Dart — see references/effective-dart.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

