AlphornAlphorn Docs

AI Agent Notifications

Notifications from AI coding agents (Claude Code, Codex, Cursor, Gemini CLI, Aider) when they finish or need input. Plus AGENTS.md snippet and Agent Skill.

AI coding agents run for minutes or hours, and they stop whenever they need a decision from you. Alphorn turns those moments into a notification on the channel you actually look at (Slack, Telegram, SMS, push, email, or any other supported channel), with filters so a blocked agent can page you while a finished task only lands in a chat.

Every agent integration is the same HTTP request:

curl -fsS --max-time 5 -X POST https://app.alphorn.dev/n/V1StGXR8_Z5jdHi6B-myT \
  -H "Authorization: Bearer $ALPHORN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Claude Code - my-app", "message": "Needs permission to run tests", "priority": 4, "tags": ["ai-agent", "claude-code", "permission"]}'

Create a webhook first (see Webhooks) and use its Endpoint URL (plus its API key, if you switched on Require API key).

Set up your agent

Using the same fields across all agents keeps your filters simple:

SituationpriorityTags
Task finished2ai-agent, <agent>, completed
Waiting for input3ai-agent, <agent>, waiting
Needs permission or blocked4ai-agent, <agent>, permission
Failed4ai-agent, <agent>, error

Put the project name in the title (for example Claude Code - my-app) so you can tell parallel sessions apart. Alphorn truncates title to 200 and message to 4,000 characters, so you can pass an agent's last response without trimming it. See the API Reference for all fields.

Let the agent notify you itself

Hooks fire on fixed events. To let the agent decide when a notification is worth sending (for example "tell me when the migration is done"), give it instructions. Set two environment variables where the agent runs:

export ALPHORN_WEBHOOK_URL="https://app.alphorn.dev/n/V1StGXR8_Z5jdHi6B-myT"
export ALPHORN_API_KEY="alp_..."

The snippets below build the JSON with jq, so the agent's environment needs jq and curl.

AGENTS.md snippet

Add this to the AGENTS.md (or CLAUDE.md) of your project. Codex, Cursor, and many other agents read AGENTS.md automatically. Claude Code reads CLAUDE.md, which can import it with a line containing @AGENTS.md.

AGENTS.md
## Notifications

Notify the user with Alphorn when a long-running task finishes or fails, or when you
are blocked on a decision and the user may not be watching. Do not notify for routine steps.

```bash
curl -fsS --max-time 5 -X POST "$ALPHORN_WEBHOOK_URL" \
  -H "Authorization: Bearer $ALPHORN_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg t "<short title>" --arg m "<what happened, what you need>" \
        '{title: $t, message: $m, priority: 3, tags: ["ai-agent"]}')"
```

- priority: 2 = finished, 3 = needs input, 4 = blocked or failed
- Start the title with the project name. Never include secrets in the message.

Agent Skill

Agents that support Agent Skills (including Claude Code) load a skill only when it is relevant. Save this as ~/.claude/skills/alphorn-notify/SKILL.md for all projects, or .claude/skills/alphorn-notify/SKILL.md for one project:

SKILL.md
---
name: alphorn-notify
description: Send the user a notification through Alphorn. Use when the user asks to be notified, pinged, or alerted, when a long-running task finishes or fails, or when you are blocked and the user may be away.
---

# Notify the user with Alphorn

Requires ALPHORN_WEBHOOK_URL and ALPHORN_API_KEY in the environment, plus jq and curl.

```bash
curl -fsS --max-time 5 -X POST "$ALPHORN_WEBHOOK_URL" \
  -H "Authorization: Bearer $ALPHORN_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg t "$TITLE" --arg m "$MESSAGE" --argjson p 3 \
        '{title: $t, message: $m, priority: $p, tags: ["ai-agent"]}')"
```

- Title: project name plus a few words, e.g. "my-app - tests passing".
- Message: what happened and what you need from the user, in one or two sentences.
- Priority: 2 = finished, 3 = needs input, 4 = blocked or failed.
- A 201 response means the notification was accepted.
- 401: the Authorization header is missing or malformed, or the API key is wrong. Check that ALPHORN_API_KEY is set.
- 400: invalid JSON body. 403: webhook disabled. 404: wrong webhook URL. 413: body too large (over 1 MiB). 429: quota exceeded, don't retry right away. 508: loop detected.
- Never include secrets, tokens, or file contents in the message.

Custom agents

For an agent you build yourself, send a notification at the decision points:

import os
import requests

WEBHOOK = os.environ["ALPHORN_WEBHOOK_URL"]
HEADERS = {"Authorization": "Bearer " + os.environ["ALPHORN_API_KEY"]}

def notify(event, message, priority=3):
    requests.post(WEBHOOK, json={
        "title": f"Agent - {event}",
        "message": message,
        "priority": priority,
        "tags": ["ai-agent", event],
    }, headers=HEADERS, timeout=5)

# When the agent needs human input
notify("waiting", "Agent is blocked and needs your decision")

# When a task completes
notify("completed", f"Finished in {duration}m: {summary}", priority=2)

# When something goes wrong
notify("error", f"{error}", priority=4)

# Cost tracking
notify("cost", f"${cost:.2f} spent of ${budget:.2f} budget",
       priority=4 if cost > budget * 0.8 else 2)

Routing examples

ChannelFilterPurpose
TelegramTags has any of waiting, permissionInstant alert when any agent is blocked
Slack (#dev)Tags has any of ai-agentAll agent activity
SMSPriority greater than 3Only when an agent is stuck or failed
EmailTags has any of completedArchive of finished tasks

On this page