fix(v0.2.0): resolve macro conflicts, sync load order, and fix skill packaging

- Standardized def-cognitive-tool to 5-argument signature.
- Consolidated *cognitive-tools* as a hash table in package.lisp.
- Removed skills from opencortex.asd to enforce dynamic Skill Engine loading.
- Added missing (in-package :opencortex) to various skill files.
- Fixed let/let* sequential binding issues in emacs-edit and self-edit.
- Updated opencortex.sh to initialize skills before running doctor.
- Fixed uiop:user-homedir-pathname usage in config-manager.
This commit is contained in:
2026-04-28 10:46:24 -04:00
parent 3dddfe3e3d
commit 80e327dd20
10 changed files with 81 additions and 63 deletions

View File

@@ -400,18 +400,8 @@ EXAMPLES:
#+begin_src lisp #+begin_src lisp
** Cognitive Tool Registration ** Cognitive Tool Registration
#+begin_src lisp :tangle (expand-file-name "skills.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness")) #+begin_src lisp :tangle (expand-file-name "skills.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
(defvar *cognitive-tools* nil "Registry of available Agent capabilities.") ;; Cognitive tools are registered in *cognitive-tools* (defined in package.lisp)
;; using the def-cognitive-tool macro.
(defmacro def-cognitive-tool (name arg-list &body body)
"Registers a new cognitive tool (capability) into the global registry."
`(setf (getf *cognitive-tools* ,name)
(list :args ',arg-list
:executor (lambda (args)
(let ,(mapcar (lambda (arg)
(let ((arg-name (if (listp arg) (first arg) arg)))
`(,arg-name (getf args ,(intern (string arg-name) :keyword)))))
arg-list)
,@body)))))
#+end_src #+end_src
(def-cognitive-tool :eval "Evaluates raw Common Lisp code in the harness image. Use this for complex calculations or internal state inspection." (def-cognitive-tool :eval "Evaluates raw Common Lisp code in the harness image. Use this for complex calculations or internal state inspection."

View File

@@ -18,23 +18,7 @@
(:file "harness/perceive") (:file "harness/perceive")
(:file "harness/reason") (:file "harness/reason")
(:file "harness/act") (:file "harness/act")
(:file "harness/loop") (:file "harness/loop"))
(:file "skills/org-skill-policy")
(:file "skills/org-skill-bouncer")
(:file "skills/org-skill-scribe")
(:file "skills/org-skill-gardener")
(:file "skills/org-skill-lisp-utils")
(:file "skills/org-skill-literate-programming")
(:file "skills/org-skill-engineering-standards")
(:file "skills/org-skill-self-edit")
(:file "skills/org-skill-emacs-edit")
(:file "skills/org-skill-tool-permissions")
(:file "skills/org-skill-self-fix")
(:file "skills/org-skill-peripheral-vision")
(:file "skills/org-skill-gateway-manager")
(:file "skills/org-skill-diagnostics")
(:file "skills/org-skill-config-manager"))
:build-operation "program-op" :build-operation "program-op"
:build-pathname "opencortex-server" :build-pathname "opencortex-server"

View File

@@ -99,6 +99,7 @@ case "$COMMAND" in
--eval '(load (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))' \ --eval '(load (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))' \
--eval "(push (truename \"$OC_DATA_DIR/\") asdf:*central-registry*)" \ --eval "(push (truename \"$OC_DATA_DIR/\") asdf:*central-registry*)" \
--eval '(ql:quickload :opencortex)' \ --eval '(ql:quickload :opencortex)' \
--eval '(opencortex:initialize-all-skills)' \
--eval '(opencortex:doctor-main)' --eval '(opencortex:doctor-main)'
;; ;;

View File

@@ -13,6 +13,7 @@ The *CLI Gateway* is the primary sensory and actuating interface for human inter
* Implementation * Implementation
#+begin_src lisp #+begin_src lisp
(in-package :opencortex)
(defvar *cli-port* 9105) (defvar *cli-port* 9105)
(defvar *cli-server-socket* nil) (defvar *cli-server-socket* nil)

View File

@@ -75,15 +75,38 @@ Secrets are appended to `~/.config/opencortex/.env`, while structural metadata i
** Registry Persistence ** Registry Persistence
#+begin_src lisp :tangle (expand-file-name "org-skill-config-manager.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills")) #+begin_src lisp :tangle (expand-file-name "org-skill-config-manager.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
(defvar *providers* nil "Global registry of configured LLM providers.") (defvar *providers* nil "Global registry of configured LLM providers.")
#+end_src
#+begin_src lisp :tangle (expand-file-name "org-skill-config-manager.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills")) (defun get-oc-config-dir ()
"Returns the XDG-compliant config directory for OpenCortex."
(let ((env (uiop:getenv "OC_CONFIG_DIR")))
(if (and env (> (length env) 0))
(uiop:ensure-directory-pathname env)
(uiop:merge-pathnames* ".config/opencortex/" (user-homedir-pathname)))))
(defun save-providers () (defun save-providers ()
"Persist provider configuration to XDG config directory." "Persist provider configuration to XDG config directory."
(let ((path (merge-pathnames "providers.lisp" (get-oc-config-dir)))) (let ((path (merge-pathnames "providers.lisp" (get-oc-config-dir))))
(ensure-directories-exist path) (ensure-directories-exist path)
(with-open-file (s path :direction :output :if-exists :supersede) (with-open-file (s path :direction :output :if-exists :supersede)
(format s ";;; OpenCortex Provider Metadata~%~s~%" *providers*)))) (format s ";;; OpenCortex Provider Metadata~%~s~%" *providers*))))
(defun prompt-for (label &optional default)
"Prompts the user for input on the CLI."
(format t "~a~@[ [~a]~]: " label default)
(finish-output)
(let ((input (read-line)))
(if (string= input "")
(or default "")
input)))
(defun save-secret (provider field val)
"Appends a secret to the XDG .env file."
(let ((env-file (merge-pathnames ".env" (get-oc-config-dir)))
(var-name (format nil "~:@(~a_~a~)" provider field)))
(ensure-directories-exist env-file)
(with-open-file (out env-file :direction :output :if-exists :append :if-does-not-exist :create)
(format out "~a=~a~%" var-name val))
(setf (uiop:getenv var-name) val)))
#+end_src #+end_src
** Registry API ** Registry API

View File

@@ -89,10 +89,10 @@ Converts AST back to org format, preserving structure.
(defun emacs-edit-print-headline (ast &key indent-level) (defun emacs-edit-print-headline (ast &key indent-level)
"Converts a HEADLINE AST node to org text. "Converts a HEADLINE AST node to org text.
INDENT-LEVEL is number of leading asterisks." INDENT-LEVEL is number of leading asterisks."
(let ((level (or indent-level 1)) (let* ((level (or indent-level 1))
(stars (make-string level :initial-element #\*)) (stars (make-string level :initial-element #\*))
(title (or (getf (getf ast :properties) :TITLE) "")) (title (or (getf (getf ast :properties) :TITLE) ""))
(todo (getf (getf ast :properties) :TODO))) (todo (getf (getf ast :properties) :TODO)))
(format nil "~a ~a~%~a" (format nil "~a ~a~%~a"
stars stars
(if todo (format nil "[~a] " (string-upcase todo)) "") (if todo (format nil "[~a] " (string-upcase todo)) "")
@@ -200,17 +200,17 @@ Add a new headline to an existing AST.
(defun emacs-edit-add-headline (ast title &key todo properties) (defun emacs-edit-add-headline (ast title &key todo properties)
"Adds a new headline to AST. "Adds a new headline to AST.
Returns modified AST." Returns modified AST."
(let ((new-id (emacs-edit-generate-id)) (let* ((new-id (emacs-edit-generate-id))
(new-props (list :ID new-id (new-props (list :ID new-id
:TITLE title :TITLE title
:TODO (or todo "TODO") :TODO (or todo "TODO")
:CREATED (format nil "[~a]" :CREATED (format nil "[~a]"
(multiple-value-bind (s mi h d mo y) (multiple-value-bind (s mi h d mo y)
(decode-universal-time (get-universal-time)) (decode-universal-time (get-universal-time))
(format nil "~a-~a-~a ~a:~a" (format nil "~a-~a-~a ~a:~a"
y mo d h mi))))) y mo d h mi)))))
(merged-props (loop for (k v) on properties by #'cddr (merged-props (loop for (k v) on properties by #'cddr
collect k collect v))) collect k collect v)))
(setf merged-props (append merged-props new-props)) (setf merged-props (append merged-props new-props))

View File

@@ -13,6 +13,7 @@ The *Homoiconic Memory* skill provides the core persistence layer for OpenCortex
* Implementation * Implementation
#+begin_src lisp #+begin_src lisp
(in-package :opencortex)
(defun memory-org-to-json (source) (defun memory-org-to-json (source)
"Converts Org-mode source to JSON AST." "Converts Org-mode source to JSON AST."

View File

@@ -49,23 +49,33 @@ The *LLM Gateway* skill provides a unified interface for interacting with multip
** Cognitive Tools ** Cognitive Tools
#+begin_src lisp :tangle (expand-file-name "org-skill-llm-gateway.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills")) #+begin_src lisp :tangle (expand-file-name "org-skill-llm-gateway.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
(def-cognitive-tool :get-ollama-embedding (text) (def-cognitive-tool :get-ollama-embedding
(let* ((host (or (uiop:getenv "OLLAMA_HOST") "localhost:11434")) "Generates vector embeddings via Ollama API."
(url (format nil "http://~a/api/embeddings" host)) ((:text :type :string :description "Text to embed."))
(body (cl-json:encode-json-to-string `((model . "nomic-embed-text") (prompt . ,text))))) :body (lambda (args)
(handler-case (let ((text (getf args :text)))
(let* ((response (dex:post url :headers '(("Content-Type" . "application/json")) :content body)) (let* ((host (or (uiop:getenv "OLLAMA_HOST") "localhost:11434"))
(json (cl-json:decode-json-from-string response))) (url (format nil "http://~a/api/embeddings" host))
(cdr (assoc :embedding json))) (body (cl-json:encode-json-to-string `((model . "nomic-embed-text") (prompt . ,text)))))
(error (c) (harness-log "OLLAMA EMBED ERROR: ~a" c) nil)))) (handler-case
(let* ((response (dex:post url :headers '(("Content-Type" . "application/json")) :content body))
(json (cl-json:decode-json-from-string response)))
(cdr (assoc :embedding json)))
(error (c) (harness-log "OLLAMA EMBED ERROR: ~a" c) nil))))))
#+end_src #+end_src
#+begin_src lisp :tangle (expand-file-name "org-skill-llm-gateway.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills")) #+begin_src lisp :tangle (expand-file-name "org-skill-llm-gateway.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
(def-cognitive-tool :ask-llm (prompt system-prompt provider model) (def-cognitive-tool :ask-llm
(execute-llm-request :prompt prompt "Unified interface for interacting with LLM providers."
:system-prompt system-prompt ((:prompt :type :string :description "The user prompt")
:provider provider (:system-prompt :type :string :description "The system prompt (optional)")
:model model)) (:provider :type :keyword :description "The provider (e.g., :ollama, :openai)")
(:model :type :string :description "The model name"))
:body (lambda (args)
(execute-llm-request :prompt (getf args :prompt)
:system-prompt (getf args :system-prompt)
:provider (getf args :provider)
:model (getf args :model))))
#+end_src #+end_src
** Skill Registration ** Skill Registration

View File

@@ -37,6 +37,13 @@ Fast paren balancing for syntax errors.
(concatenate 'string code (make-string (- opens closes) :initial-element #\)))) (concatenate 'string code (make-string (- opens closes) :initial-element #\))))
((> closes opens) ((> closes opens)
(concatenate 'string (make-string (- closes opens) :initial-element #\() code))))) (concatenate 'string (make-string (- closes opens) :initial-element #\() code)))))
(defun copy-hash-table (table)
"Returns a shallow copy of a hash table."
(let ((new-table (make-hash-table :test (hash-table-test table)
:size (hash-table-count table))))
(maphash (lambda (k v) (setf (gethash k new-table) v)) table)
new-table))
#+end_src #+end_src
** Parse Target Location ** Parse Target Location
@@ -152,8 +159,8 @@ Provide a fixed version of the code as a lisp form.")
"Balances parentheses in a code string." "Balances parentheses in a code string."
((:code :type :string :description "The code to balance")) ((:code :type :string :description "The code to balance"))
:body (lambda (args) :body (lambda (args)
(let ((code (getf args :code)) (let* ((code (getf args :code))
(balanced (self-edit-balance-parens code))) (balanced (self-edit-balance-parens code)))
(handler-case (handler-case
(progn (progn
(read-from-string balanced) (read-from-string balanced)

View File

@@ -12,7 +12,8 @@ The *Shell Actuator* provides a controlled interface for the OpenCortex to execu
* Implementation * Implementation
#+begin_src lisp #+begin_src lisp :tangle (expand-file-name "org-skill-shell-actuator.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
(in-package :opencortex)
(defparameter *allowed-commands* '("ls" "git" "rg" "grep" "date" "echo" "cat" "node" "python3" "sbcl")) (defparameter *allowed-commands* '("ls" "git" "rg" "grep" "date" "echo" "cat" "node" "python3" "sbcl"))