Skip to content

feat: configurable notifications + webhook (Slack/Discord)#47

Merged
kienbui1995 merged 1 commit intomainfrom
feat/notification-config
Apr 13, 2026
Merged

feat: configurable notifications + webhook (Slack/Discord)#47
kienbui1995 merged 1 commit intomainfrom
feat/notification-config

Conversation

@kienbui1995
Copy link
Copy Markdown
Owner

@kienbui1995 kienbui1995 commented Apr 13, 2026

Notification Config

Setting Type Default Description
notifications bool true Enable/disable bell + desktop notifications
notification_webhook string none URL to POST when turn completes

Webhook payload: {"text": "magic-code: turn complete"} — compatible with Slack incoming webhooks and Discord webhooks.

Config example:

[default]
notifications = false
notification_webhook = "https://hooks.slack.com/services/T.../B.../xxx"

197 tests, 0 warnings.

Summary by CodeRabbit

  • New Features

    • Notifications can be enabled or disabled via configuration.
    • Optional webhook support to send turn-complete events to custom endpoints.
  • Chores

    • Updated CLI dependencies to support async webhook delivery.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds config-backed notifications: RuntimeConfig now has notifications: bool and notification_webhook: Option<String> (defaults set in code). CLI notifications (terminal bell, OS notifications) are only emitted when notifications is true; an optional async POST to a webhook is sent when notification_webhook is Some(URL).

Changes

Cohort / File(s) Summary
Config Types
mc/crates/mc-config/src/types.rs
Added pub notifications: bool and pub notification_webhook: Option<String> to RuntimeConfig; both are initialized to hardcoded defaults (true, None) in from_layers (layers are not read for these fields).
CLI Dependency & Notification Logic
mc/crates/mc-cli/Cargo.toml, mc/crates/mc-cli/src/main.rs
Added reqwest.workspace = true dependency entry. run_tui/end-of-turn logic now checks config.notifications before emitting bell or OS notifications (notify-send on Linux, osascript on macOS). If config.notification_webhook is Some, spawns a Tokio task that POSTs {"text":"magic-code: turn complete"} via reqwest (send result ignored).

Sequence Diagram(s)

sequenceDiagram
  participant TUI as "TUI / run_tui"
  participant Config as "RuntimeConfig"
  participant OS as "OS notifier\n(notify-send / osascript)"
  participant Task as "Tokio task\n(reqwest)"
  participant Webhook as "External Webhook"

  TUI->>Config: read notifications & webhook fields
  alt notifications == true
    TUI->>OS: emit bell / desktop notification
  end
  alt notification_webhook is Some(url)
    TUI->>Task: spawn async POST task(url, payload)
    Task->>Webhook: POST {"text":"magic-code: turn complete"}
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 thump-thump with a nibble of code
Bells wait for a kindly flag,
Webhooks race in a tiny task.
I hop, I post, I softly brag—
Turn complete! —a rabbit's async ask. 🥕🔔

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature being added: configurable notifications with webhook support for Slack/Discord integration.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/notification-config

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
mc/crates/mc-cli/src/main.rs (1)

515-526: Consider logging webhook failures for debuggability.

Webhook errors are silently discarded, which can make troubleshooting difficult if users configure an invalid URL or encounter network issues. A trace-level log would help without being noisy.

♻️ Suggested improvement
                     if let Some(ref url) = config.notification_webhook {
                         let url = url.clone();
                         tokio::spawn(async move {
                             let client = reqwest::Client::new();
-                            let _ = client
+                            if let Err(e) = client
                                 .post(&url)
                                 .json(&serde_json::json!({"text": "magic-code: turn complete"}))
                                 .send()
-                                .await;
+                                .await
+                            {
+                                tracing::debug!("webhook notification failed: {e}");
+                            }
                         });
                     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-cli/src/main.rs` around lines 515 - 526, The webhook POST in the
tokio::spawn block currently discards errors; update the async task that creates
reqwest::Client::new() and calls .post(&url).json(...).send().await to inspect
the Result and log failures at trace level (e.g., via tracing::trace! or
log::trace!), including the error details and a brief context like
"notification_webhook POST failed" and the notification identifier (but avoid
logging sensitive payload); reference config.notification_webhook, the
tokio::spawn async closure, and the .send().await call to locate where to add
the Result handling and trace logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mc/crates/mc-config/src/types.rs`:
- Around line 160-163: The new RuntimeConfig fields notifications and
notification_webhook are never read from TOML because DefaultLayer lacks them
and from_layers hardcodes values; update DefaultLayer to include pub
notifications: Option<bool> and pub notification_webhook: Option<String>, then
in RuntimeConfig::from_layers where layers are iterated (the layer merge loop
inside from_layers) read and merge these fields from each layer (e.g., if
layer.notifications.is_some() set the accumulating value, same for
notification_webhook) and finally use the merged values when constructing Self
in from_layers instead of the hardcoded literals so TOML-provided values
override defaults.

---

Nitpick comments:
In `@mc/crates/mc-cli/src/main.rs`:
- Around line 515-526: The webhook POST in the tokio::spawn block currently
discards errors; update the async task that creates reqwest::Client::new() and
calls .post(&url).json(...).send().await to inspect the Result and log failures
at trace level (e.g., via tracing::trace! or log::trace!), including the error
details and a brief context like "notification_webhook POST failed" and the
notification identifier (but avoid logging sensitive payload); reference
config.notification_webhook, the tokio::spawn async closure, and the
.send().await call to locate where to add the Result handling and trace logging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c67f115-dcd0-4374-b519-92cd7ebecdeb

📥 Commits

Reviewing files that changed from the base of the PR and between a9c2f74 and 03a482a.

⛔ Files ignored due to path filters (1)
  • mc/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • mc/crates/mc-cli/Cargo.toml
  • mc/crates/mc-cli/src/main.rs
  • mc/crates/mc-config/src/types.rs

Comment on lines +160 to +163
/// Enable desktop/bell notifications when agent finishes. Default: true.
pub notifications: bool,
/// Webhook URL to POST when agent completes a turn (Slack/Discord/custom).
pub notification_webhook: Option<String>,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Configuration fields are not read from TOML layers — settings will have no effect.

The notifications and notification_webhook fields are added to RuntimeConfig, but they're hardcoded in from_layers (lines 296-297) without reading from any layer. The DefaultLayer struct is missing these fields, so the TOML config example from the PR description won't work:

[default]
notifications = false  # This will be ignored!
notification_webhook = "https://..."  # This will be ignored!

To fix this:

  1. Add the fields to DefaultLayer with Option<> wrappers
  2. Read and merge them in the from_layers loop
🐛 Proposed fix

Add fields to DefaultLayer:

 pub struct DefaultLayer {
     pub provider: Option<String>,
     pub model: Option<String>,
     pub max_tokens: Option<u32>,
     pub permission_mode: Option<String>,
+    pub notifications: Option<bool>,
+    pub notification_webhook: Option<String>,
     #[serde(default)]
     pub tool_permissions: std::collections::HashMap<String, String>,
 }

Add merging logic in from_layers (inside the layer loop):

+        let mut notifications: Option<bool> = None;
+        let mut notification_webhook: Option<String> = None;
         // ... in the for loop:
+        if let Some(v) = layer.default.notifications {
+            notifications = Some(v);
+        }
+        if let Some(ref v) = layer.default.notification_webhook {
+            notification_webhook = Some(v.clone());
+        }

Then in the Self { ... } block:

-            notifications: true,
-            notification_webhook: None,
+            notifications: notifications.unwrap_or(true),
+            notification_webhook,

Also applies to: 296-297

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-config/src/types.rs` around lines 160 - 163, The new
RuntimeConfig fields notifications and notification_webhook are never read from
TOML because DefaultLayer lacks them and from_layers hardcodes values; update
DefaultLayer to include pub notifications: Option<bool> and pub
notification_webhook: Option<String>, then in RuntimeConfig::from_layers where
layers are iterated (the layer merge loop inside from_layers) read and merge
these fields from each layer (e.g., if layer.notifications.is_some() set the
accumulating value, same for notification_webhook) and finally use the merged
values when constructing Self in from_layers instead of the hardcoded literals
so TOML-provided values override defaults.

- notifications: true/false in config (default: true)
- notification_webhook: optional URL for Slack/Discord/custom
- Bell + desktop notification gated by config
- Webhook POSTs {"text": "magic-code: turn complete"} on each turn

197 tests, 0 warnings.
@kienbui1995 kienbui1995 force-pushed the feat/notification-config branch from 03a482a to cdbaded Compare April 13, 2026 04:04
@kienbui1995 kienbui1995 enabled auto-merge (squash) April 13, 2026 04:04
@kienbui1995 kienbui1995 merged commit 619de6e into main Apr 13, 2026
7 of 8 checks passed
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.

1 participant