UDS CLI Next Mode
UDS CLI Next is the next-generation implementation of UDS CLI. It is available as an alpha preview behind the NextMode feature flag while Legacy mode remains the default.
Why Next Mode Exists
Section titled “Why Next Mode Exists”UDS CLI Next is designed to support the next phase of UDS bundle workflows:
- Better Bundles design
- next-generation bundle authoring and artifact structure
- self-contained OCI artifacts for registry-backed and offline workflows
- HCL-based bundle definitions with
bundle.uds.hcl- reusable
localsfor shared registries, versions, and package names - package dependency ordering with
depends_on, allowing deployers to run independent packages in parallel for faster deploys - HCL functions that can be extended by UDS CLI, including the supported
file()function for reading local file contents into bundle, defaults, and config values - clearer validation for required fields, invalid attributes, and invalid types
- reusable
- Zarf package values as a first-class citizen instead of bespoke bundle-level Helm overrides
- a library-first design that other UDS tools can consume directly
- stronger artifact integrity, signing, and verification paths
Better Bundles Design
Section titled “Better Bundles Design”UDS CLI Next implements the Better Bundles design for the next generation of UDS bundles. The previous bundle design fell short as UDS workflows matured: bundle configuration relied on bespoke overrides, package contents were hidden behind indirect OCI blob references, bundles did not have a distinct media type for registries to identify, and the artifact shape was harder for downstream tools to parse consistently.
Better Bundles focuses on making bundle artifacts easier for humans, registries, and downstream deployment tools to reason about. Beyond the HCL authoring model above, it defines:
- a bundle-specific OCI media type so registries and tooling can identify UDS bundles directly
- an artifact layout where package manifests and layers are represented explicitly instead of hidden behind generic blob indirection
- one bundle artifact that can contain OCI-hosted and local Zarf packages in a consistent internal OCI layout
- build-time configuration that is sealed into the artifact, plus deploy-time variables for environment-specific values
- an artifact shape that supports low-side build, high-side configuration, and high-side deployment workflows
When a bundle is pushed to an OCI registry, the tag resolves to a root OCI index. The root index selects the requested architecture and points at a child index for that architecture. Each child index is the canonical single-architecture bundle artifact and directly references the bundle definition plus the included Zarf package content:
oci://registry.example.com/my-org/my-app:1.0.0└── root OCI index ├── linux/amd64 child index │ └── artifactType: application/vnd.defenseunicorns.uds.bundle.v1 │ ├── bundle definition manifest │ │ ├── bundle.uds.hcl │ │ ├── defaults.uds.hcl │ │ ├── values/package_id/0.yaml │ │ ├── oci/oci-layout │ │ └── oci/index.json │ ├── Zarf package manifest: package-a │ │ ├── package config blob │ │ └── package layer blobs │ └── Zarf package manifest: package-b │ ├── package config blob │ └── package layer blobs └── linux/arm64 child index └── artifactType: application/vnd.defenseunicorns.uds.bundle.v1 ├── bundle definition manifest ├── Zarf package manifest: package-a └── Zarf package manifest: package-bThis layout makes package content explicit and inspectable while keeping the bundle self-contained for registry-backed and offline workflows. Tags can point at multiple architecture-specific child indexes, while digest-pinned references can address a single child index directly. Registry-backed packages and local Zarf packages are normalized into the same internal OCI layout, so downstream tooling can consume one consistent artifact shape.
Mode Status
Section titled “Mode Status”| Mode | Status | Notes |
|---|---|---|
| Legacy | Default | Existing uds-bundle.yaml workflows continue to work. |
| Next | Alpha preview | Enabled with NextMode; command coverage is still expanding. |
Next mode is planned to become the default in beta. Legacy mode will be removed after the beta migration window.
Current Capabilities
Section titled “Current Capabilities”Next mode currently supports the core bundle flows needed to exercise HCL bundles and artifact-based deployment:
| Capability | Current support |
|---|---|
| Bundle definition format | bundle.uds.hcl using the Next HCL bundle schema |
| Development deployment | Deploy directly from a bundle definition with uds bundle dev deploy |
| Bundle artifact creation | Create local bundle artifacts with uds bundle create |
| Bundle artifact deployment | Deploy created local artifacts or OCI references with uds bundle deploy |
| Package verification | Verify package signatures when configured by the bundle definition |
| Bundle signing | Create signed bundles when signing options are configured, or unsigned bundles for local alpha workflows |
| Bundle signature verification | Verify signed bundle artifacts during deploy, with an explicit skip flag available for unsigned local artifacts |
| Retained Legacy commands | Non-bundle commands that are still needed during migration remain available in Next mode |
Enabling Next Mode
Section titled “Enabling Next Mode”Next mode can be enabled per command with the NextMode feature flag:
uds --features=NextMode=true versionCLI_FEATURES=NextMode=true uds versionAll UDS CLI Next bundle definition files must be named bundle.uds.hcl.
Bundle Quick Start
Section titled “Bundle Quick Start”This quickstart creates a local k3d cluster with the UDS k3d package, initializes Zarf, and deploys podinfo.
Prerequisites: Docker and k3d must be installed and running.
Create bundle.uds.hcl:
uds { bundle_api_version = "uds.dev/v1alpha1"}
metadata { name = "next-quickstart" description = "Next mode quickstart bundle" version = "0.1.0"}
package "uds_k3d_dev" { source = "oci://ghcr.io/defenseunicorns/packages/uds-k3d:0.20.2" signature_verification { verify = false }}
package "init" { source = "oci://ghcr.io/zarf-dev/packages/init:v0.83.0" signature_verification { keyless { certificate_identity_regexp = "https://github\\.com/zarf-dev/zarf/\\.github/workflows/release\\.yml@refs/tags/v\\d+\\.\\d+\\.\\d+" certificate_oidc_issuer = "https://token.actions.githubusercontent.com" } } depends_on = [package.uds_k3d_dev]}
package "podinfo" { source = "oci://ghcr.io/defenseunicorns/uds-cli/podinfo:0.0.2" signature_verification { verify = false } depends_on = [package.init]}Deploy directly from the bundle definition during development:
CLI_FEATURES=NextMode=true uds bundle dev deploy .Or create an unsigned bundle artifact and deploy it:
CLI_FEATURES=NextMode=true uds bundle create --unsigned .CLI_FEATURES=NextMode=true uds bundle deploy ./uds-bundle-next-quickstart-<ARCH>-0.1.0.tar.zst --skip-signature-verificationReplace ARCH with the bundle architecture, such as amd64 or arm64.
The --unsigned flag is required here because this quickstart does not configure bundle signing. Deploying the unsigned artifact requires --skip-signature-verification.
Bundle File Structure
Section titled “Bundle File Structure”uds { bundle_api_version = "uds.dev/v1alpha1" # Required}
metadata { name = "my-bundle" # Required description = "Description" # Optional version = "1.0.0" # Optional}
package "package_id" { source = "oci://registry/package:tag" # Required namespace = "custom-namespace" # Optional depends_on = [package.other_package] # Optional values_files = ["values/config.yaml"] # Optional optional_components = ["component-name"] # Optional
signature_verification { # Required verify = false # Explicit bypass }}Package membership is implicit. Every package "<id>" block in bundle.uds.hcl is part of the bundle.
Package Signature Verification
Section titled “Package Signature Verification”Every package passed to uds bundle create must declare its verification posture. Configure exactly one public_key or keyless verification method, or explicitly bypass verification with verify = false. A bypass creates the bundle with a prominent warning.
Keyless verification requires one certificate identity constraint and one OIDC issuer constraint. Exact and regular-expression variants are mutually exclusive. trusted_root is optional. When it is omitted, verification uses Zarf’s embedded Sigstore trusted root.
signature_verification { keyless { # Choose exactly one certificate identity constraint: certificate_identity = "https://github.com/my-org/api/.github/workflows/release.yml@refs/heads/main" # certificate_identity_regexp = "https://github.com/my-org/.*/.github/workflows/release.yml@refs/heads/main"
# Choose exactly one OIDC issuer constraint: certificate_oidc_issuer = "https://token.actions.githubusercontent.com" # certificate_oidc_issuer_regexp = "https://.*token.actions.githubusercontent.com"
# Optional Sigstore trusted-root JSON. If omitted, use the embedded public Sigstore root. # trusted_root = file("keys/trusted-root.json")
# Transparency-log and SCT checks are enabled by default. These settings # are available for explicitly opting into reduced verification protections. # insecure_ignore_tlog = true # insecure_ignore_sct = true
# Enable RFC 3161 signed-timestamp verification when applicable. # use_signed_timestamps = true }}Transparency-log and SCT verification are enabled by default. Enable insecure_ignore_tlog or insecure_ignore_sct only when reduced verification protection is intentional.
Direct development deploys from a bundle directory or bundle.uds.hcl attempt the configured package verification and warn instead of stopping when the same policy would fail uds bundle create. Deploying an already-built bundle artifact does not reverify its contained packages.
HCL Helpers
Section titled “HCL Helpers”Using Locals
Section titled “Using Locals”Use locals to reduce duplication:
locals { repo = "ghcr.io/my-org" version = "1.0.0"}
package "app" { source = "oci://${local.repo}/my-app:${local.version}" signature_verification { verify = false }}Reading Values from Files
Section titled “Reading Values from Files”Use file(path) to read the contents of a regular UTF-8 text file into an HCL expression. It is available in bundle.uds.hcl, defaults.uds.hcl, and config.uds.hcl. Relative paths are resolved from the directory containing the HCL file.
locals { description = file("metadata/description.txt")}
metadata { name = "my-bundle" description = local.description}The function can also be used directly in variable values and templates:
variables = { tls_cert = file("my_tls_cert_file")}When uds bundle create and uds bundle reconfigure build an artifact, they replace file() expressions in bundle.uds.hcl and defaults.uds.hcl with their evaluated values. File paths are evaluated relative to the HCL file itself. Any file() calls in config.uds.hcl are evaluated when the config is read.
CLI Commands
Section titled “CLI Commands”| Command | Description |
|---|---|
uds bundle create [directory] | Create a bundle artifact from a directory containing bundle.uds.hcl. |
uds bundle inspect <bundle-reference> | Display metadata and packages from a local .tar.zst or OCI bundle artifact. |
uds bundle push <bundle-tarball> <oci-reference> | Push a bundle artifact to an OCI registry. |
uds bundle pull <ref> | Pull a bundle artifact from an OCI registry. |
uds bundle dev deploy [path] | Deploy directly from a bundle definition or its directory. Defaults to the current directory. |
uds bundle deploy <artifact> | Deploy a created local .tar.zst or OCI bundle artifact. |
uds bundle remove [bundle-definition] | Remove a bundle from Kubernetes. Defaults to the current directory. |
uds bundle sign <bundle-artifact> | Sign a created bundle artifact. |
uds bundle verify <bundle-artifact> | Verify a created bundle artifact signature. |
uds bundle reconfigure <source> --defaults <defaults-file> | Reconfigure bundle defaults from a local artifact or OCI reference and produce a derivative artifact. |
Global Bundle Flags
Section titled “Global Bundle Flags”These flags apply to all uds bundle subcommands:
| Flag | Default | Description |
|---|---|---|
-a, --architecture | host arch | Target CPU architecture, such as amd64 or arm64. |
-o, --output | text | Output format: text, json, or yaml. |
--plain-http | false | Allow plain HTTP for a registry only when HTTPS is unavailable. |
--skip-tls-verify | false | Skip TLS certificate verification. |
--tmp-dir | system temp | Directory for temporary working files. |
--concurrency | 10 | Degree of parallelism for concurrent operations. For deploy, applies within a dependency level. |
--config | none | Path to config.uds.hcl for deploy-time variables and options. |
--prompt | false | Enable interactive confirmation before package deployment or removal begins. |
Deploying a Bundle
Section titled “Deploying a Bundle”Both deploy commands are non-interactive by default and deploy packages within a dependency level in parallel. Levels run sequentially: level N must finish before level N+1 starts.
Use uds bundle dev deploy to deploy directly from a bundle definition while authoring a bundle. It does not create an intermediate artifact, so bundle provenance and bundle-signature verification are unavailable.
# Deploy from the bundle definition in the current directoryCLI_FEATURES=NextMode=true uds bundle dev deploy
# Deploy from a bundle definition in a specific directoryCLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle
# Deploy with an interactive confirmation promptCLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle --prompt
# Deploy serially without a promptCLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle --concurrency 1
# Deploy with deploy-time configurationCLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle --config config.uds.hcl
# Deploy with custom package-registry settingsCLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle --architecture amd64 --plain-http --concurrency 5
# Deploy only a subset of packagesCLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle --packages nginx,podinfo
# Deploy a package out of dependency order. Use with caution.CLI_FEATURES=NextMode=true uds bundle dev deploy ./my-bundle --packages podinfo --forceUse uds bundle deploy to deploy a created artifact.
# Deploy a local unsigned artifactCLI_FEATURES=NextMode=true uds bundle deploy uds-bundle-my-app-amd64-1.0.0.tar.zst --skip-signature-verification
# Pull and deploy a tagged unsigned OCI artifactCLI_FEATURES=NextMode=true uds bundle deploy oci://registry.example.com/my-org/my-app:1.0.0 --skip-signature-verification
# Deploy a digest-pinned unsigned OCI artifactCLI_FEATURES=NextMode=true uds bundle deploy oci://registry.example.com/my-org/my-app@sha256:<digest> --skip-signature-verificationDeploy-specific flags:
| Flag | Default | Description |
|---|---|---|
--prompt | false | Enable interactive confirmation before package deployment begins. |
-p, --packages | all | Comma-separated list of specific packages to deploy. When a selected package’s dependencies are not also selected, the deploy is rejected. |
-f, --force | false | Deploy packages even if their dependencies are not selected. Use with caution. |
Removing a Bundle
Section titled “Removing a Bundle”# Remove all packages in current directory bundleCLI_FEATURES=NextMode=true uds bundle remove
# Remove bundle from a specific directoryCLI_FEATURES=NextMode=true uds bundle remove ./my-bundle
# Remove only specific packagesCLI_FEATURES=NextMode=true uds bundle remove --packages uds_k3d_dev,init
# Remove with an interactive confirmation promptCLI_FEATURES=NextMode=true uds bundle remove --promptPackages are removed in reverse order to respect dependency ordering. Packages not currently deployed on the cluster are skipped with a warning.
Remove-specific flags:
| Flag | Default | Description |
|---|---|---|
-p, --packages | all | Comma-separated list of specific packages to remove. |
-f, --force | false | Remove packages even if other bundle packages depend on them. |
Deploy-Time Configuration
Section titled “Deploy-Time Configuration”A config.uds.hcl file lets you provide variables for Helm value templating and Zarf package variable substitution without modifying the bundle itself. Pass it with --config:
CLI_FEATURES=NextMode=true uds bundle dev deploy --config ./config.uds.hclExample config.uds.hcl:
variables = { cluster_name = "my-production-cluster" replica_count = 3 enable_metrics = true}Variables are available in values_files through Go template syntax:
clusterName: {{ .vars.cluster_name }}replicaCount: {{ .vars.replica_count }}Top-level scalar variables are also passed to Zarf as ###ZARF_PKG_VAR_<NAME>### substitutions. Variable names are automatically uppercased.
Bundle-Level Variable Defaults
Section titled “Bundle-Level Variable Defaults”A defaults.uds.hcl file placed alongside bundle.uds.hcl provides the lowest-priority layer of variable configuration. It is auto-discovered when a bundle is created. No flag is required. When present in the same directory, uds bundle create adds defaults.uds.hcl to the bundle artifact so those defaults travel with the artifact.
At deploy time, defaults stored in the artifact are applied first, then overridden by values in config.uds.hcl or future variable sources.
Example defaults.uds.hcl:
variables = { cluster_name = "my-default-cluster" replica_count = 1 enable_metrics = false}Reconfiguring a Bundle
Section titled “Reconfiguring a Bundle”Use uds bundle reconfigure to replace the defaults in an existing bundle artifact and produce a new derivative artifact. This is useful when the package content stays the same, but environment-specific defaults need to change before publishing or deploying.
Reconfigure is efficient because it updates bundle defaults without rebuilding package content. The derivative artifact can reuse the existing package blobs and only change the bundle metadata/defaults layers that need to change.
Reconfigure requires a source bundle artifact or OCI reference and a new defaults.uds.hcl file:
# Create an unsigned derivative artifact from a local unsigned bundle.# Efficient: package content is reused; only the defaults-bearing bundle layers change.CLI_FEATURES=NextMode=true uds bundle reconfigure ./uds-bundle-my-app-amd64-1.0.0.tar.zst \ --defaults ./defaults.prod.uds.hcl \ --skip-signature-verification \ --unsigned
# Reconfigure from an unsigned OCI bundle reference.# Efficient: use an existing published artifact as the source for a new environment-specific derivative.# OCI reconfigure publishes a derivative tag based on --suffix, so --output-dir is not used.CLI_FEATURES=NextMode=true uds bundle reconfigure oci://registry.example.com/my-org/my-app:1.0.0 \ --defaults ./defaults.prod.uds.hcl \ --skip-signature-verification \ --suffix -prod \ --unsignedBy default, reconfigure verifies the source bundle signature before creating the derivative artifact. Use --skip-signature-verification only when intentionally working with an unsigned or untrusted artifact. The new artifact must also be signed, or created with --unsigned for local alpha workflows.
Reconfigure-specific flags:
| Flag | Default | Description |
|---|---|---|
--defaults | required | Path to the replacement defaults.uds.hcl file. |
--output-dir | current directory | Directory for the reconfigured local tarball. |
--suffix | -reconfigured | Suffix for the output artifact name. |
--unsigned | false | Create an unsigned reconfigured bundle. |
--skip-signature-verification | false | Skip verification of the source bundle signature. |
Signing and Verifying Bundle Artifacts
Section titled “Signing and Verifying Bundle Artifacts”Use uds bundle sign to add signature evidence to a created bundle artifact, and uds bundle verify to verify that signature evidence before trusting an artifact.
# Sign with keyless identityCLI_FEATURES=NextMode=true uds bundle sign ./uds-bundle-my-app-amd64-1.0.0.tar.zst --keyless
# Sign with a local key or KMS URICLI_FEATURES=NextMode=true uds bundle sign ./uds-bundle-my-app-amd64-1.0.0.tar.zst --signing-key ./cosign.key
# Verify with a public keyCLI_FEATURES=NextMode=true uds bundle verify ./uds-bundle-my-app-amd64-1.0.0.tar.zst --public-key ./cosign.pub
# Verify with keyless certificate constraintsCLI_FEATURES=NextMode=true uds bundle verify ./uds-bundle-my-app-amd64-1.0.0.tar.zst \ --certificate-identity-regexp 'https://github\.com/my-org/.*/.github/workflows/release\.yml@refs/heads/main' \ --certificate-oidc-issuer 'https://token.actions.githubusercontent.com'uds bundle create can also sign during creation when signing flags are provided, or create an unsigned artifact with --unsigned.
Publishing and Pulling Bundle Artifacts
Section titled “Publishing and Pulling Bundle Artifacts”Use uds bundle push to publish a local bundle artifact to an OCI registry, and uds bundle pull to retrieve one.
# Publish to a registryCLI_FEATURES=NextMode=true uds bundle push ./uds-bundle-my-app-amd64-1.0.0.tar.zst oci://registry.example.com/my-org/my-app:1.0.0
# Pull an unsigned artifact to the current directoryCLI_FEATURES=NextMode=true uds bundle pull oci://registry.example.com/my-org/my-app:1.0.0 --skip-signature-verification
# Pull an unsigned artifact to a specific existing directorymkdir -p ./downloadsCLI_FEATURES=NextMode=true uds bundle pull oci://registry.example.com/my-org/my-app:1.0.0 -d ./downloads --skip-signature-verificationBy default, pull verifies the bundle signature. Use --skip-signature-verification only when intentionally pulling an unsigned or untrusted artifact.
Inspecting a Bundle
Section titled “Inspecting a Bundle”The inspect command shows metadata from a built bundle artifact. Provide a local .tar.zst artifact or an OCI bundle reference. Source directories and standalone bundle.uds.hcl files are not accepted.
# Inspect a local bundle artifactCLI_FEATURES=NextMode=true uds bundle inspect ./my-bundle.tar.zst
# Inspect an OCI bundle artifactCLI_FEATURES=NextMode=true uds bundle inspect oci://registry.example.com/my-bundle:1.0.0Package verification status describes verification performed during bundle creation. Inspect output does not replace bundle signature verification for integrity decisions.
Example output:
Name: my-appVersion: 1.0.0
Packages (2) Name: database Source: oci://ghcr.io/my-org/packages/postgres:15.0.0
Name: api Source: oci://ghcr.io/my-org/packages/my-api:2.0.0 DependsOn: databaseStructured Output
Section titled “Structured Output”Bundle commands that emit result objects support structured output through --output or -o, including create, inspect, pull, and reconfigure:
| Format | Flag | Description |
|---|---|---|
text | -o text | Human-readable output. |
json | -o json | JSON for scripting and pipelines. |
yaml | -o yaml | YAML for configuration tooling. |
# Pipe inspect output to jqCLI_FEATURES=NextMode=true uds bundle inspect ./my-bundle.tar.zst -o json | jq '.packages[].name'
# Suppress logs for pure structured outputCLI_FEATURES=NextMode=true uds bundle inspect ./my-bundle.tar.zst -o json 2>/dev/null
# YAML output for toolingCLI_FEATURES=NextMode=true uds bundle create --unsigned -o yamlLogs always go to stderr. Structured output always goes to stdout. Use 2>/dev/null to suppress logs when piping stdout.