Files
memex/notes/org-skill-cron.org

5.4 KiB

SKILL: Cron Agent (Universal Literate Note)

Overview

The Cron Agent serves as the system's temporal conscience. It provides autonomous, time-aware capabilities by hooking into the background heartbeat, enabling proactive executive assistance.

Phase A: Demand (PRD)

1. Purpose

Define automated behaviors for deadline monitoring and temporal alerting.

2. User Needs

  • Punctuality: Monitor deadlines and alerts across the Memex.
  • Efficiency: Symbolic filtering (System 2) to minimize LLM calls.
  • Multi-Channel Awareness: Routing alerts to Emacs or external delivery.

3. Success Criteria

TODO Heartbeat Trigger Verification

TODO Timestamp Parsing Accuracy

TODO Overdue Task Detection

Phase B: Blueprint (PROTOCOL)

1. Architectural Intent

Interfaces for temporal perception and task auditing. Source of truth is the current system time and Org timestamps.

2. Semantic Interfaces

(defun trigger-skill-cron (context)
  "Triggers on :sensor :heartbeat.")

(defun parse-org-timestamp (ts-str)
  "Converts Org timestamp string to machine-comparable format.")

(defun neuro-skill-cron (context)
  "Neural drafting of alerts for overdue tasks.")

Phase D: Build (Implementation)

Heartbeat Perception

(defun trigger-skill-cron (context)
  (let ((type (getf context :type))
        (payload (getf context :payload)))
    (when (and (eq type :EVENT) (eq (getf payload :sensor) :heartbeat))
      ;; Side-effect: Check if it's time for the nightly grooming cycle
      (trigger-nightly-grooming)
      t))) ; Return T to trigger the skill

Temporal Parsing & Nightly Cycle

(defun parse-org-timestamp (ts-str)
  (let ((match (nth-value 1 (cl-ppcre:scan-to-strings "<(\\d{4})-(\\d{2})-(\\d{2}).*>" ts-str))))
    (if match
        (encode-universal-time 0 0 0 
                               (parse-integer (aref match 2)) 
                               (parse-integer (aref match 1)) 
                               (parse-integer (aref match 0)))
        nil)))

(defun trigger-nightly-grooming ()
  "Checks if the current time is within the nightly grooming window (e.g., 3:00 AM - 4:00 AM).
   If so, and it hasn't run today, it injects a grooming stimulus."
  (let* ((now (local-time:now))
         (hour (local-time:timestamp-hour now)))
    (when (= hour 3) ; 3 AM
      (kernel-log "CRON - Initiating Nightly Grooming Cycle...")
      (org-agent:inject-stimulus `(:type :EVENT :payload (:sensor :grooming-cycle))))))

Context Injection

  "Retrieves all headlines with DEADLINE timestamps in the next N days.
   Enables Temporal Context Injection for System 1."
  (let* ((now (get-universal-time))
         (future-limit (+ now (* days 24 60 60)))
         (all-headlines (org-agent:list-objects-by-type :HEADLINE))
         (upcoming nil))
    (dolist (obj all-headlines)
      (let* ((attrs (org-agent:org-object-attributes obj))
             (deadline-str (getf attrs :DEADLINE))
             (deadline-time (when deadline-str (parse-org-timestamp deadline-str))))
        (when (and deadline-time (< deadline-time future-limit) (> deadline-time (- now 86400)))
          (push (list :title (getf attrs :TITLE) :deadline deadline-str) upcoming))))
    upcoming))

(defun context-get-stalled-waiting-items (&optional (days 3))
  "Finds items marked WAITING that have not been updated in N days."
  (let* ((now (get-universal-time))
         (past-limit (- now (* days 24 60 60)))
         (all-headlines (org-agent:list-objects-by-type :HEADLINE))
         (stalled nil))
    (dolist (obj all-headlines)
      (let* ((attrs (org-agent:org-object-attributes obj))
             (state (getf attrs :TODO-STATE))
             (last-sync (org-agent:org-object-last-sync obj)))
        (when (and (equal state "WAITING") (< last-sync past-limit))
          (push (list :title (getf attrs :TITLE)) stalled))))
    stalled))

Neuro-Cognitive Intelligence

(defun neuro-skill-cron (context)
  "Neural stage for temporal awareness. 
   Injects upcoming calendar events and stalled items into the cognitive loop."
  (let* ((upcoming (context-get-upcoming-deadlines 3)) ; Look 3 days ahead
         (stalled (context-get-stalled-waiting-items 3)) ; Look 3 days back
         (now-str (local-time:format-timestring nil (local-time:now))))
    (format nil "
      CURRENT TIME: ~a
      
      UPCOMING DEADLINES (Next 3 Days):
      ---
      ~{~a: ~a~%~}
      ---

      STALLED WAITING ITEMS (> 3 days old):
      ---
      ~{~a~%~}
      ---
      
      TASK:
      If any deadline is CRITICAL or OVERDUE, propose a proactive alert or plan adjustment.
      If there are stalled WAITING items, propose a follow-up action to unblock them.
    " now-str 
    (loop for item in upcoming append (list (getf item :deadline) (getf item :title)))
    (loop for item in stalled collect (getf item :title)))))

Registration

(defskill :skill-cron
  :priority 60
  :trigger #'trigger-skill-cron
  :neuro #'neuro-skill-cron
  :symbolic (lambda (action context) action))