Distribute your source-based Unix program as a single plain-text shell script
  • Shell 91.5%
  • Awk 6.7%
  • Makefile 1.8%
Find a file
2026-06-12 11:40:17 -06:00
.forgejo/workflows Don’t run CI on tag pushes 2026-04-20 21:55:33 -06:00
bin Encode files with stricter, owner-only permissions 2026-04-16 16:25:30 -06:00
lib/brut-pack brut-pack 0.5.0 2026-06-12 11:29:56 -06:00
libexec Support symlinks in bundles 2026-06-11 21:40:22 -06:00
test Support symlinks in bundles 2026-06-11 21:40:22 -06:00
vendor Update Brat 2026-04-21 21:36:08 -06:00
.gitignore Add a dist build 2026-04-14 10:51:20 -06:00
.program.env.sh brut-pack 0.5.0 2026-06-12 11:29:56 -06:00
CHANGELOG.md brut-pack 0.5.0 2026-06-12 11:29:56 -06:00
LICENSE.md Initial commit 2026-04-13 17:04:31 -06:00
Makefile Fix Makefile and tests on FreeBSD 2026-04-15 15:14:04 -06:00
README.md Add missing line-break separator 2026-06-12 11:40:17 -06:00

brut-pack

brut-pack bundles your source-based Unix program into a single-file, plain-text portable executable for deployment or distribution.


Jump to: Installation | Usage | Contributing | License



Overview

Source-based programs written in shell, awk, and sed can be organized into multiple files using the conventional Unix filesystem layout:

  • bin/ — your programs main executables
  • lib/ — shared library files and scripts
  • libexec/ — subcommands and helper executables
  • share/ — documentation, templates, and other plain-text assets

When a program conforms to these conventions, it can be trivially packaged and installed by any Unix package manager.

Thats great when you intend to use a program system-wide. Sometimes, though, you want to operate outside the jurisdiction of a package manager. For example, you might want to “vendor” a specific version of a program directly into a source code repository so it can be used to bootstrap another process. Or perhaps youd just like to be able to copy a program around from one host to another as a single file.

These are the cases brut-pack is designed for. Run brut-pack encode from your programs root directory to produce a bundle on standard output:

$ brut-pack encode >myprog
$ chmod +x myprog
$ ./myprog

The bundle is a plain-text POSIX shell script that embeds your programs files as inline data, similar in format to a shar archive. The first time its run, the bundle unpacks its files into a private, content-addressed directory in temporary storage. Then it immediately execs the corresponding executable in bin/. Subsequent runs reuse the previously extracted files as a cache with very little performance overhead. Because this cache lives on volatile temporary storage, old programs are garbage-collected naturally by the operating system at boot.


Portability

brut-pack is written in POSIX shell and awk, targeting the POSIX.1-2024 standard. Bundles produced by brut-pack have no additional dependencies; brut-pack itself needs only a working sha256sum command, present on nearly all contemporary Unix systems.

We test brut-pack using Brat with continuous integration on the following platforms:

sh awk
Alpine Linux busybox ash busybox awk
Debian Linux dash mawk
Fedora Linux Bash gawk
FreeBSD FreeBSD ash nawk
macOS Bash (3.2) nawk

Build Status



Installation

brut-pack runs entirely from source and has no build step or dependencies to install.


Installing brut-pack Globally

Download and extract the latest release archive and symlink bin/brut-pack into your PATH. For example, to install brut-pack in /usr/local:

# curl -sL https://codeberg.org/sstephenson/brut-pack/archive/latest.tar.gz | tar -C /usr/local -xzf -
# ln -s /usr/local/brut-pack/bin/brut-pack /usr/local/bin/brut-pack

Or if you prefer a per-user installation (assuming $HOME/.local/bin is in your PATH):

$ curl -sL https://codeberg.org/sstephenson/brut-pack/archive/latest.tar.gz | tar -C ~/.local -xzf -
$ ln -s ~/.local/brut-pack/bin/brut-pack ~/.local/bin/brut-pack

Vendoring brut-pack in Your Project

Download the latest brut-packed bundle from the package registry and commit it directly to your repository:

$ mkdir -p vendor
$ curl -sL https://codeberg.org/api/packages/sstephenson/generic/brut-pack/latest/brut-pack >vendor/brut-pack
$ chmod +x vendor/brut-pack
$ vendor/brut-pack encode >dist/myprog



Usage

Run brut-pack encode from your programs root directory to produce a bundle on standard output.

Note: Your program must have at least one executable file in bin/.

Note: At this time, only plain-text files are supported in brut-pack bundles.


Saving Your Bundle

Every bundle produced by brut-pack uses its own filename to determine which bundled executable to run.

Redirect the output of brut-pack encode to a file with the same name as an executable in bin/. Then use chmod +x to set the bundles execute bit. (If your program has more than one executable in bin/, you can copy or link the bundle once for every corresponding file.)

For example, if your program has an executable bin/myprog, you should name your bundle myprog:

$ brut-pack encode >myprog
$ chmod +x myprog
$ ./myprog

Listing Files to be Bundled

Run brut-pack list to show the program files that will be included in the bundle: executables, libraries, regular files, and symlinks in bin/, lib/, libexec/, and share/, plus any files in the root directory with “license” in the name. Any files whose names begin with a dot are excluded automatically from the bundle.


Your bundle can include symbolic links as long as the paths they point to are relative, not absolute, and do not traverse outside the bundles root directory. This ensures that your bundle is relocatable to arbitrary locations on the filesystem.

For example, you can have a symbolic link libexec/myprog-x that points to the relative path ../bin/myprog. You cannot have symbolic links that point to /dev/zero or ../../../../../etc/passwd.


Specifying Program Metadata

If a .program.env.sh file is present in the root directory, brut-pack sources it to embed a metadata comment at the top of the bundle. The file should be a shell script that sets one or more of the following variables:

Variable Description
PROGRAM_NAME Program name
PROGRAM_VERSION Version string
PROGRAM_DESCRIPTION One-line description
PROGRAM_AUTHOR Author name and email
PROGRAM_WEB_URL Project URL (preferred over PROGRAM_GIT_URL)
PROGRAM_GIT_URL Git repository URL

Additionally, if your program directory is a Git repository, brut-pack will append the short hash of the latest commit from git describe in parentheses following the version string.


Verifying Bundle Integrity

Run brut-pack verify <FILE> to verify that a bundles embedded hash matches the hash of the files it contains.

To print the hash embedded in a bundle, use brut-pack hash <FILE>.


Adjusting Runtime Behavior

You can set the following environment variables when running a bundle to override the default extraction and execution behavior.

Variable Description Defaults to…
BRUT_PACK_NAME Name of the executable in bin/ to run The basename of the bundle file
BRUT_PACK_PREFIX Root directory for the extraction cache $XDG_RUNTIME_DIR, $TMPDIR, or /tmp



Contributing

brut-pack is hosted on Codeberg: https://codeberg.org/sstephenson/brut-pack

We welcome issues and tested pull requests from human contributors. However, before submitting a large pull request, or one that changes behavior that is not a bug, we ask that you please open an issue first so we can discuss whether it is a good fit for the project.


About the Test Suite

brut-packs tests live in the test/ directory; the test/*.brat files together comprise its test suite. The tests are written using Brat, a parallel TAP testing harness. Run them with:

$ vendor/brat -j 8 test/*.brat

Reporting Issues

brut-pack is portable software and compatibility is a moving target. When reporting issues, please be sure to include information about your operating system, including its release version, and the versions and lineage of the sh and awk commands.


Code Conventions

When contributing changes to brut-pack, please respect the conventions of existing code in lib/brut-pack/ and libexec/.

Shell should be written with set -eu and careful consideration of what is specified by POSIX. See the Shell Command Language specification for more details.

Similarly, awk code should be written in the subset specified by POSIX.



License

brut-pack is free software, distributable under the terms of the MIT + Trans Rights License. See LICENSE.md for details.


© 2026 Sam Stephenson. Handwritten in Mexico City.