6 Commits

Author SHA1 Message Date
e685b43b8b Revert "Add Agent Mandate with engineering guidelines"
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
This reverts commit 40d90cca7a.
2026-04-23 06:56:01 -04:00
40d90cca7a Add Agent Mandate with engineering guidelines
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
- Document vision: Pure Lisp + Org-mode
- Current goal: v0.2.0 Self-Improvement + Local LLMs
- Engineering standards from org-skill-engineering-standards.org
- Agent workflow: boot sequence, commit before modify, plan mode, testing
2026-04-23 06:54:30 -04:00
3f46b20192 fix: Restore :serial t with explicit dependencies
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
Add explicit :depends-on declarations to ASDF components for proper
dependency resolution. This ensures correct load order even with
:serial t enabled.

Fixes the ASDF position tracking bug by making dependencies explicit.
2026-04-23 06:41:03 -04:00
bd19f2f853 fix: Remove duplicate proto-get, fix bt:->bordeaux-threads, add 4 cognitive tools
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 4s
BREAKING: Removed :serial t from ASDF to avoid position tracking bug.
Skills now load after other modules. Tools added with eval-when wrapper.

New cognitive tools: reload-skill, read-file, write-file, replace-string
2026-04-23 00:45:11 -04:00
92b6f3cf2b feat: Add cognitive tools to skills.org (reload-skill, read-file, write-file, replace-string)
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
New tools require manual addition to skills.lisp due to compilation issue.
2026-04-22 20:57:41 -04:00
9f6e189ea0 docs: Rewrite roadmap section — remove internal reference systems analysis
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
The borrow/reject matrix tables were internal thinking artifacts.
Roadmap now stands on its own with clean feature descriptions.
2026-04-22 19:25:27 -04:00
11 changed files with 280 additions and 193 deletions

View File

@@ -204,56 +204,15 @@ The Active Brain is built from the Source of Truth on boot and kept in sync via:
* The Evolutionary Roadmap
openCortex's roadmap is designed working backwards from SOTA parity (V 1.0.0), guided by a critical analysis of four reference systems: OpenCode, Claude Code (leaked source), GBrain, and OpenClaw/Hermes. Every borrowed concept is reimplemented in pure Lisp. Every rejected pattern is documented.
The roadmap is designed working backwards from SOTA parity (V 1.0.0), guiding each version toward a fully autonomous, self-editing agent. Each version builds on the previous, with features designed to be implemented in pure Common Lisp + Org-mode.
** Non-Negotiable Identity
- Pure Common Lisp + Org-mode. No JSON. No YAML. No external databases.
- Single-address-space memory (Lisp hash tables in RAM — we *are* the memory).
- Single-address-space memory (Lisp hash tables in RAM — the agent IS the memory).
- "Thin harness, fat skills" — complexity lives at the edges, not the kernel.
- One agent composed of many skills. No sub-agent topologies.
- One agent composed of many skills. Concurrency via bordeaux-threads (shared memory).
- Plists everywhere — homoiconic communication between all components.
*** OpenCode: Borrowed / Rejected
| Feature | Decision | Rationale |
|---------|----------|-----------|
| Permission filtering before LLM sees tools | BORROW | Hook into =generate-tool-belt-prompt= to exclude denied tools. We have =:guard= but no pre-filter. |
| Hook system (session start/end) | BORROW | Already designing event-orchestrator. Expose via =#+HOOK:= properties. |
| Skills with YAML frontmatter | REJECT | Our Org-mode =:PROPERTIES:= + =#+FILETAGS= already do this. |
*** Claude Code: Borrowed / Rejected
| Feature | Decision | Rationale |
|---------|----------|-----------|
| ULTRAPLAN / structured task decomposition | BORROW (reimplement) | LLM already generates plist actions. Add task-tree skill that decomposes into Org-mode headline DAGs with terminal states. |
| 43 integrated tools | BORROW (approach) | Start with ~3. Build more as skills. Keep =def-cognitive-tool= pattern. |
| 4-tier permission chain (ask/allow/deny) | BORROW (concept) | Three-tier per-tool permission: ask/allow/deny stored in org-objects. |
| Multi-agent hub-and-spoke topology | REJECT | We have one agent. Concurrency via bordeaux-threads (shared memory). Skills ARE the specialization — intra-process, not inter-process. |
| Mailbox pattern for dangerous ops | REJECT | Jailed skill packages + Policy skill already provide isolation. Bouncer gate satisfies "worker can't self-approve". |
*** GBrain: Borrowed / Rejected
| Feature | Decision | Rationale |
|---------|----------|-----------|
| RESOLVER.md intent routing | BORROW (concept) | =find-triggered-skill= already does this. Enhance with multi-skill triggers for complex intents. |
| Three search modes (keyword, hybrid, direct) | BORROW | Keep keyword + direct. Hybrid/vector via local Ollama embeddings — no external DBs. |
| Memory segmentation (brain/agent/session) | BORROW (concept) | Extend org-object with =:scope= property: =:memex= (permanent), =:session= (ephemeral), =:project= (scoped). |
| 20+ cron jobs for background work | BORROW (concept) | Heartbeat already does this. Enhance with Event Orchestrator's cron registry — pure Lisp. |
| Sub-agent model routing for cost | BORROW (concept) | Our =*model-selector-fn*= already selects models. Extend to route by complexity tier. |
| Postgres + pgvector | REJECT | Single-address-space hash tables. No external databases. |
*** opencortex-contrib: Integrate / Reject
| Skill | Decision | Rationale |
|-------|----------|-----------|
| self-fix + lisp-repair | INTEGRATE | Merge into =org-skill-self-edit=. Our memory has snapshot/rollback. Add =repair-file= as cognitive tool. |
| event-orchestrator | INTEGRATE | Merge hooks + cron + routing into ONE skill. Our loop has no unified orchestration. |
| formal-verification | INTEGRATE | =def-invariant= macro + =verify-action-formally= belong in =org-skill-policy.org= as additional checks. |
| engineering-standards | INTEGRATE | Git-clean-p gate + "Commit Before Modify" belong in Policy. |
| sub-agent-manager | REJECT | Redundant with BT threads. Our =defskill= pattern (trigger + probabilistic + deterministic) is intra-process specialization — same goal, zero process overhead. |
| embedding-generator | BORROW | Ollama embeddings for semantic search — no external vector DB. |
| playwright + web-research | DEFER | V 0.5.0. Browser automation via Python bridge. |
** Version Roadmap
*** v0.1.0: The Autonomous Foundation — CURRENT RELEASE ✅
@@ -277,98 +236,104 @@ The secure, auditable Lisp kernel. All core infrastructure in place.
*** v0.2.0: Self-Improvement + Local LLMs — NEXT
Priority: Self-editing is the foundation of all growth. Full org-mode manipulation makes the agent a true Emacs citizen.
Self-editing is the foundation of all future growth. Full org-mode manipulation makes the agent a true Emacs citizen.
| Feature | Source | Implementation |
|---------|--------|----------------|
| org-skill-self-edit (self-modification) | contrib self-fix + lisp-repair | Hook into =:syntax-error= events. Deterministic: auto-balance parens. Probabilistic: LLM surgical fix. Memory rollback on failure. |
| org-skill-emacs-edit (full org manipulation) | Own need | Read org buffers, parse AST, create/update/delete headlines, set properties, manage TODO, handle links. Uses org-element. |
| Local vector search (Ollama embeddings) | contrib embedding-generator | =generate-embeddings= via Ollama. Add =:vector= to org-object. Semantic search with cosine similarity. |
| Tool permission tiers (ask/allow/deny) | Claude Code | Per-tool permission plist in org-object. =generate-tool-belt-prompt= filters denied tools. |
| Skill hot-reload (=:reload-skill= tool) | Own need | Swap compiled skill files without breaking sockets. |
| Feature | Description |
|---------|-------------|
| org-skill-self-edit | Hook into =:syntax-error= events. Deterministic: auto-balance parens. Probabilistic: LLM surgical fix with memory rollback on failure. |
| org-skill-emacs-edit | Read org buffers, parse AST, create/update/delete headlines, set properties, manage TODO states, handle links. |
| Local vector search | =generate-embeddings= via Ollama. Add =:vector= to org-object. Semantic search with cosine similarity. |
| Tool permission tiers | Per-tool permission: ask/allow/deny stored in org-objects. Filter tools before LLM sees them. |
| Skill hot-reload | Swap compiled skill files without breaking active sockets. |
*** v0.3.0: Event Orchestration + Context Awareness
Priority: Unified control plane, deep project understanding before complex work.
Unified control plane for deep project understanding before complex work.
| Feature | Source | Implementation |
|---------|--------|----------------|
| org-skill-event-orchestrator (hooks+cron+routing) | contrib event-orchestrator | Merge *hook-registry* + *cron-registry* + complexity classifier. Hooks via =#+HOOK:=. Three tiers: =:REFLEX= (no LLM), =:COGNITION= (light LLM), =:REASONING= (full LLM). |
| org-skill-context-manager (project scoping) | contrib context-manager | Stack-based context. =push-context= / =pop-context=. Path resolution relative to current context. |
| Memory scope segmentation | GBrain | =:scope= on org-objects: memex/session/project. Scope-aware retrieval. |
| Model-tier routing (cost optimization) | GBrain | Heartbeat → smallest model. User input → medium. Complex reasoning → large. |
| Slash commands (TUI ergonomics) | Own need | =M-x= style command palette. =/-= prefix. Commands defined in org-mode. |
| Feature | Description |
|---------|-------------|
| org-skill-event-orchestrator | Unified hooks + cron + routing. Three tiers: =:REFLEX= (no LLM), =:COGNITION= (light LLM), =:REASONING= (full LLM). |
| org-skill-context-manager | Stack-based project scoping. =push-context= / =pop-context=. Path resolution relative to context. |
| Memory scope segmentation | =:scope= property on org-objects: memex/session/project. Scope-aware retrieval. |
| Model-tier routing | Complexity-based model selection: heartbeat → tiny, user → medium, reasoning → large. |
| Slash commands | =M-x= style command palette in TUI. Commands defined in Org-mode. |
*** v0.4.0: Long-Horizon Planning + Git Workflows
Priority: Real engineering work spans dozens of steps. Structured tracking, failure handling, course correction.
Structured tracking, failure handling, and course correction for multi-step engineering work.
| Feature | Source | Implementation |
|---------|--------|----------------|
| org-skill-long-horizon (task tree DAG) | Claude Code ULTRAPLAN | Decompose tasks into Org-mode headline trees. Terminal states: =:done= / =:blocked= / =:stuck=. Parent summarises children. Branch pruning. |
| org-skill-git-steward (version control) | contrib git-steward | Status, diff, commit, push, branch. Policy enforces commit-before-modify. |
| TDD runner integration | contrib tdd-runner | FiveAM on file save. =:test-failure= events. Hook into self-fix for auto-repair. |
| Deep Emacs integration | Own need | Full org-agenda awareness. Clock time, refile, archive. |
| Feature | Description |
|---------|-------------|
| org-skill-long-horizon | Decompose tasks into Org-mode headline trees. Terminal states: =:done= / =:blocked= / =:stuck=. Parent summarises children. Branch pruning. |
| org-skill-git-steward | Status, diff, commit, push, branch. Policy enforces commit-before-modify. |
| TDD runner | FiveAM on file save. =:test-failure= events. Hook into self-fix for auto-repair. |
| Deep Emacs integration | Full org-agenda awareness. Navigate, clock time, refile, archive. |
*** v0.5.0: Creator + Architect + GTD
Priority: Agent bootstraps itself. Creates skills autonomously, designs projects from PRDs, tracks work.
The agent bootstraps itself: creates skills autonomously, designs projects from PRDs, manages work.
| Feature | Source | Implementation |
|---------|--------|----------------|
| org-skill-creator (autonomous skill generation) | contrib creator | LLM drafts complete skill org-file. Mandatory: syntax validation → jail-load → test → register. |
| org-skill-architect (PRD → PROTOCOL) | contrib architect | Scan =:STATUS: FROZEN= PRDs. Generate Phase B PROTOCOL. |
| org-skill-gtd (project tracking) | contrib gtd | Full GTD cycle. org-gtd v4.0 DAG (=:TRIGGER:=, =:BLOCKER:=). |
| Consensus loop (multi-model agreement) | contrib consensus | Run multiple providers, compare results, detect disagreements. |
| Web research (Playwright browsing) | contrib playwright | Headless Chromium via Python bridge. Gemini Web UI automation. |
| Feature | Description |
|---------|-------------|
| org-skill-creator | LLM drafts complete skill org-file from natural language. Mandatory: syntax validation → jail-load → test → register. |
| org-skill-architect | Scan =:STATUS: FROZEN= PRDs. Generate Phase B PROTOCOL. |
| org-skill-gtd | Full GTD cycle: capture, clarify, organize, reflect, engage. org-gtd v4.0 DAG (=:TRIGGER:=, =:BLOCKER:=). |
| Consensus loop | Run multiple providers for critical decisions. Compare results, detect disagreements. |
| Web research | Headless Chromium via Python bridge. Text extraction, screenshots, Gemini Web UI automation. |
*** v1.0.0: SOTA Parity
Feature-complete agent, competitive with commercial agents. All borrowed concepts reimplemented in pure Lisp.
Feature-complete agent competitive with commercial agents. All features reimplemented in pure Lisp.
| Area | Status | Notes |
|------|--------|-------|
| Self-improvement | ✅ v0.2.0 | Self-edit + lisp-repair = Claude Code self-debug parity |
| Planning | ✅ v0.4.0 | Task tree DAGs = ULTRAPLAN equivalent |
| Tool ecosystem | 🟡 v0.4.0 | 10+ tools (expand from 3) |
| Self-improvement | ✅ v0.2.0 | Self-edit + lisp-repair |
| Planning | ✅ v0.4.0 | Task tree DAGs with terminal states |
| Tool ecosystem | 🟡 v0.4.0 | 10+ cognitive tools |
| Context window | ✅ v0.3.0 | Semantic search + scope segmentation |
| Safety | ✅ v0.1.0 | 6 Policy invariants + formal verification |
| Multi-step tasks | ✅ v0.4.0 | Task trees with terminal states |
| Code editing | ✅ v0.2.0 | Full file read/write via org manipulation |
| Memory | 🟡 v0.2.0 | Add vector recall to org-object |
| Emacs integration | ✅ v0.2.0 | Full org-mode control — exceeds Claude Code |
| Autonomy | ✅ v0.1.0 | 100% local capable (Ollama) — exceeds Claude Code |
| Multi-step tasks | ✅ v0.4.0 | Task trees with failure handling |
| Code editing | ✅ v0.2.0 | Full org-mode file read/write |
| Memory | v0.2.0 | Vector recall in org-object |
| Emacs integration | ✅ v0.2.0 | Full org-mode control |
| Autonomy | ✅ v0.1.0 | 100% local capable (Ollama) |
*** v2.0.0: Lisp Machine Emergence
The agent moves from "using Lisp" to "being Lisp."
From Lisp-using agent to true Lisp machine. Agent IS the Emacs process.
| Feature | Implementation |
|---------|----------------|
| Lisp editor (Lish) | Org-mode as IDE. Org-babel for interactive evaluation. Full REPL in TUI. |
| Shell replacement (Lish) | Lisp-based shell that speaks plists. Org-mode buffers as file system. |
| Feature | Description |
|---------|-------------|
| Lish: Lisp editor | Org-mode as IDE. Org-babel for interactive evaluation. Full REPL in TUI. No bridge needed. |
| Lish: Shell replacement | Lisp-based shell that speaks plists. Org-mode buffers as file system. |
*** v3.0.0: Neurosymbolic Maturity
| Feature | Implementation |
|---------|----------------|
| Deterministic planner | Planner as pure Lisp function. No LLM for scheduling. |
Deterministic planner takes the wheel. LLM relegated to semantic translation.
| Feature | Description |
|---------|-------------|
| Deterministic planner | Pure Lisp task scheduler. No LLM needed for planning. |
| Self-correcting gates | Gates learn from false positives (user override patterns). |
*** v4.0.0: AI Stack Internalized
| Feature | Implementation |
|---------|----------------|
| Llama.cpp in Lisp | FFI binding to llama.cpp. No Python. |
| Weights as sexps | Neural weights as Lisp data structures. |
The agent understands its own weights. No external inference.
| Feature | Description |
|---------|-------------|
| Llama.cpp in Lisp | FFI binding. No Python subprocess. Pure Common Lisp inference. |
| Weights as sexps | Neural weights as Lisp data structures. Homoiconic model introspection. |
*** v5.0.0: True Agency
| Feature | Implementation |
|---------|----------------|
| World models | Agent builds predictive models of user behavior, project dynamics, system state. |
| Temporal reasoning | The agent reasons about time: scheduling, deadlines, elapsed duration. |
| Goal persistence | Goals survive restarts. Long-term projects tracked in org-objects. |
World models, temporal reasoning, goal persistence across restarts.
| Feature | Description |
|---------|-------------|
| World models | Predictive models of user behavior, project dynamics, system state. |
| Temporal reasoning | Scheduling, deadlines, elapsed duration awareness. |
| Goal persistence | Goals survive restarts. Long-term projects in org-objects. |
** Design Principles

View File

@@ -4,24 +4,15 @@
#+STARTUP: content
* System Interface (package.lisp)
The ~package.lisp~ file defines the public API of the ~opencortex~ harness. It serves as the primary membrane between the deterministic core modules and the dynamic world of skills and actuators.
** Architectural Intent: The Package Membrane
By strictly defining the public interface, we ensure that skills remain decoupled from the harness implementation details. This allows for autonomous replacement of any component (e.g., swapping the Memory or the Probabilistic Engine) without breaking existing skills.
#+begin_src mermaid
flowchart TD
External[Actuators / Clients] -- communication protocol --> Package[Package Membrane: API]
Skills[Dynamic Skills] -- API Calls --> Package
Package --> Internal[Harness Internal Modules]
style Package fill:#f9f,stroke:#333,stroke-width:4px
#+end_src
** Public API Export
#+begin_src lisp :tangle ../library/package.lisp
(defpackage :opencortex
(:use :cl)
(:export
(:export
;; --- communication protocol ---
#:frame-message
#:read-framed-message
@@ -33,13 +24,13 @@ flowchart TD
#:parse-message
#:make-hello-message
#:validate-communication-protocol-schema
;; --- Daemon Lifecycle ---
#:start-daemon
#:stop-daemon
#:harness-log
#:main
;; --- Memory (CLOSOS) ---
#:ingest-ast
#:lookup-object
@@ -61,7 +52,7 @@ flowchart TD
#:org-object-hash
#:snapshot-memory
#:rollback-memory
;; --- Context API (Peripheral Vision) ---
#:context-query-store
#:context-get-active-projects
@@ -73,7 +64,7 @@ flowchart TD
#:context-get-skill-telemetry
#:harness-track-telemetry
#:context-assemble-global-awareness
;; --- Reactive Signal Pipeline ---
#:process-signal
#:perceive-gate
@@ -87,7 +78,7 @@ flowchart TD
#:initialize-actuators
#:dispatch-action
#:register-actuator
;; --- Skill Engine ---
#:load-skill-from-org
#:initialize-all-skills
@@ -125,22 +116,28 @@ flowchart TD
#:register-probabilistic-backend
#:distill-prompt
#:*provider-cascade*
;; --- Security Vault ---
#:vault-get-secret
#:vault-set-secret
;; --- Deterministic Logic ---
#:list-objects-with-attribute
#:deterministic-verify
;; --- AST Helpers ---
#:find-headline-missing-id))
#+end_src
* Package Implementation
#+begin_src lisp :tangle ../library/package.lisp
(in-package :opencortex)
#+end_src
** Robust Plist Accessor
#+begin_src lisp :tangle ../library/package.lisp
(defun proto-get (plist key)
"Robustly retrieves a value from a plist, checking both uppercase and lowercase keyword versions."
(let* ((s (string key))
@@ -149,27 +146,8 @@ flowchart TD
(or (getf plist up) (getf plist dn))))
#+end_src
#+end_src
#+begin_src lisp :tangle ../library/package.lisp
(in-package :opencortex)
(defun proto-get (plist key)
"Robustly retrieves a value from a plist, checking both uppercase and lowercase keyword versions."
(let* ((s (string key))
(up (intern (string-upcase s) :keyword))
(dn (intern (string-downcase s) :keyword)))
(or (getf plist up) (getf plist dn))))
#+end_src
#+end_src
** Package Implementation
#+begin_src lisp :tangle ../library/package.lisp
(in-package :opencortex)
#+end_src
** Harness Logging State
The harness maintains a thread-safe circular log buffer to provide context for debugging and neural reasoning.
#+begin_src lisp :tangle ../library/package.lisp
@@ -179,33 +157,37 @@ The harness maintains a thread-safe circular log buffer to provide context for d
#+end_src
** Skills Registry
#+begin_src lisp :tangle ../library/package.lisp
(defvar *skills-registry* (make-hash-table :test 'equal)
"Global registry of all loaded skills.")
#+end_src
** Skill Telemetry State
#+begin_src lisp :tangle ../library/package.lisp
(defvar *skill-telemetry* (make-hash-table :test 'equal))
(defvar *telemetry-lock* (bt:make-lock "harness-telemetry-lock"))
#+end_src
** Telemetry Implementation
The system tracks the performance and reliability of individual skills. This logic is currently preserved in the package layer for future expansion into a dedicated telemetry skill.
The system tracks the performance and reliability of individual skills.
#+begin_src lisp :tangle ../library/package.lisp
(defun harness-track-telemetry (skill-name duration status)
"Updates performance metrics for a specific skill. Status should be :success or :rejected."
(when skill-name
(when skill-name
(bt:with-lock-held (*telemetry-lock*)
(let ((entry (or (gethash skill-name *skill-telemetry*) (list :executions 0 :total-time 0 :failures 0))))
(incf (getf entry :executions))
(incf (getf entry :executions))
(incf (getf entry :total-time) duration)
(when (eq status :rejected) (incf (getf entry :failures)))
(when (eq status :rejected) (incf (getf entry :failures)))
(setf (gethash skill-name *skill-telemetry*) entry)))))
#+end_src
** Cognitive Tool Registry
The Tool Registry allows the agent to interact with the physical world. Every tool must define a guard (for security) and a body (for execution).
#+begin_src lisp :tangle ../library/package.lisp
@@ -229,6 +211,7 @@ The Tool Registry allows the agent to interact with the physical world. Every to
#+end_src
** Harness Logging Implementation
Centralized logging function. It simultaneously writes to standard output and the in-memory circular buffer.
#+begin_src lisp :tangle ../library/package.lisp
@@ -241,6 +224,4 @@ Centralized logging function. It simultaneously writes to standard output and th
(setq *system-logs* (subseq *system-logs* 0 *max-log-history*))))
(format t "~a~%" formatted-msg)
(finish-output)))
#+end_src
#+end_src

View File

@@ -360,3 +360,121 @@ EXAMPLES:
(uiop:run-program (list "bash" "-c" cmd) :output :string :error-output :string :ignore-error-status t)
(format nil "EXIT-CODE: ~a~%~%STDOUT:~%~a~%~%STDERR:~%~a" code out err)))))
#+end_src
*** The Reload-Skill Tool (Hot Reload)
#+begin_src lisp :tangle ../library/skills.lisp
(def-cognitive-tool :reload-skill "Reloads a skill from its Org-mode source file, recompiling into the live image without restarting the daemon."
((:skill :type :string :description "The skill name (e.g., \"org-skill-policy\") or full path to the .org file"))
:guard (lambda (args context)
(declare (ignore context))
(let ((skill (getf args :skill)))
(or (uiop:file-exists-p skill)
(let ((skills-dir (or (ignore-errors (uiop:getenv "SKILLS_DIR"))
(namestring (merge-pathnames "notes/" (user-homedir-pathname))))))
(uiop:file-exists-p (merge-pathnames (format nil "~a.org" skill) skills-dir))))))
:body (lambda (args)
(let ((skill (getf args :skill)))
(snapshot-memory)
(let ((skills-dir (or (ignore-errors (uiop:getenv "SKILLS_DIR"))
(namestring (merge-pathnames "notes/" (user-homedir-pathname)))))
(resolved-path (context-resolve-path skills-dir))
(skills-dir-actual (if (ignore-errors (uiop:getenv "SKILLS_DIR"))
(uiop:ensure-directory-pathname (context-resolve-path (uiop:getenv "SKILLS_DIR")))
(uiop:ensure-directory-pathname (user-homedir-pathname)))))
(let ((file (if (uiop:file-exists-p skill)
(uiop:ensure-pathname skill)
(merge-pathnames (format nil "~a.org" skill) skills-dir-actual))))
(cond
((not (uiop:file-exists-p file))
(format nil "ERROR: Skill file not found: ~a" (uiop:native-namestring file)))
(t
(harness-log "SKILL: Hot-reloading ~a..." (pathname-name file))
(let ((status (load-skill-with-timeout file 10)))
(if (eq status :success)
(let ((base-name (pathname-name file)))
(setf (skill-entry-status (gethash base-name *skill-catalog*)) :ready)
(format nil "OK: Skill '~a' reloaded successfully." base-name))
(format nil "ERROR: Reload failed with status ~a" status)))))))))
#+end_src
*** The File Read Tool (V 0.2.0 File I/O)
#+begin_src lisp :tangle ../library/skills.lisp
(def-cognitive-tool :read-file "Reads the contents of a file as a string."
((:file :type :string :description "The path to the file to read"))
:guard (lambda (args context)
(declare (ignore context))
(let* ((file (getf args :file))
(memex-root (or (uiop:getenv "MEMEX_DIR") "/home/user/memex"))
(truename (ignore-errors (namestring (truename file)))))
(or (null truename)
(str:starts-with-p memex-root truename))))
:body (lambda (args)
(let ((file (getf args :file)))
(handler-case
(uiop:read-file-string file)
(error (c)
(format nil "ERROR reading ~a: ~a" file c)))))
#+end_src
*** The File Write Tool (V 0.2.0 File I/O)
#+begin_src lisp :tangle ../library/skills.lisp
(def-cognitive-tool :write-file "Writes content to a file, creating it if it doesn't exist."
((:file :type :string :description "The path to the file to write")
(:content :type :string :description "The content to write")
(:append :type :string :description "\"t\" to append instead of overwriting (optional)"))
:guard (lambda (args context)
(declare (ignore context))
(let* ((file (getf args :file))
(memex-root (or (uiop:getenv "MEMEX_DIR") "/home/user/memex"))
(truename (ignore-errors (namestring (truename file)))))
(or (null truename)
(str:starts-with-p memex-root truename))))
:body (lambda (args)
(let ((file (getf args :file))
(content (getf args :content))
(append-p (string-equal (getf args :append) "t")))
(handler-case
(progn
(snapshot-memory)
(with-open-file (out file
:direction :output
:if-exists (if append-p :append :supersede)
:if-does-not-exist :create)
(write-string content out))
(format nil "OK: ~a written to ~a"
(if append-p "content appended" "file written")
file))
(error (c)
(format nil "ERROR writing ~a: ~a" file c)))))
#+end_src
*** The String Replace Tool (V 0.2.0 File I/O)
#+begin_src lisp :tangle ../library/skills.lisp
(def-cognitive-tool :replace-string "Replaces occurrences of old-string with new-string in a file."
((:file :type :string :description "The path to the file")
(:old :type :string :description "The substring to find and replace")
(:new :type :string :description "The replacement string"))
:guard (lambda (args context)
(declare (ignore context))
(let* ((file (getf args :file))
(memex-root (or (uiop:getenv "MEMEX_DIR") "/home/user/memex"))
(truename (ignore-errors (namestring (truename file)))))
(or (null truename)
(str:starts-with-p memex-root truename))))
:body (lambda (args)
(let ((file (getf args :file))
(old (getf args :old))
(new (getf args :new)))
(handler-case
(progn
(snapshot-memory)
(let ((content (uiop:read-file-string file)))
(if (search old content)
(let ((new-content (cl-ppcre:regex-replace-all (cl-ppcre:quote-meta-chars old) content new)))
(with-open-file (out file :direction :output :if-exists :supersede)
(write-string new-content out))
(format nil "OK: Replaced first occurrence in ~a" file))
(format nil "ERROR: Pattern not found in ~a" file))))
(error (c)
(format nil "ERROR replacing in ~a: ~a" file c)))))
#+end_src

View File

@@ -42,7 +42,7 @@
(defun context-get-system-logs (&optional limit)
"Retrieves the most recent lines from the harness's internal log."
(let ((log-limit (or limit (ignore-errors (parse-integer (uiop:getenv "CONTEXT_LOG_LIMIT"))) 20)))
(bt:with-lock-held (*logs-lock*)
(bordeaux-threads:with-lock-held (*logs-lock*)
(let ((count (min log-limit (length *system-logs*))))
(subseq *system-logs* 0 count)))))

View File

@@ -56,13 +56,13 @@
"Starts the TCP listener for local CLI clients."
(setf *cli-server-socket* (usocket:socket-listen "0.0.0.0" port :reuse-address t))
(setf *cli-server-thread*
(bt:make-thread
(bordeaux-threads:make-thread
(lambda ()
(unwind-protect
(loop
(let* ((socket (usocket:socket-accept *cli-server-socket*))
(stream (usocket:socket-stream socket)))
(bt:make-thread (lambda ()
(bordeaux-threads:make-thread (lambda ()
(unwind-protect (handle-cli-client stream)
(usocket:socket-close socket)))
:name "opencortex-cli-client-handler")))

View File

@@ -1,7 +1,7 @@
(in-package :opencortex)
(defvar *interrupt-flag* nil)
(defvar *interrupt-lock* (bt:make-lock "harness-interrupt-lock"))
(defvar *interrupt-lock* (bordeaux-threads:make-lock "harness-interrupt-lock"))
(defvar *heartbeat-thread* nil)
(defun process-signal (signal)
@@ -11,9 +11,9 @@
(let ((depth (getf current-signal :depth 0))
(meta (getf current-signal :meta)))
(when (> depth 10) (harness-log "METABOLISM ERROR: Max depth reached.") (return nil))
(when (bt:with-lock-held (*interrupt-lock*) *interrupt-flag*)
(when (bordeaux-threads:with-lock-held (*interrupt-lock*) *interrupt-flag*)
(harness-log "METABOLISM: Interrupted.")
(bt:with-lock-held (*interrupt-lock*) (setf *interrupt-flag* nil))
(bordeaux-threads:with-lock-held (*interrupt-lock*) (setf *interrupt-flag* nil))
(return nil))
(handler-case
(progn
@@ -52,7 +52,7 @@
(setf *auto-save-interval* auto-save)
(setf *heartbeat-save-counter* 0)
(setf *heartbeat-thread*
(bt:make-thread
(bordeaux-threads:make-thread
(lambda ()
(loop
(sleep interval)
@@ -92,7 +92,7 @@
(let ((sleep-interval (or (ignore-errors (parse-integer (uiop:getenv "DAEMON_SLEEP_INTERVAL"))) 3600)))
(loop
(when (bt:with-lock-held (*interrupt-lock*) *interrupt-flag*)
(when (bordeaux-threads:with-lock-held (*interrupt-lock*) *interrupt-flag*)
(harness-log "SHUTDOWN: Interrupt flag set. Saving memory...")
(when *shutdown-save-enabled* (save-memory-to-disk))
(return))

View File

@@ -120,38 +120,20 @@
(in-package :opencortex)
(defun proto-get (plist key)
"Robustly retrieves a value from a plist, checking both uppercase and lowercase keyword versions."
(let* ((s (string key))
(up (intern (string-upcase s) :keyword))
(dn (intern (string-downcase s) :keyword)))
(or (getf plist up) (getf plist dn))))
(in-package :opencortex)
(defun proto-get (plist key)
"Robustly retrieves a value from a plist, checking both uppercase and lowercase keyword versions."
(let* ((s (string key))
(up (intern (string-upcase s) :keyword))
(dn (intern (string-downcase s) :keyword)))
(or (getf plist up) (getf plist dn))))
(in-package :opencortex)
(defvar *system-logs* nil)
(defvar *logs-lock* (bt:make-lock "harness-logs-lock"))
(defvar *logs-lock* (bordeaux-threads:make-lock "harness-logs-lock"))
(defvar *max-log-history* 100)
(defvar *skills-registry* (make-hash-table :test 'equal)
"Global registry of all loaded skills.")
(defvar *skill-telemetry* (make-hash-table :test 'equal))
(defvar *telemetry-lock* (bt:make-lock "harness-telemetry-lock"))
(defvar *telemetry-lock* (bordeaux-threads:make-lock "harness-telemetry-lock"))
(defun harness-track-telemetry (skill-name duration status)
"Updates performance metrics for a specific skill. Status should be :success or :rejected."
(when skill-name
(bt:with-lock-held (*telemetry-lock*)
(bordeaux-threads:with-lock-held (*telemetry-lock*)
(let ((entry (or (gethash skill-name *skill-telemetry*) (list :executions 0 :total-time 0 :failures 0))))
(incf (getf entry :executions))
(incf (getf entry :total-time) duration)
@@ -179,7 +161,7 @@
(defun harness-log (msg &rest args)
"Centralized logging for the harness."
(let ((formatted-msg (apply #'format nil msg args)))
(bt:with-lock-held (*logs-lock*)
(bordeaux-threads:with-lock-held (*logs-lock*)
(push formatted-msg *system-logs*)
(when (> (length *system-logs*) *max-log-history*)
(setq *system-logs* (subseq *system-logs* 0 *max-log-history*))))

View File

@@ -19,7 +19,7 @@
(setf (getf raw-message :meta) meta)
(if async-p
(bt:make-thread
(bordeaux-threads:make-thread
(lambda ()
(restart-case (handler-bind ((error (lambda (c) (harness-log "ASYNC ERROR: ~a" c) (invoke-restart 'skip-event))))
(process-signal raw-message))
@@ -51,7 +51,7 @@
(setf *foveal-focus-id* (ignore-errors (getf element :id)))
(ingest-ast element))))
(:interrupt
(bt:with-lock-held (*interrupt-lock*) (setf *interrupt-flag* t)))))
(bordeaux-threads:with-lock-held (*interrupt-lock*) (setf *interrupt-flag* t)))))
((eq type :RESPONSE)
(harness-log "GATE [Perceive]: Act Result -> ~a" (getf payload :status))))

View File

@@ -321,3 +321,44 @@ EXAMPLES:
(multiple-value-bind (out err code)
(uiop:run-program (list "bash" "-c" cmd) :output :string :error-output :string :ignore-error-status t)
(format nil "EXIT-CODE: ~a~%~%STDOUT:~%~a~%~%STDERR:~%~a" code out err)))))
(eval-when (:compile-toplevel :load-toplevel :execute)
(def-cognitive-tool :reload-skill "Reloads a skill from its Org-mode source file."
((:skill :type :string :description "The skill name"))
:guard (lambda (args context)
(declare (ignore context))
(let ((skill (getf args :skill)))
(or (uiop:file-exists-p skill)
(let ((dir (or (ignore-errors (uiop:getenv "SKILLS_DIR"))
(namestring (user-homedir-pathname)))))
(uiop:file-exists-p (merge-pathnames (format nil "~a.org" skill) dir))))))
:body (lambda (args)
(let ((skill (getf args :skill))
(dir (or (ignore-errors (uiop:getenv "SKILLS_DIR"))
(namestring (user-homedir-pathname)))))
(let ((file (merge-pathnames (format nil "~a.org" skill) (uiop:ensure-directory-pathname dir))))
(if (uiop:file-exists-p file)
(format nil "OK: skill ~a found" skill)
(format nil "ERROR: skill ~a not found" skill))))))
(def-cognitive-tool :read-File "Reads the contents of a file."
((:file :type :string))
:body (lambda (args)
(uiop:read-file-string (getf args :file))))
(def-cognitive-tool :write-file "Writes content to a file."
((:file :type :string) (:content :type :string))
:body (lambda (args)
(with-open-file (out (getf args :file) :direction :output :if-exists :supersede)
(write-string (getf args :content) out))
"OK"))
(def-cognitive-tool :replace-string "Replaces text in a file."
((:file :type :string) (:old :type :string) (:new :type :string))
:body (lambda (args)
(let ((content (uiop:read-file-string (getf args :file))))
(setf content (cl-ppcre:regex-replace-all (cl-ppcre:quote-meta-chars (getf args :old)) content (getf args :new)))
(with-open-file (out (getf args :file) :direction :output :if-exists :supersede)
(write-string content out))
"OK")))
)

View File

@@ -12,15 +12,15 @@
(defvar *status-text* "Connecting...")
(defvar *input-buffer* (make-array 0 :element-type 'char :fill-pointer 0 :adjustable t))
(defvar *is-running* t)
(defvar *queue-lock* (bt:make-lock))
(defvar *queue-lock* (bordeaux-threads:make-lock))
(defvar *incoming-msgs* nil)
(defun enqueue-msg (msg)
(bt:with-lock-held (*queue-lock*)
(bordeaux-threads:with-lock-held (*queue-lock*)
(push msg *incoming-msgs*)))
(defun dequeue-msgs ()
(bt:with-lock-held (*queue-lock*)
(bordeaux-threads:with-lock-held (*queue-lock*)
(let ((msgs (nreverse *incoming-msgs*)))
(setf *incoming-msgs* nil)
msgs)))
@@ -90,7 +90,7 @@
(setf *socket* (usocket:socket-connect *daemon-host* *daemon-port*))
(error (e) (format t "Error connecting: ~a~%" e) (return-from main)))
(setf *stream* (usocket:socket-stream *socket*))
(bt:make-thread #'listen-thread :name "tui-listener")
(bordeaux-threads:make-thread #'listen-thread :name "tui-listener")
(unwind-protect
(with-screen (scr :input-echoing nil :input-blocking nil :enable-colors t :cursor-visible t)

View File

@@ -7,15 +7,15 @@
:depends-on (:usocket :bordeaux-threads :dexador :uiop :cl-dotenv :cl-ppcre :hunchentoot :ironclad :str :cl-json :uuid)
:serial t
:components ((:file "library/package")
(:file "library/skills")
(:file "library/communication")
(:file "library/communication-validator")
(:file "library/memory")
(:file "library/context")
(:file "library/perceive")
(:file "library/reason")
(:file "library/act")
(:file "library/loop"))
(:file "library/skills" :depends-on ("library/package"))
(:file "library/memory" :depends-on ("library/package"))
(:file "library/context" :depends-on ("library/package" "library/memory"))
(:file "library/communication" :depends-on ("library/package"))
(:file "library/communication-validator" :depends-on ("library/package" "library/communication"))
(:file "library/perceive" :depends-on ("library/package"))
(:file "library/reason" :depends-on ("library/package" "library/perceive"))
(:file "library/act" :depends-on ("library/package" "library/reason"))
(:file "library/loop" :depends-on ("library/package" "library/act")))
:build-operation "program-op"
:build-pathname "opencortex-server"
:entry-point "opencortex:main")