sendblue-notify

Text the user's phone when a long-running task, agent turn, or scheduled job finishes — via @sendblue/cli for outbound, optionally wired to a Claude Code Stop hook for automatic fire.

5 stars

Best use case

sendblue-notify is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Text the user's phone when a long-running task, agent turn, or scheduled job finishes — via @sendblue/cli for outbound, optionally wired to a Claude Code Stop hook for automatic fire.

Teams using sendblue-notify should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/sendblue-notify/SKILL.md --create-dirs "https://raw.githubusercontent.com/FrancoStino/opencode-skills-collection/main/bundled-skills/sendblue/sendblue-notify/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/sendblue-notify/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How sendblue-notify Compares

Feature / Agentsendblue-notifyStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Text the user's phone when a long-running task, agent turn, or scheduled job finishes — via @sendblue/cli for outbound, optionally wired to a Claude Code Stop hook for automatic fire.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Sendblue Notify

## Overview

Outbound, fire-and-forget notifications from a local Claude Code session, script, or scheduled job to the user's phone via Sendblue. This is the "walk away from the terminal" pattern: kick off something long, get an iMessage when it lands. This skill owns **when to notify and what to say**. Actual sending goes through [[sendblue-cli]]. Hook wiring (so notifications fire automatically) goes through [[update-config]].

## When to Use This Skill

- Use when the user says "text me when X is done", "ping my phone", "notify me on completion", "let me know when the build/deploy/migration finishes", or "send me an iMessage when…".
- Use when the user asks to wire a hook that texts on agent stop, `/loop` iteration, or `/schedule` completion.
- Use when an agent turn is genuinely long-running and the user has gone heads-down on something else.
- Do **not** use for short, interactive tasks where the user is watching the terminal — the notify is noise.

## Prerequisites

The CLI must be installed and authenticated:

```bash
npx @sendblue/cli whoami        # confirms creds
# or, if first run:
npx @sendblue/cli setup
```

The user's phone number must be a verified contact on the account. On the free plan, the contact has to text the Sendblue number once before outbound sends work — confirm with `sendblue contacts` before relying on notify in an unattended workflow.

Cache the destination number once per project rather than re-asking. A `NOTIFY_NUMBER` env var or a one-line `.notify-number` file is fine; defer storage strategy to whatever the surrounding project already does.

## How It Works

### Step 1: Decide whether notify is appropriate

Notify is for **long, unattended work** — not chatter. Good triggers:

- Agent turns over ~2 minutes (build, large refactor, migration, dataset crunch).
- `/loop` and `/schedule` jobs that produce a discrete result.
- CI / deploy completion when watched from the terminal.
- Multi-step playbooks where the user has gone heads-down on something else.

Bad triggers (do not silently wire these):

- Every `Stop` event, regardless of duration — produces spam, trains the user to ignore.
- Read-only or sub-second commands.
- Anything inside a tight loop.

If the user asks for "notify me when done" on a short task, do the obvious one-shot inline send (Example 1) and **do not** install a global hook.

### Step 2: Pick a delivery pattern

- **One-shot inline send** — default for a single ad-hoc task. No config changes.
- **`Stop` hook** — opt-in, project-scoped, for sessions the user explicitly wants on automatic notify. Always gate by duration.
- **End-of-`/loop` or `/schedule` ping** — append the send to the routine's body.

### Step 3: Compose the notification copy

- **One line, under ~140 chars** — fits in the lock-screen preview.
- **Lead with outcome** — ✅/❌, "done", "failed", "needs review".
- **Include something actionable** — branch name, error tail, PR number, duration.
- **No emojis the user didn't ask for** beyond a single status glyph.
- **No agent self-narration** ("I have completed the task as requested" — just say what happened).

## Examples

### Example 1: One-shot inline send

For a single task, append the send to the command. This is the default — no config changes, no surprise behavior later.

Branch on the task's exit status with an `if`/`else`. Do **not** use a `task && send-success || send-failure` chain: if the task succeeds but the success-send itself returns non-zero, the `||` fires the failure message — so the user sees ❌ even though the task completed. The `if`/`else` keeps the outcome tied solely to the task.

```bash
if long_running_thing; then
  npx @sendblue/cli send +15551234567 "✅ done: $(date +%H:%M)"
else
  npx @sendblue/cli send +15551234567 "❌ failed: $(date +%H:%M)"
fi
```

Or, when the result is interesting, include a one-line summary:

```bash
RESULT=$(run-migration 2>&1 | tail -1)
npx @sendblue/cli send +15551234567 "migration done — $RESULT"
```

### Example 2: Claude Code `Stop` hook (opt-in, scoped)

Register a `Stop` hook in `.claude/settings.json` (project-scoped) — never in global settings unless asked. Defer the actual file edit to [[update-config]]. The hook command itself should:

1. Run cheaply (it fires on *every* `Stop`).
2. Gate on duration — skip sends for turns under a threshold (e.g. 90s).
3. Never fail the parent — pipe to `|| true` so a notify error doesn't surface as a hook failure.

```bash
[ "$CLAUDE_TURN_DURATION_SECONDS" -ge 90 ] && \
  npx @sendblue/cli send "$NOTIFY_NUMBER" "turn done in ${CLAUDE_TURN_DURATION_SECONDS}s" || true
```

(Adjust the env var names to whatever the hook contract actually provides — verify against the current Claude Code hooks reference before writing the config; the harness owns those names, not this skill.)

Show the proposed hook config to the user and get confirmation before invoking [[update-config]]. Automated outbound messages are a footgun if the threshold is wrong.

### Example 3: End-of-`/loop` or `/schedule` ping

```bash
/loop 10m "check deploy; npx @sendblue/cli send +15551234567 \"deploy: \$(deploy-status)\""
```

For `/schedule`, the routine itself can shell out at the end. Same copy rules apply.

## Composing with textme

If the user has `@textme` installed (njerschow/textme — daemon that lets you *text Claude* from your phone), notify is still useful and not redundant. They run in opposite directions:

- **textme**: phone → Claude (user initiates from the phone).
- **sendblue-notify**: local Claude → phone (Claude initiates from a local session).

You can install both: textme on a server for inbound, notify as a local `Stop`-hook for outbound. Different problems, same Sendblue account.

## Best Practices

- ✅ **Default to one-shot inline sends** for single tasks. Only escalate to a hook when the user asks for automatic notify.
- ✅ **Gate hooks by duration.** A 90s threshold is a sensible starting default.
- ✅ **Show the hook config before installing it** and get explicit user confirmation.
- ✅ **Store the destination number per-user** (env var or gitignored file), not in committed config.
- ❌ **Don't install global hooks** unless the user explicitly asks. Project-scoped is the default.
- ❌ **Don't let a failed notify fail the parent.** Trail with `|| true`.

## Limitations

- Notify is outbound-only. For "text Claude from the phone" use the `@textme` skill instead.
- On the free Sendblue plan, the destination phone must have texted the Sendblue number at least once before outbound succeeds. Verify with `sendblue contacts` before relying on notify in an unattended workflow.
- This skill does not own credentials, account setup, or the hook config file format. Those belong to [[sendblue-cli]] and [[update-config]] respectively.

## Security & Safety Notes

- **Lock-screen previews leak.** Anyone holding the phone can read notification copy. Do not embed secrets, customer data, full error stacks, or auth tokens. Link to a log, dashboard, or PR instead.
- **Confirm before sending or wiring hooks.** Preview the destination, message template, trigger, and duration gate; wait for explicit user confirmation before running `sendblue send` or editing hook config.
- **Automated outbound is a footgun.** A misconfigured `Stop` hook can fire dozens of messages a minute. Always gate by duration and prove the threshold in a dry run before committing.
- **Per-user numbers.** The destination phone number is a personal identifier — keep it in user-local config (env var, gitignored file), not in committed repo files or CI logs.
- **Free-plan verification is silent.** If the destination contact hasn't texted in once, sends return an API error but the user just sees "no text arrived". Confirm verification before wiring an unattended hook.

## Common Pitfalls

- **Spam from over-eager `Stop` hooks.** Always gate by duration. A user who gets pinged every 4 seconds will rip the hook out within an hour.
- **Hardcoding the destination number in committed files.** Use an env var or gitignored file; the number is per-user, not per-repo.
- **Letting a failed notify fail the parent.** Always trail with `|| true` in hooks; surface the failure in logs, not by aborting the agent turn.
- **Free-plan contact gotcha.** If the destination contact hasn't texted in once on a free-plan account, the send silently fails for the user's purposes. Verify with `sendblue contacts` before wiring an unattended hook. Or `sendblue upgrade` to the AI Agent plan.
- **PII in notification copy.** Lock-screen previews are visible to anyone holding the phone. Don't embed secrets, customer data, or full error stacks — link to a log or PR instead.
- **Burying the outcome.** "Task complete. Here is a summary of what I did…" wastes the preview line. Lead with ✅/❌ and the verb.

## Related Skills

- `@sendblue-cli` — Owns the actual send mechanism. This skill calls into it.
- `@sendblue-api` — HTTP alternative for app code where notify lives inside a long-running service.
- `@update-config` — Wires the `Stop` hook into `.claude/settings.json`. This skill owns the *what* and *when*; update-config owns the *where*.
- `@textme` — Inbound counterpart (phone → Claude). Composes well with notify.

## Links

- Underlying CLI: <https://github.com/sendblue-api/sendblue-cli>
- Sendblue: <https://sendblue.com>
- API docs: <https://docs.sendblue.com>

Related Skills

sendblue-cli

5
from FrancoStino/opencode-skills-collection

Send iMessage and SMS from the shell via the @sendblue/cli npm package — outbound sends, contact management, and account setup with no API client or webhook server required.

sendblue-api

5
from FrancoStino/opencode-skills-collection

Send and receive iMessage, SMS, and RCS from application code via the Sendblue HTTP API — text, media, group messages, send styles, reactions, typing indicators, status callbacks, and inbound webhooks.

zustand-store-ts

5
from FrancoStino/opencode-skills-collection

Create Zustand stores following established patterns with proper TypeScript types and middleware.

zoom-automation

5
from FrancoStino/opencode-skills-collection

Automate Zoom meeting creation, management, recordings, webinars, and participant tracking via Rube MCP (Composio). Always search tools first for current schemas.

zoho-crm-automation

5
from FrancoStino/opencode-skills-collection

Automate Zoho CRM tasks via Rube MCP (Composio): create/update records, search contacts, manage leads, and convert leads. Always search tools first for current schemas.

zod-validation-expert

5
from FrancoStino/opencode-skills-collection

Expert in Zod — TypeScript-first schema validation. Covers parsing, custom errors, refinements, type inference, and integration with React Hook Form, Next.js, and tRPC.

zipai-optimizer

5
from FrancoStino/opencode-skills-collection

Ultra-dense token optimizer skill for prompt caching, log pruning, AST-based inspection, and minified JSON payloads.

zeroize-audit

5
from FrancoStino/opencode-skills-collection

Detects missing zeroization of sensitive data in source code and identifies zeroization removed by compiler optimizations, with assembly-level analysis, and control-flow verification. Use for auditing C/C++/Rust code handling secrets, keys, passwords, or other sensitive data.

zendesk-automation

5
from FrancoStino/opencode-skills-collection

Automate Zendesk tasks via Rube MCP (Composio): tickets, users, organizations, replies. Always search tools first for current schemas.

zapier-make-patterns

5
from FrancoStino/opencode-skills-collection

No-code automation democratizes workflow building. Zapier and Make (formerly Integromat) let non-developers automate business processes without writing code. But no-code doesn't mean no-complexity - these platforms have their own patterns, pitfalls, and breaking points.

youtube-summarizer

5
from FrancoStino/opencode-skills-collection

Extract transcripts from YouTube videos and generate comprehensive, detailed summaries using intelligent analysis frameworks

youtube-full

5
from FrancoStino/opencode-skills-collection

Fetch YouTube transcripts, search videos, browse channels, and extract playlists via TranscriptAPI — no yt-dlp, no Google API key, works from any cloud server.