- Shell 88.6%
- Lua 11.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .config | ||
| config/baremetal-packages | ||
| docker | ||
| docs | ||
| lib | ||
| scripts | ||
| tests | ||
| .bashrc | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .tmux.conf | ||
| AGENTS.md | ||
| annotate-llm-commits.sh | ||
| build-dev-image.sh | ||
| environment-versions.env | ||
| gpg-agent.conf | ||
| gpg.conf | ||
| README.md | ||
| setup-environment.sh | ||
Neovim development containers
This branch provides Neovim development containers based on the offline setup,
but uses Neovim's built-in vim.pack package manager and
tree-sitter-manager instead of repository-vendored Neovim plugins.
AI Disclosure
My initial config of Neovim and tmux are from my own brain, and developed over the course of several years. The original idea of putting my configs into a container image came out of necessity from working on an airgapped system. GPT-5.4-Luna was used as an agent to manipulate git submodules to be pinned to specific release tags, as well as initial development of Dockerfiles. The "docs" folder contains logs from the aforementioned agent, and are retained for transparency. After the agent did some manipulation, I went back through to clean up and confirm intent of all configs and Dockerfiles. Previous commits are not confirmed to be stable. If you intend to use the contents of this repo, please use tagged releases.
Quick start
Create the local environment file:
cp .env.example .env
# Edit .env and replace the generic RHEL image placeholders.
Build your preferred base docker container:
./build-dev-image.sh --help
The script sources .env, which is intentionally ignored by Git. Image names,
tags, base image names, and base image tags remain machine-specific; tool
versions are sourced from environment-versions.env and are not hardcoded in
the Dockerfiles. The builder resolves its repository directory automatically,
so it can be invoked from any working directory.
The images are run as interactive development shells, for example:
docker run --rm -it --network=none dotfiles-neovim:work
Optionally, replace the tag with the selected Debian, Alpine, or Rocky image tag.
:TSInstall <language>
:TSInstallSync <language>
:TSUpdate
Known gaps include (for Debian) ruff and pyright.
Cross-distribution bare-metal environment entrypoint
setup-environment.sh is the singular root entrypoint for setup, update, and
status/update checks. It detects /etc/os-release and uname -m, normalizes the
architecture, and dispatches to a unique launcher for every supported pair:
- Debian:
x86_64,arm64,riscv64 - Rocky Linux:
x86_64,arm64,riscv64(RISC-V package availability is experimental) - Alpine Linux:
x86_64,arm64,riscv64 - Void Linux:
x86_64,arm64,riscv64
The architecture launcher can be selected with --arch for dry-run planning,
but it does not emulate foreign binaries. Native arm64/riscv64 execution
requires a matching host, container runtime, or binfmt registration.
Bare-metal application and dependency inventory with valid sources
This is the authoritative application inventory; the setup scripts embed the same entries so the repository has one reviewable source of truth:
| Application | Debian 13 source/mapping | Alpine 3.22 source/mapping | Rocky Linux 10 source/mapping | Void Linux source/mapping | FreeBSD source/mapping |
|---|---|---|---|---|---|
| Inkscape | inkscape (source: Debian package) |
inkscape (source: Alpine package) |
inkscape (source: Rocky package query) |
inkscape (source: Void package) |
graphics/inkscape (source: FreshPorts) |
| Complete GNOME Desktop | task-gnome-desktop (source: Debian task package) |
gnome gnome-apps gdm dbus (source: Alpine GNOME guide) |
Server with GUI plus gdm (source: Rocky GNOME guide) |
dbus gnome gnome-apps gdm (source: Void GNOME guide) |
Not mapped by WIP launcher (source: FreeBSD GNOME docs) |
| Firefox ESR | firefox-esr (source: Debian package) |
firefox (source: Alpine package) |
firefox when available (source: Rocky package query) |
firefox when available (source: Void package) |
www/firefox (source: FreshPorts) |
| Blender | blender (source: Debian package) |
blender (source: Alpine package) |
blender (source: Rocky package query) |
blender (source: Void package) |
graphics/blender (source: FreshPorts) |
| Steam | steam-installer (source: Debian package) |
Not mapped by launcher (source: Alpine package query) | Not mapped by launcher (source: Rocky package query) | Not mapped by launcher (source: Void package query) | games/steam (source: FreshPorts) |
| Tailscale | tailscale (source: Tailscale Debian stable) |
tailscale (source: Alpine package) |
tailscale (source: Tailscale RHEL stable) |
tailscale when available (source: Void package) |
security/tailscale (source: FreshPorts) |
| GIMP | gimp (source: Debian package) |
gimp (source: Alpine package) |
gimp (source: Rocky package query) |
gimp (source: Void package) |
graphics/gimp (source: FreshPorts) |
| Discord, Telegram Desktop, GNOME extension manager | Flathub packages (source: Flathub) | Flathub packages (source: Flathub) | Flathub packages (source: Flathub) | Flathub packages (source: Flathub) | Discord net-im/discord, Telegram net-im/telegram-desktop (source: FreshPorts) |
Flatpak entries are documented as valid upstream sources but are not silently
installed by these bare-metal scripts. --headless skips GUI inventory entries;
non-GUI baseline tools are unaffected.
Nontrivial bare-metal dependencies
The following table records the nontrivial dependencies requested by the setup
scripts. Package names are distribution-specific; uv supplies the Python
package-management workflow and pip is intentionally not installed.
| Dependency family | Debian 13 | Alpine 3.22 | Rocky Linux 10 | Void Linux | FreeBSD WIP |
|---|---|---|---|---|---|
| Core shell/network | bash git curl ca-certificates tar gzip xz-utils unzip rsync btop lynx (native apt) |
bash git curl ca-certificates tar gzip xz unzip rsync btop lynx (native apk) |
bash git curl ca-certificates tar gzip xz unzip rsync btop lynx (native dnf) |
bash git curl ca-certificates tar gzip xz unzip rsync btop lynx (native xbps) |
bash, git, curl, ca_root_nss, rsync, btop, and lynx/links/elinks via pkg/Ports (pkg/Ports) |
| Build/autotools | cmake ninja-build make pkg-config gettext libtool autoconf automake build-essential (native apt) |
cmake ninja make pkgconf gettext libtool autoconf automake build-base (native apk) |
cmake ninja-build make pkgconf-pkg-config gettext libtool autoconf automake (native dnf) |
cmake ninja make pkg-config gettext libtool autoconf automake base-devel (native xbps) |
gmake, cmake, ninja, pkgconf, gettext-runtime, libtool, autoconf, automake (pkg/Ports) |
| C/C++ compilers | gcc, g++, clang, lld, llvm (native apt) |
gcc, g++, clang20, llvm (native apk) |
gcc, gcc-c++, clang, lld, llvm (native dnf) |
base-devel, clang, lld, llvm (native xbps) |
base-system clang plus versioned LLVM/Clang pkg/Ports candidates; gcc is not assumed (pkg/Ports) |
| Python/package workflow | python3, python3-dev, python3-venv, uv (native apt; external source links above) |
python3, uv (native apk; external source links above) |
python3, python3-devel, uv (native dnf; external source links above) |
python3, uv (native xbps; external source links above) |
python3; uv package/source availability is WIP and must be validated on the target (pkg/Ports; external source links above) |
| JavaScript/runtime | nodejs, npm (native apt) |
nodejs, npm (native apk) |
nodejs, nodejs-npm (native dnf) |
nodejs, npm (native xbps) |
versioned node and npm pkg/Ports candidates (pkg/Ports) |
| Rust/tooling | rustc, cargo (native apt) |
rust, cargo (native apk) |
rust, cargo (native dnf) |
rust, cargo (native xbps) |
rust pkg/Ports package (pkg/Ports) |
| Interactive/VCS utilities | openssh-client, gnupg, tmux, wget, ripgrep, fd-find, tree, zip, less (native apt) |
openssh-client, gnupg, tmux, wget, ripgrep, fd, tree, zip, less (native apk) |
openssh-clients, gnupg2, tmux, wget, ripgrep, fd-find, tree, zip, less (native dnf) |
openssh, gnupg, tmux, wget, ripgrep, fd, tree, zip, less (native xbps) |
tmux, tree, less, rsync, gdb via pkg/Ports (pkg/Ports) |
| Debug/data/test | gdb, gdbserver, gfortran, protobuf-compiler, libprotobuf-dev, libgtest-dev, jq, shellcheck (native apt) |
gdb, gfortran, protobuf, protobuf-dev, gtest-dev, jq, shellcheck (native apk) |
gdb, gdb-gdbserver, gcc-gfortran, protobuf, protobuf-compiler, protobuf-devel, gtest-devel, jq, ShellCheck (native dnf) |
gdb/toolchain equivalents, jq, ShellCheck (native xbps) |
gdb, jq, ShellCheck; protobuf/GTest availability is target-dependent (pkg/Ports) |
| Editor/language support | Neovim source build, tree-sitter CLI, uv, Ruff, Pyright (native apt; external source links above) |
Neovim source build, tree-sitter-cli, uv, Ruff, Pyright (native apk; external source links above) |
Neovim source build, tree-sitter CLI, uv, Ruff, Pyright (native dnf; external source links above) |
Neovim source build, tree-sitter/toolchain support, uv, Ruff, Pyright (native xbps; external source links above) |
Neovim source build; language-tool availability is WIP (pkg/Ports; external source links above) |
| Extended development image tools | Dockerfile adds python3-pytest, black, mypy, flake8, isort, pylint, pre-commit, tox, default-jdk, Gradle, Go, protobuf, GTest (native apt) |
Dockerfile adds py3-pytest, gfortran, OpenJDK 21, Gradle, Go, protobuf, GTest, tree-sitter CLI (native apk) |
Dockerfile adds python3-pytest, OpenJDK 21, Go, protobuf, GTest; Gradle remains a documented gap (native dnf) |
Native image-specific availability varies (native xbps) | WIP; use pkg/Ports mappings above (pkg/Ports) |
| Optional server | Docker official repository: docker-ce, Buildx, Compose plugin; Podman fallback (native apt) |
Native Docker/Compose packages when available; Podman fallback otherwise (native apk) | Docker official RHEL-compatible repository: docker-ce, Buildx, Compose plugin; Podman fallback (native dnf) |
Native Docker/Compose packages when available; Podman fallback otherwise (native xbps) | Podman fallback; bhyve is the VM alternative and has no Compose (pkg/Ports) |
The Docker development images use the same dependency policy: they omit pip
packages and install the pinned UV_VERSION from uv's official installer.
Bare-metal package strings are centralized in
config/baremetal-packages/packages.env; each unique
launcher sources its matching manifest so package-name corrections are made in
one place.
The launchers are in scripts/; shared implementation is in
lib/environment-common.sh. Rocky launchers enable CRB and attempt EPEL when
supported, while Alpine uses version-independent compiler package matching.
Every bare-metal launcher requests rsync, btop, npm, and lynx as part of
its baseline tools. If lynx is not available under a native package name, the
shared Linux engine and FreeBSD launcher try the permitted links, links2, or
elinks alternatives through the native package manager/pkg/Ports. Each
launcher uses its native package manager
(apt, dnf, apk, or xbps), skips packages unavailable in that distribution
rather than aborting the complete matrix, and builds Neovim from a versioned
source prefix when needed. It uses upstream binaries or package-manager
fallbacks for uv, Ruff, and Pyright when the requested distribution version is
not available. Re-running setup or update preserves existing configuration
and reports partial installations instead of deleting them.
sudo ./setup-environment.sh update
sudo ./setup-environment.sh setup --yes
./setup-environment.sh check --check-updates
./setup-environment.sh update --dry-run --os alpine --arch riscv64
./tests/test-baremetal-setup.sh
--headless excludes every GUI application represented in this README inventory
while retaining non-GUI entries. --server adds a server runtime: Debian uses
Docker's official repository, Rocky uses Docker's official RHEL-compatible
repository, and Alpine/Void use their native official package repositories when
Docker and Compose packages are available. If the selected Linux source cannot
provide Docker and Compose, the script warns about Podman's incompatibilities
and attempts podman plus podman-compose instead. Use
--server-runtime=podman to request that fallback explicitly.
On FreeBSD, Docker Engine has no official repository/package in this WIP
launcher, so --server warns and attempts Podman. Use
--server-runtime=bhyve (or --bhyve) to select bhyve as a relevant VM-isolation
substitute; bhyve is not Docker-compatible and does not provide Compose.
After a non-dry server setup, the launcher validates the selected runtime and
its Compose command (docker compose, podman-compose, or podman compose)
and reports missing commands as a partial setup. The persistent state record
also stores server_requested, server_runtime, and server_compose, which
are shown by a later check operation.
--check-updates reports installed and target versions, release dates when the
upstream release API provides them, a changelog/release URL, and a GitHub
comparison link. Existing upstream tools are not changed without an interactive
confirmation or --yes; --no-update suppresses those offers. --skip-source,
--skip-external, and --skip-apps allow a staged recovery on constrained
systems. Runtime source state and atomic complete/partial setup markers are stored under
/var/lib/dotfiles-environment, not in the repository. If Void’s configured
mirror is unreachable, set VOID_REPOSITORY to an alternate xbps repository
URL before running the root entrypoint.
FreeBSD environment setup (WIP)
scripts/setup-freebsd.sh is an experimental POSIX-shell FreeBSD entrypoint.
The root setup-environment.sh dispatcher recognizes FreeBSD and routes to it
without requiring Bash. It prefers FreeBSD pkg binary packages, uses an
already-present /usr/ports tree only for missing dependency fallbacks, and
builds the configured Neovim release from source under a versioned prefix.
sudo ./setup-environment.sh update
./setup-environment.sh update --dry-run --os freebsd --arch riscv64
This WIP script has not been executed on a FreeBSD host in the current
environment. FreeBSD package names, Ports origins, GUI applications, and
RISC-V package availability must be confirmed on the target FreeBSD release.
Use --skip-ports to avoid Ports fallback, --fetch-ports to explicitly
clone the shallow official Ports tree when no tree exists, --prefer-ports to
try Ports before pkg, and --update-ports to refresh an existing tree once.
--ports-root=DIR, --ports-url=URL, and --ports-branch=X override the
Ports location and Git source; the equivalent PORTS_ROOT, PORTS_URL, and
PORTS_BRANCH environment variables are also supported. Use check to inspect
core command availability and persisted state without installing anything. Set
NEOVIM_SHA256 to require source-archive verification with FreeBSD sha256(1);
otherwise the WIP script warns that verification is intentionally skipped.
Inline comments cite the FreeBSD Handbook and relevant manual pages used for
the implementation.
Environment setup entrypoint
The generic setup-environment.sh dispatcher and the launchers under scripts/
are the single implementation for setup, update, and status checks. Redundant
Debian compatibility wrappers are intentionally not provided; invoke the root
dispatcher directly:
sudo ./setup-environment.sh update
./setup-environment.sh update --dry-run --os debian --arch x86_64
All bare-metal and Docker tool versions are maintained in the single tracked
environment-versions.env file; .env and .env.example contain
image/configuration values only.
Neovim and GDB configuration
The Neovim configuration uses vim.pack to install its plugins from their
upstream repositories when network access is available. It provides completion,
LSP integration, Tree-sitter parser management, diagnostics, formatting, linting,
file navigation, and direct GNU GDB integration. <leader>dt invokes
:GdbStartGTest, which prompts for a test binary and optional
--gtest_filter; argument boundaries are preserved for paths containing spaces.
The GDB configuration permits project-provided debugger scripts to auto-load from
any path through .config/gdb/gdbinit.
CRB and EPEL are enabled by the Rocky helper. This resolves Ninja, pytest, Protobuf development files, GoogleTest development files, ShellCheck, btop, ripgrep, and fd-find. Gradle remains unavailable in the enabled Rocky repositories.
Trouble and Neovim v0.12.6
Trouble is tracked from its upstream main branch rather than the explicit
v3.7.1 release. This is intentional: the release has compatibility issues
with Neovim v0.12.6, while the upstream branch contains the current API fixes
needed by this configuration. The offline variant uses the existing Trouble
submodule at the corresponding main commit; the networked variant uses
vim.pack with branch = "main".
Rust on ESP projects
For Rust-on-ESP work, use the Espressif IDF Rust container rather than the
ordinary development images. Select an espressif/idf-rust tag matching the
ESP-IDF release required by the project:
docker run --rm -it \
--mount type=bind,src="$PWD",dst=/workspace \
--workdir /workspace \
espressif/idf-rust:<tag> bash
Build and test from inside that container so the Espressif Rust toolchain,
ESP-IDF, target linker, and project rust-toolchain.toml/.cargo/config.toml
are selected together. The Neovim Rust Analyzer configuration detects those
project files, enables Cargo build scripts, and applies the configured target
when available.
TODOS
- add ruff organise imports
- add script to run on baremetal to set up and install all required apps and dependencies