Files
org-agent-contrib/org-skill-org-gtd-archive-roam-daily.org

6.5 KiB

SKILL: Org-GTD Archive Roam Daily (Universal Literate Note)

Overview

The Org-GTD Archive Roam Daily skill enables chronological archiving of completed GTD tasks. Instead of a flat archive file, tasks are moved to their respective `org-roam-dailies` files based on their `:CREATED:` property, preserving contextual and temporal integrity.

Phase A: Demand (PRD)

1. Purpose

Define the requirements for chronologically-aware task archiving.

2. User Needs

  • Temporal Alignment: Archive tasks to the daily file matching their creation date.
  • Context Preservation: Maintain all properties and sub-elements during the move.
  • Robust Extraction: Correctly parse `:CREATED:` property timestamps.
  • Fail-safe Logic: Default to current date if `:CREATED:` is missing (with a warning).

3. Success Criteria

TODO Successful extraction of [YYYY-MM-DD] from   CREATED

TODO Automated creation of non-existent daily files during archive

TODO Subtree relocation verification

Phase B: Blueprint (PROTOCOL)

Phase B: Blueprint (PROTOCOL)

1. Architectural Intent

The system will utilize Emacs Lisp to extract the `:CREATED:` property from a GTD task, derive a date, locate (or create) the corresponding `org-roam-daily` file, and move the task subtree to that file. Error handling will include a fallback mechanism to the current date, accompanied by a user notification. The design emphasizes modularity and testability.

2. Semantic Interfaces (Lisp Signatures)

  • `(org-gtd-archive-roam-daily &optional subtree)`

    • Purpose: Main entry point. Archives a GTD task to its corresponding `org-roam-daily` file based on the `:CREATED:` property.
    • Arguments:

      • `subtree` (optional): The subtree to archive. Defaults to the current subtree.
    • Return Value: `t` on success, `nil` on failure.
    • Side Effects: Modifies Org files.
  • `(org-gtd-archive-roam-daily-extract-created-date subtree)`

    • Purpose: Extracts the date from the `:CREATED:` property of a subtree.
    • Arguments:

      • `subtree`: The subtree to extract the date from.
    • Return Value: A string in `YYYY-MM-DD` format, or `nil` if the property is missing or invalid.
  • `(org-gtd-archive-roam-daily-get-daily-file-path date)`

    • Purpose: Determines the file path for a given date, according to `org-roam-dailies` conventions.
    • Arguments:

      • `date`: A string in `YYYY-MM-DD` format.
    • Return Value: A string representing the file path.
  • `(org-gtd-archive-roam-daily-ensure-daily-file-exists file-path)`

    • Purpose: Creates an `org-roam-daily` file if it does not already exist.
    • Arguments:

      • `file-path`: The path to the `org-roam-daily` file.
    • Return Value: `t` if the file exists (either originally or after creation), `nil` if creation failed.
    • Side Effects: Creates a new file.
  • `(org-gtd-archive-roam-daily-move-subtree subtree file-path)`

    • Purpose: Moves a subtree to a specified file.
    • Arguments:

      • `subtree`: The subtree to move.
      • `file-path`: The destination file path.
    • Return Value: `t` on success, `nil` on failure.
    • Side Effects: Modifies Org files.
  • `(org-gtd-archive-roam-daily-warn message)`

    • Purpose: Displays a warning message to the user.
    • Arguments:

      • `message`: The warning message to display.
    • Return Value: `nil`
    • Side Effects: Displays a message.

Implementation

Emacs Lisp Logic (org-gtd-archive-roam-daily.el)

(require 'org-roam-dailies)
(require 'org-element)
(require 'org-time)

(defun amero-get-org-heading-created-property ()
  "Extract the :CREATED: property from the current Org heading.
  Returns a time string or nil if not found."
  (interactive)
  (save-excursion
    (org-back-to-heading t)
    (org-entry-get (point) "CREATED")))

(defun amero-parse-created-timestamp (timestamp-string)
  "Parse an Org-mode timestamp string like '[2026-03-16 Mon 14:05]'
  into an Emacs internal time object.
  Returns nil if parsing fails."
  (ignore-errors
    (org-time-string-to-time timestamp-string)))

(defun amero-get-daily-note-file (time-object)
  "Get the Org-roam daily note file for a given Emacs TIME-OBJECT.
  Creates the file if it doesn't exist. Returns the file path."
  (let* ((date-string (format-time-string org-roam-dailies-capture-templates-date-format time-object))
         (file-path (expand-file-name (concat date-string ".org")
                                      (expand-file-name org-roam-dailies-directory org-roam-directory))))
    ;; Ensure the directory exists
    (unless (file-exists-p (file-name-directory file-path))
      (make-directory (file-name-directory file-path) t))
    ;; Create file if it doesn't exist
    (unless (file-exists-p file-path)
      (with-temp-buffer
        (insert (format "#+title: %s\n" date-string))
        (write-file file-path)))
    file-path))

(defun org-gtd-archive-roam-daily ()
  "Archive the current Org heading to an Org-roam daily file
  based on its :CREATED: property."
  (interactive)
  (unless (org-before-first-heading-p (point))
    (user-error "Point is not on an Org heading or within an Org file."))

  (let* ((created-timestamp-string (amero-get-org-heading-created-property))
         (created-time-object (and created-timestamp-string
                                   (amero-parse-created-timestamp created-timestamp-string)))
         (heading-start (save-excursion (org-back-to-heading t) (point)))
         (heading-end (save-excursion (org-end-of-subtree t) (point)))
         (heading-content (buffer-substring-no-properties heading-start heading-end))
         daily-file-path)

    (unless created-time-object
      (user-error "No date error: Heading is missing a valid :CREATED: property."))

    (setq daily-file-path (amero-get-daily-note-file created-time-object))

    (with-current-buffer (find-file-noselect daily-file-path)
      (goto-char (point-max))
      (insert "\n\n" heading-content)
      (save-buffer))

    ;; Remove the original heading
    (delete-region heading-start heading-end)
    (message "Archived heading to %s" daily-file-path)))

(provide 'org-gtd-archive-roam-daily)