Files
passepartout/skills/org-skill-ast-normalization.org

3.8 KiB

SKILL: AST Normalization Agent (Universal Literate Note)

Overview

The AST Normalization Agent maintains the structural integrity of the Org-mode Abstract Syntax Tree. It ensures all nodes adhere to strict metadata requirements and handles deterministic refactoring.

Phase A: Demand (PRD)

1. Purpose

Define automated structural enforcement and refactoring for the Org AST.

2. User Needs

  • Structural Enforcement: Mandatory unique IDs for all headlines.
  • Deterministic Preemption: Symbolic verification must override neural suggestions if errors exist.
  • Fidelity: Preservation of content during metadata normalization.

3. Success Criteria

TODO ID Injection

TODO Neural Preemption

TODO Subtree Refactoring Verification

Phase B: Blueprint (PROTOCOL)

Phase D: Build (Implementation)

Normalization Logic

(defun headline-ensure-id (headline)
  "Checks if a headline node has a unique ID. If not, generates and injects one."
  (let* ((props (getf headline :properties))
         (id (getf props :ID)))
    (if (and id (not (equal id "")))
        headline
        (let* ((new-id (org-agent:org-id-new))
               (new-props (append props (list :ID new-id))))
          (org-agent:kernel-log "AST - Injected new ID ~a into headline '~a'" new-id (getf props :TITLE))
          (setf (getf headline :properties) new-props)
          headline))))

(defun ast-normalize-recursive (ast)
  "Recursively ensures all headlines in the AST have unique IDs."
  (let ((type (getf ast :type))
        (contents (getf ast :contents)))
    (when (eq type :HEADLINE)
      (setf ast (headline-ensure-id ast)))
    (when contents
      (setf (getf ast :contents)
            (mapcar (lambda (child)
                      (if (listp child)
                          (ast-normalize-recursive child)
                          child))
                    contents)))
    ast))

(defun ast-normalize-file (filepath)
  "Reads a file (via Emacs actuator if possible, otherwise local), normalizes it, and returns the AST."
  (let ((ast (org-agent:context-query-store (format nil "file:~a" filepath))))
    (if ast
        (ast-normalize-recursive ast)
        (progn
          (org-agent:kernel-log "AST ERROR - Could not find AST for ~a in store." filepath)
          nil))))
#+begin_src

** Cognitive Tools
#+begin_src lisp
(org-agent:def-cognitive-tool :normalize-subtree "Ensures every headline in the current subtree has a unique ID."
  :parameters ((:id :type :string :description "The ID of the root headline to normalize"))
  :body (lambda (args)
          (let* ((id (getf args :id))
                 (obj (org-agent:lookup-object id)))
            (if obj
                (progn
                  (org-agent:kernel-log "AST - Normalizing subtree starting at ~a" id)
                  ;; Implementation note: In a real system, we'd reconstruct the AST from the store,
                  ;; normalize it, and then re-ingest it.
                  "SUBTREE NORMALIZATION INITIATED.")
                "ERROR: Node not found."))))

Skill Definition

(org-agent:defskill :skill-ast-normalization
  :priority 150 ; High priority, keeps the graph clean
  :trigger (lambda (context)
             (let ((payload (getf context :payload)))
               (eq (getf payload :sensor) :buffer-save)))
  :neuro nil
  :symbolic (lambda (action context)
              (let* ((payload (getf context :payload))
                     (ast (getf payload :ast)))
                (when ast
                  (ast-normalize-recursive ast))
                action)))