Bounty Ended with 50 reputation awarded by George
2 Update answer according to updated question - add find-based solution
source | link

EDIT: Using find and Helm

The solution below uses the shell command find to get a list of filenames. I use split-string so the files show up in the Helm prompt without the common prefix (instead I include the common prefix in the source's name). Because of that, I need to use f-join to so append-to-file gets the correct filename. Note that Helm has a transformers feature to alter how candidates are displayed, but I didn't use them here since I'm less familiar with them.

Using f-join brings a dependency on f.el, which you will need to install (in Spacemacs it's already installed). Using seq-map brings a dependency on seq.el, which requires Emacs 25.1 or newer. Both of these can be replaced by functions available in Emacs 24.5 and older (cl-map instead of seq-map, several string and filename functions instead of f-join).

(require 'f)
(require 'helm)
(require 'seq)

(defun helm-append-to-file (start end)
  (interactive "r")
  (let* ((path "/path/to/files")
        (relative-filename
          (helm :sources (helm-build-sync-source "append"
                          :candidates (get-candidates path))
                :buffer "*helm append to file*"
                :prompt "File to append to: "))
        (filename (f-join path relative-filename)))
    (append-to-file start end filename)))

(defun get-candidates (path)
  "Get names of capture files.
Return a list of filenames. Each filename is relative to PATH."
  ;; use -print0 just in case a filename contains a newline
  (let ((find-command (format "find -L '%s' -wholename '*/capture.md' -print0" path)))
    ;; remove common path prefix so candidates are easier to read in helm prompt
    (seq-map (lambda (s) (string-remove-prefix path s))
            ;; "\0" matches -print0
            (split-string (shell-command-to-string find-command) "\0" t))))

EDIT: Using find and Helm

The solution below uses the shell command find to get a list of filenames. I use split-string so the files show up in the Helm prompt without the common prefix (instead I include the common prefix in the source's name). Because of that, I need to use f-join to so append-to-file gets the correct filename. Note that Helm has a transformers feature to alter how candidates are displayed, but I didn't use them here since I'm less familiar with them.

Using f-join brings a dependency on f.el, which you will need to install (in Spacemacs it's already installed). Using seq-map brings a dependency on seq.el, which requires Emacs 25.1 or newer. Both of these can be replaced by functions available in Emacs 24.5 and older (cl-map instead of seq-map, several string and filename functions instead of f-join).

(require 'f)
(require 'helm)
(require 'seq)

(defun helm-append-to-file (start end)
  (interactive "r")
  (let* ((path "/path/to/files")
        (relative-filename
          (helm :sources (helm-build-sync-source "append"
                          :candidates (get-candidates path))
                :buffer "*helm append to file*"
                :prompt "File to append to: "))
        (filename (f-join path relative-filename)))
    (append-to-file start end filename)))

(defun get-candidates (path)
  "Get names of capture files.
Return a list of filenames. Each filename is relative to PATH."
  ;; use -print0 just in case a filename contains a newline
  (let ((find-command (format "find -L '%s' -wholename '*/capture.md' -print0" path)))
    ;; remove common path prefix so candidates are easier to read in helm prompt
    (seq-map (lambda (s) (string-remove-prefix path s))
            ;; "\0" matches -print0
            (split-string (shell-command-to-string find-command) "\0" t))))
1
source | link

As @db48x wrote, append-to-file uses Emacs' default completion facilities, which means calling the function completion-read. In turn, the variable completing-read-function determines what backend to use for completion. By controlling completion-read-function you decide what completion interface you want. Reading file names is a bit different, because it's done by read-file-name which is controlled by read-file-name-function. However, the default behavior is that read-file-name calls completing-read.

When helm-mode is enabled, it sets completing-read-function to helm--completing-read-default and read-file-name-function to helm--generic-read-file-name. In addition, in newer Emacs version (24.4+) Helm uses add-function to override these variables instead of setq. I assume that's because with setq it needs to know the original value when disabling helm-mode, but with add-function it doesn't.

The completion you get when invoking append-to-file is actually a generic helm file name completion, which isn't as heavy and feature-rich as the command helm-find-files. In fact, most Helm commands don't use interactive to read arguments, because they want more features than the generic Helm completion. Instead, they have a minimal interactive declaration and call helm function for reading arguments and performing actions, thus utilizing Helm's features. Notably, this includes helm-find-files and helm-projectile-find-file.

To change the default completion backend, you can just disable helm-mode and set completing-read-function and read-file-name-function to whatever you wish. Helm commands will still function through Helm as usual, and won't be affected by this change.

Alternatively, if you want append-to-file to use different completion, but still use Helm as the general completion backend, you will need to wrap append-to-file in another command. That command should read the arguments and then call append-to-file (non-interactively). With Helm, you could start with the following and modify according to your needs and how much of Helm's features you want to use:

(defun helm-append-to-file (start end)
  (interactive "r")
  (let ((filename
         (helm :sources some-helm-sources
               :buffer "*helm append to file*"
               :prompt "File to append to: ")))
    (append-to-file start end filename)))

Note that if (helm ...) changes the current buffer or region then append-to-file won't append the region you expect it to, so you'll want to wrap (helm ...) in a save-excursion or similar. You could use :candidates instead of :sources, but at that point you won't be much better off than the generic Helm completion. You might be lucky enough to find suitable pre-existing sources, so you don't need to write your own, but otherwise you will have to learn how to write a Helm source. You can look at helm-projectile.el and the macro helm-projectile-command to see how helm-projectile commands are defined.

For more info on Emacs completion you can visit section 19.6 of the elisp manual or read the relevant functions' documentation.