:PROPERTIES: :ID: 97d0945e-9405-4da8-82e1-0e742063a99a :CREATED: [2026-03-31 Tue 16:14] :EDITED: [2026-04-07 Tue 13:42] :END: #+TITLE: SKILL: Org-GTD Archive Roam Daily (Universal Literate Note) #+STARTUP: content #+FILETAGS: :emacs:gtd:roam:archiving:psf: * 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) :PROPERTIES: :STATUS: FROZEN :END: ** 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) :PROPERTIES: :STATUS: SIGNED :END: * Phase B: Blueprint (PROTOCOL) :PROPERTIES: :STATUS: DRAFT :END: ** 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) #+begin_src elisp :tangle projects/org-gtd-archive-roam-daily/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) #+end_src