Unix utilities, in one Go binary, anywhere.

A BusyBox-style multi-call binary in Go — 84 Unix utilities, one ~3 MB statically-linked executable, native on Linux, macOS, and Windows.

topsail
$ topsail seq 100 | topsail sort -rn | topsail head -3
100
99
98

$ topsail find . -name '*.go' -size +1k -mtime -7
./internal/cli/dispatch.go
./applets/awk/awk.go
./applets/sed/sed.go

$ topsail tar -czf src.tgz internal/ --exclude='*_test.go'
$ topsail sha256sum src.tgz
4f2a8b1c3e7d… *src.tgz
0
Applets
0
Tests
0
Binary
0
Targets
0
Runtime

Everything you reach for, in one place

A familiar POSIX surface. Real flag coverage, not stubs. One static binary that runs unchanged on glibc, musl/Alpine, distroless, and scratch.

One Static Binary, 84 Utilities

Every common shell tool dispatched through a single executable — POSIX coreutils plus jq, curl, host, ping, tar/zip/gzip, hashing, and the BusyBox parity gap-fillers. Symlink to any applet name and dispatch becomes transparent.

$ topsail --list | wc -l
84
$ ln -s topsail ls && ./ls -la
~3MB
Static Binary

Fully Static

CGO_ENABLED=0 go build — runs unchanged on glibc, musl/Alpine, distroless, and scratch. No interpreter, no shared libs, no surprises.

Real Applets

find with -exec, -prune, parens, boolean ops. sed with addresses, ranges, multi-command scripts. awk via goawk. jq via gojq. sort -k FIELD -t SEP. Symbolic chmod modes.

Microsecond Startup

No interpreter cold-start. Pipelines that spawn 1000 instances feel native. tail -f follows files; xargs handles binary-safe paths via -0.

710
Unit Tests

Cosign-Signed Releases

Each release ships a checksums.txt.sigstore.json Sigstore bundle (signature + certificate + Rekor inclusion proof) plus a syft-generated SBOM per archive. Keyless OIDC via GitHub Actions — no key management.

$ cosign verify-blob \\
  --bundle checksums.txt.sigstore.json \\
  --certificate-identity-regexp '...' \\
  checksums.txt

Hackable

One Go package per applet — most are 100–300 lines. Add a new one by dropping a module under applets/ with NAME, HELP, USAGE, and Main(argv).

Linux Packages

Each release ships .deb, .rpm, and .apk alongside the tarballs. Packages install the binary, man pages, and shell completions for bash / zsh / fish to their canonical paths.

Six Native Targets

Linux × x86_64 / ARM64, macOS × Intel / Apple Silicon, Windows × x86_64 / ARM64. Cross-compiled from a single CI job; no per-OS runners required.

All 84, organized

Each applet implements common POSIX flags. Run topsail <applet> --help for per-applet usage.

File operations
cat
cp
mv
rm
mkdir
rmdir
touch
find
chmod
chown
ln
stat
truncate
unlink
mktemp
Text processing
tac
rev
head
tail
wc
nl
sort
uniq
cut
paste
tr
tee
xargs
printf
echo
expand
unexpand
split
comm
join
fold
column
tsort
factor
shuf
sum
seq
yes
Heavy text
grepegrep
grepfgrep
sed
awkgawk
awknawk
JSON & data
jq
Network
curlwget
hostnslookup
ping
Hashing & integrity
md5sum
sha256sum
sha512sum
Archives
tar
gzip
gunzip
zip
unzip
Encoding
base64
xxd
Filesystem & paths
ls
du
df
file
basename
dirname
realpath
readlink
pwd
which
System & process
uname
hostname
whoami
id
date
env
sleep
expr
test[
true
false
nproc
time
timeout

Four-layer dispatch

Clean separation between the entry point, dispatch logic, applet registry, and per-applet implementations. Adding an applet means dropping one Go package plus one blank import.

1

Entry

cmd/topsail/main.go imports internal/applets for side-effect registration, then calls cli.Run(os.Args). Same entry path whether the binary is invoked directly, via topsail <applet>, or through a symlink.

2

Dispatch

internal/cli matches argv[0]'s basename against the registry (multi-call mode); .exe suffix is stripped on Windows. Unknown invocations fall through to topsail <applet> [args] wrapper mode. --help only — -h stays free for applets like df -h.

3

Registry

internal/applet exposes Register, Get, and All, guarded by a sync.RWMutex. Duplicate names or alias collisions panic at startup — every conflict surfaces immediately, never at runtime in production.

4

Applets

74 packages under applets/, each implementing the four-symbol contract: Name, Aliases, Help, Usage, Main(argv) -> int. Stdio reads/writes go through internal/ioutil package-level vars so tests swap in bytes.Buffers directly.

Install or build

Pre-built binaries on the releases page, plus distro packages. Build from source for the full hackable experience.

install.sh
# Linux / macOS — pre-built tarball
$ OS=$(uname -s | tr '[:upper:]' '[:lower:]')
$ ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
$ curl -fL -o topsail.tar.gz \\
    "https://github.com/Real-Fruit-Snacks/topsail/\\
    releases/latest/download/topsail_${OS}_${ARCH}.tar.gz"
$ tar xzf topsail.tar.gz && ./topsail --version

# Linux distro packages (.deb / .rpm / .apk)
$ sudo dpkg -i topsail_amd64.deb         # Debian/Ubuntu
$ sudo rpm -i  topsail_amd64.rpm         # Fedora/RHEL
$ sudo apk add --allow-untrusted topsail_amd64.apk  # Alpine

# Or build from source — Go 1.25+
$ git clone https://github.com/Real-Fruit-Snacks/topsail
$ cd topsail && make build
→ ./topsail (~3 MB, fully static)

# Or via go install
$ go install github.com/Real-Fruit-Snacks/topsail/cmd/topsail@latest
usage.sh
# Daily pipelines (find + awk + jq, all in one binary)
$ topsail find . -name '*.go' -mtime -7
$ topsail awk -F, '{s+=$3} END{print s/NR}' data.csv

# Real jq via gojq
$ topsail jq '.servers[] | select(.region == "us") | .name' inv.json

# Sort by field with custom separator
$ topsail sort -t : -k 3 -n /etc/passwd

# Symlink for transparent dispatch
$ ln -s topsail ls && ./ls -la

# Verify a release with cosign v3 bundle
$ cosign verify-blob \\
    --bundle checksums.txt.sigstore.json \\
    --certificate-identity-regexp '...' \\
    --certificate-oidc-issuer https://token.actions.githubusercontent.com \\
    checksums.txt
Verified OK