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
** Cognitive Tool Registration
#+begin_src lisp :tangle (expand-file-name "skills.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
(defvar *cognitive-tools* nil "Registry of available Agent capabilities.")
(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)))))
;; Cognitive tools are registered in *cognitive-tools* (defined in package.lisp)
;; using the def-cognitive-tool macro.
#+end_src
(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/reason")
(:file "harness/act")
(: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"))
(:file "harness/loop"))
:build-operation "program-op"
:build-pathname "opencortex-server"

View File

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

View File

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

View File

@@ -75,15 +75,38 @@ Secrets are appended to `~/.config/opencortex/.env`, while structural metadata i
** Registry Persistence
#+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.")
#+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 ()
"Persist provider configuration to XDG config directory."
(let ((path (merge-pathnames "providers.lisp" (get-oc-config-dir))))
(ensure-directories-exist path)
(with-open-file (s path :direction :output :if-exists :supersede)
(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
** 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)
"Converts a HEADLINE AST node to org text.
INDENT-LEVEL is number of leading asterisks."
(let ((level (or indent-level 1))
(stars (make-string level :initial-element #\*))
(title (or (getf (getf ast :properties) :TITLE) ""))
(todo (getf (getf ast :properties) :TODO)))
(let* ((level (or indent-level 1))
(stars (make-string level :initial-element #\*))
(title (or (getf (getf ast :properties) :TITLE) ""))
(todo (getf (getf ast :properties) :TODO)))
(format nil "~a ~a~%~a"
stars
(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)
"Adds a new headline to AST.
Returns modified AST."
(let ((new-id (emacs-edit-generate-id))
(new-props (list :ID new-id
:TITLE title
:TODO (or todo "TODO")
:CREATED (format nil "[~a]"
(multiple-value-bind (s mi h d mo y)
(decode-universal-time (get-universal-time))
(format nil "~a-~a-~a ~a:~a"
y mo d h mi)))))
(merged-props (loop for (k v) on properties by #'cddr
collect k collect v)))
(let* ((new-id (emacs-edit-generate-id))
(new-props (list :ID new-id
:TITLE title
:TODO (or todo "TODO")
:CREATED (format nil "[~a]"
(multiple-value-bind (s mi h d mo y)
(decode-universal-time (get-universal-time))
(format nil "~a-~a-~a ~a:~a"
y mo d h mi)))))
(merged-props (loop for (k v) on properties by #'cddr
collect k collect v)))
(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
#+begin_src lisp
(in-package :opencortex)
(defun memory-org-to-json (source)
"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
#+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)
(let* ((host (or (uiop:getenv "OLLAMA_HOST") "localhost:11434"))
(url (format nil "http://~a/api/embeddings" host))
(body (cl-json:encode-json-to-string `((model . "nomic-embed-text") (prompt . ,text)))))
(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))))
(def-cognitive-tool :get-ollama-embedding
"Generates vector embeddings via Ollama API."
((:text :type :string :description "Text to embed."))
:body (lambda (args)
(let ((text (getf args :text)))
(let* ((host (or (uiop:getenv "OLLAMA_HOST") "localhost:11434"))
(url (format nil "http://~a/api/embeddings" host))
(body (cl-json:encode-json-to-string `((model . "nomic-embed-text") (prompt . ,text)))))
(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
#+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)
(execute-llm-request :prompt prompt
:system-prompt system-prompt
:provider provider
:model model))
(def-cognitive-tool :ask-llm
"Unified interface for interacting with LLM providers."
((:prompt :type :string :description "The user prompt")
(:system-prompt :type :string :description "The system prompt (optional)")
(: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
** Skill Registration

View File

@@ -37,6 +37,13 @@ Fast paren balancing for syntax errors.
(concatenate 'string code (make-string (- opens closes) :initial-element #\))))
((> closes opens)
(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
** Parse Target Location
@@ -152,8 +159,8 @@ Provide a fixed version of the code as a lisp form.")
"Balances parentheses in a code string."
((:code :type :string :description "The code to balance"))
:body (lambda (args)
(let ((code (getf args :code))
(balanced (self-edit-balance-parens code)))
(let* ((code (getf args :code))
(balanced (self-edit-balance-parens code)))
(handler-case
(progn
(read-from-string balanced)

View File

@@ -12,7 +12,8 @@ The *Shell Actuator* provides a controlled interface for the OpenCortex to execu
* 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"))