4.5 KiB
SKILL: Emacs Bridge Agent (Actuator/Sensor I/O)
Overview
The Emacs Bridge Agent is the system's primary sensory and motor interface to the Emacs environment. It abstracts the complexities of TCP socket management and protocol framing, allowing the core cognitive kernel to interact with the user's buffers as if they were native data structures.
The Bridge Mandate
- Isolation: The core kernel must remain agnostic of the underlying transport layer (TCP).
- Persistence: The bridge must maintain a stable, multi-client server to handle simultaneous Emacs sessions.
- Dispatch: It must reliably route cognitive decisions (actions) to the correct actuator and capture user events (sensors) for processing.
Symbolic Implementation (The Logic)
This skill is unique in that it initializes the system's I/O infrastructure rather than performing high-level reasoning.
Architectural Intent: TCP Sensory Layer
This section establishes the socket listener and the handler for incoming Org-Agent Communication Protocol (OACP) messages. It ensures that every user action in Emacs is piped directly into the kernel's cognitive loop.
(defvar *emacs-server-thread* nil)
(defvar *emacs-server-socket* nil)
(defvar *active-emacs-clients* nil "List of active Emacs socket streams.")
(defvar *emacs-clients-lock* (bt:make-lock "emacs-clients-lock"))
(defun handle-emacs-client (stream)
"Handle a single OACP connection from Emacs."
(bt:with-lock-held (*emacs-clients-lock*)
(push stream *active-emacs-clients*))
(unwind-protect
(handler-case
(loop
(let* ((len-buf (make-string 6))
(read-len (read-sequence len-buf stream)))
(when (zerop read-len) (return))
(let* ((msg-len (parse-integer len-buf :radix 16))
(msg-buf (make-string msg-len)))
(read-sequence msg-buf stream)
(let ((plist (read-from-string msg-buf)))
(org-agent:kernel-log "BRIDGE: Received message type ~a" (getf plist :type))
;; PROCESS: Send the message through the 4-stage cognitive loop
(org-agent:cognitive-loop plist)))))
(error (c) (org-agent:kernel-log "BRIDGE ERROR: ~a" c)))
(bt:with-lock-held (*emacs-clients-lock*)
(setf *active-emacs-clients* (remove stream *active-emacs-clients*)))
(close stream)))
(defun start-emacs-server (&key (port 9105))
"Start the OACP listener for Emacs."
(setf *emacs-server-socket* (usocket:socket-listen "0.0.0.0" port :reuse-address t))
(setf *emacs-server-thread*
(bt:make-thread
(lambda ()
(loop
(let ((conn (usocket:socket-accept *emacs-server-socket*)))
(bt:make-thread (lambda () (handle-emacs-client (usocket:socket-stream conn)))
:name "org-agent-emacs-handler"))))
:name "org-agent-emacs-daemon"))
(org-agent:kernel-log "BRIDGE: Listening on port ~a" port))
Architectural Intent: Outbound Actuation
The dispatcher translates internal symbolic actions into framed OACP messages, broadcasting them to all connected Emacs clients to update the UI or refactor buffers.
(defun broadcast-to-emacs (action-plist)
"Translate an action into OACP framing and send to all connected Emacs clients."
(let ((action-msg (org-agent:frame-message (prin1-to-string action-plist))))
(bt:with-lock-held (*emacs-clients-lock*)
(dolist (client *active-emacs-clients*)
(ignore-errors
(write-string action-msg client)
(force-output client))))))
Registration
Architectural Intent: Core Integration
This block bootstraps the server and registers the `:emacs` actuator with the kernel's event bus, ensuring the bridge is active from the moment the skill is loaded.
;; Register the actuator with the core Event Bus
(org-agent:register-actuator :emacs #'broadcast-to-emacs)
;; Register as a skill so it appears on the dashboard
(defskill :skill-emacs-bridge
:priority 100
:trigger (lambda (context) nil)
:neuro (lambda (context) nil)
:symbolic (lambda (action context) action))
;; Start the socket server when this skill is loaded by the daemon
(let* ((env-port (uiop:getenv "ORG_AGENT_DAEMON_PORT"))
(port (if env-port (parse-integer env-port :junk-allowed t) 9105)))
(unless *emacs-server-thread*
(start-emacs-server :port port)))