From Bug Handler
Use when connecting bug_handler to a delivery backend or enriching its reports - writing a custom Reporter (Sentry, Crashlytics, Slack, first-party HTTP endpoint), a custom ContextProvider (feature/session/cart context), or an EventTransform. Also use when someone tries to use the shipped Sentry/Crashlytics "adapters" (they are empty placeholder files).
How this skill is triggered — by the user, by Claude, or both
Slash command
/bug-handler:extend-pipelineThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Three extension points: `Reporter` (delivery), `ContextProvider` (enrichment),
Three extension points: Reporter (delivery), ContextProvider (enrichment),
EventTransform (reshaping). The shipped
reporters/adapters/{sentry,crashlytics}.dart files are EMPTY placeholders -
never import them; write the reporter in the app.
send(event) returns true iff delivered. Return false ONLY for genuine
delivery failure - false re-queues the event into the durable outbox for
retry on the next flush().isReportable policy,
noise suppression), return TRUE. Returning false for skips makes the outbox
grow forever with events you will never send.event.toMap(). It is the sanitized payload embedded
by the client. Building output from event.context/event.exception fields
directly bypasses every sanitizer - a privacy bug.event.exception is a SerializedException, not the
original subtype. Type checks like event.exception is ValidationException
silently stop matching for replayed events; prefer payload fields
(payload['exception']['type']) when filtering must survive replay.Full working SentryReporter (transport-only Sentry, skip semantics, level
mapping) and LoggerReporter templates: Patterns A and B in
../../references/production-patterns.md. For Sentry, also apply the bootstrap
side of Pattern A (strip OnErrorIntegration so Sentry does not double-capture
what bug_handler already owns).
class CartContextProvider extends ContextProvider with CachedContextProvider {
const CartContextProvider(this.cart);
final CartService cart;
@override
String get name => 'cart'; // key in event context
@override
Duration get cacheDuration => const Duration(seconds: 30);
@override
Future<Map<String, dynamic>> collect() async => {
'items': cart.items.length,
'total': cart.total,
};
}
Rules:
CachedContextProvider, override collect(), NOT getData() (the mixin
owns getData: TTL cache + in-flight dedupe + never-throw).getData() must never throw - return {} on failure..name, DateTime via toIso8601String().manualReportOnly => true for heavy or sensitive data (collected only when
manual: true, i.e. user-initiated reports).validateData; that is fine.baseProviders/additionalProviders, or runtime via
BugReportClient.instance.addContextProvider(...) (dedupes by equality;
lifecycle-bound data like the current user belongs at runtime with
clearContextProviders() on logout).tune-privacy skill if you add any.ReportEvent Function(ReportEvent), applied in order BEFORE sanitization.
Use for tagging/normalizing (e.g., copy metadata['source'] into a context
tag, rewrite devMessages for grouping). Transforms cannot cancel delivery -
that is Policy/Reporter territory. Keep them pure; return e.copyWith(...).
dart analyze + dart format on new files.ReportEvent (or SerializedException-based one via
ReportEvent.fromMap) and assert send() returns true/false per your matrix,
and that skipped events return true.setup-reporting skill; confirm the backend received the sanitized payload
(spot-check that a known-sensitive field arrives masked)."Send our bug_handler reports to Crashlytics" -> new CrashlyticsReporter extends Reporter in the app's reporting module: send maps
event.toMap() into FirebaseCrashlytics.instance.recordError(exception: payload['exception']['devMessage'], reason: ..., information: [...]), returns
false only on thrown delivery errors; registered after ConsoleReporter; unit
test with a fabricated event; smoke test confirms masked payload in console.
npx claudepluginhub omar-hanafy/bug_handler --plugin bug-handlerGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Dispatches multiple subagents concurrently for independent tasks without shared state. Use when facing 2+ unrelated failures or subsystems that can be investigated in parallel.