Ruby, PHP, JVM and others
The three levels work the same everywhere. What changes per ecosystem is which provider builds the environment and what the runtime is allowed to do by default.
Read the three levels first if you haven't.
Providers
-e @<provider>:<file> builds a layered environment image from a dependency
file. Most providers answer to two names — the package manager's, and the
runtime's — so -e @gem:Gemfile and -e @ruby:Gemfile are the same thing.
| Provider | Also answers to | Typical file |
|---|---|---|
pip | requirements.txt | |
uv | requirements.txt | |
poetry | pyproject.toml | |
npm | package.json | |
yarn | package.json | |
gem | ruby | Gemfile |
composer | php | composer.json |
maven | java, javac, mvn | pom.xml |
cargo | rustc | Cargo.toml |
go-install | go | — (installs named packages) |
cabal | ghc | .cabal |
cpanm | perl | cpanfile |
hex | elixir | mix.exs |
renv | r | renv.lock |
luarocks | lua | .rockspec |
galaxy | ansible | requirements.yml |
apt | ubuntu | — (installs named packages) |
The environment image is cached by the content hash of the file, so an unchanged dependency file means no rebuild.
Runtime capabilities
Verified with boks --info <tool>. "None" means the strongest default boks
has: working directory mounted read-only, no network.
| Tool | Default capabilities |
|---|---|
ruby, php, java, R, Rscript, lua, perl | none |
python, node, go, javac, mvn, gradle, elixir, mix | rw |
composer, uv | net, rw |
cargo, rustc | none |
Two patterns are worth noticing:
- Runtimes that only interpret are locked down hardest.
ruby,php,perl,luaandRcannot even write the working directory. If your script writes a file, that is a--cap rwor acapabilities: [rw]line in.boksrc— and the fact that you had to say so is the feature. - Build tools mostly grant
rw, and Rust's doesn't.javac,mvn,gradle,goandmixall write their own output directories by default.cargo/rustcare the exception — see Go, Rust and C/C++.
Known wart:
boks --info npmandboks --info pipdisplayCAPS rwand omit thenetthey really run with. Those two get their network from a per-tool-name entry in the index policy rather than from the shared image label the view reads. The grant is real; the display under-reports it.
Ruby
# level 1
boks -e @gem:Gemfile ruby app.rb
# level 2 — .boksrc
tools:
ruby:
env_file: Gemfile
boks ruby app.rb
# level 3
boks -i ruby
ruby app.rb
bundle install has no working-tree equivalent under boks the way npm install does — the environment image is the bundle. -e @gem:Gemfile runs
bundle install into a layered boks-env-ruby-* image, including gems with
native extensions, which build against a compiler-having variant.
Remember that ruby itself has no capabilities: a script that writes a
file needs rw granted explicitly.
See ruby-gemfile
and ruby-simple.
PHP
boks -e @composer:composer.json php app.php
composer is one of the few tools shipping net+rw on its own image label,
so boks composer require … works with no flags — and php itself still has
none, so a request your app makes is a capability you granted on purpose.
See php-composer.
JVM
boks -e @maven:pom.xml java -jar target/app.jar
boks --cap net mvn package
boks --cap net gradle build
mvn and gradle have rw (they write target/, build/) but not net —
the first dependency resolution needs --cap net, or a capabilities: [net]
line in .boksrc. java itself has neither, which is the right default for
running a jar.
Gradle writes a per-directory cache wherever it is invoked, so a project
.gitignore wants .gradle/.
See java-maven-simple,
kotlin-gradle-simple,
scala-sbt-simple,
clojure-lein-simple.
Elixir
boks -e @hex:mix.exs elixir app.exs
boks --cap net mix deps.get
elixir and mix both have rw. See
elixir-hex.
R
boks -e @renv:renv.lock Rscript analysis.R
R/Rscript have no capabilities, so writing a plot or a CSV needs rw
granted. See
r-renv
and the R environments reference.
Perl, Lua, Ansible
boks -e @cpanm:cpanfile perl script.pl
boks -e @luarocks:app.rockspec lua app.lua
boks -e @galaxy:requirements.yml ansible-playbook site.yml
See perl-simple,
lua-luarocks,
ansible-galaxy.
A note on tool names
Not every package-manager name is a runnable tool. gem and bundle are
provider names — -e @gem:Gemfile works — but there is no boks gem in the
index; boks gem install colorize answers Unknown tool 'gem'. When in
doubt, boks --search <name> is the reliable check.
(boks --info <name> is not, currently: for a name that is in neither the
index nor your own config it invents a boks.sh/<name>:latest entry and
reports it as "not pulled yet" rather than saying the tool is unknown.)