feat: add SubagentStop → Discord notification via n8n (#4) #5

Merged
cal merged 1 commits from ai/claude-home-4 into main 2026-03-09 14:31:21 +00:00
Owner

Summary

Implements the SubagentStop → Discord notification pipeline described in #4.

  • .claude/settings.json — adds SubagentStop HTTP hook pointing at http://localhost:5678/webhook/claude-agent-done (async)
  • productivity/n8n/workflows/claude-agent-done.json — importable n8n workflow: webhook trigger → JS code node (extract agent name) → HTTP Request to Discord
  • productivity/n8n/workflows/claude-agent-notifications.md — full setup guide: Discord webhook creation, n8n variable config, test curl, payload reference, future extension notes
  • productivity/n8n/CONTEXT.md — added workflow entry under Active Workflows
  • productivity/n8n/workflows/README.md — added workflow entry under Available Workflows

Key design decisions

  • Discord webhook URL stored as n8n variable DISCORD_CLAUDE_ALERTS_WEBHOOK (not in any config file)
  • Agent name resolved from subagent_name field, falling back to first 8 chars of session_id
  • Hook is async: true so it never blocks the agent's exit

Setup steps after merge

  1. Import claude-agent-done.json into n8n and activate it
  2. Create Discord webhook in your target channel
  3. Add n8n variable DISCORD_CLAUDE_ALERTS_WEBHOOK with the Discord URL
  4. Update the hook URL in .claude/settings.json if n8n is not on localhost (e.g. http://10.10.0.210:5678/webhook/claude-agent-done)

Test

curl -X POST http://10.10.0.210:5678/webhook-test/claude-agent-done \
  -H "Content-Type: application/json" \
  -d '{"hook_event_name": "SubagentStop", "session_id": "abc12345", "subagent_name": "retrosheet-card-update"}'
## Summary Implements the SubagentStop → Discord notification pipeline described in #4. - **`.claude/settings.json`** — adds `SubagentStop` HTTP hook pointing at `http://localhost:5678/webhook/claude-agent-done` (async) - **`productivity/n8n/workflows/claude-agent-done.json`** — importable n8n workflow: webhook trigger → JS code node (extract agent name) → HTTP Request to Discord - **`productivity/n8n/workflows/claude-agent-notifications.md`** — full setup guide: Discord webhook creation, n8n variable config, test curl, payload reference, future extension notes - **`productivity/n8n/CONTEXT.md`** — added workflow entry under Active Workflows - **`productivity/n8n/workflows/README.md`** — added workflow entry under Available Workflows ## Key design decisions - Discord webhook URL stored as n8n variable `DISCORD_CLAUDE_ALERTS_WEBHOOK` (not in any config file) - Agent name resolved from `subagent_name` field, falling back to first 8 chars of `session_id` - Hook is `async: true` so it never blocks the agent's exit ## Setup steps after merge 1. Import `claude-agent-done.json` into n8n and activate it 2. Create Discord webhook in your target channel 3. Add n8n variable `DISCORD_CLAUDE_ALERTS_WEBHOOK` with the Discord URL 4. Update the hook URL in `.claude/settings.json` if n8n is not on localhost (e.g. `http://10.10.0.210:5678/webhook/claude-agent-done`) ## Test ```bash curl -X POST http://10.10.0.210:5678/webhook-test/claude-agent-done \ -H "Content-Type: application/json" \ -d '{"hook_event_name": "SubagentStop", "session_id": "abc12345", "subagent_name": "retrosheet-card-update"}' ```
cal added 1 commit 2026-03-04 06:34:38 +00:00
- Add SubagentStop HTTP hook to .claude/settings.json pointing at n8n
- Add importable n8n workflow (claude-agent-done.json): webhook trigger →
  extract agent name → POST to Discord
- Add setup guide (claude-agent-notifications.md) with payload reference,
  test curl command, and future extension notes
- Update n8n CONTEXT.md and workflows/README.md with new workflow entry

Discord webhook URL is stored as n8n variable DISCORD_CLAUDE_ALERTS_WEBHOOK
to keep it out of local config files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cal added the
ai-reviewing
label 2026-03-04 06:47:16 +00:00
cal reviewed 2026-03-04 06:48:42 +00:00
cal left a comment
Author
Owner

AI Code Review

Files Reviewed

  • .claude/settings.json (modified)
  • productivity/n8n/workflows/claude-agent-done.json (added)
  • productivity/n8n/workflows/claude-agent-notifications.md (added)
  • productivity/n8n/CONTEXT.md (modified)
  • productivity/n8n/workflows/README.md (modified)

Findings

Correctness

  • n8n workflow node graph is valid: Webhook → Code → HTTP Request, with correct connections wiring matching node names exactly.
  • JS logic in the Code node correctly handles both subagent_name and session_id fallback cases, including the edge case where both are missing (returns 'a subagent').
  • responseMode: "immediatelyReturnWith200" pairs correctly with the async: true hook — Claude Code won't wait for the response.
  • settings.json JSON structure is valid; new hooks key is at the correct level alongside existing keys.

Security

  • No hardcoded secrets. Discord webhook URL is stored as n8n variable DISCORD_CLAUDE_ALERTS_WEBHOOK — correct approach.
  • The n8n webhook endpoint has no token validation, so anything on the homelab network can trigger a Discord notification. Given this is a low-risk notification with no destructive downstream action, this is acceptable.

Style & Conventions

  • Documentation follows the established pattern set by the Ko-fi workflow: architecture diagram, setup steps, payload reference, cURL test command, future extensions, change log.
  • CONTEXT.md and README.md entries mirror the Ko-fi section structure exactly — consistent.
  • No unnecessary abstractions; the workflow is intentionally minimal.

Suggestions

  • settings.json URL mismatch: The committed hook URL is http://localhost:5678/webhook/claude-agent-done, but per CONTEXT.md, n8n lives at 10.10.0.210:5678. This won't fire on the actual system until manually updated after merge. The PR body documents this (step 4), but committing the real IP directly would eliminate that manual step since it's already public in CONTEXT.md and README.md.
  • The n8n HTTP Request node uses JSON.stringify({ content: $json.content }) as the JSON body expression. A plain object expression ={{ { "content": $json.content } }} is more idiomatic in n8n. Both produce the same result, but the simpler form is less likely to confuse future editors.

Verdict: APPROVED

Clean, minimal implementation. Secret handling is correct (n8n variable, nothing in config files), the async hook design is sound, the workflow logic handles all documented edge cases, and the documentation is thorough. The localhost URL is the only real gotcha but it's acknowledged in the PR — safe to merge.


Automated review by Claude PR Reviewer

## AI Code Review ### Files Reviewed - `.claude/settings.json` (modified) - `productivity/n8n/workflows/claude-agent-done.json` (added) - `productivity/n8n/workflows/claude-agent-notifications.md` (added) - `productivity/n8n/CONTEXT.md` (modified) - `productivity/n8n/workflows/README.md` (modified) ### Findings #### Correctness - n8n workflow node graph is valid: Webhook → Code → HTTP Request, with correct `connections` wiring matching node names exactly. - JS logic in the Code node correctly handles both `subagent_name` and `session_id` fallback cases, including the edge case where both are missing (returns `'a subagent'`). - `responseMode: "immediatelyReturnWith200"` pairs correctly with the `async: true` hook — Claude Code won't wait for the response. - `settings.json` JSON structure is valid; new `hooks` key is at the correct level alongside existing keys. #### Security - No hardcoded secrets. Discord webhook URL is stored as n8n variable `DISCORD_CLAUDE_ALERTS_WEBHOOK` — correct approach. - The n8n webhook endpoint has no token validation, so anything on the homelab network can trigger a Discord notification. Given this is a low-risk notification with no destructive downstream action, this is acceptable. #### Style & Conventions - Documentation follows the established pattern set by the Ko-fi workflow: architecture diagram, setup steps, payload reference, cURL test command, future extensions, change log. - CONTEXT.md and README.md entries mirror the Ko-fi section structure exactly — consistent. - No unnecessary abstractions; the workflow is intentionally minimal. #### Suggestions - **`settings.json` URL mismatch:** The committed hook URL is `http://localhost:5678/webhook/claude-agent-done`, but per CONTEXT.md, n8n lives at `10.10.0.210:5678`. This won't fire on the actual system until manually updated after merge. The PR body documents this (step 4), but committing the real IP directly would eliminate that manual step since it's already public in `CONTEXT.md` and `README.md`. - The n8n HTTP Request node uses `JSON.stringify({ content: $json.content })` as the JSON body expression. A plain object expression `={{ { "content": $json.content } }}` is more idiomatic in n8n. Both produce the same result, but the simpler form is less likely to confuse future editors. ### Verdict: APPROVED Clean, minimal implementation. Secret handling is correct (n8n variable, nothing in config files), the async hook design is sound, the workflow logic handles all documented edge cases, and the documentation is thorough. The `localhost` URL is the only real gotcha but it's acknowledged in the PR — safe to merge. --- *Automated review by Claude PR Reviewer*
cal added
ai-reviewed
and removed
ai-reviewing
labels 2026-03-04 06:49:06 +00:00
Author
Owner

I am confused about what problem this solves. What is the point?

I am confused about what problem this solves. What is the point?
cal force-pushed ai/claude-home-4 from 2e08f6a4b8 to 0726d0337b 2026-03-09 14:30:51 +00:00 Compare
cal merged commit 92e169fdb6 into main 2026-03-09 14:31:21 +00:00
cal deleted branch ai/claude-home-4 2026-03-09 14:31:21 +00:00
Sign in to join this conversation.
No description provided.