diff --git a/registry/client.go b/registry/client.go
index 4b9f0c4..c279e31 100644
--- a/registry/client.go
+++ b/registry/client.go
@@ -30,6 +30,13 @@ func Client(host string, opts *ociclient.Options) (ociregistry.Interface, error)
 			clientOptions.Transport = http.DefaultTransport
 		}
 
+		// make sure we set User-Agent explicitly; this is first so that everything else has an explicit layer at the bottom setting User-Agent so we don't miss any requests
+		// IMPORTANT: this wrapper stays first! (https://github.com/cue-labs/oci/issues/37#issuecomment-2628321222)
+		clientOptions.Transport = &userAgentRoundTripper{
+			roundTripper: clientOptions.Transport,
+			userAgent:    "https://github.com/docker-library/meta-scripts", // TODO allow this to be modified via environment variable
+		}
+
 		// if we have a rate limiter configured for this registry, shim it in
 		if limiter, ok := registryRateLimiters[host]; ok {
 			clientOptions.Transport = &rateLimitedRetryingRoundTripper{
diff --git a/registry/user-agent.go b/registry/user-agent.go
new file mode 100644
index 0000000..1c818c9
--- /dev/null
+++ b/registry/user-agent.go
@@ -0,0 +1,31 @@
+package registry
+
+// https://github.com/docker-library/meta-scripts/issues/111
+// https://github.com/cue-labs/oci/issues/37
+
+import (
+	"fmt"
+	"maps"
+	"net/http"
+)
+
+// an implementation of [net/http.RoundTripper] that transparently injects User-Agent (as a wrapper around another [net/http.RoundTripper])
+type userAgentRoundTripper struct {
+	roundTripper http.RoundTripper
+	userAgent    string
+}
+
+func (d *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
+	// if d is nil or if d.roundTripper is nil, we'll just let the runtime panic because those are both 100% coding errors in the consuming code
+
+	if d.userAgent == "" {
+		// arguably we could `panic` here too since this is *also* a coding error, but it'd be pretty reasonable to source this from an environment variable so `panic` is perhaps a bit user-hostile
+		return nil, fmt.Errorf("missing userAgent in userAgentRoundTripper! (request %s)", req.URL)
+	}
+
+	// https://github.com/cue-lang/cue/blob/0a43336cccf3b6fc632e976912d74fb2c9670557/internal/cueversion/transport.go#L27-L34
+	reqClone := *req
+	reqClone.Header = maps.Clone(reqClone.Header)
+	reqClone.Header.Set("User-Agent", d.userAgent)
+	return d.roundTripper.RoundTrip(&reqClone)
+}