Skip to content

Messaging Hub

This tutorial walks through examples/messaging_hub/smart_inbox.py — a script that connects OpenJarvis to messaging platforms, triages incoming messages by priority, drafts context-aware replies, and produces end-of-day summaries. It demonstrates channel integration, structured agent output, and memory-backed aggregation across multiple messages.

Prerequisites

  • Python 3.10 or later
  • OpenJarvis installed: uv sync --extra dev from the repository root
  • An inference engine running (Ollama with qwen3:8b pulled, or cloud API keys)
  • For live channel mode: channel-specific credentials (see Setting Up Real Channels)

Quick Start: Demo Mode

Demo mode processes five sample messages with no channel setup or credentials required. It is the fastest way to see the triage pipeline in action:

Terminal
python examples/messaging_hub/smart_inbox.py --demo

Expected output (abbreviated):

Smart Inbox — Demo Mode
Model: qwen3:8b  |  Engine: ollama
============================================================
Processing 5 messages...

  [1/5] Classifying: URGENT: Server is down in production...
           -> URGENT
  [2/5] Classifying: Hey, just wanted to share this interest...
           -> FYI
  [3/5] Classifying: Can you review my PR #42 by end of day...
           -> ACTION_REQUIRED
  [4/5] Classifying: Meeting reminder: Team standup at 10am...
           -> FYI
  [5/5] Classifying: Buy now! Limited time offer on premium...
           -> SPAM

  #   Category          Message                             Reply
  ---------------------------------------------------------------
  1   URGENT            URGENT: Server is down...           On it — escalating now.
  2   FYI               Hey, just wanted to share...        Thanks for sharing!
  3   ACTION_REQUIRED   Can you review my PR #42...         Will review before EOD.
  4   FYI               Meeting reminder: Team standup...   N/A
  5   SPAM              Buy now! Limited time offer...      N/A

Generating end-of-day summary...

Override the model or engine:

Terminal
python examples/messaging_hub/smart_inbox.py --demo --model gpt-4o --engine cloud

How Message Classification Works

Each incoming message goes through a structured prompt that asks the agent to output exactly two fields — a category and a reply — in a parseable format. The script then extracts those fields and builds a triage table.

graph TD
    A[Incoming message] --> B[OrchestratorAgent]
    B --> C{think tool: internal reasoning}
    C --> D{memory_store: persist context}
    D --> E[Structured response]
    E --> F{Parse CATEGORY and REPLY}
    F -->|URGENT| G[Flag for immediate attention]
    F -->|ACTION_REQUIRED| H[Add to action list]
    F -->|FYI| I[Log for reference]
    F -->|SPAM| J[Discard]
    G --> K[Triage table]
    H --> K
    I --> K
    J --> K
    K --> L[memory_search: cross-reference]
    L --> M[End-of-day summary]

After all messages are processed, a second orchestrator call uses memory_search to retrieve the stored triage log and produces a grouped summary with open action items highlighted.

The Classification Prompt

The agent receives a structured prompt that specifies the output format exactly. This makes the response reliably parseable without a complex schema:

examples/messaging_hub/smart_inbox.py
CLASSIFICATION_PROMPT = (
    "You are a smart inbox assistant. Classify the following message into "
    "exactly one category: URGENT, ACTION_REQUIRED, FYI, or SPAM.\n"
    "Then draft a short reply if appropriate (not for SPAM).\n\n"
    "Respond in this exact format:\n"
    "CATEGORY: <category>\n"
    "REPLY: <reply or N/A>\n\n"
    "Message:\n{message}"
)

The think tool lets the agent reason internally before committing to a category, and memory_store persists each classification so the summary prompt can reference the full triage log.

Setting Up Real Channels

  1. Add the Slack MCP server to your configuration:

    Terminal
    jarvis add slack
    
  2. Set your credentials in .env (gitignored):

    .env
    SLACK_BOT_TOKEN=xoxb-...
    SLACK_APP_TOKEN=xapp-...
    
  3. Invite the bot to the target Slack channel in the Slack workspace settings.

  4. Run the script in live channel mode:

    Terminal
    python examples/messaging_hub/smart_inbox.py --channel slack
    
  1. Ensure Node.js 22 or later is installed.

  2. Configure the WhatsApp Baileys bridge. See the channel documentation for full setup steps.

  3. Start the bridge — it will print a QR code. Scan it with the WhatsApp mobile app to authenticate.

  4. Run the script:

    Terminal
    python examples/messaging_hub/smart_inbox.py --channel whatsapp
    

OpenJarvis supports LINE, Viber, Mastodon, Rocket.Chat, Zulip, XMPP, Twitch, Nostr, and more. List all available channels:

Terminal
jarvis channel list
jarvis channel status

Each channel requires its own environment variables. Run jarvis add <channel> where available to auto-generate the configuration template.

Live channel mode

Live channel mode requires channel credentials and the corresponding channel subsystem to be running. Use --demo to verify the triage logic before connecting to a real channel.

Channel Configuration via TOML

The messaging.toml recipe in examples/messaging_hub/ captures the agent and channel defaults declaratively:

examples/messaging_hub/messaging.toml
[channel]
default = "slack"

[agent]
type = "orchestrator"
max_turns = 5
temperature = 0.3
tools = ["think", "memory_store", "memory_search"]

You can load this recipe programmatically:

Loading the messaging recipe
from openjarvis.recipes import load_recipe
from openjarvis import SystemBuilder

recipe = load_recipe("examples/messaging_hub/messaging.toml")
system = SystemBuilder(**recipe.to_builder_kwargs()).build()
response = system.ask(CLASSIFICATION_PROMPT.format(message=incoming_message))
system.close()

Adding Custom Triage Rules

Extend the classification categories by editing CLASSIFICATION_PROMPT. For example, to add a FOLLOW_UP category for messages that need a response within 48 hours:

Custom classification prompt
CLASSIFICATION_PROMPT = (
    "Classify into: URGENT, ACTION_REQUIRED, FOLLOW_UP, FYI, or SPAM.\n"
    "Then draft a short reply if appropriate (not for SPAM).\n\n"
    "Respond in this exact format:\n"
    "CATEGORY: <category>\n"
    "REPLY: <reply or N/A>\n\n"
    "Message:\n{message}"
)

You can also add domain rules in the system prompt via messaging.toml — for instance, routing any message containing "P0" or "incident" directly to URGENT regardless of phrasing.

Scheduling the Daily Summary

After processing all messages, the end-of-day summary call runs immediately in the script. For production use, schedule it independently via the OpenJarvis scheduler:

Terminal
jarvis scheduler create "Daily inbox summary" \
    --type cron --value "0 17 * * *"

Or use the operator recipe pattern to run a persistent triage agent on a schedule. See the operator recipes in src/openjarvis/recipes/data/operators/ for ready-made examples.

See Also