feat(sentry-monitor): bundle Sentry error monitoring into the fork#4
Conversation
Adds a bundled, default-on (DSN-gated) plugin that forwards every error-bearing OpenClaw lifecycle event to Sentry: model_call_ended, agent_end, after_tool_call, message_sent, subagent_ended, cron_changed, and abnormal session_end, plus node-level uncaught/unhandled rejections. Inactive (safe no-op) until BOON_SENTRY_DSN or plugin-config dsn is set. Vendored from @getboon/openclaw-monitor and adapted for in-fork bundling: ships in core dist, @sentry/node mirrored at root as an internalized bundled-plugin runtime dependency, ignored in both knip bundled-dep lists. Strictly typed: pure per-hook capture builders return a discriminated SentryCapture union; dispatch is typed against a minimal structural client; lifecycle hooks register via the typed api.on(...) API using the real openclaw/plugin-sdk/types so core field changes surface at compile time (no casts). Registered on the bundled typed-hook contract allowlist. Extensive unit tests cover every trigger boundary, dispatch routing, and the register() activation paths. Docs at docs/gateway/sentry-monitor.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
4 issues found across 18 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="extensions/sentry-monitor/src/register.ts">
<violation number="1" location="extensions/sentry-monitor/src/register.ts:42">
P2: Environment and host are conflated into one variable, causing incorrect Sentry environment and host tagging.</violation>
</file>
<file name="extensions/sentry-monitor/package.json">
<violation number="1" location="extensions/sentry-monitor/package.json:1">
P2: Missing `"devDependencies": { "@openclaw/plugin-sdk": "workspace:*" }`. The plugin code imports `definePluginEntry` from `openclaw/plugin-sdk/plugin-entry` (index.ts) and imports from `openclaw/plugin-sdk/plugin-entry` in register.ts. Every other extension that imports from the plugin SDK declares it as a workspace devDependency. Without it, TypeScript may fail to resolve the types in independent workspace resolution or when the package is consumed outside the monorepo workspace context.</violation>
<violation number="2" location="extensions/sentry-monitor/package.json:1">
P2: Missing `"private": true` — this is a bundled plugin shipped inside the core dist (not published independently). Every other internal-only bundled extension (admin-http-rpc, canvas, clickclack, deepgram, elevenlabs, senseaudio, webhooks, etc.) sets `"private": true` in package.json to prevent accidental npm publication. Without it, `npm publish` (or similar tooling) could attempt to publish this workspace package.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
- Register sentry-monitor in the bundled startup-id allowlists
(EXPECTED_BUNDLED_STARTUP_PLUGIN_IDS + empty-config startup) so the
bundled-plugin-metadata contract passes.
- Resolve DSN/environment with `||` so an empty-string config value falls
through to the env var instead of disabling the plugin.
- Validate tracesSampleRate (typeof number) before passing to Sentry.init.
- cron_changed: also capture deliveryStatus="not-delivered" (silently
dropped output), use `||` for the message to avoid a blank Error(""),
and stop shipping the free-form `summary` (content) — metadata only.
- Strengthen tests: handler wiring + dispatch, shutdown flush, empty-DSN
env fallthrough, tracesSampleRate guard, cron not-delivered / no-summary,
dispatch message contexts+extra forwarding.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
- register: separate `hostname` (host tag = real machine) from `environment` (configurable Sentry env) so a custom environment no longer pollutes the host tag. - cron_changed: capture on status="error" even when the error text is missing (the `||` message fallback covers the blank case). - package.json: add `"private": true` (internal bundled plugin, never published) and the `@openclaw/plugin-sdk` workspace devDependency to match every other SDK-importing extension. - tests updated for the run-error-without-text case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
typeof NaN === "number", so the prior guard let NaN through to Sentry.init. Use Number.isFinite (with the typeof check to keep the narrowing) so NaN, Infinity, strings, and missing values all fall back to 0. Covered by a parametrized test (string / NaN / Infinity). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CodeQL and OpenGrep workflows hardcoded `blacksmith-*` runners, which only exist on the upstream org — on the getboon fork those jobs queued forever (and were cancelled by each push), never completing. ci.yml already falls back to GitHub-hosted runners on forks; mirror that for the security workflows by switching to ubuntu-24.04 (and macos-latest for the macOS CodeQL job) so they actually run here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Testbox workflows (ci-check-testbox, ci-build-artifacts-testbox, and the two windows-*-testbox) rely on Blacksmith-proprietary actions (useblacksmith/begin-testbox + run-testbox) and Blacksmith runners that the getboon fork does not have, so the PR-triggered ones queued forever and never completed. They are also redundant on the fork: ci.yml already runs the same build/check steps on GitHub-hosted ubuntu-24.04. None are required checks, reusable workflows, or referenced elsewhere. Remove them on the fork. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Reviewed the full diff (not just the description): clean plugin boundary — no Sentry code in src/**, DSN-gated, errors-only with no prompt/message/tool content. Verified all 5 cubic findings are actually fixed in-tree (private:true, plugin-sdk devDep, host/environment split, cron status==error capture, Number.isFinite NaN guard). Boundary-invariant + bundled-metadata allowlists and knip ignores updated correctly. CI fully green. Good to ship. Non-blocking: smoke-test a live event against a real Sentry project once BOON_SENTRY_DSN is wired.
Summary
Bundles Sentry error monitoring directly into the fork as a default-on, DSN-gated plugin (
extensions/sentry-monitor/), replacing the separately git-installed@getboon/openclaw-monitor. It forwards every error-bearing lifecycle event to Sentry and stays a clean plugin tapping hooks — no Sentry code in coresrc/**.model_call_ended(error),agent_end(fail),after_tool_call(error),message_sent(fail),subagent_ended(error/timeout/killed/reset/deleted),cron_changed(run/delivery error),session_end(unknown), plus node uncaught/unhandled rejections. Errors only; no prompt/message/tool content. Inactive untilBOON_SENTRY_DSNor plugin-configdsnis set.@sentry/node@8.45.0mirrored at root as an internalized bundled-plugin runtime dep (bonjour/@homebridge/ciaopattern), ignored in both knip bundled-dep lists.docs/gateway/sentry-monitor.md(+ nav);plugin: sentry-monitorlabeler entry.Design / typing
SentryCaptureunion; dispatch typed against a minimal structural client.api.on(...)API (per the bundled-plugin contract; file added to the typed-hook allowlist), using the realopenclaw/plugin-sdk/types— so a core field change is a compile error, and there are no casts.Tests
44 unit tests across
format,captures,dispatch,register: every trigger boundary, dispatch routing, and theregister()activation paths (no-DSN inactive; env/config DSN → init + all 7 hooks + flush).Verification
CI on the prior branch (same tree) was green across lint, docs, dependencies, contracts, and bundled-extension checks.
Real behavior proof
Behavior addressed: Sentry error reporting ships with the fork by default (DSN-gated) as a bundled plugin rather than a separate git install.
Real environment tested: local build + unit/type/lint verification; plugin compiles into
dist/extensions/sentry-monitor/and is discovered by the bundled-plugin build pipeline; full CI suite exercised on the identical tree.Exact steps or command run after this patch: the commands above plus
pnpm build; CI checks on the pushed branch.Evidence after fix: 44/44 tests pass; oxlint 0 errors; both tsgo lanes exit 0; clean build; dep audit ok; CI lint/docs/dependencies/contracts/bundled checks green.
Observed result after fix: bundled plugin builds, typechecks, lints, and is wired default-on + DSN-gated.
What was not tested: no live gateway run delivering a real event to a Sentry project (logic covered against a mocked client). Channel connect/disconnect capture is out of scope (needs a new core
channel_connection_changedhook — follow-up).Supersedes #3 (recreated with a single signed commit).
🤖 Generated with Claude Code
Summary by cubic
Bundles Sentry error monitoring as a default-on, DSN-gated plugin, replacing
@getboon/openclaw-monitor. It forwards only error events to Sentry, stays off with no DSN, and improves host vs environment tagging.New Features
extensions/sentry-monitor/using typedapi.on(...)hooks.@sentry/nodebundled; docs atdocs/gateway/sentry-monitor.md. Strictly typed with unit tests; no prompt/message/tool content sent.Bug Fixes
sentry-monitorin bundled startup allowlists; separateshostname(host tag) from Sentryenvironment.dsn/environmentwith||; rejects non-finitetracesSampleRatebeforeSentry.initand defaults to 0.cron_changed: capture onstatus="error"anddeliveryStatus="not-delivered", avoid blank messages, remove free-formsummary.private; adds a workspace devDependency on@openclaw/plugin-sdk.Written for commit 67f96f3. Summary will update on new commits.