Skip to content

elentok/dfl

Repository files navigation

dfl

Logo

dfl is a Go-based runtime for bootstrapping and maintaining a dotfiles repo.

It is designed to replace an ad hoc shell framework with a single binary that can:

  • run repo setup from a stable entrypoint
  • install named dotfiles components
  • install GitHub release binaries
  • provide reusable runtime commands for installer scripts
  • bootstrap from a minimal shell installer
  • self-update from GitHub releases

Install

To set up dfl for your dotfiles repo, start from the dotfiles repo bootstrap script.

Example using elentok/dotfiles/bootstrap:

mkdir -p ~/.dotfiles
cd ~/.dotfiles
curl -fsSL https://raw.githubusercontent.com/elentok/dotfiles/main/bootstrap -o bootstrap
chmod +x bootstrap
./bootstrap

That dotfiles-side bootstrap flow:

  1. resolves the repo root from the script location
  2. installs dfl to ~/.local/bin/dfl if it is missing
  3. runs dfl setup --repo <repo-root>

This repository also ships the public installer shim used by bootstrap:

./install-dfl.sh

That command is for installing the dfl binary itself. After dfl is installed, the normal maintenance entrypoint is:

dfl update

Core Commands

Run the repo setup script:

dfl setup

Target a specific repo explicitly:

dfl setup --repo ~/.dotfiles

Install one or more components from the resolved repo:

dfl install fish
dfl install fish nvim git
dfl i tmux

Preview the update flow without making changes:

dfl --dry-run update --repo ~/.dotfiles

Show the resolved repo root:

dfl repo-root

Print the binary version:

dfl version

Runtime Commands

dfl also exposes lower-level runtime commands intended for use by component installer scripts.

Examples:

dfl has-command git
dfl os is-mac
dfl pkg brew install ripgrep
dfl pkg github install elentok/gx elentok/colr
dfl symlink tmux.conf ~/.tmux.conf
dfl copy config.toml ~/.config/myapp/config.toml
dfl inject core/ai/AGENTS.md ~/.codex/AGENTS.md
dfl inject --link core/ai/AGENTS.md ~/.codex/AGENTS.md
dfl merge-json ~/.claude/settings.json settings.base.json ~/.claude/settings.json
dfl mkdir ~/.config/myapp
dfl backup ~/.gitconfig
dfl shell "Reload config" -- sh -c 'echo hello'
dfl confirm "Overwrite existing config?"

These commands are designed to produce consistent step-style output and to support --dry-run.

dfl inject <source-file> <target-file> appends a managed injected block to the target file using HTML comment markers, and replaces that managed block on rerun instead of duplicating it. Use dfl inject --link <source-file> <target-file> to inject a reference payload line in the form @/absolute/path/to/source instead of file contents.

dfl merge-json <input...> <output> deep-merges two or more JSON files into the output file (the last argument). Objects merge recursively, arrays are unioned (deduplicated, first-seen order), and on scalar conflicts the later input wins. The output path may be one of the inputs for an in-place merge, e.g. dfl merge-json ~/.claude/settings.json settings.base.json ~/.claude/settings.json keeps runtime-written keys while letting the managed base win the keys it declares.

dfl confirm <question> [yes|no] prompts for a single-keypress yes/no answer and exits 0 for yes or 1 for no, so it slots straight into shell conditionals:

if dfl confirm "Do something?"; then
  # do it
fi

The default is no (Question (y/N)?); pass yes to default to yes (Question (Y/n)?). Pressing Enter accepts the default, Esc/Ctrl-C/Ctrl-D cancel (treated as no), and any other key is ignored. The prompt is written to stderr, and when stdin is not a terminal the default is used without blocking.

GitHub package installs use the repository basename as the binary name and install into ~/.local/bin. For example:

dfl pkg github install elentok/gx

That installs the release binary to a versioned path like ~/.local/bin/gx-v1.2.3, points ~/.local/bin/gx at it via symlink, and keeps the newest three installed versions for rollback.

Release Artifacts

Releases are published for:

  • macOS amd64
  • macOS arm64
  • Linux amd64
  • Linux arm64

Release archives are named like:

dfl_Darwin_arm64.tar.gz
dfl_Linux_x86_64.tar.gz

Shell Completions

dfl can generate shell completion scripts via the completion subcommand.

Fish:

dfl completion fish > ~/.config/fish/completions/dfl.fish

Bash:

dfl completion bash > /etc/bash_completion.d/dfl

Zsh:

dfl completion zsh > "${fpath[1]}/_dfl"

Development

Run the test suite:

make test

Build locally:

go build ./...

The release pipeline injects the version string with GoReleaser using -X dfl/internal/buildinfo.Version=<tag>.

Notes

  • dfl setup expects a dotfiles repo layout with a repo-specific core/setup entrypoint.
  • dfl install resolves components from the target repo and executes their install scripts.
  • GitHub-installed binaries use a managed ~/.local/bin/<binary>-<version> plus ~/.local/bin/<binary> symlink layout.

About

Dotfiles framework

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages