Skip to content
ocx
install

Run a command with its dependencies

Use this page to run a tool together with the tools it depends on, and to inspect the dependency tree.

A publisher can declare that a package needs other packages to work. A web app needs a JavaScript runtime. A build tool needs a compiler. The publisher pins each dependency to an exact OCI digest. OCX handles dependencies for you.

Pull the package, and OCX resolves the closure transitively:

Terminal window
ocx package pull "acme/webapp:2.0.0"

Say acme/webapp:2.0 declares dependencies on nodejs/node:24 and oven-sh/bun:1.3. All three packages land in the package store. Only acme/webapp:2.0 is the explicit install. The dependencies are stored but do not show up as top-level installs.

To run the package with its dependency environments configured, use ocx package exec:

Terminal window
ocx package exec "acme/webapp:2.0.0" -- serve --version

ocx package exec first composes the environments of all dependencies in topological order. Then it launches the command. ocx package env exports the same composed environment for use in your own shell.

Name more than one package before -- to run a command with all their environments composed. A dependency that two roots share is emitted once, as composition order describes:

Terminal window
ocx package exec "nodejs/node:24.0.0" "oven-sh/bun:1.3.0" -- bun --version

This puts Node.js and Bun on PATH for the one bun --version command. ocx package env takes the same list when you need the variables in your own shell.

ocx package deps shows the declared relationships. The default tree view annotates non-public dependencies, so you can see which deps cross the interface surface:

--flat shows the resolved evaluation order, which is the exact sequence OCX uses when it composes environments. This is the primary debugging tool when environment variables are not what you expect:

--why traces the path from a root package to a transitive dependency:

Two dependencies may set the same scalar variable, for example both set JAVA_HOME to different paths. OCX applies last-writer-wins semantics: the package later in topological order wins, silently. Inspect the order with ocx package deps --flat and decide whether the conflict is real.

Project toolchains behave the same way. Suppose you add a package with dependencies and also declare one of those dependencies as a top-level binding in ocx.toml. Both contribute environment variables. Either remove the redundant binding, because the transitive dependency provides it, or accept that the top-level entry’s value wins the conflict.