Skip to main content

build

Bundle your Lua source and produce a .c4z driver package. Building is entirely local — no account or controller required.

Preview

The driverforge CLI is in preview. Commands and flags documented here may change before the stable release. Follow along or share feedback on our roadmap.

Fast by design

driverforge is a self-contained native binary. It runs the whole build in one process — bundling, encryption, and packaging — instead of orchestrating the chain of separate scripts and tools typically needed to package Control4 drivers. Builds finish in a fraction of the time, and produce a standard .c4z that Composer and your controllers install and run exactly like any other.

Usage

driverforge build [options]

Run it from a driver project — a directory with src/manifest.c4zproj (the CLI walks up from the current directory to find it, or point --c4zproj at a manifest elsewhere). The driver name comes from the manifest; driver.xml and the squishy build file live alongside it in src/.

What it does

  1. Reads src/manifest.c4zproj to determine the driver name and contents
  2. Bundles the Lua modules described by your squishy file into a single driver.lua
  3. Stamps driver.xml (modified time, plus the version when you ask for a bump) and, when configured, encrypts the driver script
  4. Packages everything into a .c4z in dist/
  5. Optionally emits a source map and/or an unpacked copy

Options

OptionDescription
--configuration, -cBuild a named configuration — swaps src/config.<name>.lua in as config.lua for this build. Omit to build the default config.lua as-is
--increment, -iBump the version per the project's versioning scheme before building. Requires an initialised project
--versionStamp an exact <version> for this build, persisted to driver.xml on success. Works without init; mutually exclusive with --increment
--c4zprojPath to the .c4zproj manifest (default src/manifest.c4zproj)
--output-dir, -oDirectory for the built .c4z (default dist/)
--sourcemap, -sAlso emit a Lua source map (dist/<driver>.lua.map)
--unpack, -uAlso leave an unpacked copy of the package in dist/
--encryptForce script encryption on for this build (--encrypt=false forces it off). Default follows the configuration's entry in the project config, then driver.xml
--no-suffixBuild a named configuration under the naked driver name — no -<name> artifact or (name) device-name suffix (--no-suffix=false forces suffixing back on)
--allow-executeDevelopment build: append C4:AllowExecute(true) to the built driver script, enabling Director's Lua command window. Applied to the artifact only, never written to source

Shipping is its own command now: driverforge sync and driverforge deploy each build first, so there is no build --sync or build --deploy.

Output

A build writes to dist/ (or the directory you pass with -o/--output-dir):

dist/
├── my-driver.c4z # packaged driver
├── driver.lua.map # source map (with --sourcemap, when the driver is squished)
└── my-driver/ # unpacked copy (with --unpack)

Build configurations

driverforge build uses your committed src/config.lua as the driver's configuration. Pass --configuration <name> (or -c <name>) to swap a committed src/config.<name>.lua override in for the build instead — for example --configuration release. It's an opt-in system; see Build configuration for the full picture.

Naming. A plain build (the default configuration) keeps the driver's naked name (my-driver.c4z). A named configuration is suffixed so builds coexist — driverforge build --configuration release produces my-driver-release.c4z and adds a (release) suffix to the device name in Composer. A release configuration can opt out of the suffixes — --no-suffix, or "suffix": false in the project config — to ship under the naked name; see Per-configuration defaults.

Per-configuration defaults. An initialised project can set encryption and naming defaults per configuration in .driverforge/config.json, so driverforge build -c release alone produces the final release artifact. Flags always override the config. See Per-configuration defaults.

Versioning

A plain build never touches the driver's <version>: what's authored is what ships. Pass --increment to bump it per the project's versioning scheme, or --version to stamp an exact value. See Versioning for the schemes and the full picture of when versions change.

Examples

Basic build:

driverforge build

Release build (swaps in config.release.lua) with a version bump and a source map:

driverforge build --configuration release -i -s

Full release artifact — encrypted, naked name — with no config file, using flags alone (or set these once per configuration in the project config and drop the flags):

driverforge build -c release --encrypt --no-suffix

Build with the manifest and output directory somewhere non-standard:

driverforge build --c4zproj packaging/manifest.c4zproj -o build/out

Source maps

Build with --sourcemap to emit a .map alongside the package so Anvil can map error stack traces back to your original source files instead of the bundled output. See driverforge sourcemap for the details.

driverforge build --sourcemap

Global flags

Every driverforge command also accepts these global flags: --verbose/-v, --project-dir, --no-tui, --no-update-check, and --help/-h. See the overview for details.