Reg — Docker Registry Client
A command-line client for working with Docker / OCI image registries that
speak the OCI Distribution Spec
(implemented by distribution/distribution, Harbor, GitLab Container
Registry, etc.).
- License: MIT (see LICENSE)
- Author: Chapvic, 2026
Table of contents
- Features
- Requirements
- Installation
- Configuration
- Credentials vault
- Authentication
- Command architecture
- Command reference
- Global flags
- Output format and exit codes
- Pagination
- Multi-arch and platform selection
- Push optimizations
- OCI image layout
- Docker save / load compatibility
- Localization
- Bash completion
- Recipes
- License
Features
- Object-grouped CLI:
repo,blob,image,manifest,auth,referrer,config— each group contains subcommands for a specific object type. - Top-level aliases for the most common operations
(
pull,push,copy,rm,tag,untag,exist,digest,login,logout,token,whoami). - Local config management:
config get/set/unset/list— safe, comment-preserving, secret-masking, no registry access needed. - List repositories (flat and nested tree), filter by glob.
- Find tags by regexp, find the newest tag by build time.
- Inspect tags, manifests, configs, platforms, sizes.
- Check existence and digest with
manifest exist/manifest digest. - Pull images into OCI image layout directory or
.tararchive. - Push images back, with
-mount-fromand-chunk-size. - Copy images between registries without writing to disk.
- Export/import in
docker save/docker loadformat. - Blob-level access:
blob info,blob get(with sha256 verification, atomic write,-o -streaming to stdout,-vprogress),blob delete. - Image inspection:
image config(raw config blob or single field),image files(file listing across layers with whiteout handling),image history(build history). - Delete tags, manifests, blobs, per-platform submanifests, or entire repositories — with explicit force flags and a capability pre-check.
- Hygiene:
repo prune(delete tags by age or keep N newest, withlatestprotection and-dry-run),repo stats(tags, unique blobs, total size, platforms, created range),repo verify(integrity of manifests and blobs;-deepfor content sha256). - Multi-arch aware: automatic platform selection or
-platform. - Bearer auth: auto-discovers the auth service from
WWW-Authenticate, supports-token, credentials vault,~/.docker/config.json. - Credentials management:
auth login/auth logout/auth status/auth migrate, with two vault backends (docker,local). - Diagnostics:
ping(with-vtiming) andcapabilities. - OCI 1.1 referrers:
referrer list(requiresdistributionv3.0+). - Localized error messages and help: English and Russian.
- Pure JSON on stdout; a stable, script-friendly output format.
- Single-dash flags everywhere:
-r,-config,-mount-from,-chunk-size, etc.
Requirements
- Go 1.21+ (to build from source).
- A registry compatible with the OCI Distribution Spec — tested with
distribution/distributionv2.8.3 behindalauda/registry-auth. Referrers API (referrer list,referrerscapability) requiresdistributionv3.0+.
Installation
Build from source
git clone <repo> reg
cd reg
make check # verify Go >= 1.21
make # dynamic build (depends on system glibc)
# or:
make static # static build (CGO_ENABLED=0), portable across Linux machines
# or:
make debug # ./reg-debug with DWARF, for delve (dlv) / pprof
The binary is ./reg. Verify with:
./reg
make runs go mod tidy first, so go.mod and go.sum are always in
sync before compilation.
Install system-wide
sudo make install # installs /usr/local/bin/reg
sudo make uninstall # removes it
Makefile targets
| Target | Purpose |
|---|---|
make / make build |
dynamic build (go mod tidy + go build -v -trimpath -ldflags="-s -w") |
make static |
static build with CGO_ENABLED=0 |
make debug |
debug build ./reg-debug (no optimizations, DWARF) |
make deps |
go mod tidy — synchronize go.mod and go.sum |
make check |
verify Go version >= 1.21 |
make install |
install existing ./reg to /usr/local/bin |
make uninstall |
remove /usr/local/bin/reg |
make clean |
remove ./reg and ./reg-debug |
make help |
short cheat sheet |
Static build note. Use make static for a fully static binary that
runs on any Linux (including Alpine, distroless, scratch) without extra
dependencies.
Configuration
File location
The config file is stored at ~/.reg/reg.conf. The ~/.reg directory
is created automatically (mode 0700) on every startup if it does not
exist — even for commands that do not read the config (e.g. reg help).
The same directory holds the local vault file by default
(~/.reg/credentials.json), so everything lives in one place.
In CI/CD, an explicit config path can be provided via -config <path>:
reg -config ./ci/reg.conf repo list
reg -config /etc/reg/reg.conf repo list
reg -config ~/configs/reg.conf repo list # ~/ is expanded
If -config is not given, ~/.reg/reg.conf is used. If the file does
not exist, an empty config is used (no error); all values must then be
provided via CLI flags.
Template
A template is shipped as reg.conf.example:
cp reg.conf.example ~/.reg/reg.conf
$EDITOR ~/.reg/reg.conf
Keys
# ~/.reg/reg.conf
registry=https://registry.tld # default registry for -r
username=myuser # auth service username
password=mypass # auth service password
token=eyJhbGciOi... # preset Bearer token
lang=ru # message language (en | ru)
insecure=0 # skip TLS certificate verification
vault=docker # credentials vault: docker | local
vault_file=~/.reg/credentials.json # local vault file (only vault=local)
| Key | Required | Description |
|---|---|---|
registry |
yes (if -r not set) |
default registry URL |
username / user |
no | auth service username |
password / pass |
no | auth service password |
token |
no | preset Bearer token |
lang |
no | language for messages and help (en, ru) |
insecure |
no | 0/1/true/false/yes/no/on/off |
vault |
no | docker (default) or local — credentials storage |
vault_file |
no | path to the local vault file; only valid with vault=local; default ~/.reg/credentials.json |
CLI over config
CLI flags take precedence over config values. -insecure is a bool
flag; if passed explicitly (-insecure=false), it overrides a config
value of insecure=1 for that single run.
Managing the config
The config group provides safe local management of ~/.reg/reg.conf
(no registry access needed; works even before a registry is configured):
reg config get <key> # read a value
reg config set <key> <value> # write a value
reg config unset <key> # remove a key
reg config list # list all keys and values
Semantics:
- Comment-preserving:
set/unsetedit the file line-by-line, keeping comments and the order of other lines. An inline comment on a replaced line is dropped. - Key normalization: keys are case-insensitive (normalized to lower-case).
- Validation (known keys):
insecure∈ {0,1,true,false,yes,no,on,off} (normalized to0/1);lang∈ {en,ru};vault∈ {docker,local}. Unknown keys are written as-is. - No cross-validation:
set vault_file ...whilevault=dockerdoes not fail here;regwill fail on the next start. This matches the low-level nature ofconfig set. - Secret masking in
list: values ofpasswordandtokenare printed as"***"; useconfig get <secret-key>to read them. - File mode: new file —
0600; existing file — current permissions are preserved (a warning is not printed here;auth statusand the local vault do warn when permissions are wider than0600). - Missing keys:
config geton a missing key exits with code 1;config unseton a missing key is a no-op (code 0). - Creating the file:
config setcreates~/.reg/reg.confif it does not exist.config liston a missing file prints{}.
Output examples:
$ reg config get lang
{"key": "lang", "value": "ru"}
$ reg config set insecure 1
{"key": "insecure", "value": "1", "updated": true}
$ reg config unset lang
{"key": "lang", "removed": true}
$ reg config list
{
"registry": "https://registry.tld",
"insecure": "1",
"password": "***",
"token": "***"
}
Credentials vault
The vault stores registry credentials used for authentication. Two
backends are supported; the choice is made in the config file via
vault=.
vault=docker (default)
- Storage:
~/.docker/config.json, compatible withdocker login. - Credential helpers are supported:
credsStoreandcredHelpers(exec protocoldocker-credential-<name> get|store|erase). - If a helper is configured for a registry,
reg auth login/logoutinvoke the helper. Helper failure is an error; there is no fallback to plaintext. - If no helper is configured,
auths.<host>.authis used (base64, the same asdocker login— this is encoding, not encryption). - If
vaultis not set in the config,auth loginprints a warning and usesdocker.
vault=local
- Storage: a Docker-compatible JSON file (
auths.<host>.authbase64). - File path from
vault_file; default~/.reg/credentials.json. - Path rules:
vault_file=cred.json→~/.reg/cred.jsonvault_file=~/.config/credentials.json→~/.config/credentials.jsonvault_file=/var/run/vault.json→ full pathvault_file=./ci/cred.json→ relative to cwd
- File permissions: created with
0600; if read with broader permissions, a warning is printed to stderr.
If vault_file is set but vault is not local, the client fails at
startup.
auth migrate
Copies credentials between vaults:
reg auth migrate -from docker -to local
reg auth migrate -from local -to docker
-fromand-toare required and must differ.- Source file must exist; otherwise the command fails.
- Credential helpers are honored on the docker side.
- If an entry exists in the target and
-overwriteis not set, it is skipped (not an error). -dry-runprints the plan without writing.-registry <host>migrates only the specified registry.- Non-interactive; no confirmation prompts.
- Errors per entry do not abort the run; they are collected in
failedand the exit code is 1.
Output (from_path and to_path are absolute paths; the example below
uses /home/user for illustration):
{
"dry_run": false,
"from": "docker",
"from_path": "/home/user/.docker/config.json",
"to": "local",
"to_path": "/home/user/.reg/credentials.json",
"migrated": ["registry.tld", "other.tld"],
"skipped": [{"registry": "third.tld", "reason": "already exists"}],
"failed": [{"registry": "fourth.tld", "error": "..."}]
}
Authentication
The client performs token-based Bearer authentication against the auth
service advertised by the registry's WWW-Authenticate challenge.
Token sources (in priority order)
-tokenflagtoken=in the config file- Automatic acquisition from the auth service, using credentials from:
-user/-passflagsusername/passwordin the config- the configured vault (
vault=docker→~/.docker/config.json;vault=local→ the vault file)
- Anonymous token, if no credentials are available
The client caches the token in memory and re-acquires it once on a
401 Unauthorized response.
Scope handling
The scope field in WWW-Authenticate can contain commas
(e.g. repository:myapp:pull,push). The parser handles quoted values
correctly, so both pull and push scopes are honored.
Inspecting the token
reg auth token— decode the current JWT and print all payload fields.reg auth token -raw— print the raw token string.reg auth whoami— printsub,scope,access.reg auth token myapp/reg auth whoami myapp— fetch a token with a scope targetingmyapp.
Top-level aliases reg token and reg whoami are also available.
TLS verification
-insecure (or insecure=1 in the config) disables TLS certificate
verification for both the registry and the auth service.
Command architecture
Commands are grouped by the object they operate on. Each group has subcommands; the most common subcommands also have top-level aliases.
| Group | Subcommands | Aliases |
|---|---|---|
repo |
list, tree, tags, info, manifest, delete, find, latest, prune, stats, verify |
— |
blob |
info, get, delete |
— |
image |
pull, push, copy, config, files, history |
pull, push, copy |
manifest |
rm, tag, untag, exist, digest |
rm, tag, untag, exist, digest |
auth |
login, logout, status, migrate, token, whoami |
login, logout, token, whoami |
referrer |
list |
— |
config |
get, set, unset, list |
— |
| Global | export, import, ping, capabilities, help |
— |
Global commands operate either on the registry as a whole (ping,
capabilities), on interoperability with Docker (export, import), or
on the local config file only (config, help).
All flags are single-dash (-name), including -mount-from,
-chunk-size, -from, -to, -dry-run, -overwrite, -registry.
Command reference
repo list
reg repo list [-a] [-filter <pattern>]
Filter pattern: * (any chars, including /), ? (one char), anchored
(use *sub* for substring).
repo tree
reg repo tree [-a] [-s] [-h]
-s computes repository sizes (expensive); -h (requires -s) prints
human-readable sizes.
repo tags
reg repo tags <repo> [-a] [-d]
Tags sorted in natural order (1.9 < 1.10, 1.5 < 1.5-slim < 1.5.1).
repo info
reg repo info <repo>[:<tag>|@<digest>] [-platform <os/arch>]
repo manifest
reg repo manifest <repo>[:<tag>|@<digest>]
repo delete
reg repo delete <repo> [-f]
Empty repository — no-op; non-empty without -f — error. Requires
storage.delete.enabled: true; a capability pre-check is performed.
repo find
reg repo find <repo> <pattern> [-a]
Filters tags by the Go regular expression <pattern>.
repo latest
reg repo latest <repo> [-a]
Fetches all tags, reads each config blob (created), prints the newest.
repo prune
reg repo prune <repo> [-keep N | -older-than <dur>] [-dry-run] [-force-latest]
Deletes tags by one of two mutually exclusive strategies:
-keep N— keep the N newest tags (bycreated) and delete the rest.-older-than <dur>— delete tags older than<dur>(acceptsNs/Nm/NhandNd, e.g.30d).
Requires storage.delete.enabled: true; a capability pre-check is
performed. Full tag traversal is always performed (no -a).
The latest tag is protected by default; use -force-latest to include
it in the deletion plan. Tags whose created field is missing or not
RFC3339 are not deleted and are listed in unreadable.
Output (with -dry-run):
{"repository": "myapp", "dry_run": true, "keep": 3,
"would_delete": ["1.5", "1.4", "1.3"],
"protected": ["latest"],
"unreadable": []}
repo stats
reg repo stats <repo> [-h]
Prints a summary of the repository: number of tags, unique manifests,
unique blobs (deduplicated across manifests), total size (manifests +
unique configs + unique layers, including submanifests of multi-arch
indexes, one level deep), list of platforms (union of desc.Platform
and (os, architecture, variant) from config blobs), oldest_created /
newest_created from config blobs. -h prints size instead of
size_bytes.
Full tag traversal is always performed (no -a). State is not modified;
only manifests and config blobs are downloaded (layers are not).
Output:
{"repository": "myapp",
"tags_count": 12,
"unique_manifests": 8,
"unique_blobs": 45,
"size_bytes": 123456789,
"config_count": 8,
"layer_count": 37,
"platforms": ["linux/amd64", "linux/arm64"],
"oldest_created": "2024-01-15T10:30:00Z",
"newest_created": "2024-10-01T12:00:00Z"}
repo verify
reg repo verify <repo> [-deep] [-jobs N] [-v]
Verifies integrity of the repository:
- For each tag:
HEADmanifest → digest; a tag whose manifest returns 404 is reported astag_dangling. - For each unique manifest digest (top-level and submanifests of
multi-arch indexes, one level deep):
GETbody and recompute sha256 → compare with digest; parse the body asManifestorManifestList. - For each unique config/layer blob:
HEAD→ 200/404. - With
-deep:GETbody of every blob and recompute sha256.
-jobs <N> controls parallelism (default 8). Full tag traversal is
always performed (no -a). No -platform flag: all platforms are
verified. Nested indexes of indexes (extremely rare) are not expanded.
Possible kind values: manifest_head_failed,
manifest_digest_mismatch, manifest_parse_failed, tag_dangling,
blob_missing, blob_head_failed, blob_digest_mismatch.
Output:
{"repository": "myapp",
"checked_tags": 12,
"checked_manifests": 8,
"checked_blobs": 45,
"deep": false,
"issues": []}
Exit codes: 0 — issues empty; 1 — at least one issue, or a fatal
error (e.g. cannot list tags).
blob info
reg blob info <image>@<digest>|<image>:<digest>
Output includes exists and (if present) size.
blob get
reg blob get <image>@<digest>|<image>:<digest> [-o <path>|-] [-v]
Downloads the blob by digest, verifies sha256 on the fly (mismatch —
temporary file removed, command fails), and saves it atomically
(<path>.tmp → rename). With -o -, the blob is streamed to stdout
and the status JSON is written to stderr (so the binary stream is not
polluted). With -v, progress events (start, done) are written to
stderr as one JSON line per event.
If the given digest refers to a manifest (not a blob), the command
fails with an explicit hint to use reg manifest digest or
reg repo manifest.
Output (JSON to stdout, or to stderr when -o - is used):
{"repository": "...", "digest": "sha256:...",
"path": "/abs/path/to/file", "size": 12345678,
"content_type": "application/octet-stream"}
blob delete
reg blob delete <image>@<digest>|<image>:<digest>
Requires storage.delete.enabled: true; a capability pre-check is
performed.
image pull
reg image pull <image>[:<tag>|@<digest>] [-o <dir>] [-f [<name>]] [-platform <os/arch>] [-v]
Also reg pull. Each blob is verified by sha256; repeated runs are
idempotent.
image push
reg image push <local-path> <image>:<tag> [-mount-from <src>] [-chunk-size <bytes>]
Also reg push. Existing blobs are skipped.
image copy
reg image copy <src> <dst> [-platform <os/arch>] [-mount-from <src-repo>]
Also reg copy. Without -platform, multi-arch indexes are copied whole.
image config
reg image config <image>[:<tag>|@<digest>] [-platform <os/arch>] [-field <path>] [-raw]
Downloads the config blob of the image.
- Default — wrapper with metadata:
{repository, tag, digest, platform, config}. -raw— the config blob itself, without wrapper.-field <path>— a single field, selected by dot-separated keys into the config blob (e.g.config.Env,architecture). Result is wrapped with{repository, tag, digest, platform, field, value}.-field <path> -raw— only the field value.
Missing field — error. Field present with JSON null — printed as
null. Array indices are not supported.
image files
reg image files <image>[:<tag>|@<digest>] [-platform <os/arch>] [-all | -layer <digest>] [-name <regexp>] [-n] [-v]
Lists files of the image. Three modes:
- Default — final set of files: layers applied bottom-up, whiteouts
processed (
.wh.<name>removes<dir>/<name>;.wh..wh..opqremoves all contents of<dir>/from lower layers). Whiteout files are not listed.layerfield points to the layer where the final version of the file appeared. -all— all entries of all layers as-is, without merging; whiteouts are listed as regular entries.-layer <digest>— only entries of the given layer (liketar tf).
-all and -layer are mutually exclusive. -name <regexp> filters by
the full (normalized) path. -n normalizes paths to absolute form
(./foo → /foo); without -n, paths are printed as in tar. -v
prints progress events to stderr.
Hardlinks are printed as type: "hardlink" with link; symlinks as
type: "symlink" with link. size is present only for regular files.
mode is the octal permission string.
image history
reg image history <image>[:<tag>|@<digest>] [-platform <os/arch>] [-raw]
Downloads the config blob of the image and prints its history array.
Default — wrapper {repository, tag, digest, platform, history}; with
-raw — only the array. Element fields: created, created_by,
author, comment, empty_layer.
manifest rm
reg manifest rm <image>[:<tag>|@<digest>] [-p <platform>] [-f]
Also reg rm. Requires storage.delete.enabled: true; a capability
pre-check is performed.
manifest tag
reg manifest tag <image>:<tag> <new_tag>
Also reg tag.
manifest untag
reg manifest untag <image>:<tag>
Also reg untag. Requires storage.delete.enabled: true.
manifest exist
reg manifest exist <image>[:<tag>|@<digest>]
Also reg exist. Exit code 0 — present; 1 — absent or error.
manifest digest
reg manifest digest <image>[:<tag>|@<digest>]
Also reg digest.
auth login
reg auth login <registry> [-user <u>] [-pass <p>]
Also reg login. Credential sources (priority):
-user/-passREG_USERNAME/REG_PASSWORD- interactive prompt (password without echo)
If vault is not set in the config, a warning is printed (default
docker is used).
auth logout
reg auth logout <registry>
Also reg logout.
auth status
reg auth status
Output:
{"vault": "docker", "path": "/home/user/.docker/config.json",
"registries": [
{"registry": "registry.tld", "user": "myuser", "via": "helper:pass"},
{"registry": "other.tld", "user": "other", "via": "auths"}
]}
via — auths (plaintext in config.json), helper:<name> (credentials
in a credential helper), or file (for vault=local). The path field
is absolute (the ~ form is illustrative only).
auth migrate
reg auth migrate -from docker|local -to docker|local [-dry-run] [-overwrite] [-registry <host>]
See Credentials vault for semantics.
auth token
reg auth token [-raw] [<repo>]
Also reg token.
auth whoami
reg auth whoami [<repo>]
Also reg whoami.
referrer list
reg referrer list <image>@<digest> [-type <artifactType>]
Requires distribution v3.0+. On older registries, an explicit error
is returned.
config get
reg [-config <path>] config get <key>
Reads a value from the config file (~/.reg/reg.conf by default). Exit
code 1 if the key is absent. Secret values are printed as-is.
Output:
{"key": "registry", "value": "https://registry.tld"}
config set
reg [-config <path>] config set <key> <value>
Writes the value into the config file, preserving comments and the order
of other lines. Validates known keys (insecure, lang, vault); unknown
keys are written as-is. Creates the file (mode 0600) if it does not
exist; preserves existing permissions on update.
Output:
{"key": "insecure", "value": "1", "updated": true}
config unset
reg [-config <path>] config unset <key>
Removes the key from the config file (all matching lines). No-op if the key is absent; the file remains even if empty.
Output:
{"key": "lang", "removed": true}
config list
reg [-config <path>] config list
Prints all keys and values from the config file in the order they appear.
Only keys actually present in the file are listed (defaults are not
synthesized). Secret values (password, token) are masked as "***".
Output:
{
"registry": "https://registry.tld",
"insecure": "0",
"lang": "en",
"vault": "docker",
"password": "***",
"token": "***"
}
export
reg export <image>[:<tag>|@<digest>] [-o <file.tar>] [-platform <os/arch>]
Produces a docker save tar; accepted by docker load. Default output:
<repo>-<tag>.tar; .tar is appended if missing.
import
reg import <file.tar> <image>:<tag>
Reads a docker save tar, gzip-compresses layers, uploads config and
layers, and pushes the manifest. Only single-image tars supported.
ping
reg ping [-v]
GET /v2/; output {"ok": true, "apiVersion": "registry/2.0"}.
With -v — also duration_ms.
capabilities
reg capabilities <repo>
{"repository": "myapp", "ping_ok": true, "api_version": "registry/2.0",
"delete_manifest": true, "delete_tag": true, "delete_blob": true,
"referrers": true}
The same probe is used internally by manifest rm, manifest untag,
blob delete, repo delete, repo prune as a pre-check.
help
reg help <command>
reg help <group> <subcommand>
-h, -help, --help inside a command are rejected with
no such option: <flag>. -h is reserved for human-readable in
repo tree and repo stats.
Warnings
For commands that take a repository name (repo tags, repo info,
repo manifest, repo delete, repo find, repo latest, repo prune,
repo stats, repo verify, capabilities), if the argument looks like
a registry URL (contains a . and no /), a warning is printed to
stderr. Use -r to set the registry.
Global flags
Specified before the command:
| Flag | Description |
|---|---|
-r <registry> |
registry URL; default from config |
-config <path> |
config file path (default ~/.reg/reg.conf); ~/ is expanded; missing file means empty config |
-lang <lang> |
message language (en, ru) |
-token <token> |
Bearer token |
-user <user> |
auth service username |
-pass <pass> |
auth service password |
-insecure |
skip TLS certificate verification |
Output format and exit codes
- Success: JSON to
stdout, exit code0. - Error:
{"error": "..."}tostderr, exit code1. - Progress for
image pull -v,blob get -v,image files -v,repo verify -v: separate JSON lines tostderr. - Blob get with
-o -: the binary blob goes tostdout; the status JSON goes tostderr(so the binary stream is not polluted).
JSON is emitted indented with 3 spaces. HTML escaping is disabled:
<, >, & are printed as-is.
Special exit codes:
manifest exist—0present,1absent or error.auth migrate—0if no failures (skipped entries are not failures),1if at least one entry infailed.repo verify—0ifissuesempty;1if at least one issue.config get—1if the key is absent.
Pagination
repo list, repo tree, repo tags, repo find, repo latest
support -a:
- Without
-a: one request withn=100. - With
-a: full traversal viaLink: rel="next"or?last=<last element>.
repo prune, repo stats, repo verify always traverse all tags
(no -a flag): partial results would be misleading for these commands.
Multi-arch and platform selection
For multi-arch images, the requested platform is selected via
-platform <os/arch[/variant]> or the current OS/arch.
manifest rm -p <platform> removes only that platform, updating the
index. With -p <platform> -f, if the removed platform was the last one,
the entire image is removed.
Push optimizations
Cross-repository mount. If a blob already exists in another
repository on the same registry, -mount-from <src> asks the registry
to mount the blob instead of uploading it.
Chunked upload. -chunk-size <bytes> enables chunked upload
(POST → PATCH × N → PUT).
OCI image layout
image pull (without -f) creates an OCI Image Layout directory:
<dir>/
├── oci-layout
├── index.json
└── blobs/
└── sha256/
├── <manifest-digest>
├── <config-digest>
└── <layer-digest>...
Compatible with skopeo, crane, oras, podman load, and accepted
unchanged by reg image push.
Docker save / load compatibility
reg export produces a docker save tar:
manifest.json
<config-hex>.json
<layer-hex>/layer.tar
Accepted by docker load. reg import reads the same format. Only
single-image tars supported.
Localization
Language order:
-langflaglang=in the config- Environment:
LANGUAGE→LC_ALL→LC_MESSAGES→LANG - Fallback:
en
Supported languages: en, ru. Unknown values silently fall back to
en.
Not translated. JSON responses, JSON field names, and progress event
names in image pull -v / blob get -v / image files -v /
repo verify -v.
Bash completion
reg-completion.bash in the project root provides tab completion for
all groups, subcommands, flags, platform values, language values, vault
values (for -from/-to), and files (for image push / import).
# For the current session:
source ./reg-completion.bash
# Per-user (persistent):
mkdir -p ~/.local/share/bash-completion/completions
cp reg-completion.bash ~/.local/share/bash-completion/completions/reg
# System-wide:
sudo cp reg-completion.bash /usr/share/bash-completion/completions/reg
Recipes
Is the tag present?
reg manifest exist myapp:1.5 && echo "present"
# or the alias:
reg exist myapp:1.5 && echo "present"
Get the digest of a tag.
reg manifest digest myapp:1.5
List only namespaced repositories, with human-readable sizes.
reg repo list -a -filter 'myorg/*'
reg repo tree -a -s -h
Find the newest tag by date.
reg repo latest myapp
Find version tags by regexp.
reg repo find myapp '^1\.'
Repository hygiene: keep only 10 newest tags.
reg repo prune myapp -keep 10 -dry-run
reg repo prune myapp -keep 10
Repository hygiene: drop tags older than 90 days.
reg repo prune myapp -older-than 90d -dry-run
reg repo prune myapp -older-than 90d
Repository summary (tags, blobs, size, platforms).
reg repo stats myapp
reg repo stats myapp -h
Verify integrity (HEAD + manifest sha256 + blob presence).
reg repo verify myapp
reg repo verify myapp -jobs 16
Deep verify (also downloads every blob and checks its sha256).
reg repo verify myapp -deep -jobs 4 -v
Download a single layer by digest.
reg blob get myapp@sha256:1111aaaa... -o /tmp/layer.tar
sha256sum /tmp/layer.tar # matches the digest
Stream a layer to stdout without touching the disk.
reg blob get myapp@sha256:1111aaaa... -o - | tar -tzf -
reg blob get myapp@sha256:1111aaaa... -o - -v > /tmp/layer.tar
Inspect image config.
reg image config myapp:1.5
reg image config myapp:1.5 -raw | jq .config.Env
reg image config myapp:1.5 -field config.Env
List files in the final image (with whiteout handling).
reg image files myapp:1.5 -n
reg image files myapp:1.5 -n -name '^/etc/.*'
reg image files myapp:1.5 -all -n -name '\.wh\.'
reg image files myapp:1.5 -layer sha256:1111aaaa... -n
Build history.
reg image history myapp:1.5
reg image history myapp:1.5 -raw | jq '.[-5:]'
Copy an image between registries, mounting blobs.
reg image copy registry.tld/myapp:1.5 other.tld/myapp:1.5 -mount-from myorg/myapp
Export to docker-save tar, then load into a local Docker daemon.
reg export myapp:1.5 -o /tmp/myapp.tar
docker load -i /tmp/myapp.tar
Import from docker-save tar into a registry.
docker save myapp:1.5 -o /tmp/myapp.tar
reg import /tmp/myapp.tar registry.tld/myapp:1.5-copy
Pull an image for ARM64.
reg image pull myapp:1.5 -o /var/lib/images -platform linux/arm64
Push a locally prepared OCI layout, mounting blobs from myorg/myapp.
reg image push ./myapp-1.5 registry.tld/myapp:1.5 -mount-from myorg/myapp
Remove one tag without touching other tags pointing to the same digest.
reg manifest untag myapp:1.5
# or the alias:
reg untag myapp:1.5
Remove a specific platform from a multi-arch image.
reg manifest rm myapp:1.5 -p linux/amd64
Remove the last remaining platform, deleting the whole image.
reg manifest rm myapp:1.5 -p linux/amd64 -f
Wipe an entire repository.
reg repo delete myapp -f
Check registry availability and delete support.
reg ping -v
reg capabilities myapp
Log in and inspect the current access.
reg auth login registry.tld -user myuser -pass mypass
reg auth status
reg auth whoami myapp
Migrate docker credentials to a local vault.
# In ~/.reg/reg.conf: set vault=local and (optionally) vault_file=...
reg auth migrate -from docker -to local -dry-run
reg auth migrate -from docker -to local
Manage the config locally (no registry needed).
reg config set registry https://registry.tld
reg config set lang ru
reg config get registry
reg config list
reg config unset lang
CI/CD: bootstrap the config from a template and log in non-interactively.
mkdir -p ~/.reg
cp ./reg.conf.example ~/.reg/reg.conf
reg config set registry https://registry.tld
REG_USERNAME=myuser REG_PASSWORD="$REG_PASS" reg auth login registry.tld
reg -config /etc/reg/reg.conf repo list
Work with a self-signed registry.
reg -insecure ping
reg -insecure repo list
License
MIT — see LICENSE for the full text.
Copyright (c) 2026, Chapvic