I've been working on an alternative syntax for org-capture-templates. The result is a package called "DOCT" (declarative org capture templates):

https://github.com/progfolio/doct

A brief list of what I believe to be improvements over the current syntax/implementation:

For exmaple, you have a template with an entry type of `'entry' and you forget the leading star in the template string. Days later you go to use that template. It's borked. You have a number of options:

None of these are ideal and all of them result in distraction. DOCT performs a number of checks ahead of time when possible to prevent these types of errors.

`org-capture-templates` is a flat list. The relationship between templates is hardcoded in each template's "keys" value. If you want to change the key for a top-level menu, you must then change it in each descendant's keys. DOCT uses nested plists and implements property inheritance.

Currently if you want to have a hook run for a particular template, you have to filter against `org-capture-plist' to check for the appropriate :key value. As stated above, this is fragile and you have to update that key value in numerous places if it ever changes. The same goes for `org-capture-templates-contexts`. DOCT allows specifying per-template contexts and hooks with the rest of the template's configuration.

A common pattern for attaching data to a template is to add to `org-capture-plist'. This pollutes `org-capture-plist' more than necessary. DOCT adds custom data to `org-capture-plist' under a single :doct keyword and allows users to access that data in the template string with familiar %-escape syntax.

This example is one I use daily for taking notes in programming projects:

(doct
 `("Note"
   :keys "n"
   :file ,(defun my/project-note-file ()
            (let ((file (expand-file-name "notes.org" (when (functionp 'projectile-project-root)
                                                        (projectile-project-root)))))
              (with-current-buffer (find-file-noselect file)
                (org-mode)
                ;;set to utf-8 because we may be visiting raw file
                (setq buffer-file-coding-system 'utf-8-unix)
                (when-let ((headline (doct-get :headline)))
                  (unless (org-find-exact-headline-in-buffer headline)
                    (goto-char (point-max))
                    (insert "* " headline)
                    (org-set-tags (downcase headline))))
                (unless (file-exists-p file) (write-file file))
                file)))
   :template (lambda () (concat  "* %{todo-state} " (when (y-or-n-p "link?") "%A\n") "%?"))
   :todo-state "TODO"
   :children (("bug"           :keys "b" :headline "Bugs")
              ("documentation" :keys "d" :headline "Documentation")
              ("enhancement"   :keys "e" :headline "Enhancements" :todo-state "IDEA")
              ("feature"       :keys "f" :headline "Features"     :todo-state "IDEA")
              ("optimization"  :keys "o" :headline "Optimizations")
              ("miscellaneous" :keys "m" :headline "Miscellaneous")
              ("security"      :keys "s" :headline "Security"))))

Each template inherits its parent's file finding function,template string, and a default :todo-state. The template string access the child's :todo-state keyword with the "%{KEYWORD}" syntax in the template string.

I would be happy to work on getting these features into Org if there is any interest. Any feedback is welcome.

Thanks, nv.