Skip to content

feat: add OS notifications for completed/failed tasks#976

Open
yehyal wants to merge 19 commits intopingdotgg:mainfrom
yehyal:feat/notifications
Open

feat: add OS notifications for completed/failed tasks#976
yehyal wants to merge 19 commits intopingdotgg:mainfrom
yehyal:feat/notifications

Conversation

@yehyal
Copy link
Copy Markdown

@yehyal yehyal commented Mar 12, 2026

Summary

Adds OS notifications when a task completes or fails, with a user-facing toggle and a settings test button.

Why

Addresses issue
Notifications are important for backgrounded work. This keeps users in the loop without requiring the app to stay focused.

What Changed

  • Added notification levels (off, important, normal, verbose) to control when OS alerts fire.
  • Emit OS notifications for:
    • Important: approval required, user input required, task failed
    • Normal: important + task completed
    • Verbose: normal + task activity updates (task.started, task.progress)
  • Keep completion notifications separate from activity notifications to avoid duplicates.
  • Add the Settings test notification button.
  • Add/extend unit tests around notification helpers.

Levels are easy to extend by adding new activity kinds or mapping logic in nativeNotifications.ts.

Screenshots / Video

  • settings page
Screenshot 2026-03-16 at 17 17 18
  • Demo video (notification firing):
t3code-preview-notification.mp4

Notes

  • Notifications are only sent when the app is in the background and the toggle is enabled.

Note

Add OS notifications for completed and failed tasks

  • Adds a NotificationLevel setting (Off, Important, Normal, Verbose) to client settings, configurable in the General settings panel with permission request and test notification support.
  • Implements notification logic in nativeNotifications.ts: detects app backgrounding, checks/requests browser permission, and resolves turn completion and attention notification payloads with deduplication.
  • Hooks notification dispatch into the event loop in __root.tsx, emitting OS notifications for task failures (Important+), completions (Normal+), approval/input requests (Important+), and progress (Verbose), only when the app is backgrounded.
  • Migrates legacy localStorage settings to server/client storage on the first server welcome event via migrateLocalSettingsToServer.

Macroscope summarized 25bcce0.


Note

Medium Risk
Adds new background notification behavior triggered from the orchestration event loop and introduces a new persisted client setting plus a one-shot settings migration; mistakes could cause noisy/duplicate notifications or missed alerts.

Overview
Adds OS/native notifications for orchestration events when the app is backgrounded, driven by a new notificationLevel client setting (off/important/normal/verbose) that gates which task completions, failures, and activity updates generate alerts.

Introduces nativeNotifications helpers (permission checks, background detection, notification payload resolution + de-dupe) with comprehensive unit tests, wires dispatch into __root.tsx event batching/snapshot recovery, and extends the General settings panel to manage permission and send a test notification. Also adds a one-time migration to move legacy localStorage settings into the new server/client settings stores on welcome.

Reviewed by Cursor Bugbot for commit 25bcce0. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 12, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d3be0e05-a598-4897-acec-499bcd369678

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the vouch:unvouched PR author is not yet trusted in the VOUCHED list. label Mar 12, 2026
@yehyal yehyal marked this pull request as ready for review March 12, 2026 15:37
Comment thread apps/web/src/routes/_chat.settings.tsx Outdated
@github-actions github-actions Bot added the size:L 100-499 changed lines (additions + deletions). label Mar 12, 2026
@yehyal yehyal requested a review from juliusmarminge March 12, 2026 20:16
Comment thread apps/web/src/routes/__root.tsx Outdated
const previous = lastSessionByThreadRef.current.get(thread.id);

// A completed/failed turn transitions from running with an activeTurnId
// to a session with no active turn and status ready/error.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also notify on input/approval requested?

also maybe have the setting be more configurable than a boolean flag so users can set more granular levels of when they wanna be notified

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to push out a mvp first for just task status notification, but I can definitely work on adding it for input/approval

can you give me a bit more info regarding fine tuning the notifications? some example scenarios / levels that you want to add

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which style do you prefer

image

Codex App current style:
image

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will proceed with the first style, to match the current option styling like with the theme

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verbose Level Preview

Screenshot 2026-03-16 at 16 57 30

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Mar 16, 2026
@yehyal yehyal requested a review from juliusmarminge March 16, 2026 16:14
@Mahendradeokar
Copy link
Copy Markdown

@juliusmarminge, I also want this feature in T3code. Very useful.

I believe all the requested changes have been made by @yehyal. If anything else is needed, let me know and I’ll update it.

I really want this feature in T3code!

Cc: @yehyal

@AashishSinghal
Copy link
Copy Markdown

AashishSinghal commented Apr 1, 2026

Was using a similar but minimal version on my local, this seems like a good extended version of the same to have. I would love to have this in as well.

@julian-gargicevich
Copy link
Copy Markdown

I'd love to see this merged!

@juliusmarminge
Copy link
Copy Markdown
Member

I will get this in. Just have more important stuff right now. But i have not forgotten about it!

@yehyal
Copy link
Copy Markdown
Author

yehyal commented Apr 2, 2026

I'll work on resolving conflicts in mean time

@luisKisters
Copy link
Copy Markdown

Hey, is there any way I could help to bring this forward? I really want this feature in t3code

@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels May 2, 2026
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 2, 2026

Approvability

Verdict: Needs human review

2 blocking correctness issues found. New feature adding OS notifications with ~1200 lines of new code introducing notification infrastructure, settings UI, and orchestration event handling. Multiple critical unresolved review comments identify bugs: undefined functions (fallbackToSnapshotRecovery, OLD_SETTINGS_KEY) that will cause runtime errors, and the notification pipeline being flagged as non-functional dead code.

You can customize Macroscope's approvability policy. Learn more.

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels May 2, 2026
Comment thread packages/contracts/src/settings.ts Outdated
Comment thread packages/contracts/src/settings.ts Outdated
Comment thread apps/web/src/routes/__root.tsx
const events = await api.orchestration.replayEvents(recovery.getState().latestSequence);
if (!disposed) {
applyEventBatch(events);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical routes/__root.tsx:560

fallbackToSnapshotRecovery() is called at line 563 but is never defined in scope, so replay recovery failures throw a ReferenceError instead of falling back to snapshot recovery. Consider defining the function or replacing the call with runSnapshotRecovery("replay-failed").

Also found in 1 other location(s)

apps/web/src/hooks/useSettings.ts:298

OLD_SETTINGS_KEY is referenced on line 298 and 326 but is not defined anywhere in the visible file. This will cause a ReferenceError when migrateLocalSettingsToServer() is called.

🤖 Copy this AI Prompt to have your agent fix this:
In file apps/web/src/routes/__root.tsx around line 560:

`fallbackToSnapshotRecovery()` is called at line 563 but is never defined in scope, so replay recovery failures throw a `ReferenceError` instead of falling back to snapshot recovery. Consider defining the function or replacing the call with `runSnapshotRecovery("replay-failed")`.

Evidence trail:
apps/web/src/routes/__root.tsx lines 551-572 (viewed at REVIEWED_COMMIT): `recoverFromSequenceGap` catch block at line 563 calls `void fallbackToSnapshotRecovery()`. `runSnapshotRecovery` is defined at line 572 with parameter `reason: "bootstrap" | "replay-failed"`. git_grep for `fallbackToSnapshotRecovery` in apps/web/src/routes/__root.tsx returns only the single call at line 563 — no definition exists.

Also found in 1 other location(s):
- apps/web/src/hooks/useSettings.ts:298 -- `OLD_SETTINGS_KEY` is referenced on line 298 and 326 but is not defined anywhere in the visible file. This will cause a `ReferenceError` when `migrateLocalSettingsToServer()` is called.

const reconcileSnapshotDerivedState = () => {
const threads = useStore.getState().threads;
const projects = useStore.getState().projects;
syncProjects(projects.map((project) => ({ id: project.id, cwd: project.cwd })));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High routes/__root.tsx:447

syncProjects is called with { id, cwd } objects, but syncProjects in apps/web/src/uiStateStore.ts reads project.key and project.logicalKey. Since id and key are different property names, project.key is always undefined, which corrupts the currentProjectCwdById map and breaks project ordering logic that depends on stable keys.

Suggested change
syncProjects(projects.map((project) => ({ id: project.id, cwd: project.cwd })));
syncProjects(projects.map((project) => ({ key: project.id, cwd: project.cwd })));
🤖 Copy this AI Prompt to have your agent fix this:
In file apps/web/src/routes/__root.tsx around line 447:

`syncProjects` is called with `{ id, cwd }` objects, but `syncProjects` in `apps/web/src/uiStateStore.ts` reads `project.key` and `project.logicalKey`. Since `id` and `key` are different property names, `project.key` is always `undefined`, which corrupts the `currentProjectCwdById` map and breaks project ordering logic that depends on stable keys.

Evidence trail:
apps/web/src/routes/__root.tsx:447 — syncProjects called with `{ id: project.id, cwd: project.cwd }`
apps/web/src/routes/__root.tsx:506 — same pattern
apps/web/src/uiStateStore.ts:37-43 — `SyncProjectInput` interface requires `key`, `logicalKey`, `cwd`
apps/web/src/uiStateStore.ts:240-242 — `syncProjects` reads `project.key` and `project.logicalKey`

Comment thread apps/web/src/routes/__root.tsx
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 004aa02. Configure here.

Comment thread apps/web/src/routes/__root.tsx
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

@yehyal is attempting to deploy a commit to the Ping Labs Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants