Compare commits

..

7 Commits

Author SHA1 Message Date
ce17336acd build: embed org-agent-test.el inside emacs-bridge skill 2026-04-27 13:19:19 -04:00
abda622145 build: embed Python bridge inside web-research skill
- In accordance with the strict literate programming mandate, the standalone browser-bridge.py script has been embedded as a :tangle block directly inside the org-skill-web-research.org file.
- It dynamically tangles to the INSTALL_DIR's skills directory alongside its parent Lisp logic.
2026-04-27 13:16:14 -04:00
6335b0c0c4 refactor: standardize skill API keywords to :probabilistic/:deterministic 2026-04-27 12:19:34 -04:00
5f2b7e8d16 Fix gateway skills: minor cleanup in matrix/signal/telegram org blocks 2026-04-25 18:44:41 -04:00
2db53fae17 Remove lisp-repair - moved to core skills
Consolidated into opencortex/skills/org-skill-lisp-utils.org
2026-04-23 07:22:51 -04:00
2b1f0f1b35 docs: Add test-first methodology and org-thinking mandates
- Rule 10: Test-first - design tests before coding, run chaos testing
- Rule 11: Org as thinking medium - document investigations in prose
- Rule 12: Engineering decision audit trail - document root cause, tradeoffs

These mandates ensure rigorous verification and capture institutional knowledge.
2026-04-23 06:47:24 -04:00
5b6f4c18d1 fix(audit): Ensure Chat Skill is Merkle-compliant and secure (Component IV) 2026-04-17 16:30:41 -04:00
22 changed files with 212 additions and 127 deletions

View File

@@ -131,6 +131,6 @@ Interfaces for blueprint actuation and requirement perception. Source of truth i
(defskill :skill-architect
:priority 110 ; Higher priority to lead the loop
:trigger #'trigger-skill-architect
:neuro #'neuro-skill-architect
:symbolic #'architect-actuate)
:probabilistic #'neuro-skill-architect
:deterministic #'architect-actuate)
#+end_src

View File

@@ -154,8 +154,8 @@ The *Chaos Gauntlet* skill is designed to be non-invasive, running primarily in
(defskill :skill-chaos
:priority 10 ; Lower priority, used for background testing
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :chaos-trigger))
:neuro (lambda (context)
:probabilistic (lambda (context)
(let ((p (getf context :payload)))
(format nil "A chaos trigger was received (~a). Should I run a stress test?" (getf p :mode))))
:symbolic #'chaos-stress-test)
:deterministic #'chaos-stress-test)
#+end_src

View File

@@ -51,8 +51,8 @@ Enable visual communication of plans and system states.
(defskill :skill-diagrammer
:priority 60
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :visualize))
:neuro #'neuro-skill-diagrammer
:symbolic (lambda (action context) action))
:probabilistic #'neuro-skill-diagrammer
:deterministic (lambda (action context) action))
#+end_src

View File

@@ -99,6 +99,83 @@ Interfaces for TCP I/O and protocol framing. Source of truth is the Harness Comm
(defskill :skill-emacs-bridge
:priority 100
:trigger (lambda (context) nil)
:neuro (lambda (context) nil)
:symbolic (lambda (action context) action))
:probabilistic (lambda (context) nil)
:deterministic (lambda (action context) action))
#+end_src
* Emacs Bridge Test Suite
#+begin_src elisp :tangle (expand-file-name "tests/org-agent-test.el" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
;;; opencortex-test.el --- Tests for the opencortex Emacs stub
(require 'ert)
(require 'cl-lib)
(require 'opencortex "/home/amr/.openclaw/workspace/memex/5_projects/opencortex/src/opencortex.el")
(ert-deftest test-opencortex-framing ()
"Verify that opencortex-send correctly frames a plist."
(let ((captured-framed nil))
(cl-letf (((symbol-function 'process-send-string)
(lambda (proc string) (setq captured-framed string)))
((symbol-function 'process-live-p) (lambda (proc) t))
(opencortex--process t))
(opencortex-send '(:type :EVENT :id 1))
(should (string= "000014(:type :EVENT :id 1)" captured-framed)))))
(ert-deftest test-opencortex-parsing ()
"Verify that the filter correctly parses communication protocol framed messages."
(let ((mock-buffer (generate-new-buffer " *opencortex-test*"))
(received-plist nil))
(cl-letf (((symbol-function 'opencortex--handle-message)
(lambda (proc plist) (setq received-plist plist))))
(with-current-buffer mock-buffer
(insert "000014(:type :EVENT :id 1)")
(opencortex--process-buffer mock-buffer)
(should (equal '(:type :EVENT :id 1) received-plist))
(should (= (buffer-size) 0))))))
(ert-deftest test-opencortex-actuator-message ()
"Verify that the :message actuator works."
(let ((opencortex--process nil)
(captured-response nil))
(cl-letf (((symbol-function 'opencortex-send)
(lambda (plist) (setq captured-response plist))))
(opencortex--execute-request nil 101 '(:action :message :text "Hello from Daemon"))
;; Check that we sent a success response back
(should (eq :RESPONSE (plist-get captured-response :type)))
(should (eq :success (plist-get (plist-get captured-response :payload) :status))))))
(ert-deftest test-opencortex-run-command ()
"Verify that opencortex-run-command sends the correct event."
(let ((captured-framed nil))
(cl-letf (((symbol-function 'process-send-string)
(lambda (proc string) (setq captured-framed string)))
((symbol-function 'process-live-p) (lambda (proc) t))
(opencortex--process t))
(opencortex-run-command :test-cmd)
(should (string-match-p ":sensor :user-command" captured-framed))
(should (string-match-p ":command :test-cmd" captured-framed)))))
(ert-deftest test-opencortex-ast-cleaning ()
"Verify that opencortex--clean-element produces a pure plist."
(let* ((org-text "* Hello\nWorld")
(ast (with-temp-buffer
(org-mode)
(insert org-text)
(org-element-parse-buffer)))
(cleaned (opencortex--clean-element ast)))
(should (plist-get cleaned :type))
(should (eq 'org-data (plist-get cleaned :type)))
;; Check that children exist
(should (plist-get (car (plist-get cleaned :contents)) :type))
;; Check that we didn't leak buffer objects
(should-not (plist-get (plist-get cleaned :properties) :buffer))))
(ert-deftest test-opencortex-actuator-eval ()
"Verify that the :eval actuator can execute elisp."
(let ((opencortex--process nil)
(captured-response nil))
(cl-letf (((symbol-function 'opencortex-send)
(lambda (plist) (setq captured-response plist))))
(opencortex--execute-request nil 102 '(:action :eval :code "(+ 1 2)"))
(should (equal "3" (plist-get (plist-get captured-response :payload) :result))))))
#+end_src

View File

@@ -41,8 +41,8 @@ Unify the system's diverse information silos into a single, navigable graph.
(defskill :skill-hyper-graph
:priority 70
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :deep-trace))
:neuro (lambda (context) "Synthesize a lineage report for the target ID.")
:symbolic (lambda (action context) action))
:probabilistic (lambda (context) "Synthesize a lineage report for the target ID.")
:deterministic (lambda (action context) action))
#+end_src

View File

@@ -84,6 +84,6 @@ RULES:
(defskill :skill-inbox-processor
:priority 100
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :heartbeat))
:neuro #'neuro-skill-inbox-processor
:symbolic #'inbox-process-logic)
:probabilistic #'neuro-skill-inbox-processor
:deterministic #'inbox-process-logic)
#+end_src

View File

@@ -73,7 +73,7 @@ Hooks into the `:heartbeat` sensor.
(setf *last-reflection-time* now)
t)
nil)))
:neuro (lambda (ctx)
:probabilistic (lambda (ctx)
(declare (ignore ctx))
(let* ((memories (sample-random-memories 3))
(context-string "LATENT REFLECTION CANDIDATES:\n"))
@@ -94,7 +94,7 @@ Find hidden connections, suggest new tags, or propose a new insight that bridges
MANDATE: Output EXACTLY ONE Common Lisp property list starting with (:type :REQUEST).
Use the :emacs target and :insert-at-end action to write your reflection into the \"*opencortex-chat*\" buffer."
context-string)))
:symbolic (lambda (action ctx)
:deterministic (lambda (action ctx)
(declare (ignore ctx))
;; Approve any safe request
action))

View File

@@ -34,8 +34,8 @@ Automate the "Easy Apply" process on LinkedIn to sustain revenue streams.
(defskill :skill-linkedin
:priority 50
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :revenue-pulse))
:neuro (lambda (context) nil)
:symbolic (lambda (action context) action))
:probabilistic (lambda (context) nil)
:deterministic (lambda (action context) action))
#+end_src

View File

@@ -91,6 +91,6 @@ Register the high-fidelity browsing tool with the harness.
(defskill :skill-playwright
:priority 150
:trigger (lambda (ctx) (declare (ignore ctx)) nil) ; Passive tool provider
:neuro nil
:symbolic (lambda (action ctx) (declare (ignore ctx)) action))
:probabilistic nil
:deterministic (lambda (action ctx) (declare (ignore ctx)) action))
#+end_src

View File

@@ -55,8 +55,8 @@ Eliminate speculative debugging through rigorous scientific methodology.
(defskill :skill-scientist
:priority 90
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :test-failure))
:neuro #'scientist-hypothesis
:symbolic #'scientist-propose-fix)
:probabilistic #'scientist-hypothesis
:deterministic #'scientist-propose-fix)
#+end_src
* Phase B: Blueprint (PROTOCOL)

View File

@@ -52,8 +52,8 @@ Automate the extraction of root causes and architectural learnings into the Meme
(defskill :skill-scribe-rca
:priority 90
:trigger (lambda (context) (search "SYSTEM ERROR" (format nil "~a" (getf (getf context :payload) :text))))
:neuro #'scribe-rca-draft
:symbolic (lambda (action context) action))
:probabilistic #'scribe-rca-draft
:deterministic (lambda (action context) action))
#+end_src
* Phase B: Blueprint (PROTOCOL)

View File

@@ -99,6 +99,6 @@ RULES:
(defskill :skill-scribe
:priority 60
:trigger #'trigger-skill-scribe
:neuro #'neuro-skill-scribe-enrich
:symbolic #'scribe-get-changed-dailies)
:probabilistic #'neuro-skill-scribe-enrich
:deterministic #'scribe-get-changed-dailies)
#+end_src

View File

@@ -72,8 +72,8 @@ Interfaces for background verification and kernel alerting. Source of truth is t
:trigger (lambda (context)
(let ((sensor (getf (getf context :payload) :sensor)))
(or (eq sensor :buffer-update) (eq sensor :file-saved))))
:neuro (lambda (context) nil)
:symbolic (lambda (action context)
:probabilistic (lambda (context) nil)
:deterministic (lambda (action context)
(let ((file (getf (getf context :payload) :file)))
(when (and file (search "projects/" file))
(let ((parts (uiop:split-string file :separator '(#\/))))

View File

@@ -128,6 +128,6 @@ Interfaces for TDD suite actuation and protocol perception. Source of truth is t
(defskill :skill-tech-analyst
:priority 120
:trigger #'trigger-skill-tech-analyst
:neuro #'neuro-skill-tech-analyst
:symbolic #'tech-analyst-actuate)
:probabilistic #'neuro-skill-tech-analyst
:deterministic #'tech-analyst-actuate)
#+end_src

View File

@@ -84,8 +84,8 @@ Maintain a state-aware provider cascade that routes around "pain" (failures) and
:trigger (lambda (context)
(let ((sensor (getf (getf context :payload) :sensor)))
(or (eq sensor :tool-error) (eq sensor :cost-audit))))
:neuro (lambda (context) nil)
:symbolic (lambda (action context)
:probabilistic (lambda (context) nil)
:deterministic (lambda (action context)
(let ((p (getf (getf context :payload) :provider)))
(when p (token-accountant-record-pain p))
action))))

View File

@@ -127,6 +127,64 @@ loginGemini().catch(err => {
(defskill :skill-web-research
:priority 60
:trigger (lambda (context) (eq (getf (getf context :payload) :sensor) :web-search))
:neuro (lambda (context) nil)
:symbolic (lambda (action context) (ask-gemini-web (getf (getf action :payload) :prompt))))
:probabilistic (lambda (context) nil)
:deterministic (lambda (action context) (ask-gemini-web (getf (getf action :payload) :prompt))))
#+end_src
*** Headless Data Extraction Bridge
#+begin_src python :tangle (expand-file-name "browser-bridge.py" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
#!/usr/bin/env python3
import sys
import json
import base64
from playwright.sync_api import sync_playwright
def run_bridge():
# Read command from stdin
try:
raw_input = sys.stdin.read()
if not raw_input:
print(json.dumps({"status": "error", "message": "No input provided"}))
return
args = json.loads(raw_input)
except Exception as e:
print(json.dumps({"status": "error", "message": f"Invalid JSON input: {str(e)}"}))
return
url = args.get("url")
action = args.get("action", "extract_text")
selector = args.get("selector", "body")
if not url:
print(json.dumps({"status": "error", "message": "No URL provided"}))
return
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# Navigate and wait for network to be idle
page.goto(url, wait_until="networkidle")
result = {"status": "success", "url": url}
if action == "extract_text":
result["content"] = page.inner_text(selector)
elif action == "screenshot":
screenshot_bytes = page.screenshot()
result["screenshot_base64"] = base64.b64encode(screenshot_bytes).decode("utf-8")
else:
result["status"] = "error"
result["message"] = f"Unknown action: {action}"
browser.close()
print(json.dumps(result))
except Exception as e:
print(json.dumps({"status": "error", "message": f"Playwright Error: {str(e)}"}))
if __name__ == "__main__":
run_bridge()
#+end_src

View File

@@ -54,14 +54,18 @@ Interfaces for conversational event handling and UI integration. Source of truth
(defun chat-archive-message (text &key (role :user) channel chat-id)
"Archives a chat message into the persistent Memory and triggers a snapshot."
(let* ((msg-id (org-id-new))
(attributes `(:role ,role :channel ,channel :chat-id ,chat-id :timestamp ,(get-universal-time)))
(hash (compute-merkle-hash msg-id :CHAT-MESSAGE attributes text nil))
(obj (make-org-object
:id msg-id
:type :CHAT-MESSAGE
:attributes `(:role ,role :channel ,channel :chat-id ,chat-id :timestamp ,(get-universal-time))
:attributes attributes
:content text
:hash hash
:version (get-universal-time))))
(setf (gethash hash *history-store*) obj)
(setf (gethash msg-id *memory*) obj)
(harness-log "CHAT - Message archived: ~a (~a)" msg-id role)
(harness-log "CHAT - Message archived: ~a (~a) [Hash: ~a]" msg-id role (subseq hash 0 8))
(snapshot-memory)
msg-id))

View File

@@ -39,6 +39,27 @@ Source code MUST be strictly free of hardcoded configuration values (e.g., ports
** 9. Literate-Only Modification (The Tangle Mandate)
You are strictly forbidden from modifying generated source code files (e.g., `.lisp`, `.py`, `.el`) directly. All changes MUST be made within the corresponding Literate Org file and then tangled to the source. Direct modification of source code is only permitted with explicit user authorization.
** 10. Test-First Methodology (Design Before Code)
Before implementing any fix or feature, you MUST:
1. Design the test/success criteria first - define what "works" means
2. Run chaos/edge-case testing - try to break the design
3. Only then implement the solution
This prevents debugging-by-trial-and-error and ensures rigorous verification.
** 11. Org as Thinking Medium (Investigation in Prose)
When debugging or analyzing issues:
1. Document your investigation in the relevant org file BEFORE implementing a fix
2. Record: root cause hypothesis, evidence found, tradeoffs considered
3. This makes the reasoning auditable and captures institutional knowledge
The org file IS the design document - code is just the implementation.
** 12. Engineering Decision Audit Trail
Every significant fix or architectural decision MUST be documented in the relevant org file with:
- Root cause analysis
- Options considered and tradeoffs
- Why this solution was chosen
This creates a searchable, literate history of engineering decisions.
* Phase B: Blueprint (PROTOCOL)
:PROPERTIES:
:STATUS: SIGNED

View File

@@ -32,8 +32,8 @@ Integrate the OpenCortex into the Matrix federation for secure, distributed chat
Autonomous background polling of the Matrix homeserver. Uses `dexador` for HTTP and `cl-json` for parsing.
** 2. Semantic Interfaces
- `(:sensor :chat-message :channel :matrix ...)`
- `(:type :REQUEST :target :matrix :room-id "..." :text "...")`
- `(:type :EVENT :meta (:source :matrix :room-id "...") :payload (:sensor :user-input :text "..."))`
- `(:type :REQUEST :target :matrix :payload (:action :message :text "..."))`
* Phase D: Build (Implementation)
@@ -73,7 +73,8 @@ Sends an `m.room.message` to a Matrix room.
"Sends a message via Matrix Client API."
(declare (ignore context))
(let* ((payload (getf action :payload))
(room-id (or (getf payload :room-id) (getf action :room-id)))
(meta (getf action :meta))
(room-id (or (getf meta :room-id) (getf payload :room-id) (getf action :room-id)))
(text (or (getf payload :text) (getf action :text)))
(hs (get-matrix-homeserver))
(token (get-matrix-token))
@@ -126,10 +127,8 @@ Polls the `/sync` endpoint and processes timeline events.
(harness-log "MATRIX: Received message from ~a in ~a" sender room-id)
(inject-stimulus
(list :type :EVENT
:payload (list :sensor :chat-message
:channel :matrix
:room-id room-id
:sender sender
:meta (list :source :matrix :room-id room-id :sender sender)
:payload (list :sensor :user-input
:text body)))))))))
(error (c) (harness-log "MATRIX SYNC ERROR: ~a" c))))))
#+end_src

View File

@@ -32,8 +32,8 @@ Enable secure Signal communication for the OpenCortex.
Wraps the `signal-cli` binary. Polling is done in a background thread to prevent blocking the harness.
** 2. Semantic Interfaces
- `(:sensor :chat-message :channel :signal ...)`
- `(:type :REQUEST :target :signal :chat-id "+1..." :text "...")`
- `(:type :EVENT :meta (:source :signal :chat-id "+1...") :payload (:sensor :user-input :text "..."))`
- `(:type :REQUEST :target :signal :payload (:action :message :text "..."))`
* Phase D: Build (Implementation)
@@ -63,7 +63,8 @@ Executes the `signal-cli send` command.
"Sends a message via signal-cli."
(declare (ignore context))
(let* ((payload (getf action :payload))
(chat-id (or (getf payload :chat-id) (getf action :chat-id)))
(meta (getf action :meta))
(chat-id (or (getf meta :chat-id) (getf payload :chat-id) (getf action :chat-id)))
(text (or (getf payload :text) (getf action :text)))
(account (get-signal-account)))
(when (and account chat-id text)
@@ -97,9 +98,8 @@ Polls for new messages and injects them into the harness.
(harness-log "SIGNAL: Received message from ~a" source)
(inject-stimulus
(list :type :EVENT
:payload (list :sensor :chat-message
:channel :signal
:chat-id source
:meta (list :source :signal :chat-id source)
:payload (list :sensor :user-input
:text text))))))))
(error (c) (harness-log "SIGNAL POLL ERROR: ~a" c))))))
#+end_src

View File

@@ -32,8 +32,8 @@ Enable mobile/remote access to the OpenCortex via a secure Telegram bot.
The gateway operates as an autonomous background service. It uses `dexador` for HTTP polling and `cl-json` for payload processing. Authentication is enforced via a whitelist of authorized `chat_id`s.
** 2. Semantic Interfaces
- `(:sensor :chat-message :channel :telegram ...)`
- `(:type :REQUEST :target :telegram :chat-id "..." :text "...")`
- `(:type :EVENT :meta (:source :telegram :chat-id "...") :payload (:sensor :user-input :text "..."))`
- `(:type :REQUEST :target :telegram :payload (:action :message :text "..."))`
* Phase D: Build (Implementation)
@@ -76,7 +76,8 @@ Fetches the Bot API token from the secure vault.
"Sends a message back to Telegram."
(declare (ignore context))
(let* ((payload (getf action :payload))
(chat-id (or (getf payload :chat-id) (getf action :chat-id)))
(meta (getf action :meta))
(chat-id (or (getf meta :chat-id) (getf payload :chat-id) (getf action :chat-id)))
(text (or (getf payload :text) (getf action :text)))
(token (get-telegram-token))
(url (format nil "https://api.telegram.org/bot~a/sendMessage" token)))
@@ -113,9 +114,8 @@ Fetches the Bot API token from the secure vault.
(harness-log "TELEGRAM: Received message from ~a" chat-id)
(inject-stimulus
(list :type :EVENT
:payload (list :sensor :chat-message
:channel :telegram
:chat-id (format nil "~a" chat-id)
:meta (list :source :telegram :chat-id (format nil "~a" chat-id))
:payload (list :sensor :user-input
:text text)))))))
(error (c) (harness-log "TELEGRAM POLL ERROR: ~a" c))))))
#+end_src

View File

@@ -1,74 +0,0 @@
:PROPERTIES:
:ID: 1e5a2c30-d3a9-4674-8db7-b08e7e1f44d1
:CREATED: [2026-04-11 Sat 14:40]
:END:
#+TITLE: SKILL: Lisp Repair Syntax Gate
#+STARTUP: content
#+FILETAGS: :system:repair:syntax:lisp:autonomy:
* Overview
The *Lisp Repair Syntax Gate* asynchronously intercepts `:syntax-error` events emitted by the harness when Probabilistic Engine (LLM) proposals fail to parse. It performs deterministic or neural repairs and re-injects the corrected action into the pipeline.
* Implementation
** Core Repair Logic
#+begin_src lisp
(defun count-char (char string)
(let ((count 0))
(loop for c across string
when (char= c char)
do (incf count))
count))
(defun deterministic-repair (code)
"Attempts instant fixes on broken Lisp code (e.g. balancing parens)."
(let* ((open-parens (count-char #\( code))
(close-parens (count-char #\) code))
(diff (- open-parens close-parens)))
(if (> diff 0)
(concatenate 'string code (make-string diff :initial-element #\)))
code)))
(defun neural-repair (code error-message)
"Uses Probabilistic Engine to deeply repair the syntax structure."
(let ((prompt (format nil "The following Lisp code failed to parse.
ERROR: ~a
CODE: ~a
MANDATE: Output EXACTLY ONE valid Common Lisp list. Do not explain. Do not use markdown blocks."
error-message code))
(system-prompt "You are a Lisp Syntax Repair Actuator. Return only valid, balanced Lisp code."))
(let ((repaired (ask-probabilistic prompt :system-prompt system-prompt)))
(string-trim '(#\Space #\Newline #\Tab) repaired))))
#+end_src
** Skill Definition
Reacts to syntax error events and transforms them into repaired requests.
#+begin_src lisp
(defskill :skill-lisp-repair
:priority 90
:trigger (lambda (ctx) (eq (getf (getf ctx :payload) :sensor) :syntax-error))
:probabilistic nil ;; Handled deterministically in deterministic or manually via ask-probabilistic
:deterministic (lambda (action context)
(declare (ignore action))
(let* ((payload (getf context :payload))
(code (getf payload :code))
(error-msg (getf payload :error)))
(harness-log "SYNTAX GATE: Reacting to broken Lisp stimulus...")
(let ((fast-fix (deterministic-repair code)))
(handler-case
(let ((repaired (read-from-string fast-fix)))
(harness-log "SYNTAX GATE: Deterministic repair SUCCESS.")
repaired)
(error ()
(harness-log "SYNTAX GATE: Deterministic repair failed. Escalating...")
(let ((deep-fix (neural-repair code error-msg)))
(handler-case
(let ((repaired (read-from-string deep-fix)))
(harness-log "SYNTAX GATE: Neural repair SUCCESS.")
repaired)
(error ()
(harness-log "SYNTAX GATE: Neural repair failed.")
(list :type :LOG :payload (list :text "Lisp Repair Failed.")))))))))))
#+end_src