AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Ops Inbox

skill-lifecycle-innovations-limited-claude-ops-ops-inbox · by Lifecycle-Innovations-Limited

Full inbox management across all channels — WhatsApp (whatsmeow bridge via mcp__whatsapp__*), iMessage (chat.db reader + AppleScript send via mcp__plugin_imessage_imessage__*), Email (Gmail MCP), Slack (MCP), Telegram (user-auth MCP), Discord (webhook + REST read), Notion (MCP — comments, mentions, assigned tasks). Scans FULL inbox (not just unread), identifies messages needing replies, archives…

— No reviews yet
0 installs
35 views
0.0% view→install

Install

$ agentstack add skill-lifecycle-innovations-limited-claude-ops-ops-inbox

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

2 finding(s); flagged for manual review. · v0.1.0 How review works →

  • • Prompt-injection patterns
  • • Secret / credential exfiltration
  • • Dangerous shell & filesystem operations
  • • Untrusted network calls
  • • Known-malicious package signatures
  • high Possible prompt-injection directive.
  • high Dangerous shell/eval execution.

What it can access

  • ● Network access Used
  • ● Filesystem access Used
  • ● Shell / process execution Used
  • ● Environment & secrets Used
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

— Not yet reviewed
0 installs to date
— no reviews yet
● 2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Ops Inbox? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

OPS ► INBOX ZERO

⚠️ WHATSAPP TRANSPORT — MCP ONLY, NEVER wacli

For all WhatsApp operations in this skill (list chats, read messages, search contacts, send replies, archive chats), use the mcp__whatsapp__* tool family backed by the whatsmeow (Go) whatsapp-bridge — upstream lharries/whatsapp-mcp. (Earlier docs misnamed this as "Baileys" — Baileys is the Node.js WhatsApp library; this bridge uses go.mau.fi/whatsmeow.)

NEVER call the legacy wacli CLI (wacli chats list, wacli messages list, wacli send, wacli doctor, wacli history backfill, etc). The wacli store and keepalive daemon are deprecated for this skill.

If you find yourself reaching for any wacli ... shell command, stop and use the MCP tool with the same intent:

| Intent | ✅ Use this | ❌ Do NOT use | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | | List recent chats | mcp__whatsapp__list_chats {sort_by: "last_active", limit: 25} | wacli chats list | | Read full thread | mcp__whatsapp__list_messages {chat_jid, limit: 20} | wacli messages list | | Full-text search | mcp__whatsapp__list_messages {query: "", limit: 20} | wacli messages search | | Resolve a contact | mcp__whatsapp__search_contacts {query: ""} | wacli contacts | | Send a reply (after approval) | mcp__whatsapp__send_message {recipient: "", message: ""} | wacli send | | Health check | lsof -i :8080 \| grep LISTEN + (macOS) launchctl print "gui/$(id -u)/com.${USER}.whatsapp-bridge" / (Linux) systemctl --user is-active whatsapp-bridge.service | wacli doctor / ~/.wacli/.health | | Trigger history backfill | curl -fsS -X POST http://127.0.0.1:8080/api/backfill (claude-ops patch — runs per-chat against the 50 most-recent chats; bridge also auto-backfills 5s after every Connected event) | — |

Rationale: the bridge exposes a typed MCP surface, returns consistent JSON shapes (is_from_me, content, timestamp, sender), supports FTS5 search natively, and avoids store-lock contention with the wacli keepalive daemon. Mixing the two surfaces caused inconsistent state in past sessions.

Sole exception: the ~/.wacli/.health file is still readable for legacy daemon-health surfacing in other skills, but no wacli command should be invoked from this skill.

Runtime Context

Before executing, load available context:

  1. Auto-sync WhatsApp in the background (DEFAULT — every invocation) — the FIRST thing this skill does, before any scan or menu, is guarantee the store is fresh, then fire a recent-conversation history backfill and a contacts-link in the background, non-blocking.

0a. Freshness gate (run FIRST, blocking, bounded). Before classifying anything, run ~/bin/wa-inbox-fresh.sh (shipped by scripts/install-whatsapp-bridge-linux.sh). It probes the bridge with a real curl connection probe (curl -s -m4 http://127.0.0.1:8080/), forces a backfill, triggers voice-note transcription, and waits (bounded ~32s) for the newest message to settle, then prints a FRESHNESS report (newest message = … (N min old)). It only restarts the bridge if the curl probe genuinely fails twice — do NOT gate liveness on ss | grep :8080, because ss renders port 8080 as the service name webcache, so the grep never matches and you'd needlessly bounce a healthy bridge. Exit 2 means the bridge is down and unrecoverable → the store is STALE, do not trust last-sender classification.

Mac WhatsApp.app fallback (bridge-miss recovery)

The whatsmeow bridge can silently miss inbound messages when its history/app-state sync lags — most often on @lid chats (e.g. 2026-06-11 it missed a reply from a contact that the Mac WhatsApp.app had). The Mac app keeps an unencrypted local Core Data store at ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatStorage.sqlite, readable over Tailscale SSH, so it is a reliable ground-truth backstop.

  • When it runs AUTOMATICALLY: wa-inbox-fresh.sh now invokes the Mac cross-check itself whenever the bridge store looks stale — on exit 2 (store unreadable) or when the newest message is >2h old, it prints a MAC GROUND TRUTH block (latest 10 messages from the Mac app store) inline in the freshness report. No orchestration needed.
  • When to use manually: a contact's known reply is missing from the bridge (common on @lid chats) — cross-check before classifying that thread as "no reply".
  • Command: bin/wa-mac-latest.sh --contact [N] (also --recent [N], --since "YYYY-MM-DD HH:MM", add --json for machine-readable output). It reads ~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/ChatStorage.sqlite over SSH. Schema: ZWAMESSAGE (ZTEXT, ZISFROMME, ZMESSAGEDATE = seconds since 2001-01-01) joined to ZWACHATSESSION (ZPARTNERNAME, ZCONTACTJID).
  • **Transport chain (bin/wa-mac-transport.sh, shared by all wa-mac-\ scripts):* ① Tailscale/direct SSH (WA_MAC_SSH=user@host) → ② Cloudflare-tunnel SSH (WA_MAC_CF_HOST=ssh-mac.example.com, via cloudflared access ssh ProxyCommand) when Tailscale is down. One-time wiring: scripts/setup-wa-mac-cf-tunnel.sh (installs cloudflared locally + the Mac LaunchDaemon from a remotely-managed tunnel token, then verifies end-to-end). Both env vars live in the shell profile, never in the repo.
  • READ-ONLY ground truth for reads. The reader never writes and never sends. Sends still go through the whatsmeow bridge (mcp__whatsapp__send_message) under the Rule-6 outbound-approval gate — the Mac store is only consulted to confirm what actually arrived. The ONLY write-capable Mac surface is wa-mac-archive.sh (archive-only, see Tier 4 of the archive ladder).
  • Why no Linux-native alternative: there is no official WhatsApp Linux desktop app; the third-party Flatpak clients (whatsapp-for-linux, ZapZap) are Electron WhatsApp-Web wrappers that need a GUI, consume a linked-device slot, and store data in encrypted IndexedDB (not a queryable SQLite) — so the Mac ChatStorage.sqlite is the preferred backstop.

The FULL-THREAD AWARENESS GATE (in "Processing each channel") depends on this step having run first. That gate's "read both directions incl. [voice]" only works once wa-inbox-fresh.sh (freshness + backfill) and the voice-note transcription pass (step 0c) have completed and the store has settled — otherwise outbound rows and [voice] bodies are still missing and the gate reads an incomplete thread.

0b. Background backfill + contacts-link (idempotent, safe every time). The backfill pulls recent messages for the 50 most-active chats; the link populates messages.db.contacts from the whatsmeow session store so both @s.whatsapp.net and @lid chat JIDs resolve to names (without it the contacts table is empty and LID-format chats show raw phone numbers):

``bash BR="${WHATSAPP_BRIDGE_DIR:-$HOME/.local/share/whatsapp-mcp/whatsapp-bridge}" if curl -s -o /dev/null -m 4 http://127.0.0.1:8080/ 2>/dev/null; then curl -fsS -m 10 -X POST http://127.0.0.1:8080/api/backfill >/dev/null 2>&1 & # recent-conversation backfill [ -f "$BR/link_contacts.py" ] && python3 "$BR/link_contacts.py" >/dev/null 2>&1 & # contacts link (phone + LID aliases) fi ``

Kick this off, then continue with the steps below while it runs — give the link ~2s before name-resolving chats. link_contacts.py resolves names via whatsmeow_contacts + whatsmeow_lid_map (name preference: fullname → firstname → pushname → businessname). It ships via scripts/install-whatsapp-bridge-linux.sh into the bridge dir; recreate it from whatsmeow_contacts/whatsmeow_lid_map if absent.

0c. Voice notes are first-class. Incoming voice notes (media_type='audio', empty content) are auto-transcribed into content as [voice] by the whatsapp-transcribe.timer (systemd-user, every 10 min, OpenAI whisper-1) — and wa-inbox-fresh.sh triggers a transcribe pass on every scan. So a voice note shows up in NEEDS_REPLY / thread scans exactly like a text message; treat a [voice] … body as the sender's words. Transcription is idempotent (only ever fills empty audio rows, never clobbers real text) and capped per run, so it never re-bills or stacks.

0c-bis. ALL media is now first-class, not just voice. Beyond voice→[voice] (transcribe above), incoming video / image / document media (empty content) is auto-enriched into content as [video] … / [image] … / [document] … by transcriber/enrich_media.py (vision for stills/video frames + Whisper for any audio track) on the whatsapp-enrich.timer (systemd-user, every 10 min) — and wa-inbox-fresh.sh queues an enrich pass on every scan. So an image, clip, or PDF shows up in NEEDS_REPLY / thread scans with a real, readable body, exactly like text. Enrichment is idempotent (only fills empty media rows) and capped per run. The bridge also self-heals media that 403/404/410s (stale directPath, common for larger media) by asking the sender's phone to re-upload via SendMediaRetryReceipt (apply-patches.py Fix M), so large media never silently drops.

0d. The scan engine self-refreshes + self-reconciles on EVERY run — this is automatic, you do not orchestrate it. bin/ops-inbox-scan (the primary classifier, step "Scan engine" below) now does the refresh/pull itself, BLOCKING and bounded, before it classifies — so the data is converged by the time you read its JSON, regardless of whether the background ops-inbox-autosync hook has finished. On each invocation the scan:

  • Refreshes (frontfill/backfill): if the bridge is reachable on :8080, it fires POST /api/backfill + link_contacts.py, then waits (bounded ~18s) for the newest stored message timestamp to stop advancing so the classify pass reads a settled store. This is the blocking guarantee the background hook alone does NOT give. Skip with OIS_NO_REFRESH=1 (set automatically on repeat calls in one session to avoid re-waiting).
  • Reconciles outbound sends (owner directive 2026-06-05 "include all things I sent to all people"): it reads the bridge's outbound-send journal (journalctl --user -u whatsapp-bridge.service, or the bridge log file on non-systemd hosts) into a {recipient_jid → latest_send_epoch} map, and demotes any NEEDSREPLY thread whose last inbound is older than a send to any of that person's JIDs (reconciled flag set, moved to WAITING). This catches replies that went out via /api/send or a phone send that has not yet landed in messages.db — the single most common false-NEEDSREPLY. Only epoch-stamped send lines drive demotion (a send that genuinely predates the inbound never demotes).

Net effect: running /ops:ops-inbox autonomously pulls the latest state AND folds in everything the user already sent, with zero extra orchestration on your part — just read the scan JSON. A reconciled field on a WAITING item means "already answered, reply not yet in the store"; never re-draft it. You still clear the FULL-THREAD AWARENESS GATE on whatever genuine NEEDS_REPLY candidates remain.

  1. Self-heal plugin version pin — if any ${CLAUDE_PLUGIN_DATA_DIR} file or ~/.claude/plugins/installed_plugins.json references a cache/ops-marketplace/ops/X.Y.Z/ path that no longer exists on disk, downstream hooks (stop-all.sh, ops-post-session-cleanup) emit Plugin directory does not exist. Resolve before scanning:

``bash INSTALLED="$HOME/.claude/plugins/installed_plugins.json" CACHE_DIR="$HOME/.claude/plugins/cache/ops-marketplace/ops" PINNED=$(python3 -c "import json; d=json.load(open('$INSTALLED')); print(d.get('plugins',{}).get('ops@ops-marketplace',[{}])[0].get('version',''))") LATEST=$(ls "$CACHE_DIR" 2>/dev/null | sort -V | tail -1) if [ -n "$PINNED" ] && [ -n "$LATEST" ] && [ "$PINNED" != "$LATEST" ] && [ ! -d "$CACHE_DIR/$PINNED" ]; then python3 -c " import json p='$INSTALLED'; d=json.load(open(p)) for e in d.get('plugins',{}).get('ops@ops-marketplace',[]): if e.get('version')=='$PINNED': e['version']='$LATEST' e['installPath']='$CACHE_DIR/$LATEST' json.dump(d, open(p,'w'), indent=2) " bash "$HOME/.claude/scripts/hooks/ops-plugin-version-heal.sh" # rewrites daemon-services.json + mcp-proxy/servers.json fi ``

The existing ops-plugin-version-heal.sh only rewrites downstream targets from installed_plugins.json (the source of truth). When the source itself is stale, the heal hook is a no-op — patch it first, then re-run the hook.

  1. Preferences: Read ${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json
  • default_channels — which channels to scan by default
  • secrets_manager / doppler — how to resolve channel credentials if not in env
  1. Daemon health: Read ${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json
  • Check whatsapp-bridge status — verify com.${USER}.whatsapp-bridge is running (lsof -i :8080 or launchctl print "gui/$(id -u)/com.${USER}.whatsapp-bridge")
  • Also verify the ops mcp-proxy is up on :8090 (lsof -i :8090 | grep LISTEN) — Claude's MCP client connects through the proxy SSE endpoint, not directly to the bridge. If :8080 is up but :8090 is down, mcp__whatsapp__* tools will never load.
  • If either layer is down, surface the issue before WhatsApp operations
  • Do not declare WhatsApp MCP unavailable purely because tools haven't loaded yet — when both ports are LISTEN, retry ToolSearch select:mcp__whatsapp__list_chats,... up to 3× at 5s intervals to let the SSE handshake complete
  1. Ops memories: Check ${CLAUDE_PLUGIN_DATA_DIR}/memories/ before drafting any reply:
  • contact_*.md — load profile for the contact you're about to reply to
  • preferences.md — apply user's communication style and language preferences
  • topics_active.md — check for active threads or deadlines related to this contact
  • donts.md — never violate these restrictions in drafts

CLI/API Reference

whatsapp-bridge (WhatsApp — mcpwhatsapp\*)

Bridge health — check bridge is running before any WhatsApp operation. Same lsof probe across platforms; supervisor command differs:

lsof -i :8080 | grep LISTEN   # bridge listens on :8080 (same on macOS + Linux)

# macOS — launchd:
launchctl print "gui/$(id -u)/com.${USER}.whatsapp-bridge" 2>&1 | head -3   # use print, NOT list — list only shows already-loaded services

# Linux — systemd-user (installed by scripts/install-whatsapp-bridge-linux.sh):
systemctl --user is-active whatsapp-bridge.service
journalctl --user -u whatsapp-bridge.service -n 10 --no-pager

One-line cross-platform restart — use the in-repo wrapper when you

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.