Please disregard this. I keep forgetting about your “template” requirement.
This below works on my end.
I am not really concerned with the “circular behavior” or that the “capture template to have implementation details (the calls for the evaluation of the let-bound-variables instead of the “normal” way of referencing prompts)”.
An inner scope can work with variables in the outer scope. In this case, it’s only me using this let-binding, and can guarantee that it works for me and I don’t need to worry about usage by others.
(defvar var "")
(setq org-roam-capture-templates
'(("s" "special" plain ""
:target
(file+head "./${id}.org" "
#+title: ${title}
#+author: %(identity var)
#+id: ${id}
This is a template %(identity var)
"))))
(let ((var (read-string "Author: ")))
(org-roam-capture nil "s"))