fix: suppress notification spam on app re-open#623
Merged
Conversation
- Add background_task notification category (default ON) so users can toggle off background-task pings via Settings → Notifications - Route notify-user builtin through notifyIfEnabled gate so the category toggle takes effect - Add 60s startup grace period: background-task notifications fired within 60s of launch are suppressed, killing the reopen flood where all queued agents complete at once - Suppress new_email notifications for emails older than 5 min so Gmail's startup backlog replay doesn't surface day-old mail Fixes both issues reported by Ramnique. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Background task runs were triggering "Response ready / Your agent finished responding" on every completion. Skip the automatic chat_completion notification when finalState.runUseCase === 'background_task_agent' — background tasks notify explicitly via notify-user when they have something worth surfacing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- runtime.ts: also skip chat_completion ping for knowledge_sync useCase (agent_notes_agent was opening notes view on click) - sync_gmail.ts: new_email notification now links to specific email thread (rowboat://open?type=email&threadId=...) - App.tsx: add email case to parseDeepLink, parse threadId param, wire threadId through applyViewState, update viewStatesEqual Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per team clarification, two background types are handled differently:
- knowledge_sync (auto knowledge-graph generation): never notifies;
skips the generic chat_completion ping entirely.
- background_task_agent (user-configured agents): notifies via its
own notify-user path, gated behind the toggleable "Background
agents" category, deep-linking to the background-tasks page.
- runtime.ts: skip the generic chat_completion completion ping for
both knowledge_sync and background_task_agent (the latter notifies
via notify-user, so the generic ping would duplicate it).
- builtin-tools.ts: notify-user branches on getCurrentUseCase() —
background agents route through notifyIfEnabled('background_task')
with a bg-tasks deeplink default; chat agents notify directly.
- App.tsx: add the bg-tasks deeplink target (ViewState, parseDeepLink,
applyViewState, currentViewState).
- settings-dialog.tsx: rename the category label to "Background agents".
- runner.ts: wrap the background-task run in withUseCase so tools see
the correct use-case context.
Code-mode status-tracker was calling notificationService.notify() directly, bypassing the user's notification-category toggles. Routed both calls through notifyIfEnabled() with correct categories: - needs-you state → agent_permission - idle after 30s → chat_completion Removed now-redundant container/INotificationService plumbing.
…n notify-user AsyncLocalStorage does not propagate across the background-task agent's async generator — getCurrentUseCase() returns undefined inside notify-user, causing the background_task_agent branch to be skipped and the Background agents toggle to be ignored. Fix: load persisted useCase from run record via fetchRun(ctx.runId) when ALS is falsy. Lazy dynamic import() avoids the known module-init cycle. Background-agent notifications now correctly respect the toggle and only fire when the app is in the background, with deep link to the bg-tasks page.
# Conflicts: # apps/x/apps/main/src/main.ts # apps/x/apps/renderer/src/App.tsx # apps/x/packages/core/src/background-tasks/runner.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix: background agent notifications bypass toggle and fire when focused
What changed
The
notify-usertool was callingnotificationService.notify()directly for background-agent notifications, bypassing the user's Background agents toggle in Settings and ignoring theonlyWhenBackgroundrule.Why it happened
All notification toggles are enforced by one function —
notifyIfEnabled(). Thenotify-usertool detects background agents by readinggetCurrentUseCase()viaAsyncLocalStorage. But ALS does not propagate across the runner's async generator —withUseCase()only wraps the trigger (createMessage), not the actual agent execution loop. So by the timenotify-userfires,getCurrentUseCase()returnsundefined, thebackground_task_agentbranch is skipped, and it falls through to a directservice.notify()— toggle ignored,onlyWhenBackgroundignored.The fix
When
getCurrentUseCase()returns falsy butctx.runIdis present, load the persisteduseCasefrom the run record viafetchRun(ctx.runId). The run'suseCaseis written at creation time and isn't subject to ALS propagation. A lazyimport()avoids the known module-init cycle (builtin-tools → runs/runs → agents/runtime → builtin-tools).Background-agent notifications now correctly:
onlyWhenBackground: true)Files affected
apps/x/packages/core/src/application/lib/builtin-tools.ts—notify-userALS fallback viafetchRun(ctx.runId)apps/x/packages/core/src/agents/runtime.ts— removed leftover diagnostic logAlso included:
status-tracker.tshad the same class of bug — coding-session events (needs-you,idle) calledservice.notify()directly. Routed throughnotifyIfEnabled()(agent_permission/chat_completion). Note: this path is not yet manually tested end-to-end.How to test (background agents — Arjun's spec)
cd ~/Desktop/rowboat/apps/x && npm run deps && npm run dev