#+TITLE: Communication Protocol (communication.lisp) #+AUTHOR: Amr #+FILETAGS: :harness:protocol: #+STARTUP: content * 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 #+begin_src lisp :tangle ../library/communication.lisp (in-package :opencortex) #+end_src * 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)~ #+begin_src lisp :tangle ../library/communication.lisp (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)) #+end_src #+begin_src lisp :tangle ../library/communication.lisp (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))) #+end_src * 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. #+begin_src lisp :tangle ../library/communication.lisp (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))) #+end_src * 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. #+begin_src lisp :tangle ../library/communication.lisp (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)))) #+end_src