OPS ► INBOX ZERO
Runtime Context
Before executing, load available context:
-
Preferences: Read
${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.jsondefault_channels— which channels to scan by defaultsecrets_manager/doppler— how to resolve channel credentials if not in env
-
Daemon health: Read
${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json- Check
wacli-syncstatus — if not running or auth needed, skip WhatsApp and surface the issue - Also check
~/.wacli/.healthfor live auth status before any wacli command
- Check
-
Ops memories: Check
${CLAUDE_PLUGIN_DATA_DIR}/memories/before drafting any reply:contact_*.md— load profile for the contact you're about to reply topreferences.md— apply user's communication style and language preferencestopics_active.md— check for active threads or deadlines related to this contactdonts.md— never violate these restrictions in drafts
CLI/API Reference
wacli (WhatsApp)
Health file — check ~/.wacli/.health BEFORE any wacli command:
status=connected→ proceed normallystatus=needs_auth→ prompt user: "Runwacli authin terminal, scan QR"status=needs_reauth→ prompt user: "WhatsApp session expired. Runwacli authto re-pair"- File missing → fall back to
wacli doctor --json
| Command | Usage | Output |
|---|---|---|
wacli doctor --json | Check auth/connected/lock/FTS | {data: {authenticated, connected, lock_held, fts_enabled}} |
wacli chats list --json | All chats | {data: [{JID, Name, Kind, LastMessageTS}]} |
wacli messages list --chat "<JID>" --limit N --json | Messages for chat | {data: {messages: [{FromMe, Text, Timestamp, SenderName, ChatName}]}} |
wacli messages search --query "<text>" --json | FTS search | Same as above |
wacli contacts --search "<name>" --json | Contact lookup | Contact objects |
wacli send --to "<JID>" --message "<msg>" | Send text | Success/error |
wacli history backfill --chat="<JID>" --count=50 --requests=2 --wait=30s --idle-exit=5s --json | Fetch older messages | Backfill result |
gog CLI (Gmail/Calendar)
| Command | Usage | Output |
|---|---|---|
gog gmail search "in:inbox" --max 50 -j --results-only --no-input | Full inbox scan | JSON array of threads |
gog gmail thread get <threadId> -j | Get full thread with all messages | Full message JSON |
gog gmail get <messageId> -j | Get single message | Message JSON |
gog gmail archive <messageId> ... --no-input --force | Archive messages (remove from inbox) | Archive result |
gog gmail archive --query "<gmail-query>" --max N --force | Archive by query | Archive result |
gog gmail send --to "<email>" --subject "<subj>" --body "<body>" | Send email | Send result |
gog gmail send --reply-to-message-id <msgId> --reply-all --body "text" | Reply all | Send result |
gog gmail mark-read <messageId> ... --no-input | Mark as read | Result |
gog gmail labels list -j | List all labels | Labels JSON |
Agent Teams support
If CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 is set, use Agent Teams when processing "all channels" mode. This enables:
- Channel agents run in parallel but can share context (e.g., WhatsApp agent finds a message referencing an email thread → email agent can prioritize it)
- You can steer agents: "skip WhatsApp for now, focus on email first"
- Agents report completion per-channel so you can process replies as they come in
Team setup (only when flag is enabled, "all channels" mode):
TeamCreate("inbox-channels")
Agent(team_name="inbox-channels", name="whatsapp-scanner", ...)
Agent(team_name="inbox-channels", name="email-scanner", ...)
Agent(team_name="inbox-channels", name="slack-scanner", ...)
Agent(team_name="inbox-channels", name="telegram-scanner", ...)
Agent(team_name="inbox-channels", name="notion-scanner", ...)
Each agent scans its channel and reports back classified results. You then process NEEDS_REPLY items across all channels in priority order.
If the flag is NOT set, process channels sequentially or use fire-and-forget subagents.
Pre-gathered data
${CLAUDE_PLUGIN_ROOT}/../../bin/ops-unread 2>/dev/null || echo '{}'
Environment variables
All channel credentials come from env vars or CLI auth — no hardcoded secrets.
| Variable | Default | Purpose |
|---|---|---|
GMAIL_ACCOUNT | auto-detect | Gmail account for gog CLI |
SLACK_MCP_ENABLED | false | Set true when Slack MCP server is configured |
TELEGRAM_ENABLED | false | Set true when Telegram user-auth MCP is configured |
NOTION_MCP_ENABLED | false | Set true when Notion MCP integration is configured |
WACLI_STORE | ~/.wacli | wacli store directory |
Core principle: FULL INBOX SCAN
Do NOT just check unread. Scan the FULL recent inbox for each channel and classify every conversation:
Core principle: FULL CONTEXT — NEVER ASSUME
CRITICAL SAFETY RULE — NEVER SEND WITHOUT UNDERSTANDING: Before drafting or sending ANY reply on ANY channel, you MUST have read the FULL conversation history (20+ messages) and PROVEN you understand it by summarizing:
- What the conversation is about
- What each party said (distinguish user messages from contact messages)
- What the contact is actually asking/saying in their last message
- What a sensible reply would address
Failure mode this prevents: An agent reads only the last message "je kan het toch uit Klaviyo halen?" and replies "Welke data heb je nodig?" — completely wrong because the contact was telling the user to pull data themselves (they have 2FA), not asking for data. Without the full thread, the reply was nonsensical and confused the contact.
Hard rule: if you cannot summarize the conversation arc in 2 sentences, you have not read enough messages. Go back and read more.
The user does NOT remember every thread. For EVERY message you present, you MUST build full context BEFORE showing it. Never show just a subject line and ask "what do you want to do?" — the user needs to understand what it's about first.
For every NEEDS REPLY item, gather this context automatically:
- Full thread body — read the ENTIRE thread (
gog gmail thread get/wacli messages list --limit 20), not just the last message. Summarize the full conversation arc. - Contact profile — search across channels to build a card:
gog gmail search "from:<contact_email>" --max 10— recent email historywacli contacts --search "<name>" --json— WhatsApp presencewacli messages search --query "<name>" --json --limit 5— recent WhatsApp mentions- If Linear configured: search for issues assigned to or mentioning this contact
- Present: who they are, role/company, last N interactions, relationship context
- Topic context — identify the subject matter and search for related threads:
gog gmail search "subject:<keywords>" --max 5— related email threadswacli messages search --query "<topic keywords>" --json --limit 5— related WA messages- Summarize: what this topic is about, any deadlines, any pending decisions
- ops-memories (if available) — check
~/.claude/plugins/data/ops-ops-marketplace/memories/for any stored context about this contact or topic
When presenting a NEEDS REPLY item:
━━━ [Contact Name] — [Subject] ━━━
Who: [role, company, relationship — from contact search]
History: [last 3 interactions across channels]
Thread: [2-3 sentence summary of full conversation arc]
Last msg: [full body of their last message]
Context: [related threads/decisions/deadlines found]
Draft reply: "[contextually aware draft ba