---
name: beep-notifications
description: Send a push notification to the user's phone via Beep (https://trybeep.app) when a long-running task finishes, errors, or needs human attention.
---

# Beep push notifications

Beep is a webhook-to-push-notification service. When you POST to the
user's Beep URL, their phone buzzes. Use this skill to hand control back to
the user the moment a long task is done — so they can stop tab-switching
and come back when there's actually something to see.

## When to use this skill

Use it when an asynchronous task reaches a state the user cares about:

- A long-running task finished (agent run, build, fine-tune, batch job)
- A step errored and needs human attention
- A checkpoint was reached and you want confirmation before continuing
- A scheduled job ran and you want to report the outcome

**Do not** use it for:

- Per-step progress pings during a task
- Information the user is already watching stream in the terminal
- Anything that fires more than a few times per hour — phones get noisy

## The endpoint

The user has a personal Beep webhook URL of the form:

```
https://trybeep.app/api/in/<token>
```

Read it from an environment variable — `BEEP_URL` is the convention. If it
is not set, ask the user for it once and remember it for the session.
**Never hardcode a token in committed code**; treat it like an API key.

## Sending a notification

POST JSON with `title` and `body`. Both fields are required.

### bash / curl

```bash
curl -X POST "$BEEP_URL" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Build finished",
    "body": "147 tests passed in 2m 14s"
  }'
```

### Python

```python
import os, requests

requests.post(
    os.environ["BEEP_URL"],
    json={
        "title": "Build finished",
        "body": "147 tests passed in 2m 14s",
    },
    timeout=5,
)
```

### Node / TypeScript

```ts
await fetch(process.env.BEEP_URL!, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "Build finished",
    body: "147 tests passed in 2m 14s",
  }),
});
```

### Form-encoded (works too)

```bash
curl -X POST "$BEEP_URL" -d "title=Done&body=All clean"
```

### Query-string (works too — handy when a body is awkward)

```bash
curl "$BEEP_URL?title=Done&body=All+clean"
```

## Fields

- `title` (string, required) — short headline. Keep under ~40 characters;
  phone lock screens truncate.
- `body` (string, required) — one or two sentences of detail. Include
  concrete numbers: token counts, loss values, files changed, error
  messages, durations.

## Writing good notification copy

A good notification tells the user what happened *and* whether they need
to act. Always prefer concrete numbers over vague verbs.

Good:

- title: "Claude finished" · body: "Refactored 47 files · all tests passing"
- title: "Fine-tune converged" · body: "loss 0.31 · 2.4M tokens · 4h 12m"
- title: "Backfill done" · body: "18,420,310 rows migrated · 0 errors"
- title: "Deploy failed" · body: "prod · migration 0042 timed out at step 3/7"

Avoid:

- title: "Update" · body: "Task done" — no signal, no numbers
- title: "Processing..." — not an end state; don't notify mid-flight
- title: "Error" · body: "Something went wrong" — no specifics to act on

## Error handling

Beep is fire-and-forget. If the POST fails, log it and continue — the
user's main task result matters more than the notification. Always use a
short timeout (~5s) and swallow network errors.

```python
try:
    requests.post(os.environ["BEEP_URL"], json=payload, timeout=5)
except Exception as e:
    print(f"beep notify failed: {e}")  # do not raise
```

## Common integration points

- **Claude Code**: add a `Stop` hook in `.claude/settings.json` that fires
  `curl` when an agent run finishes.
- **OpenAI Agents SDK**: call after `Runner.run(...)` completes, in both the
  success branch and the except branch.
- **Hermes by Nous Research**: call after the agent loop finishes, or from
  a training callback when fine-tuning converges.
- **OpenClaw**: call from a skill's post-run step so the daemon pings the
  user's phone when a long task wraps.
- **Bash scripts**: chain with `&& curl ...` for success, or use `trap` to
  catch error paths.
- **Python scripts**: wrap `main()` in try/finally and fire from the finally
  block so you get notified on both success and failure.

## Learn more

- Site: https://trybeep.app
- LLM-friendly docs: https://trybeep.app/llms.txt
- Support: rajat@trybeep.app
