life-docs/messenger-integration.md
2026-03-20 09:32:20 -07:00

8.8 KiB

Messenger Integration

How life-manager connects to the messenger platform. Four integration points, each with a distinct data flow and auth mechanism.

Overview

┌──────────────────────┐                        ┌──────────────────────┐
│   LIFE-MANAGER :3700 │                        │   MESSENGER :3100    │
│                       │                        │                      │
│  ┌─────────────────┐ │  ── proxy ──────────▶  │  Browse API          │
│  │ Messages Proxy  │ │  ── enqueue ────────▶  │  Send Queue          │
│  │ AI Loop         │ │  ── poll ───────────▶  │  Service API         │
│  │ Health Checker  │ │  ── health ─────────▶  │  Health Controller   │
│  └─────────────────┘ │                        │                      │
│                       │  ◀── credentials ────  │  Credential Service  │
│  Credential Keyring   │                        │                      │
└──────────────────────┘                        └──────────────────────┘

1. Messenger Proxy Module

Life-manager's /api/messages/* endpoints proxy to messenger's browse and queue APIs. The web frontend talks to life-manager only — never directly to messenger.

Life-Manager UI  →  /api/messages/conversations  →  Messenger /api/browse/conversations
                    /api/messages/folders             /api/browse/folders
                    /api/messages/search              /api/browse/search
                    /api/messages/stats               /api/browse/stats
                    /api/messages/self                /api/messages/self
                    /api/messages/queue-stats         /api/send-queue/stats
                    /api/messages/queue-history       /api/send-queue/history
                    /api/messages/attachment           (streams file directly)

Auth: X-Service-Key header, value from MESSENGER_API_KEY env var.

Config: MESSENGER_API_URL (default http://localhost:3100).

Life-manager code: messages-proxy.service.ts, messages.controller.ts

2. Messaging AI Loop

Polls messenger every minute for self-addressed messages (sent from the user's own phone to themselves). Each new message routes through the agent system, gets an LLM response, and replies via the send queue.

life-manager                         messenger
 ┌──────────────┐  GET /messages/self  ┌──────────────┐
 │messaging-loop│─────────────────────▶│  service-api  │
 │  (cron 1m)   │                      │  controller   │
 │              │◀─────────────────────│              │
 │  new msgs    │   messages since T   └──────────────┘
 │      │       │
 │      ▼       │
 │ agent-router │───▶ LLM :8210
 │      │       │
 │      ▼       │
 │  send reply  │  POST /send-queue/enqueue  ┌──────────────┐
 │              │───────────────────────────▶│  send-queue   │
 └──────────────┘                            └──────┬───────┘
                                                    │
                                             macOS agent polls
                                                    ▼
                                             sends via Messages.app

Guard: Only runs when user_awake setting is true.

Auth: X-Service-Key header on all requests to messenger.

Timestamp tracking: messaging.lastProcessed setting stores the high-water mark.

Life-manager code: messaging-loop.service.ts, messaging-conversation.service.ts

3. Credential Keyring

Messenger fetches IMAP/SMTP credentials from life-manager's keyring at startup. Falls back to env vars if life-manager is unavailable.

messenger (onModuleInit)           life-manager
 ┌──────────────┐  GET /api/credentials  ┌──────────────┐  SELECT    ┌─────────┐
 │ credential   │──────────────────────▶│  keyring      │──────────▶│ Postgres│
 │ service      │                       │  controller   │  decrypt  │ :25471  │
 │              │◀──────────────────────│              │◀──────────│         │
 │  imap creds  │    {user, pass, host} └──────────────┘           └─────────┘
 └──────┬───────┘
        │
        ▼
 connect IMAP/SMTP (Proton Bridge :1143, iCloud :993)

Direction: Messenger → life-manager (reverse of the other integrations).

Encryption: pgcrypto at rest in keyring_credentials table.

Credentials stored: icloud-imap, protonmail-imap (each with host, port, user, pass, tls, poll interval).

Messenger code: credential.service.ts

4. Service Health Check

Life-manager's health module pings messenger to report combined system status.

life-manager                          messenger
 ┌──────────────┐  GET /api/health/status  ┌──────────────┐
 │ messenger   │─────────────────────────▶│  health      │
 │  checker     │                          │  controller  │
 │              │◀─────────────────────────│              │
 │  {healthy,   │   {db_ok, device_info,   └──────────────┘
 │   latency}   │    last_seen}
 └──────────────┘

Degraded status: If last device sync was >5 minutes ago, reports degraded rather than healthy.

Config: MESSENGER_API_URL, optional MESSENGER_API_KEY.

Life-manager code: messenger.checker.ts

Message Send — Two Entry Points

Both life-manager (AI loop) and Claude Code (MCP) can send messages. They converge on the same queue:

┌──────────┐               ┌──────────┐  INSERT INTO    ┌──────────┐  GET /pending  ┌──────────┐
│  Claude  │  send_message │  MCP     │  pending_msgs   │ Postgres │◀──────────────│  Swift   │
│  Code    │──────────────▶│  Server  │────────────────▶│ messenger│               │  Agent   │
└──────────┘               └──────────┘  (direct SQL)   └──────────┘               └────┬─────┘
                                                                                       │
   ┌──────────┐               ┌──────────┐  POST /result  ┌──────────┐  AppleScript    │
   │  Life    │  POST enqueue │  Sync    │◀──────────────│  Swift   │◀───────────────┘
   │  Manager │──────────────▶│  API     │               │  Agent   │  send via
   └──────────┘  (HTTP)       │  :3100   │               └──────────┘  Messages.app
                              └──────────┘
  • MCP Server: Writes directly to pending_messages table via SQL
  • Life-Manager: Calls POST /api/send-queue/enqueue via HTTP with service key auth

Both paths result in the macOS agent picking up the message on its next poll.

Environment Variables

Variable Used By Purpose
MESSENGER_API_URL life-manager Base URL for messenger API (default: http://localhost:3100)
MESSENGER_API_KEY life-manager Service key sent as X-Service-Key header
LIFE_MANAGER_API_URL messenger Base URL for credential fetches (default: http://localhost:3700/api)
SERVICE_API_KEY messenger Validates incoming X-Service-Key headers