๐ฆ Boxwerk
Boxwerk is a tool for creating modular Ruby and Rails applications. It enables you to organize code into packages of Ruby files with clear boundaries and explicit dependencies. Boxwerk is heavily inspired by Packwerk but provides more robust enforcement at runtime using Ruby::Box, ensuring that only public constants from direct dependencies are accessible. Violations raise NameError, turning architectural rules into runtime guarantees.
As your application grows, Boxwerk helps prevent accidental coupling, enforces modularity, and makes it easier to understand and modify code without breaking other parts of the system.
{Usage Guide}[USAGE.md] ยท {API Documentation}[https://dtcristo.github.io/boxwerk/] ยท {Changelog}[CHANGELOG.md]
Features
-
Boxwerkreads standard Packwerkpackage.ymlfiles, supporting both dependency and privacy enforcement. Packwerk itself is not required. -
Packages in a
Boxwerkapplication share a set of global gems but may also define package-local ones. Multiple packages can depend on different versions of the same gem. -
Ruby::Boxprovides monkey patch isolation between packages. -
Boxwerkuses Zeitwerk to automatically load constants in packages with conventional file structure although manual loading is also supported.
Goals
-
Enforce boundaries at runtime.
Ruby::Boxturns architectural rules into runtime guarantees. Undeclared dependencies and privacy violations raiseNameError. -
Enable gradual modularization. Add
package.ymlfiles around existing code and declare dependencies incrementally. -
Feel Ruby-native. Integrates with Bundler,
gems.rb/Gemfile, and standard Ruby tools.boxwerk exec rake testfeels like any other Ruby command.
Ruby::Box
Ruby::Box (Ruby 4.0+) provides in-process isolation of classes, modules, and constants. Each box has its own top-level Object, isolated $LOAD_PATH and $LOADED_FEATURES, and independent monkey patches. Boxwerk creates one box per package and wires cross-package constant resolution through const_missing.
Set RUBY_BOX=1 before starting Ruby. See the official documentation for details. See ARCHITECTURE.md for how Boxwerk uses Ruby::Box internally.
Quick Start
Create packages with package.yml files:
my_app/
โโโ package.yml
โโโ main.rb
โโโ packs/
โโโ foo/
โ โโโ package.yml
โ โโโ lib/foo.rb
โโโ bar/
โโโ package.yml
โโโ lib/bar.rb
# package.yml (root) enforce_dependencies: true dependencies: - packs/foo - packs/bar
Install and run:
gem install boxwerk RUBY_BOX=1 boxwerk run main.rb
No Bundler or Gemfile required for basic usage. To use global or per-package gems, see USAGE.md.
CLI
boxwerk run <script.rb> Run a Ruby script in a package box boxwerk exec <command> [args...] Execute a command in the boxed environment boxwerk console Interactive console in a package box boxwerk info Show package structure and dependencies boxwerk install Install gems for all packages
Options: --package <package>, --all, --global. See USAGE.md for details.
Limitations
-
Ruby::Boxis experimental in Ruby 4.0 -
No constant reloading (restart required for code changes)
-
IRB autocomplete disabled in console
See TODO.md for plans to address these and other planned features.
Examples
-
examples/minimal/โ Three packages, dependency enforcement, no gems -
examples/complex/โ Namespaced constants, privacy, per-package gems, tests -
examples/rails/โ Usage with Rails
Development
bundle install # Install dependencies RUBY_BOX=1 bundle exec rake # Run all tests (unit, e2e, examples) bundle exec rake format # Format code
License
Available as open source under the MIT License.