feat: add SubagentStop → Discord notification via n8n (#4)
- 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>
This commit is contained in:
parent
c08e779e42
commit
0726d0337b
@ -6,5 +6,14 @@
|
||||
"allowed_working_directories": [
|
||||
"/mnt/NV2/Development/claude-home",
|
||||
"/mnt/media"
|
||||
]
|
||||
],
|
||||
"hooks": {
|
||||
"SubagentStop": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "http://localhost:5678/webhook/claude-agent-done",
|
||||
"async": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,6 +275,32 @@ ssh root@10.10.0.210 "docker stats --no-stream n8n n8n-postgres"
|
||||
|
||||
## Active Workflows
|
||||
|
||||
### Claude Agent Done → Discord
|
||||
|
||||
**Purpose:** Discord notification when a Claude Code subagent finishes (for long-running pipelines)
|
||||
|
||||
**Documentation:** `workflows/claude-agent-notifications.md`
|
||||
|
||||
**Workflow Features:**
|
||||
- Receives `SubagentStop` HTTP hook from Claude Code
|
||||
- Extracts agent name from payload (`subagent_name` or `session_id` prefix)
|
||||
- Posts `🏁 Claude agent **{name}** has finished.` to Discord
|
||||
- Discord webhook URL stored as n8n variable (not in local config)
|
||||
|
||||
**Webhook URL:**
|
||||
- Production: `http://10.10.0.210:5678/webhook/claude-agent-done`
|
||||
- Test: `http://10.10.0.210:5678/webhook-test/claude-agent-done`
|
||||
|
||||
**Related Files:**
|
||||
- `workflows/claude-agent-notifications.md` - Setup guide
|
||||
- `workflows/claude-agent-done.json` - Importable n8n workflow
|
||||
- `.claude/settings.json` (repo root) - Claude Code hook config
|
||||
|
||||
**Custom Variables:**
|
||||
- `DISCORD_CLAUDE_ALERTS_WEBHOOK` - Discord webhook URL for the target channel
|
||||
|
||||
---
|
||||
|
||||
### Ko-fi → Paper Dynasty Integration
|
||||
|
||||
**Purpose:** Automated pack distribution when users purchase on Ko-fi
|
||||
|
||||
@ -4,6 +4,27 @@ Collection of production n8n workflows and integration guides.
|
||||
|
||||
## Available Workflows
|
||||
|
||||
### Claude Agent Done → Discord
|
||||
|
||||
**Status:** Production Ready
|
||||
**Purpose:** Discord notification when a Claude Code subagent finishes
|
||||
|
||||
**Quick Links:**
|
||||
- 📖 **[claude-agent-notifications.md](claude-agent-notifications.md)** - Setup guide and payload reference
|
||||
- 📦 **[claude-agent-done.json](claude-agent-done.json)** - Importable n8n workflow
|
||||
|
||||
**Features:**
|
||||
- Triggered by Claude Code's `SubagentStop` HTTP hook
|
||||
- Extracts agent name from the event payload
|
||||
- Posts a completion message to Discord
|
||||
- Discord webhook URL kept in n8n variables (not local config)
|
||||
|
||||
**Webhook URL:**
|
||||
- Test: `http://10.10.0.210:5678/webhook-test/claude-agent-done`
|
||||
- Production: `http://10.10.0.210:5678/webhook/claude-agent-done`
|
||||
|
||||
---
|
||||
|
||||
### Ko-fi → Paper Dynasty Integration
|
||||
|
||||
**Status:** Production Ready
|
||||
|
||||
84
productivity/n8n/workflows/claude-agent-done.json
Normal file
84
productivity/n8n/workflows/claude-agent-done.json
Normal file
@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "Claude Agent Done → Discord",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"path": "claude-agent-done",
|
||||
"responseMode": "immediatelyReturnWith200",
|
||||
"options": {}
|
||||
},
|
||||
"id": "webhook-trigger",
|
||||
"name": "Claude Agent Done",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [0, 0],
|
||||
"webhookId": "claude-agent-done"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const data = $input.first().json;\nconst sessionId = data.session_id || '';\nconst agentName = data.subagent_name || (sessionId ? sessionId.substring(0, 8) : 'a subagent');\nreturn [{\n json: {\n content: `🏁 Claude agent **${agentName}** has finished.`\n }\n}];"
|
||||
},
|
||||
"id": "build-message",
|
||||
"name": "Build Discord Message",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [220, 0]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "={{ $vars.DISCORD_CLAUDE_ALERTS_WEBHOOK }}",
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={{ JSON.stringify({ content: $json.content }) }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "discord-post",
|
||||
"name": "Post to Discord",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [440, 0]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Claude Agent Done": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build Discord Message",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build Discord Message": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Post to Discord",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"staticData": null,
|
||||
"tags": [
|
||||
{
|
||||
"name": "claude-code"
|
||||
},
|
||||
{
|
||||
"name": "notifications"
|
||||
},
|
||||
{
|
||||
"name": "discord"
|
||||
}
|
||||
],
|
||||
"triggerCount": 1,
|
||||
"pinData": {}
|
||||
}
|
||||
105
productivity/n8n/workflows/claude-agent-notifications.md
Normal file
105
productivity/n8n/workflows/claude-agent-notifications.md
Normal file
@ -0,0 +1,105 @@
|
||||
# Claude Agent Done → Discord Notifications
|
||||
|
||||
Notifies a Discord channel via webhook when a Claude Code subagent finishes. Useful for long-running pipelines (10+ minutes) where you want a heads-up when work completes.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Claude Code (SubagentStop hook)
|
||||
│
|
||||
│ POST raw event JSON
|
||||
▼
|
||||
n8n Webhook: /webhook/claude-agent-done
|
||||
│
|
||||
│ Extract agent name, build message
|
||||
▼
|
||||
Discord Webhook (stored as n8n variable)
|
||||
│
|
||||
▼
|
||||
"🏁 Claude agent **{name}** has finished."
|
||||
```
|
||||
|
||||
### Why n8n as the middle layer?
|
||||
|
||||
Claude Code HTTP hooks send raw event JSON — you can't customize the body. Discord requires `{"content": "..."}`. n8n does the transformation and keeps the Discord webhook URL out of local config files.
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. n8n workflow
|
||||
|
||||
Import `claude-agent-done.json` into n8n:
|
||||
|
||||
1. n8n → Workflows → Import from File → select `claude-agent-done.json`
|
||||
2. Set the workflow to **Active**
|
||||
3. Note the production webhook URL: `http://10.10.0.210:5678/webhook/claude-agent-done`
|
||||
|
||||
### 2. Discord webhook
|
||||
|
||||
1. Open the target Discord channel → Edit Channel → Integrations → Webhooks → New Webhook
|
||||
2. Copy the webhook URL
|
||||
|
||||
### 3. n8n variable
|
||||
|
||||
Store the Discord URL so it stays out of config files:
|
||||
|
||||
1. n8n → Settings → Variables → Add Variable
|
||||
2. **Key:** `DISCORD_CLAUDE_ALERTS_WEBHOOK`
|
||||
3. **Value:** your Discord webhook URL
|
||||
|
||||
### 4. Claude Code hook config
|
||||
|
||||
The hook is configured in `.claude/settings.json` at the repo root:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SubagentStop": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "http://localhost:5678/webhook/claude-agent-done",
|
||||
"async": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** Update `localhost:5678` to match your n8n host if running remotely (e.g. `http://10.10.0.210:5678`).
|
||||
|
||||
## Testing
|
||||
|
||||
Send a test payload to verify the pipeline end-to-end:
|
||||
|
||||
```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": "test-agent"}'
|
||||
```
|
||||
|
||||
Switch to `/webhook/` (not `/webhook-test/`) once confirmed working.
|
||||
|
||||
## Payload reference
|
||||
|
||||
Claude Code sends a JSON payload on `SubagentStop`. Known fields:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `hook_event_name` | Always `"SubagentStop"` |
|
||||
| `session_id` | Agent session identifier |
|
||||
| `subagent_name` | Name of the subagent (if set) |
|
||||
|
||||
The n8n workflow uses `subagent_name` if present, falling back to the first 8 chars of `session_id`.
|
||||
|
||||
## Future extensions
|
||||
|
||||
- Route different agent names to different Discord channels
|
||||
- Add rich embeds with duration and success/failure status
|
||||
- Filter by agent name (only notify for specific long-running pipelines)
|
||||
- Route to local TTS/voice server for audio alerts
|
||||
|
||||
## Change Log
|
||||
|
||||
### 2026-03-04 - Initial setup
|
||||
- Created n8n webhook workflow (`claude-agent-done.json`)
|
||||
- Added `SubagentStop` HTTP hook to `.claude/settings.json`
|
||||
- Discord webhook URL stored as n8n variable `DISCORD_CLAUDE_ALERTS_WEBHOOK`
|
||||
Loading…
Reference in New Issue
Block a user