pkg(1)
NAME
pkg - Ur Project package and composition CLI
SYNOPSIS
pkg [global-options] command [command-options] [args...]
DESCRIPTION
pkg is the one program you talk to on an Ur Project system. It installs, removes, upgrades, inspects and verifies packages. It manages the repositories those packages come from. And it turns a set of packages into something you can deploy: a filesystem tree, an immutable slice, an OCI image or a bootable disk image.
It's also a thin layer. Resolving dependencies, applying transactions, tracking state, checking signatures and composing images all live in library crates. Every rule in these pages is enforced there, not in the argument parser, so the same rules hold no matter what is calling them.
This page is the map. Each command has its own page, listed under COMMANDS, and the ideas that run through all of them have pages in section 7. Three of those ideas are worth reading before anything else, because they're where pkg behaves differently from what you might expect.
The chain, not the version
Repositories are stacked in a precedence order. The first repository in the chain that pins a name answers for that name. Full stop. Nothing anywhere in pkg picks a package by comparing version numbers, so a stale copy in some lower repository can never win by being "newer". See pkg-chain(7).
Convergence, not comparison
pkg upgrade doesn't ask whether something is newer. It asks whether the installed artifact is the artifact the pin names, by comparing payload digests. So moving between repositories at an identical version is real work, a rebuild that came out byte-for-byte identical is no work at all, and a downgrade needs no special case. See pkg-upgrade(1).
Selection roots, not a manual flag
What you explicitly asked for is recorded as a selection root. Everything installed that no root reaches is a dependency, and pkg-autoremove(1) sweeps it. A root records your intent, a bare name or a bare set name, never a frozen list of what that expanded to on the day. See pkg-sets(7).
SPECS
How do I name a package?
Every command that takes package names accepts the same grammar.
- name
- The package's runtime content: every subpackage the winning repository carries for that name, minus build-derived output, development content, server daemons and interpreter-bound scripts. There's no main subpackage to fall back to. See pkg-subpkgs(7).
- name/subpkg
- One subpackage, checked against the repository. A subpackage the winning repository doesn't carry is refused by name, with a list of what's on offer.
- name=version
- An explicit version. This is the only form that looks at superseded builds, so it can name an artifact that's no longer current.
+set- A set: a named, unversioned member list, resolved across the whole chain. See pkg-sets(7).
No spec takes an @repo suffix. The chain decides which repository answers for a name, not you, and not the command line.
Commands that produce an artifact, pkg-compose(1) and pkg bundle create, refuse name=version, because an artifact is built from the chain's current set. pkg build --with takes only name and name/subpkg, and reads a bare name by the buildroot rules of pkg-build(1), not as runtime content.
COMMANDS
Managing the installed system
- pkg-install(1)
- Install one or more packages or sets. Alias:
add. - pkg-remove(1)
- Remove installed packages, or drop a set root. Aliases:
delete,uninstall,erase. - pkg-autoremove(1)
- Remove installed packages that no selection root reaches any more.
- pkg-upgrade(1)
- Converge the installed set onto what the repository chain pins, or with
--to, onto one published build's pins file or image.json. - pkg-check-update(1)
- Report whether updates are available, changing nothing. Cheap enough for a timer, and exits 100 when there are. Alias:
check-updates. - pkg-stage-update(1)
- Download the payloads an upgrade would install ahead of time, so the upgrade itself is fast and needs no network.
- pkg-repair(1)
- Restore an installed package's drifted files from its payload.
- pkg-triggers(1)
- Run or list the system trigger ruleset: cache and preset regeneration.
- pkg-rollback(1)
- Undo the newest transaction, or return to the state after an earlier one, and pin what moved.
- pkg-pin(1)
- Hold packages at their installed build, list local pins, or release them again with
pkg unpin.
Inspecting
- pkg-history(1)
- The transactions this machine committed, numbered the way
/var/log/pkg.lognumbers them. One in detail, or exported as a pins file. - pkg-search(1)
- Search the chain by name, capability, or shipped file. Alias:
find. - pkg-list(1)
- List installed packages, or every package the chain makes current. By default, everything a selection root reaches folds into that root's row;
--collapsewalks down from there tosets,mainandnone. - pkg-query(1)
- Print details of an installed package: files, provides, requires, conflicts. Alias:
show. - pkg-info(1)
- Print details of a manifest, by name or by path.
- pkg-license(1)
- Report what the installed set, or one package, is licensed under, and print the license text it ships.
- pkg-sbom(1)
- Emit a software bill of materials for the installed set, in SPDX or CycloneDX.
- pkg-verify(1)
- Check the files of installed packages, a set, or everything installed, on disk against their manifests. Alias:
check. - pkg-list-sets(1)
- List installed sets, or every set in the chain.
- pkg-set(1)
- Inspect sets published across the chain: membership, contributors, resolution.
Configuring repositories
- pkg-repo(1)
- Add, remove, enable, disable and list configured repositories.
Provenance and signatures
- pkg-provenance(1)
- Verify a published package's buildroot-attestation record, reproduce the build offline, or download the upstream sources it was built from.
- pkg-sign(1)
- Sign a manifest with an Ed25519 key.
- pkg-verify-sig(1)
- Verify the signature on a manifest.
Producing artifacts
- pkg-compose(1)
- Compose a closure into a filesystem root, an immutable slice, an OCI image, or a bootable disk image.
- pkg-bundle(1)
- Produce or install an offline .pkgtar bundle.
- pkg-offline(1)
- Update an air-gapped system by hand-carried bundle: export its pins, build a delta bundle for it elsewhere, apply that bundle.
Building packages
- pkg-build(1)
- Build a recipe directory on this machine into a signed local repository, with a buildroot resolved from the chain.
- pkg-keygen(1)
- Create the key
pkg buildsigns with.
Shell integration
- pkg-completion(1)
- Print a shell completion script.
GLOBAL OPTIONS
These go before or after the subcommand, and apply to every command.
--json- Emit JSON on stdout instead of human text. Errors become "
{"ok": false, "error": "..."}" on stderr. The schemas are documented per command and in pkg-cli/JSON.md. A--jsonrun can never answer a confirmation prompt, so commands that change the system also need--yes. -y,--yes- Assume yes, and skip the confirmation prompt for operations that change the system. What gets a prompt is set by the top-level
confirmkey in pkg.toml(5):none,dangerous,destructiveorall, defaultdestructive.--yesis also how a script or a--jsonrun gets through without a terminal, since nobody is there to answer the prompt. It does not get you past the trust-on-first-use prompt in pkg-repo(1). --collapse=LEVELHow far a human listing folds up the subpackages a package was split into. (
bin,lib,data,boot,modand the rest are content classes that the classifier assigns, not something you name -- see pkg-subpkgs(7).)main: each package's runtime subpackages fold into one row, with the classes in brackets: "name V-R [/bin, /lib]". Non-runtime ones (dev,man,doc,lang,server,debug,debugsrc,source, and the interpreter classes) stay on their own name/subpkg row. This is the default everywhere except pkg-list(1).none: one row per subpackage.sets,roots: fold further, onto what you selected instead of onto the package name. Only pkg-list(1) can answer these, because the question is about an installed set and the selection roots that produced it.rootsis its default for the installed set. Ask anything else for them, or askpkg list --allforroots, and you get refused by name rather than quietly handedmain.
It applies to the transaction plan (pkg-install(1), pkg-upgrade(1), pkg-remove(1), pkg-autoremove(1), pkg-offline(1)), the closure pkg-compose(1) prints, the name and capability hits of pkg-search(1), and the listing of pkg-list(1). It's presentation only. It changes no behaviour, and
--jsonalways gets the flat per-subpackage list.-v,-vv,-vvvShow what
pkgis doing, on stderr. stdout stays clean, so--json | jqworks at any level. Each level adds to the one below:-v: outcome. One line per phase, with how long it took and the counts it produced.-vv: progress. The same phases announced as they start, plus per-repo and per-package step detail.-vvv: per-item waterfall. Every manifest read, goal, closure member, blob and fetch URL. It's a lot, on purpose. Network lines start withnet:: whether a repository is reached directly or through a proxy (and which variable or file named it), every address tried, every request, response and retry. A long gap between twoconnecting tolines for one host is a connection attempt that timed out.
Anything past
-vvvbehaves as-vvv. Verbosity never changes behaviour, exit codes or the bytes on stdout. The full contract and a per-command map live in pkg-cli/VERBOSITY.md.Byte counts are printed as magnitudes (152.4 MiB). From
-vvup, the exact count rides along with each one (152.4 MiB (159771259 bytes)), for when you need to reconcile a number against something else.--no-progressDon't draw the download progress line. While
pkgwaits on the network, during the per-manifest metadata walk and each payload fetch, it repaints a single line on stderr saying what's in flight, how far along it is and how fast:metadata Common [ 145/1674] fetch [ 2/9] gcc/lib 86.4 MiB / 92.8 MiB 93% 13.4 MiB/s
That line is already off whenever stderr isn't a terminal, or
--jsonwas given, so a redirected log, a timer and a pipeline get nothing to filter out. This flag is for the interactive run that wants silence anyway. Progress is never drawn for a local repository directory, or for payloads pkg-stage-update(1) already staged. Those are file reads, not downloads.--state-rootDIR- The root directory of the client state database. Default
/var/lib/pkg. See pkg-state(5). --repoDIR- A single local repository. Default
/var/lib/pkg/repo. Used when no repositories are configured and no--repo-urlis given. See pkg-repository-layout(7). --payload-dirDIR- Where payload blobs live. The canonical layout is <dir>/data/<sha[0:2]>/<sha[2:4]>/<sha>; a flat development layout (<dir>/<sha>.pkg-data) is tried as a fallback. Defaults to
--repo, so one canonical-layout root works without passing both. --repos-dirDIR- The directory of drop-in repository definitions. Default
/etc/pkg/repos.d. This is the normal way to configure repositories. A missing directory just means no configured repositories. See pkg-repos.d(5). --pins-dirDIR- The directory of local pins. Default
/etc/pkg/pins.d. A missing directory means no local pins. See pkg-pins.d(5). --repo-urlURL- The base URL of a remote repository. Can be repeated. Together with
--tuf-root, it fetches and verifies signed metadata from <url>/metadata/. The Nth--repo-urlis verified by the Nth--tuf-root, highest precedence first. Replaces--repos-direntirely. --tuf-rootFILE- A TUF 1.root.json holding the trust anchor for the
--repo-urlin the same position. Get it out-of-band, never over the same URL the metadata lives at, or it proves nothing. --configFILE- The system client configuration. Default
/etc/pkg.toml. A missing file means the defaults. See pkg.toml(5). -h,--help- Print help. Works per subcommand too:
pkg install --help. -V,--version- Print the version, taken from the git tag at build time.
EXAMPLES
First contact with a machine
What's configured, what's installed, and what the chain offers:
pkg repo list pkg list pkg list --all pkg list-sets --all
pkg list already reads through this machine's selection roots: one row per root, then only what no root explains. To credit a set with only what it literally names, instead of everything its closure pulled in, or to drop the overlay entirely:
pkg list --collapse=sets pkg list --collapse=main
Adding a repository and installing from it
pkg repo add http://repo.example:8082/Base \ --fingerprint 4f3c...9a1b pkg repo add http://repo.example:8082/Common \ --fingerprint 71de...02c4 pkg install vim git
The everyday loop
pkg upgrade --dry-run pkg upgrade pkg autoremove --dry-run pkg autoremove
The same loop, on a metered or slow link
Ask cheaply, download on your own schedule, apply in a window:
pkg check-update pkg stage-update pkg upgrade
Finding things
pkg search compress pkg search --provides soname:libz.so.1 pkg search --file /usr/bin/gzip pkg search --file '*.so.6'
Asking what a package is, and what it owns
pkg info gzip pkg query gzip --files pkg query gzip --requires --provides
Checking that a machine hasn't drifted
pkg verify --all --quiet pkg verify coreutils --quiet pkg repair coreutils --dry-run pkg repair coreutils
Installing more than the runtime content
Manual pages and headers aren't part of a bare name, and neither is a daemon:
pkg install vim/man pkg install openssl/dev pkg install openssh/server
To opt a whole machine in, use [install] include_subpkgs in pkg.toml(5).
Scripting
Every command takes --json, and the ones that change the system also need --yes:
pkg --json list | jq -r '.packages[].name' | sort -u pkg --json --yes install vim | jq '.installed_count' pkg --json upgrade --dry-run | jq '.upgrade[] | .from.name'
Working against a repository that isn't configured
Explicit flags replace repos.d entirely. That's handy for testing a staging repository without touching the machine's configuration:
pkg --repo /srv/mirror/Common --repos-dir /nonexistent list --all pkg --repo-url http://staging:8082/Common \ --tuf-root /tmp/common.root.json search vim
Composing an artifact instead of installing
pkg compose root --output /srv/roots/minimal \ --closure +console --trust-key "$PUBKEY" pkg compose image --output /srv/images/ur.raw \ --closure +console --trust-key "$PUBKEY"
Building a package and handing it to someone
Make the key once per user, then build each recipe. --from-repo-dir puts the output repository on top of the configured chain for the bundle, so the bundle carries the dependencies too:
pkg keygen pkg build ./which --out ~/work/out pkg bundle create --from-repo-dir ~/work/out --output which.pkgtar
Seeing where the time goes
pkg -v upgrade --dry-run pkg -vv install vim pkg -vvv install vim 2> /tmp/pkg-trace.log
Auditing what you're actually running
pkg provenance verify openssl pkg provenance download-sources openssl --out /tmp/src pkg provenance rebuild openssl
EXIT STATUS
pkg exits 0 on success and 1 on any failure. The message on stderr tells you which failure. A command line that doesn't parse exits 2; under --json its message comes in the same error envelope as any other failure.
Some commands treat a non-empty result as a failure, on purpose: pkg verify exits non-zero when any file fails verification, pkg triggers run when any trigger failed, pkg provenance rebuild when the rebuild diverged, and pkg license --check when anything installed violates the [license] policy.
One command carries its answer in the exit code. pkg-check-update(1) exits 0 when nothing is available, 100 when updates are, and 1 when it couldn't tell. That's the dnf convention, so an existing timer or monitoring check works unchanged. 100 is the only exit code outside 0, 1 and 2 that pkg produces.
FILES
/etc/pkg.toml- System client configuration:
confirm, [install] include_subpkgs, [license], [history] and [network]. See pkg.toml(5). /etc/pkg/repos.d/*.toml- Repository drop-ins, one file per repository. See pkg-repos.d(5).
/etc/pkg/pins.d/*.toml- Local pins, above every repository. See pkg-pins.d(5).
/etc/pkg/*.root.json- TUF trust anchors, one per remote repository, named after the repository in lowercase. Written by
pkg repo add. /var/lib/pkg/- The client state root: installed/, installed.staging/, index/, roots.toml, history/, .lock. See pkg-state(5).
/var/log/pkg.log- One line per committed transaction, starting with its time and #number. See pkg-history(1).
/var/lib/pkg/repo/- The default single local repository, used when nothing is configured.
- ~/.cache/pkg/metadata/
- Verified TUF metadata, per user. A repeated query then costs one timestamp.json request per repository instead of a full refresh, and pkg-list(1) can still answer when a repository is unreachable.
- ~/.cache/pkg/targets/
- Fetched pkg-meta files, addressed by the sha256 the verified metadata names for them. A published pkg-meta never changes, so a cached copy is reused across snapshot rolls. It's re-hashed against the freshly verified metadata before it's parsed.
- ~/.cache/pkg/index/
- The parsed index of each repository, so the next command doesn't parse the same manifests again. One entry per repository, overwritten when the repository rolls. A local repository without targets.json is never cached.
- ~/.cache/pkg/provenance/
- Provenance records and blobs that pkg-provenance(1) fetched on demand.
- ~/.cache/pkg/rebuild/
- Scratch space for
pkg provenance rebuild. - ~/.cache/pkg/build/
- Scratch space for
pkg build, one directory per N-V-R. - ~/.config/pkg/build.key
- The key
pkg buildsigns with. Created by pkg-keygen(1). /usr/share/bash-completion/completions/pkg- Where a generated bash completion script belongs.
Every ~/.cache/pkg path honours $XDG_CACHE_HOME, and lives under /var/cache/pkg/ instead when running as root, whatever the environment says. See ENVIRONMENT.
ENVIRONMENT
XDG_CACHE_HOME- The base for every per-user cache above. Ignored when running as root, which always uses
/var/cache/pkg: a cache there is trusted without being verified again, so it has to be root's own. Falls back to ~/.cache, and to .pkg-cache in the current directory when there's no home either. XDG_CONFIG_HOME- Where the
pkg buildkey lives. Falls back to ~/.config. https_proxy,http_proxy,all_proxy,no_proxy- The proxy to reach repositories through, and the hosts that skip it, read the way curl(1) reads them; the uppercase spellings work too. Each one overrides its counterpart in the [network] table of pkg.toml(5).
SEE ALSO
Commands
pkg-install(1), pkg-remove(1), pkg-autoremove(1), pkg-upgrade(1), pkg-check-update(1), pkg-stage-update(1), pkg-search(1), pkg-list(1), pkg-list-sets(1), pkg-query(1), pkg-verify(1), pkg-repair(1), pkg-info(1), pkg-license(1), pkg-sbom(1), pkg-set(1), pkg-repo(1), pkg-compose(1), pkg-bundle(1), pkg-offline(1), pkg-build(1), pkg-keygen(1), pkg-sign(1), pkg-verify-sig(1), pkg-provenance(1), pkg-triggers(1), pkg-history(1), pkg-rollback(1), pkg-pin(1), pkg-completion(1)
File formats
pkg.toml(5), pkg-repos.d(5), pkg-pins.d(5), pkg-state(5)
Concepts
pkg-chain(7), pkg-sets(7), pkg-subpkgs(7), pkg-repository-layout(7)
Project documentation
docs/ARCHITECTURE.md, docs/design/repo.md, docs/design/trust.md, docs/design/package-sets.md, docs/design/naming.md, docs/design/install.md, docs/design/history.md, docs/design/triggers.md, docs/design/composition.md, docs/design/buildroot-attestation.md, docs/components/pkg-cli.md, pkg-cli/JSON.md, pkg-cli/VERBOSITY.md
AUTHOR
Auke Kok <sofar@foo-projects.org>