Skip to content

Conversation

@centraldogma99
Copy link

@centraldogma99 centraldogma99 commented Feb 8, 2026

Problem
The system notification message shown when an agent completes execution is hardcoded, making it difficult to identify which project's work has completed when working across multiple projects in parallel.

Solution
Expose the project name and working directory in the notification message, and allow users to freely customize the format through configuration. Additionally, fixed a bug discovered during development where notifications were never actually being sent.

Summary

  • Add message_format config option to customize OS notification messages with {project} (folder name) and {cwd} (full path) template variables
  • Refactor session-notification.ts to comply with 200 LOC rule by extracting platform functions and cleanup logic into separate modules
  • Fix config passthrough bug in index.ts where message_format was not forwarded to the notification hook
  • Fix message.updated bug: notifications were never firing because message.updated with role: "user" (metadata updates) was incorrectly cancelling the idle notification timer ~21ms after session.idle

Changes

New Files

  • src/hooks/session-notification-format.ts — Format resolver with extractProjectName() and resolveMessageFormat() using String.replace()
  • src/hooks/session-notification-format.test.ts — 10 TDD tests covering project name extraction, template variable resolution, edge cases
  • src/hooks/session-notification-platform.ts — Extracted platform detection, notification sending, sound playback, session cleanup
  • src/hooks/session-notification-utils.ts — Moved cleanupOldSessions for better separation of concerns

Modified Files

  • src/config/schema.ts — Added message_format: z.string().optional() to NotificationConfigSchema
  • src/hooks/session-notification.ts — Imports extracted modules, resolves format before sending notification; filters message.updated by role === "assistant" to fix notification bug
  • src/hooks/session-notification.test.ts — Tests for default/custom format, literal strings, assistant vs user role filtering
  • src/index.ts — Passes message_format from plugin config to notification hook

Bug Fix: Notifications Never Firing

Root Cause

After session.idle fires, OpenCode emits a message.updated event (~21ms later) to update the user message's summary metadata. The old code treated all message.updated events as "new agent activity", calling cancelPendingNotification() which cleared the idle notification timer before it could fire.

session.idle  → start 1500ms timer
message.updated (role: "user", summary update) → cancel timer (21ms later!)
→ notification never sent

Fix

Filter message.updated by role — only role === "assistant" marks session activity. This matches the existing pattern in cli/run/events.ts (line 269) and todo-continuation-enforcer.ts (line 450).

// Before: all message.updated cancelled the timer
if (sessionID) { markSessionActivity(sessionID) }

// After: only assistant messages cancel the timer
if (sessionID && role === "assistant") { markSessionActivity(sessionID) }

Usage

// .opencode/oh-my-opencode.json
{
  "notification": {
    "message_format": "{project} — Agent is ready for input"  // default
    // or: "{cwd} — Done!"
    // or: "Build complete"  (literal, no variables)
  }
}

Template Variables

Variable Description Example
{project} Folder name (path.basename) my-app
{cwd} Full working directory path /Users/me/projects/my-app

Unrecognized variables (e.g., {unknown}) pass through as-is — no errors.

Backward Compatibility

  • Default format is "{project} — Agent is ready for input" (em dash U+2014)
  • Without config, behavior is identical to before (project name replaces the old hardcoded message)
  • notification.force_enable continues to work as before

Verification

  • bun run typecheck — zero errors
  • bun run build — succeeds
  • bun test — 15 session-notification tests pass, all project tests pass
  • Manually tested: notification now fires correctly after agent completes work

@github-actions
Copy link
Contributor

github-actions bot commented Feb 8, 2026

All contributors have signed the CLA. Thank you! ✅
Posted by the CLA Assistant Lite bot.

@centraldogma99
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

…idle timer cancellation

message.updated events with role 'user' (metadata updates like summary)
were incorrectly treated as new agent activity, cancelling the idle
notification timer ~21ms after session.idle. Now only role 'assistant'
messages mark session activity, matching the pattern used by
cli/run/events.ts and todo-continuation-enforcer.ts.
…add edge case tests

Move cleanupOldSessions from platform module to utils module for
better separation of concerns. Add tests for empty format string
and missing template variables edge cases.
Replace toBe with exact macOS osascript command strings with
toContain for message content only. Also normalize BDD comment
style from //#given to // given for consistency.
@centraldogma99
Copy link
Author

recheck

@centraldogma99 centraldogma99 marked this pull request as ready for review February 8, 2026 15:40
@centraldogma99 centraldogma99 changed the title feat(session-notification): add message_format config with {project} and {cwd} template variables feat(session-notification): add message_format config and fix idle notification not firing Feb 8, 2026
@centraldogma99 centraldogma99 changed the title feat(session-notification): add message_format config and fix idle notification not firing feat/fix: add system notification message format config and fix idle notification not firing Feb 8, 2026
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 9 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

@JunyeongChoi0
Copy link

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Feb 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants