Files
passepartout/literate/communication.org
Amr Gharbeia dd3873cd5e
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
DOCS: Systematic overhaul of Literate source (Granularity & Technical Reasoning)
2026-04-21 11:49:58 -04:00

3.9 KiB

Communication Protocol (communication.lisp)

Communication Protocol (communication.lisp)

Architectural Intent: Secure Inter-Process Communication

The Communication Protocol is the bridge between the OpenCortex microharness and the outside world. To maintain the "Zero-Bloat" mandate, the protocol must be:

  1. Lightweight: Minimal overhead for low-latency terminal interaction.
  2. Deterministic: Strict S-expression framing to prevent injection attacks.
  3. Transport-Agnostic: Capable of running over TCP, Unix Sockets, or Standard I/O.

By utilizing a length-prefixed S-expression format (the "Unified Envelope"), we ensure that both human-readable text and complex Lisp data structures can be transmitted securely without the fragility of JSON or the overhead of Protobuf.

Pipeline Initialization

(in-package :opencortex)

Message Framing

Frame Serialization (frame-message)

Every message leaving the harness must be "framed." This involves two steps:

  1. Sanitization: Stripping raw Lisp objects (like streams or sockets) that cannot be serialized.
  2. Prefixed Framing: Calculating the length of the S-expression and prepending it as a 6-character hexadecimal string.

Example Frame: 00001c(:TYPE :STATUS :SCRIBE :IDLE)

(defun sanitize-protocol-message (msg)
  "Recursively strips non-serializable objects (streams, sockets) from a protocol plist."
  (if (and msg (listp msg))
      (let ((clean nil))
        (loop for (k v) on msg by #'cddr
              do (unless (member k '(:reply-stream :socket :stream))
                   (push k clean)
                   (push (if (listp v) (sanitize-protocol-message v) v) clean)))
        (nreverse clean))
      msg))
(defun frame-message (msg)
  "Serializes a message plist and prefixes it with a 6-character hex length."
  (let* ((sanitized (sanitize-protocol-message msg))
         (payload (let ((*print-pretty* nil) (*read-eval* nil)) (format nil "~s" sanitized)))
         (len (length payload)))
    (format nil "~6,'0x~a" len payload)))

Message Ingestion

Framed Message Reader (read-framed-message)

The inverse of framing. This function reads exactly the number of bytes specified by the hex-length prefix. This "byte-counted" reading is a critical security measure—it prevents buffer overflow attacks and "slowloris" type hung connections.

(defun read-framed-message (stream)
  "Reads a hex-prefixed message from a stream. Returns the parsed Lisp plist or :EOF."
  (handler-case
      (let ((len-buf (make-string 6)))
        ;; 1. Read the length prefix
        (let ((count (read-sequence len-buf stream)))
          (if (< count 6)
              :eof
              (let ((len (ignore-errors (parse-integer len-buf :radix 16))))
                (if (and len (> len 0))
                    ;; 2. Read exactly 'len' bytes
                    (let ((payload-buf (make-string len)))
                      (read-sequence payload-buf stream)
                      (let ((*read-eval* nil))
                        (read-from-string payload-buf)))
                    :error)))))
    (error (c) 
      (harness-log "PROTOCOL ERROR: ~a" c)
      :error)))

Semantic Handshakes

Hello Message (make-hello-message)

The first message sent by the daemon upon client connection. It advertises the protocol version and the agent's current capabilities.

(defun make-hello-message (version)
  "Constructs the standard HELLO handshake message."
  (list :TYPE :EVENT 
        :PAYLOAD (list :ACTION :handshake 
                       :VERSION version 
                       :CAPABILITIES '(:AUTH :SWANK :ORG-AST))))