Files
memex/notes/org-skill-inbound-gateway.org

4.1 KiB

SKILL: Inbound Multi-Channel Gateway (Universal Literate Note)

Overview

The Inbound Multi-Channel Gateway provides the sensory interface for external messaging. It enables the agent to "hear" the user from various platforms (Signal, Telegram, SMS) by normalizing disparate inbound payloads into standard Neurosymbolic Kernel stimuli.

Phase A: Demand (PRD)

1. Purpose

Define a secure and extensible ingress for external communication channels.

2. User Needs

  • Multi-Channel Ingress: Support Signal (via signal-cli), Telegram (via Bot API), and generic Webhooks.
  • Payload Normalization: Convert platform-specific JSON into standard Lisp plists.
  • Security & Authentication: Verify sender identity before injecting stimuli into the kernel.
  • Asynchronous Reception: Non-blocking monitoring of inbound message queues.

3. Success Criteria

TODO Signal-cli message reception and parsing

TODO Telegram Bot API webhook normalization

TODO Sender verification logic (Whitelisting)

TODO Autonomous stimulus injection into the Kernel Bus

Phase B: Blueprint (PROTOCOL)

1. Architectural Intent

Interfaces for external sensory perception. Source of truth is the external API callbacks and local messaging daemons.

2. Semantic Interfaces

(defun gateway-normalize-signal (raw-json)
  "Transforms a Signal-cli message into an OACP :EVENT.")

(defun gateway-normalize-telegram (raw-json)
  "Transforms a Telegram Bot payload into an OACP :EVENT.")

(defun gateway-verify-sender (sender-id channel)
  "Ensures the message is from an authorized recipient.")

(defun gateway-process-inbound (message-event)
  "Routes the normalized message through the Economist for cheap classification, 
   then places it in the 'Holding Pen' (inbox.org).")

Phase D: Build (Implementation)

Normalization Logic

(defun gateway-verify-sender (sender-id channel)
  (let ((approved (uiop:getenv "RECIPIENT_ID")))
    (string= sender-id approved)))

(defun gateway-normalize-signal (raw-json)
  (let* ((data (cl-json:decode-json-from-string raw-json))
         (sender (cdr (assoc :source data)))
         (text (cdr (assoc :message data))))
    (if (gateway-verify-sender sender :signal)
        `(:type :EVENT :payload (:sensor :inbound-message :channel :signal :text ,text))
        (progn
          (kernel-log "GATEWAY - Rejected message from unauthorized sender: ~a" sender)
          nil))))

(defun gateway-process-inbound (message-event)
  "The Holding Pen logic. It uses a low-cost model to classify the message 
   and appends it to inbox.org."
  (let* ((text (getf (getf message-event :payload) :text))
         ;; Route through Economist for cheap classification
         (backend (org-agent:economist-route-task 2)) ; Low complexity
         (classification (org-agent:ask-neuro 
                          (format nil "Classify this text into one tag (e.g., :idea:, :todo:, :link:): ~a" text)
                          :system-prompt "You are a fast, cheap triage agent. Return ONLY the tag."
                          :cascade (list backend)))
         (inbox-path (or (uiop:getenv "INBOX_FILE") "inbox.org"))
         (timestamp (local-time:format-timestring nil (local-time:now) :format '("[" :year "-" :month "-" :day " " :weekday "]"))))
    
    (with-open-file (out inbox-path :direction :output :if-exists :append :if-does-not-exist :create)
      (format out "* INBOX ~a ~a~%  Captured via ~a at ~a~%  ~a~%~%" 
              classification text (getf (getf message-event :payload) :channel) timestamp text))
    (kernel-log "GATEWAY - Message routed to Holding Pen (~a)." inbox-path)))

Registration

(defskill :skill-inbound-gateway
  :priority 100
  :trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :inbound-message))
  :neuro (lambda (context) nil)
  :symbolic (lambda (action context) (gateway-process-inbound context) nil)) ; Side-effect only