I'm a beginner at elisp and I'd like your input on my strategy for writing some code for my org/org-roam setup.

I have a file called inbox.org, that I capture stuff into when I'm on the go (via Plain Org). It's structured like this:

#+title: Capture inbox
* First thing I captured
  Some text
* Second thing I captured

I also use the org-roam dailies feature, where I create a new daily note every day. My template for dailies looks like this:

#+title: %<%Y-%m-%d (%a)>
#+location: %(gt/daily-location)
#+weather: %(gt/daily-weather)

* Diary

(gt/daily-* are helper functions that I wrote, these basically run shell scripts and insert the output)

Here's what I would like to do: I want to add a new tree to my daily file called Inbox and move all the trees out of inbox.org into that tree in my daily file. Once that's done, I want my inbox.org to contain only its title (#+title: Capture inbox) and nothing else.

I have two ideas on how to do this:

  1. Add another helper function call to my daily template, that will open inbox.org, and return the raw contents. That's easy enough to do, but the formatting is messy: top level headers from my inbox file will be at the top level of my daily note as well, and not under the Inbox tree as I would like.

  2. Hook into the org-roam-dailies-find-file-hook, which is triggered whenever you open a daily file. In that case, I would have to somehow check if the daily file opened is for today, if it's just being created (rather than me coming back to it later, when I would not want to insert the contents of inbox.org), etc.

The second option feels like the start of a cleaner solution, but I'm not sure how to proceed. Would anyone have any advice on how this could be accomplished?

  • Have you looked at org-refile? See Refiling and Archiving in the Org mode manual.
    – NickD
    Commented Nov 16, 2022 at 1:28
  • Thanks @NickD, org-refile is what I needed, but it was more the logic around it that I found difficult to figure out.
    – gosha
    Commented Nov 17, 2022 at 9:47

1 Answer 1


After a lot of trial and error, I came up with a solution that works for me (with inspiration from this answer). Here it is:

(setq gt/org-inbox-file (file-name-concat org-directory "inbox.org"))

(defun gt/refile-to-file-headline (file headline)
  "Refile tree to a specific file and a specific headline"
  (let ((pos (save-excursion
               (find-file file)
               (org-find-exact-headline-in-buffer headline))))
    (org-refile nil nil (list headline file nil pos))))

(defun gt/org-roam-today-daily-path ()
  "Return the path for today's org-roam daily note"
   (format-time-string "%F.org")))

(defun gt/refile-inbox-to-org-roam-today-daily ()
  "Refile all org trees from inbox file to today's org-roam daily note"
  (let ((inbox-buffer (find-file-noselect gt/org-inbox-file)))
    (set-buffer inbox-buffer)
     (lambda ()
       (setq org-map-continue-from 0)

(defun gt/org-roam-daily-hook ()
  "Hook called upon visiting an org-roam daily note"
  (let ((daily-buffer (current-buffer)))
    ;; Only perform this if we're visiting the buffer for today's daily
    (when (string= (buffer-file-name daily-buffer) (gt/org-roam-today-daily-path))
      (set-buffer daily-buffer))))

(add-hook 'org-roam-dailies-find-file-hook 'gt/org-roam-daily-hook)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.