How to provide assets (image files) with a template so that they could eventually be overwritten?

This is true for basic usage, but for something more complex a closure hack by @ensko can be used:

#let cover(logo: none, doc) = {
  [Logo: #image(logo(), width: 69%)]
  doc
}

#import "@local/name:0.0.0": cover
#show: cover.with(logo: () => read("tiger.jpg", encoding: none))

You either have to mandate that users provide the closure or check the type and do stuff accordingly to it.

To make it slightly better, define an additional read function:

#let read-image = read.with(encoding: none)

#let cover(logo: none, doc) = {
  [Logo: #image(logo(), width: 69%)]
  doc
}

#import "@local/name:0.0.0": cover, read-image
#show: cover.with(logo: () => read-image("tiger.jpg"))

This is still not very complex, so here, if you just need to edit image settings, you can pass image.with("file"):

#show: cover.with(logo: image.with("tiger.jpg"))

#let cover(logo: none, doc) = {
  [Logo: #logo(width: 69%)]
  doc
}

If you want, for example (package structure does have 4 predefined logo file names), to override a directory full of assets, then I’m pretty sure logo: image => read("localdir/" + image) should work and is complex enough for the hack to be actually useful.