- docs
- Concepts
- Launcher Forwarding
Launcher Forwarding
This page explains how a generated launcher embeds its package root and how a running ocx forwards its configuration to every ocx it spawns.
Launcher Embedding
Section titled “Launcher Embedding”When ocx package install generates launchers for a package’s declared entrypoints, each launcher delegates to the internal ocx launcher exec subcommand with the package-root path baked at install time.
Unix (POSIX sh):
#!/bin/sh# Generated by ocx at install time. Do not edit.exec "${OCX_BINARY_PIN:-ocx}" launcher exec '/home/alice/.ocx/packages/ocx.sh/sha256/ab/c123…' -- "${0##*/}" "$@"Windows (native .exe shim + .shim sidecar):
# entrypoints/cmake.shim — one UTF-8 line, the absolute package rootC:\Users\alice\.ocx\packages\ocx.sh\sha256\ab\c123…The companion cmake.exe is a compiled shim. It derives its entry-point name from its own filename and reads cmake.shim for the package root. It then spawns ocx launcher exec "<pkg-root>" -- "cmake" <args…> directly through CreateProcessW — never cmd.exe.
ocx launcher exec forces the self view internally — no flag needs to be baked into the launcher. The stable wire ABI is the launcher exec subcommand name pair and positional shape.
See the Entry Points in-depth page for the full launcher generation pipeline, character rejection rules, and cross-platform launcher behavior.
OCX Configuration Forwarding
Section titled “OCX Configuration Forwarding”Whenever ocx spawns a subprocess, it materializes the running ocx’s resolution-affecting policy as OCX_* env vars on the child. The most common case is the child process under ocx package exec, which may itself invoke a generated entrypoint launcher that re-shells back into ocx. This is the chokepoint that keeps configuration coherent across the chain.
| Variable | Source | Purpose |
|---|---|---|
OCX_BINARY_PIN | Resolved path of the running ocx executable | Pins the inner ocx to the same binary that installed the package |
OCX_HOME | crate::home::default_ocx_root() — the outer ocx’s own resolved data root | Set-always, even under --clean: a child that strips ambient state still resolves the same object store, not ~/.ocx from the passwd database |
OCX_OFFLINE | --offline flag on the outer invocation | Child ocx stays offline if outer was offline |
OCX_FROZEN | --frozen flag on the outer invocation | Child ocx stays frozen if outer was frozen |
OCX_REMOTE | --remote flag on the outer invocation | Child ocx uses the remote index if outer did |
OCX_CONFIG | --config flag on the outer invocation | Child ocx loads the same explicit config file |
OCX_INDEX | --index flag on the outer invocation | Child ocx reads the same local index directory |
OCX_GLOBAL | --global flag on the outer invocation | Child ocx selects the same tier |
OCX_PROJECT | --project flag on the outer invocation | Child ocx loads the same project file |
OCX_NO_CONFIG | Hermetic outer invocation | A hermetic parent’s child does not re-read the full config chain |
OCX_MIRRORS, OCX_PATCHES, OCX_PATCH_SNAPSHOT | The resolved [mirrors] and [patches] tiers, and the active snapshot | Child ocx sees the same mirror map, companion overlay and frozen companion digests |
OCX_MANAGED_CONFIG | The resolved [managed] source | Child ocx resolves the same managed tier |
OCX_RECORDS_DIR, OCX_RECORDS_NAME | The resolved [records] sink | A launcher re-entry, which takes no flags of its own, writes to the same sink |
OCX_TOOLCHAIN_DIR | The resolved toolchain root | Every composed path moves with it, so the child must agree; with no root, an inherited value is removed |
OCX_NO_VERIFY, OCX_NO_CONSENT | The flag or the ambient variable | A launcher-spawned child install keeps the CI-wide verification and stamp decisions, across --clean too |
Six more settings are read from the environment with no command-line flag behind them: OCX_DEFAULT_REGISTRY, OCX_INSECURE_REGISTRIES, OCX_ALLOW_YANKED, OCX_NO_PROJECT, OCX_NO_CONFIG_REFRESH and OCX_NO_UPDATE_CHECK. Two of them also have a config counterpart: OCX_DEFAULT_REGISTRY overlays [registry] default, and OCX_INSECURE_REGISTRIES unions with [registries.<name>] insecure.
They are forwarded as the invocation itself read them. A --clean child starts from an empty environment, so this keeps it from falling back to defaults the parent overrode. An empty value clears an inherited setting rather than travelling onward. OCX_NO_PROJECT is withheld when the invocation also carries an explicit --project, because a child reads the prune before the path. OCX_ENV is always cleared first and then written from the composed project and group [env] entries plus any --env override; OCX_LAUNCH_IDENTITIES is covered under execution records.
The running ocx’s parsed flags are authoritative. They overwrite any inherited value from the parent shell, so a stale exported OCX_OFFLINE=1 cannot override an outer ocx invoked without --offline. The same rule holds under ocx package exec --clean: the child env starts empty, then OCX_* keys are written explicitly from the outer ocx’s parsed state. No ambient shell export can bypass this.
Some variables are deliberately outside the forwarded set. OCX_LAZY_MODE, OCX_LAZY_REPORT and the three toolchain settings OCX_TOOLCHAIN_ACTIVATE, OCX_TOOLCHAIN_PINNED and OCX_TOOLCHAIN_UPDATE change when or how content reaches PATH, never which digest resolves, so a child reads its own environment. The same holds for OCX_SELF_UPDATE, OCX_UPDATE_CHECK_INTERVAL, OCX_CEILING_PATH and OCX_SIGSTORE_TRUSTED_ROOT. OCX_EXTRA_CA_CERTS is not part of the set either, so a CA supplied only through it does not reach an ocx exec --clean child. The extra_ca_certs config form survives, because the child re-reads config.toml itself. Four credentials are stripped from every child, plugins (ocx-<name>) included: OCX_IDENTITY_TOKEN, OCX_KEY_PASSWORD, OCX_SIGNING_KEY and OCX_ANNOUNCE_GIT_TOKEN. The runner variables that --ci and --ci-annotations read are not forwarded either, because the CI sink files are runner-managed paths.
OCX_AUTH_<REGISTRY>_* is not part of the forwarded set. Launcher children re-enter via ocx launcher exec using a local package root rather than a registry, so they never need credentials. Future deliberate ocx-spawns-ocx call sites that do need auth will declare that forwarding rule at their own boundary.