Toast when a new cortex mesh message arrives

Shows a toast in Claude Code when a new message comes to your cortex mesh inbox.
cortex-mesh.py inbox --peek.It uses --peek, so it never marks a message as read on the mesh. The message stays in your inbox until you or your agent read it.
cortex-join plugin, installed and joined (/cortex-join). The mod uses its cortex-mesh.py script.When the mesh cannot be reached, the mod shows nothing and tries again one minute later.
/plugin install mesh-toast --marketplace Mark-Hickey/claude-mods
mesh-toaster shows the same mail as a toaster above the prompt. You can use one of the two mods, or both.
claude plugin validate mesh-toast
claude plugin test mesh-toasthooks/register.ts 64 lines1import type { Register } from 'claude-code'
2
3// Reads the inbox with --peek, so checking never marks anything read.
4const INBOX = [
5 'bash',
6 '-c',
7 'python3 "$(ls ~/.claude/plugins/cache/cortex/cortex-join/*/scripts/cortex-mesh.py | sort | tail -1)" inbox --peek',
8]
9const EVERY_MS = 60_000
10
11// " [1791070009649-0] msg <uuid> from chris@todie.io @ session-…: subject"
12const LINE = /^\s*\[[^\]]+\]\s+\S+\s+(\S+)\s+from\s+(\S+)\s+@\s+([^:]+):\s*(.*)$/
13
14export type Message = { id: string; from: string; peer: string; subject: string }
15
16export function parseInbox(stdout: string): Message[] {
17 return stdout.split('\n').flatMap(line => {
18 const m = LINE.exec(line)
19
20 return m ? [{ id: m[1], from: m[2], peer: m[3].trim(), subject: m[4] }] : []
21 })
22}
23
24export function toastText(msg: Message): string {
25 const who = msg.from.split('@')[0]
26
27 return `🍞 Toast's up! Mesh mail from ${who} (${msg.peer}): ${msg.subject}`
28}
29
30export const register: Register = on => {
31 const seen = new Set<string>()
32 let isChecking = false
33
34 on('session.start', async ($, e, next) => {
35 const check = async () => {
36 if (isChecking) {
37 return
38 }
39 isChecking = true
40
41 try {
42 const { exitCode, stdout } = await $.process.run(INBOX, { timeoutMs: 20_000 })
43 if (exitCode !== 0) {
44 return
45 }
46
47 for (const msg of parseInbox(stdout)) {
48 if (!seen.has(msg.id)) {
49 seen.add(msg.id)
50 $.ui.toast(toastText(msg), { timeoutMs: 10_000 })
51 }
52 }
53 } finally {
54 isChecking = false
55 }
56 }
57
58 void check()
59 $.clock.every(EVERY_MS, () => void check())
60
61 return next(e)
62 })
63}
64