diff --git a/skills/org-skill-memory-archivist.org b/skills/org-skill-memory-archivist.org new file mode 100644 index 0000000..17167e9 --- /dev/null +++ b/skills/org-skill-memory-archivist.org @@ -0,0 +1,154 @@ +:PROPERTIES: +:ID: 98923a43-2be0-423c-8509-22592cfe9c9e +:CREATED: [2026-04-08 Wed 18:30] +:EDITED: [2026-04-09 Thu 15:30] +:END: +#+TITLE: SKILL: Memory Archivist (Universal Literate Note) +#+STARTUP: content +#+FILETAGS: :memory:persistence:ipfs:sovereignty: +#+DEPENDS_ON: id:e8b500e2-3f26-4c8e-8558-528061e178ca + +* Overview +The *Memory Archivist* provides long-term, decentralized, and immutable history for the agent's knowledge graph. It leverages IPFS to achieve "Sovereignty Above All," ensuring that memory state is preserved across space and time. + +* Implementation + +** Package Context +#+begin_src lisp +(in-package :org-agent) +#+end_src + +** Serialization (archivist-serialize-store) +Converts the live `*object-store*` into a JSON-compatible list of alists. + +#+begin_src lisp +(defun archivist-serialize-store () + "Serializes the entire object-store for archival." + (let ((objects nil)) + (maphash (lambda (id obj) + (declare (ignore id)) + (push `((:id . ,(org-object-id obj)) + (:type . ,(format nil "~s" (org-object-type obj))) + (:attributes . ,(loop for (k v) on (org-object-attributes obj) by #'cddr + collect (cons (format nil "~a" k) (format nil "~a" v)))) + (:content . ,(org-object-content obj)) + (:parent-id . ,(org-object-parent-id obj)) + (:children . ,(org-object-children obj)) + (:version . ,(org-object-version obj)) + (:last-sync . ,(org-object-last-sync obj)) + (:hash . ,(org-object-hash obj))) + objects)) + *object-store*) + objects)) +#+end_src + +** IPFS Integration (archivist-push-to-ipfs) +Pushes the serialized knowledge graph to the local IPFS daemon. + +#+begin_src lisp +(defun archivist-push-to-ipfs () + "Serializes the store and pushes it to IPFS, returning the CID." + (let* ((data (archivist-serialize-store)) + (json-payload (cl-json:encode-json-to-string data)) + (ipfs-url "http://127.0.0.1:5001/api/v0/add")) + (handler-case + (let* ((response (dex:post ipfs-url + :content `(("file" . ,json-payload)) + :headers '(("Content-Type" . "multipart/form-data")))) + (result (cl-json:decode-json-from-string response)) + (cid (cdr (assoc :hash result)))) + (kernel-log "ARCHIVIST - Memory checkpointed to IPFS. CID: ~a" cid) + cid) + (error (c) + (kernel-log "ARCHIVIST ERROR - IPFS push failed: ~a" c) + nil)))) +#+end_src + +** Restoration (archivist-pull-from-ipfs) +Fetches a knowledge graph image from IPFS and hydrates the `*object-store*`. + +#+begin_src lisp +(defun archivist-pull-from-ipfs (cid) + "Fetches data from IPFS by CID and restores the object-store." + (let ((ipfs-url (format nil "http://127.0.0.1:5001/api/v0/cat?arg=~a" cid))) + (handler-case + (let* ((response (dex:post ipfs-url)) + (data (cl-json:decode-json-from-string response))) + (clrhash *object-store*) + (dolist (item data) + (let* ((id (cdr (assoc :id item))) + (obj (make-org-object + :id id + :type (read-from-string (cdr (assoc :type item))) + :attributes (loop for attr in (cdr (assoc :attributes item)) + append (list (intern (string-upcase (car attr)) :keyword) (cdr attr))) + :content (cdr (assoc :content item)) + :parent-id (cdr (assoc :parent-id item)) + :children (cdr (assoc :children item)) + :version (cdr (assoc :version item)) + :last-sync (cdr (assoc :last-sync item)) + :hash (cdr (assoc :hash item))))) + (setf (gethash id *object-store*) obj))) + (kernel-log "ARCHIVIST - Knowledge graph restored from IPFS CID: ~a" cid) + t) + (error (c) + (kernel-log "ARCHIVIST ERROR - Restoration failed: ~a" c) + nil)))) +#+end_src + +** Cognitive Tools +Expose archival capabilities to System 1. + +#+begin_src lisp +(def-cognitive-tool :ipfs-checkpoint "Creates an immutable snapshot of the current knowledge graph on IPFS." + :parameters nil + :body (lambda (args) + (declare (ignore args)) + (let ((cid (archivist-push-to-ipfs))) + (if cid + (format nil "Checkpoint success. CID: ~a" cid) + "Checkpoint failed. Ensure IPFS daemon is running.")))) + +(def-cognitive-tool :ipfs-restore "Restores the entire knowledge graph from a specific IPFS CID." + :parameters ((:cid :type :string :description "The IPFS CID to restore from")) + :body (lambda (args) + (let ((cid (getf args :cid))) + (if (archivist-pull-from-ipfs cid) + (format nil "Restoration successful from ~a" cid) + "Restoration failed.")))) +#+end_src + +** Skill Definition +#+begin_src lisp +(defskill :skill-memory-archivist + :priority 80 + :trigger (lambda (ctx) (eq (getf (getf ctx :payload) :command) :checkpoint-ipfs)) + :neuro (lambda (ctx) "Propose an IPFS checkpoint if the user wants decentralized persistence.") + :symbolic (lambda (action ctx) + (let ((cid (archivist-push-to-ipfs))) + (if cid + `(:target :system :payload (:action :message :text ,(format nil "IPFS Checkpoint: ~a" cid))) + `(:target :system :payload (:action :message :text "IPFS Checkpoint failed.")))))) +#+end_src + +* Phase E: Chaos (Verification) +The Memory Archivist must be verified for serialization integrity. + +#+begin_src lisp +(defpackage :org-agent-archivist-tests + (:use :cl :fiveam :org-agent)) +(in-package :org-agent-archivist-tests) + +(def-suite archivist-suite :description "Tests for IPFS Archival.") +(in-suite archivist-suite) + +(test test-serialization-integrity + "Verify that the object-store can be serialized and partially reconstructed." + (clrhash org-agent::*object-store*) + (ingest-ast '(:type :HEADLINE :properties (:ID "test-id" :TITLE "Test Node") :raw-content "Body Text" :contents nil)) + (let* ((data (org-agent::archivist-serialize-store)) + (first-item (first data))) + (is (= 1 (length data))) + (is (equal "test-id" (cdr (assoc :id first-item)))) + (is (equal "Body Text" (cdr (assoc :content first-item)))))) +#+end_src