Field Note: Discord as the second screen for Claude Code activity
Long-running AI tasks have a coordination problem. You cannot stare at the terminal for fifteen minutes waiting for a build, but you also cannot afford to forget what was running. I route Claude Code activity to a private Discord server via webhooks: ship notifications, build failures, long-task completions, daily summaries. Discord becomes the second screen. This Field Note walks the hook architecture, the channel layout, and what an AI architect would change if they were building a team version.
By Russ. Field Note, 2026.
The existing approach
Most AI-assisted development workflows assume you are watching the terminal. The model emits a status line, you read it, you respond, the model continues. This works for tight, foreground tasks (writing a function, debugging an error). It fails for any task that runs more than a few minutes.
A long-running task in Claude Code (a backtest sweep, a multi-file refactor, a batch publish of blog posts) sits between two bad options. Option one: you watch the terminal for 15 minutes doing nothing, which is wasted attention. Option two: you switch to another task and forget to come back, which is wasted output. The model finished and is waiting for the next instruction, and you do not know.
The conventional fix is desktop notifications, which work but are noisy and easily dismissed. The fix I actually use is Discord webhooks routed to a private server.
Where it works
Discord works as an alert channel for three reasons.
- It is already where I spend ambient attention. I have Discord open on a side monitor for community participation. Routing AI alerts to a dedicated channel on that monitor means the notification lands in a context I already check. It does not land in a new context I have to remember to check.
- Webhooks are free, easy, and fast. Every Discord channel can have a webhook URL that accepts a POST request and posts the body as a channel message. No bot registration, no OAuth, no rate-limit handling for low-volume use. A bash
curl -X POSTis the entire integration on the sender side. - The channel structure becomes the project structure. I have one channel per project (#atlas, #trialedge, #mes, #marketing-bot, etc.). Then #ship-log for all version bumps across projects, #failures for any task that errored, and #daily-summary for a once-a-day digest. The channel layout becomes the dashboard.
Where it breaks
Two failure modes show up regularly.
Mode one: the alert volume drowns the signal. Early on I sent a webhook on every Claude Code session start, end, and tool call. The channels turned into log dumps that I stopped reading. The fix was a strict allowlist: alerts only fire on (a) a session that completed a meaningful task as judged by a Stop hook, (b) any error or unrecoverable failure, (c) any commit that pushed to a remote, (d) any scheduled task firing or missing its window. Everything else stays in the terminal.
Mode two: the message format matters more than I thought. A raw text dump from Claude Code is unreadable in Discord. The format that actually gets read is: one-line summary in bold, three-line context block in monospace, link to the relevant commit or file. Discord's markdown rendering helps. The discipline of one-line-summary-first is what makes the alert actionable in a glance.
What I actually do
The architecture is small.
Claude Code hooks trigger on Stop, on tool failures, on certain script completions. The hook is a tiny bash script that constructs a JSON payload and POSTs to a per-project webhook URL stored in an environment variable.
A shared library of message formatters (one for ship notes, one for failures, one for daily summary) keeps the format consistent across projects. Adding a new project means adding a new webhook URL and pointing the existing formatters at it.
A daily-summary cron runs at 8 AM. It walks the previous day's git activity across all my projects, and posts a single message to #daily-summary with what shipped, what failed, what is queued. This is the message I actually read every morning while drinking coffee.
A failures-only catch-all sits at #failures. Anything that goes wrong in any project ends up here with the project name in the message. This is the closest thing I have to a pager.
The channels and the hooks together replace what would otherwise be a custom dashboard. I do not need a status page or a Grafana board; I have Discord.
What it costs
The cost stack is rounding error.
Discord: free for personal use. The server I run for AI alerts has one user (me) and zero paid features. No bots, no Nitro, no premium tier.
Hooks: the bash scripts that POST to the webhooks are 20 to 50 lines each. They run as Claude Code Stop hooks (free), as cron jobs (free), or inline in build scripts (free).
Time: an hour to set up the webhooks per project, another hour to write the message formatters, ongoing maintenance is essentially zero.
The value is the recovered attention. Before this setup, I lost 10 to 20 minutes per day to checking terminals for completed tasks. Or worse, I forgot tasks finished and discovered them stale the next morning. Now the completions surface in Discord and I respond at my own pace.
What an AI architect would change
If I were building the team version, three changes.
A shared schema for alert messages. Right now each formatter is hand-written. A typed message schema (severity, project, summary, context, action_url) would let the formatters be auto-generated from the schema. It would also let downstream tooling (filters, threading, escalation) work consistently.
Threading by task. Discord supports threads. A long-running task that emits multiple status updates should land them in a single thread, not as separate messages. This needs the hooks to maintain a task-id state, which is harder than it sounds because tasks span sessions.
An "ack" loop. Currently the alerts are one-way. For team use, you want to acknowledge an alert (so others know it has been seen) and convert it to a follow-up task. A Discord bot that accepts emoji reactions as ack and writes them back to a tracking system would close that loop. I have not built this because solo use does not need it.
None of these are critical. The current setup works at solo scale.
What would not change
The pattern is right. Long-running tasks need ambient notification, not active monitoring. Channel-per-project is the right organizing principle because it matches how the work is already organized. The discipline of "only fire on meaningful events" is what keeps the channels readable.
The architectural principle: in any system where humans coordinate with long-running AI tasks, the alerts should land in a channel the human already watches, in a format the human can read in one glance, with a strict allowlist for what fires. Volume is the enemy. Signal is the product.
The same principle applies to monitoring pipelines for production AI systems, to ops alerts on infrastructure, to credit-committee escalation paths, to incident-response triage. Discord is the surface I happen to use. The pattern is portable.
Closing
Discord as a second screen is the personal infrastructure that makes multi-tasking across AI projects sustainable. Without ambient notification, I forget tasks finished. Without channel-per-project structure, the alerts blur together. Without strict allowlisting, the channels turn into noise. All three disciplines together turn Discord into a real coordination layer for solo AI work.
If you are evaluating how to set up ambient notification for AI-assisted work, or how to scale solo-coordination patterns into team-coordination patterns, the questions worth asking are: which channel does your human already watch (Slack, Discord, SMS, email); what is the strict allowlist for events worth alerting on; how do you format the message so it is readable in one glance; and how do you keep the volume low enough that the channel stays signal.
Those are the questions this Field Note is meant to answer.
For the project-tracking counterpart that pairs Obsidian and Claude Code into a planning-and-execution loop, see the Obsidian-Claude Code loop for project tracking. For the orchestration discipline behind structured outputs at scale, see Inside Marketing Bot v2.
Update, November 2026
Since May, Discord has become a delivery surface as well as an alert surface.
Scheduled posts. The strikeout bot's picks went out from a GitHub Action at 13:00 UTC that graded yesterday, posted today and committed the predictions back to the repository. It ran on 108 of 109 game days through October 24, 492 picks in all, with no human touching anything (season note).
The double-double bot is set to post five names through the strikeout bot's webhook at 3 PM Eastern. Two UTC crons, 19:00 and 20:00, cover the clock change, and a guard script reads the New York hour and lets one through, so the November change needs no edit. As of October 31 that workflow was written and dry-run but not live: its repository did not exist yet, and the posts so far came from my local sessions. Its posting tool defaults to a dry run, labels test posts, and never prints the webhook value.
Deliverables. In July a demand board went to a partner channel with a screenshot and the board HTML. In August a planning document went to a team channel, and the editor guide for a paid editor went to an editing webhook; the API confirmed that delivery. A finished outbound build posts its Google Sheet link to my own webhook, and on October 21 a demo link and a drafted message came the same way, so nothing reaches a recipient until I forward it. A delivery spec for a services venture calls for an ops feed of one line per job step, reusing a helper another pipeline of mine calls after every step.
What held. The allowlist discipline, where I applied it: the picks channel carries picks and results, and the double-double bot's run logs stay in files. The one-glance format: my first double-double post listed probability, price and edge per pick, I found it confusing, and that evening I replaced it with five names in the strikeout format. Channel per purpose held; channel per project did not, because two bots now share one picks channel.
What did not. The 8 AM daily-summary cron is not part of what I run, and the Stop hook is no longer where the useful posts come from. It is still installed, but plainer than I described: one global hook that posts the working directory and a session id. The posts I act on come from per-bot Actions and per-step pipeline posts. I never built the ack loop or the threading.