:PROPERTIES: :ID: 59ac52fb-2310-4a9d-8e4e-0263af15181c :CREATED: [2026-03-30 Mon 21:16] :EDITED: [2026-04-07 Tue 13:42] :END: #+TITLE: SKILL: Emacs Bridge Agent (Universal Literate Note) #+STARTUP: content #+FILETAGS: :bridge:emacs:io:system:psf: * Overview The *Emacs Bridge Agent* is the primary sensory and motor interface to Emacs. It abstracts TCP socket management, allowing the core kernel to interact with buffers as native data structures. * Phase A: Demand (PRD) :PROPERTIES: :STATUS: FROZEN :END: ** 1. Purpose Define the transport layer for OpenCortex Communication Protocol (Harness Communication). ** 2. User Needs - *Isolation:* Kernel remains transport-agnostic. - *Persistence:* Multi-client server support for simultaneous sessions. - *Dispatch:* Reliable routing of actions to actuators and sensors to the kernel. ** 3. Success Criteria *** TODO Socket Listener Initialization *** TODO Multi-client Connection Handling *** TODO Harness Communication Message Framing Verification * Phase B: Blueprint (PROTOCOL) :PROPERTIES: :STATUS: SIGNED :END: ** 1. Architectural Intent Interfaces for TCP I/O and protocol framing. Source of truth is the Harness Communication specification. ** 2. Semantic Interfaces #+begin_src lisp (defun start-emacs-server (&key (port 9105)) "Starts the Harness Communication listener.") (defun broadcast-to-emacs (action-plist) "Sends a framed message to all connected clients.") #+end_src * Phase D: Build (Implementation) ** TCP Sensory Layer #+begin_src lisp :tangle ../projects/org-skill-emacs-bridge/src/bridge-logic.lisp (defun handle-emacs-client (stream) ;; Logic for parsing length-prefixed Harness Communication messages (format nil "Handling client on stream: ~a" stream)) #+end_src ** Outbound Actuation #+begin_src lisp :tangle ../projects/org-skill-emacs-bridge/src/bridge-logic.lisp (defun stream-to-emacs (stream action-plist) "Streams a chunk of data to a specific Emacs client over Harness Communication using framing." (let* ((type (or (getf action-plist :type) :request)) (payload (getf action-plist :payload)) ;; Ensure Emacs always receives a :payload drawer (envelope (if (and (getf action-plist :type) payload) action-plist (let ((clean-payload (copy-list action-plist))) (remf clean-payload :type) (remf clean-payload :id) (list :type type :id (or (getf action-plist :id) (get-universal-time)) :payload clean-payload)))) (msg (prin1-to-string envelope)) (len (length msg)) (framed (format nil "~6,'0x~a" len msg))) (handler-case (progn (write-string framed stream) (finish-output stream)) (error (c) (kernel-log "BRIDGE - Lost client: ~a" stream) (opencortex:unregister-emacs-client stream))))) (defun broadcast-to-emacs (action-plist context) "Sends a framed message back to the client that sent the stimulus, or all clients if async." (let ((stream (getf context :reply-stream))) (if stream (stream-to-emacs stream action-plist) (progn (kernel-log "BRIDGE - Async broadcast to all clients...") (bt:with-lock-held (opencortex:*clients-lock*) (dolist (s opencortex:*emacs-clients*) (stream-to-emacs s action-plist))))))) #+end_src * Registration #+begin_src lisp (opencortex:register-actuator :emacs #'broadcast-to-emacs) (defskill :skill-emacs-bridge :priority 100 :trigger (lambda (context) nil) :probabilistic (lambda (context) nil) :deterministic (lambda (action context) action)) #+end_src