v0.2.1: polish, deploy, CI, and literate refactor
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 11s
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 11s
- Secret Exposure Gate + Privacy Filter (Bouncer) - Shell actuator safety harness (timeout, blocked patterns) - REPL-first enforcement (lisp validation gate, system-prompt-augment) - Engineering Standards lifecycle (two-track Org-first + REPL-first) - Literate Programming discipline (one function per block, reflect-back) - AGENTS.md: thin routing layer, skills are authoritative - SKILLS_DIR removed, ~/notes fallback eliminated - opencortex.sh: multi-distro (Debian+Fedora), configure, install service, backup, restore, help - infrastructure/opencortex.service (systemd user unit) - Docker: updated to debian:trixie, fixed build context - GitHub CI: lint + test workflows fixed, trigger on tags only - Gitea CI: deploy workflow paths fixed - README: one-line curl install, badges - USER_MANUAL: Deployment section (bare metal, Docker, backup) - .gitignore: skills/*.lisp and tests/*.lisp as generated artifacts - Prose/block refactor across all 35 org files - Test suite Tier 1: 43/45 pass (env-dependent failures isolated)
This commit is contained in:
@@ -5,7 +5,16 @@
|
||||
#+PROPERTY: header-args:lisp :tangle skills.lisp
|
||||
|
||||
* Overview
|
||||
The ~opencortex~ Skill Engine enables **Late-Binding Intelligence**, allowing the system to discover and integrate new cognitive capabilities at runtime.
|
||||
The Skill Engine is the dynamic loading and lifecycle manager for all OpenCortex skills. It discovers skill files in the skills directory, resolves their dependency order, loads them into jailed packages, exports their public symbols into the ~opencortex~ package, and provides the ~defskill~ macro that skills use to register themselves.
|
||||
|
||||
Key concepts:
|
||||
- ~defskill~ — macro that registers a skill with its trigger, deterministic gate, and optional probabilistic prompt
|
||||
- ~def-cognitive-tool~ — macro that registers a tool the LLM can invoke
|
||||
- ~load-skill-from-org~ / ~load-skill-from-lisp~ — load a skill from a literate Org file or a pre-tangled Lisp file
|
||||
- ~topological-sort-skills~ — orders skills by their ~#+DEPENDS_ON:~ declarations
|
||||
- ~find-triggered-skill~ — returns the highest-priority skill whose trigger matches the current context
|
||||
|
||||
The engine supports **hot-reload** — skills can be replaced at runtime without restarting the daemon.
|
||||
|
||||
* Implementation
|
||||
|
||||
@@ -14,7 +23,11 @@ The ~opencortex~ Skill Engine enables **Late-Binding Intelligence**, allowing th
|
||||
(in-package :opencortex)
|
||||
#+end_src
|
||||
|
||||
** Global Skill Registry
|
||||
** Utility functions
|
||||
Helper functions used by the skill loader and other components.
|
||||
|
||||
*** Cosine similarity
|
||||
Computes the cosine similarity between two numeric vectors. Used by the peripheral vision system for semantic relevance scoring.
|
||||
#+begin_src lisp
|
||||
(defun COSINE-SIMILARITY (v1 v2)
|
||||
"Computes cosine similarity between two vectors."
|
||||
@@ -26,17 +39,37 @@ The ~opencortex~ Skill Engine enables **Late-Binding Intelligence**, allowing th
|
||||
(let* ((x (coerce (elt v1 i) 'double-float)) (y (coerce (elt v2 i) 'double-float)))
|
||||
(incf dot (* x y)) (incf n1 (* x x)) (incf n2 (* y y))))
|
||||
(if (or (zerop n1) (zerop n2)) 0.0 (/ dot (sqrt (* n1 n2))))))))
|
||||
#+end_src
|
||||
|
||||
*** Secret masking
|
||||
Simple mask function and the vault memory hash table. Used by the Bouncer skill and credentials vault.
|
||||
#+begin_src lisp
|
||||
(defun VAULT-MASK-STRING (s) (declare (ignore s)) "[MASKED]")
|
||||
(defvar *VAULT-MEMORY* (make-hash-table :test 'equal))
|
||||
#+end_src
|
||||
|
||||
(defstruct skill name priority dependencies trigger-fn probabilistic-prompt deterministic-fn)
|
||||
** Skill data structures
|
||||
The ~skill~ struct holds all metadata about a loaded skill: its name, priority, dependencies, trigger function, probabilistic prompt generator, deterministic gate, and system prompt augmentor. The ~skill-entry~ struct tracks the loading state of each discovered skill file.
|
||||
#+begin_src lisp
|
||||
(defstruct skill name priority dependencies trigger-fn probabilistic-prompt deterministic-fn system-prompt-augment)
|
||||
#+end_src
|
||||
|
||||
#+begin_src lisp
|
||||
(defvar *skills-registry* (make-hash-table :test 'equal))
|
||||
#+end_src
|
||||
|
||||
#+begin_src lisp
|
||||
(defvar *skill-catalog* (make-hash-table :test 'equal)
|
||||
"A stateful tracking table for all skill files discovered in the environment.")
|
||||
"Tracks all discovered skill files and their loading state.")
|
||||
#+end_src
|
||||
|
||||
#+begin_src lisp
|
||||
(defstruct skill-entry filename (status :discovered) error-log (load-time 0))
|
||||
#+end_src
|
||||
|
||||
** Skill discovery (find-triggered-skill)
|
||||
Iterates the registry and returns the highest-priority skill whose trigger function matches the current context. Only skills with a probabilistic prompt are considered (skills that are purely deterministic don't need LLM intervention).
|
||||
#+begin_src lisp
|
||||
(defun find-triggered-skill (context)
|
||||
"Returns the highest priority skill whose trigger matches context."
|
||||
(let ((triggered nil))
|
||||
@@ -45,21 +78,30 @@ The ~opencortex~ Skill Engine enables **Late-Binding Intelligence**, allowing th
|
||||
(when (and (skill-probabilistic-prompt skill)
|
||||
(ignore-errors (funcall (skill-trigger-fn skill) context)))
|
||||
(push skill triggered)))
|
||||
*skills-registry*)
|
||||
*skills-registry*)
|
||||
(first (sort triggered #'> :key #'skill-priority))))
|
||||
#+end_src
|
||||
|
||||
(defmacro defskill (name &key priority dependencies trigger probabilistic deterministic)
|
||||
"Registers a new skill into the global registry."
|
||||
** Skill registration macro (defskill)
|
||||
The primary API for skills. Each skill file calls this once to register itself. The macro creates a ~skill~ struct and stores it in ~*skills-registry*~ keyed by the skill's name.
|
||||
#+begin_src lisp
|
||||
(defmacro defskill (name &key priority dependencies trigger probabilistic deterministic system-prompt-augment)
|
||||
"Registers a new skill. NAME is a keyword. TRIGGER is a function (context) → bool."
|
||||
`(setf (gethash (string-downcase (string ,name)) *skills-registry*)
|
||||
(make-skill :name (string-downcase (string ,name))
|
||||
:priority (or ,priority 10)
|
||||
:dependencies ',dependencies
|
||||
:trigger-fn ,trigger
|
||||
:probabilistic-prompt ,probabilistic
|
||||
:deterministic-fn ,deterministic)))
|
||||
:deterministic-fn ,deterministic
|
||||
:system-prompt-augment ,system-prompt-augment)))
|
||||
#+end_src
|
||||
|
||||
** Dependency resolution (resolve-skill-dependencies)
|
||||
Recursively resolves all transitive dependencies for a given skill, returning an ordered list. Uses a standard topological sort with cycle detection (a ~seen~ set prevents infinite recursion).
|
||||
#+begin_src lisp
|
||||
(defun resolve-skill-dependencies (skill-name)
|
||||
"Recursively resolves dependencies for a given skill name."
|
||||
"Resolves transitive dependencies. Returns list of skill names in dependency order."
|
||||
(let ((resolved nil) (seen nil))
|
||||
(labels ((visit (name)
|
||||
(unless (member name seen :test #'equal)
|
||||
@@ -110,7 +152,9 @@ The ~opencortex~ Skill Engine enables **Late-Binding Intelligence**, allowing th
|
||||
(if (uiop:string-suffix-p (namestring file) ".lisp")
|
||||
(progn
|
||||
(setf (gethash (string-downcase filename) name-to-file) file)
|
||||
(setf (gethash (string-downcase filename) adj) nil))
|
||||
;; Don't overwrite dependency info from .org files
|
||||
(unless (gethash (string-downcase filename) adj)
|
||||
(setf (gethash (string-downcase filename) adj) nil)))
|
||||
(multiple-value-bind (id deps) (parse-skill-metadata file)
|
||||
(setf (gethash (string-downcase filename) name-to-file) file)
|
||||
(when id (setf (gethash (string-downcase id) id-to-file) file))
|
||||
@@ -286,9 +330,9 @@ The ~opencortex~ Skill Engine enables **Late-Binding Intelligence**, allowing th
|
||||
** Initialize (initialize-all-skills)
|
||||
#+begin_src lisp
|
||||
(defun initialize-all-skills ()
|
||||
"Initializes all skills from SKILLS_DIR."
|
||||
(let* ((env-path (uiop:getenv "SKILLS_DIR"))
|
||||
(skills-dir (uiop:ensure-directory-pathname (or env-path (namestring (merge-pathnames "notes/" (user-homedir-pathname)))))))
|
||||
"Initializes all skills from the XDG skills directory."
|
||||
(let* ((data-dir (uiop:ensure-directory-pathname (or (uiop:getenv "OC_DATA_DIR") (namestring (merge-pathnames ".local/share/opencortex/" (user-homedir-pathname))))))
|
||||
(skills-dir (merge-pathnames "skills/" data-dir)))
|
||||
(unless (uiop:directory-exists-p skills-dir) (return-from initialize-all-skills nil))
|
||||
(let ((sorted-files (topological-sort-skills skills-dir)))
|
||||
(harness-log "LOADER: Initializing ~a skills..." (length sorted-files))
|
||||
|
||||
Reference in New Issue
Block a user