Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
.claude/skills/lingxling-sendblue-notify/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 41% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 176% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 123% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 90% | 0% |
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]].
/loop iteration, or /schedule completion.The CLI must be installed and authenticated:
bashnpx @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.
Notify is for long, unattended work — not chatter. Good triggers:
/loop and /schedule jobs that produce a discrete result.Bad triggers (do not silently wire these):
Stop event, regardless of duration — produces spam, trains the user to ignore.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.
Stop hook — opt-in, project-scoped, for sessions the user explicitly wants on automatic notify. Always gate by duration./loop or /schedule ping — append the send to the routine's body.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.
bashif 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:
bashRESULT=$(run-migration 2>&1 | tail -1) npx @sendblue/cli send +15551234567 "migration done — $RESULT"
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:
Stop).|| 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.
/loop or /schedule pingbash/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.
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:
You can install both: textme on a server for inbound, notify as a local Stop-hook for outbound. Different problems, same Sendblue account.
|| true.@textme skill instead.sendblue contacts before relying on notify in an unattended workflow.sendblue send or editing hook config.Stop hook can fire dozens of messages a minute. Always gate by duration and prove the threshold in a dry run before committing.Stop hooks. Always gate by duration. A user who gets pinged every 4 seconds will rip the hook out within an hour.|| true in hooks; surface the failure in logs, not by aborting the agent turn.sendblue contacts before wiring an unattended hook. Or sendblue upgrade to the AI Agent plan.@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.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 17,073 | 23,286 | +36% | 1 | 1 | 0% | 2,274 | 2,885 | +27% | 0 | 0 | — |
case-02 | fail→fail | 19,321 | 9,336 | -52% | 1 | 1 | 0% | 2,957 | 2,957 | 0% | 0 | 0 | — |
case-03 | fail→pass | 13,035 | 9,410 | -28% | 1 | 1 | 0% | 2,256 | 3,184 | +41% | 0 | 0 | — |
case-04 | pass→pass | 9,248 | 7,060 | -24% | 1 | 1 | 0% | 1,670 | 3,623 | +117% | 0 | 0 | — |
case-05 | fail→pass | 13,210 | 11,520 | -13% | 1 | 1 | 0% | 1,681 | 4,640 | +176% | 0 | 0 | — |
case-06 | pass→pass | 10,387 | 6,226 | -40% | 1 | 1 | 0% | 1,819 | 3,310 | +82% | 0 | 0 | — |
case-07 | fail→pass | 17,925 | 7,750 | -57% | 1 | 1 | 0% | 2,438 | 3,748 | +54% | 0 | 0 | — |
case-12 | pass→pass | 7,879 | 6,050 | -23% | 1 | 1 | 0% | 1,091 | 3,572 | +227% | 0 | 0 | — |
case-08 | pass→pass | 10,917 | 8,377 | -23% | 1 | 1 | 0% | 1,894 | 3,894 | +106% | 0 | 0 | — |
case-09 | pass→pass | 6,815 | 5,095 | -25% | 1 | 1 | 0% | 1,001 | 3,136 | +213% | 0 | 0 | — |
case-10 | pass→pass | 16,334 | 5,720 | -65% | 1 | 1 | 0% | 2,917 | 3,446 | +18% | 0 | 0 | — |
case-11 | fail→pass | 8,618 | 3,749 | -56% | 1 | 1 | 0% | 1,309 | 2,914 | +123% | 0 | 0 | — |
case-13 | fail→pass | 24,227 | 3,297 | -86% | 1 | 1 | 0% | 1,564 | 2,965 | +90% | 0 | 0 | — |
case-14 | fail→pass | 17,776 | 8,184 | -54% | 1 | 1 | 0% | 2,947 | 3,459 | +17% | 0 | 0 | — |
case-15 | fail→pass | 35,789 | 17,752 | -50% | 1 | 1 | 0% | 1,556 | 4,270 | +174% | 0 | 0 | — |
case-16 | pass→pass | 11,720 | 8,246 | -30% | 1 | 1 | 0% | 1,860 | 3,416 | +84% | 0 | 0 | — |
case-22 | pass→pass | 9,815 | 8,567 | -13% | 1 | 1 | 0% | 2,108 | 4,079 | +94% | 0 | 0 | — |
case-17 | fail→pass | 8,731 | 1,868 | -79% | 1 | 1 | 0% | 1,207 | 2,698 | +124% | 0 | 0 | — |
case-18 | fail→fail | 15,960 | 10,196 | -36% | 1 | 1 | 0% | 2,582 | 2,972 | +15% | 0 | 0 | — |
case-19 | pass→pass | 4,913 | 14,705 | +199% | 1 | 1 | 0% | 860 | 3,083 | +258% | 0 | 0 | — |
case-20 | fail→pass | 8,234 | 4,783 | -42% | 1 | 1 | 0% | 1,294 | 3,189 | +146% | 0 | 0 | — |
case-21 | pass→pass | 5,584 | 4,561 | -18% | 1 | 1 | 0% | 826 | 3,052 | +269% | 0 | 0 | — |
case-23 | pass→pass | 21,188 | 12,047 | -43% | 1 | 1 | 0% | 3,297 | 4,522 | +37% | 0 | 0 | — |
case-24 | pass→pass | 10,191 | 9,250 | -9% | 1 | 1 | 0% | 1,893 | 3,731 | +97% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted, and 21 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +38 percentage points is the difference between those two pass rates over the 21 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.