| Decide whether and how errors report to Sentry. Use when touching capture or error-handling paths in `web/**`, triaging Sentry noise, or changing Sentry settings.
npx skills add https://github.com/langfuse/langfuse --skill sentry-instrumentation
One idea: an event in Sentry is a promise that a human should act. If
nobody would act on it, do not send it. If you send it, make it legible (a
real Error with a stack — never a string/object/SyntheticEvent) and
routable (an area tag, a message stable enough to group). Sentry is not a
log sink; the server-side observability stack is where firehose logs live.
When adding or changing an error path in web/**, decide explicitly whether it
should reach Sentry — do not captureException (or console.error) reflexively.
Run the decision tree, then say in one line what you chose and why (in the plan
or PR description). The three outcomes:
| The failure is… | Do | Never |
|---|---|---|
| an expected user-facing state — a missing/forbidden resource, expired session, invalid user input, a malformed URL in user content | render the UX (error page / toast / plain text) | capture — it is the product working as designed |
| a transport / offline / infra failure — fetch failed, a 5xx on a poll, an LB blip | let the UI degrade; the server owns this signal | capture client-side — it is an amplified, lower-fidelity copy of a server truth |
| our code failed — an invariant broke, a parse threw, a worker failed to load | captureException a real Error with an area tag via the shared helpers | pass a raw string/object/Event |
console.error is a capture API here. instrumentation-client.ts enables
captureConsoleIntegration({ levels: ["error"] }), so **every console.error
becomes a Sentry event.** Logging an object yields an opaque [object Object]
fingerprint; logging non-actionable info still mints an issue. For
non-actionable logging use console.warn; to report a real failure, capture it
properly (below).
captureException:**
captureUnknownError(context, value, extra?)— turns any caught value into a legible Error (real Errors pass through
with their stack; everything else is synthesized), tags area, and logs via
console.warn so the console integration does not double-capture.
reportParserWorkerError(hook, event)— extracts the real fields from a Worker ErrorEvent (message/filename/lineno)
instead of stringifying it to [object ErrorEvent].
web/src/utils/sentryFilters.ts**
(documented, unit-tested), called from beforeSend in
web/instrumentation-client.ts (the
only Sentry.init in the codebase — beforeSend,
captureConsoleIntegration, denyUrls, replay masking). Add every new filter
as a named predicate there, never as an ad-hoc inline check. beforeSend
now holds NO inline checks — every filter routes through a named predicate
(isNoisyHttpClientPollEvent, isDenylistedNoiseEvent,
isReactDevtoolsInternalEvent). Keep it that way.
handleTrpcError(web/src/utils/api.ts) is the single
chokepoint every query/mutation error flows through — the place to drop
expected codes and tag the rest (the seam-classification lever, PR #15243).
area, keep the message static. `captureException(err, { tags: { area },extra }). Fingerprints group on the message, so put variable IDs in extra`,
never in the message string.
> PR references name the lever that established each pattern. Verify a cited
> symbol or swap against the current tree before relying on it — the code, not
> this doc, is the source of truth.
A NOT_FOUND / FORBIDDEN / UNAUTHORIZED the UI already renders is not a
regression. ⚠ TRPCClientError: Trace not found was the #2 issue by volume
(~30k events); PR #15243 drops those at the tRPC seam and switches the
"Project Not Found" state (which captured on every mount via
ErrorPageWithSentry) to the non-capturing ErrorPage.
Error, never a string / object / SyntheticEvent /ErrorEvent.** Those collapse to opaque [object Object] / `[object
ErrorEvent]` fingerprints with no stack. ⚠ The 5EX cluster (opaque non-Error
captures, PR #15175) and the parse-worker [object ErrorEvent] family (PR
captureUnknownError /reportParserWorkerError.
console.error mints a Sentry event — pick the level deliberately. Useconsole.warn for non-actionable logs (the #15173 pattern); use
captureException for real failures. Never console.error(someObject).
One LB 502 or a poll blip becomes thousands of browser events. ⚠ The 418
HTTP Client Error saga (~44k events → 8/24h after scoping the httpClient
integration, PR #15145) and the next-auth CLIENT_FETCH_ERROR /
Failed to fetch families (denylist, PR #15238). The real outage is visible
server-side; the client copy is noise.
over suppressing the event. ⚠ User-content markdown URLs rendered through a
Next.js <Link> logged Invalid href … passed to next/router (~40k events)
— note getSafeLinkUrl does NOT prevent this: a malformed-but-parseable URL
(a second https:// → repeated //) passes validation and <Link>'s router
still rejects it. PR #15245 renders these as a native <a> (which never runs
the router's href validation), removing the family at the source — no new
filter needed. (The older inline beforeSend invalid-href check — which
never fired anyway, wrong field, Rule 6 — was removed in #15276.)
beforeSend / denylist rule: narrow signature + written rationale +a NEGATIVE fixture proving a real error still passes.** This is the MANDATORY
review gate — for any suppression change, answer "does this rule hide a real
error?" in the PR, and add a test asserting a real 5xx / unknown code / thrown
error is NOT dropped (the sentryFilters.clienttest.ts pattern from #15145 /
captures, benign strings) carry their text on event.message /
event.logentry.message, NOT event.exception.values[0].value — a filter
that only reads the exception value silently never fires on them (the reason
the original invalid-href filter never worked).
extra, or tag. No prompttext, trace content, tokens, share-link secrets, user/session ids. Respect
the replay masking already configured for HIPAA/regions in
instrumentation-client.ts. A message that interpolates user data both leaks
and shatters grouping (Rule 5).
validations run only in the real client runtime, not jsdom — a green unit
test does NOT prove the console error is gone. Reproduce it in a browser
against the running app (Playwright), do an A/B, and confirm the event
disappears. ⚠ PR #15245 was verified this way — its native <a> fired 0
where the prior <Link> fired the error ×12. Unit tests lock the *contract*; the
browser proves the *noise removal*.
transport / our-code — and write the one-line decision. That IS the PR note.
capture). Real → captureException a real Error via the helpers, with an
area tag, static message, structured extra, no PII.
sentryFilters.ts reading theright event field, with a written rationale and a negative fixture (Rule 6).
Prefer root-causing the emission instead (Rule 5).
event removal (Rule 8).
"does this hide a real error?" answer + the negative-fixture test.
state (Rule 1).
captureException(nonError) or console.error(object) → opaque fingerprint(Rules 2, 3).
beforeSend filter with no rationale, no negative fixture, or onethat reads the wrong event field (Rule 6).
(Rules 5, 7).
beforeSend check instead of a named, tested predicate insentryFilters.ts.
— the capture contract in depth: the shared-helper APIs, the beforeSend /
denylist authoring protocol (field-reading, negative fixtures), fingerprinting
and area tagging, the known noise families, and the shipped-PR case studies
(#15145 / #15173 / #15174 / #15175 / #15238 / #15243 / #15245). Read when
authoring a suppression rule, hardening a capture path, or triaging a family.
Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take langfuse/sentry-instrumentation from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.