Personal Linux and macOS config deployed with GNU Stow.
To setup proxy:
export http_proxy="http://127.0.0.1:10808"
export https_proxy="http://127.0.0.1:10808"
export ftp_proxy="http://127.0.0.1:10808"
export no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"
git config --global http.proxy http://127.0.0.1:10808
git config --global https.proxy http://127.0.0.1:10808scripts/setup.sh installs selected applications and deploys the complete
platform profile. With a terminal attached, the one-line command first asks
where to clone/use the dotfiles repository (default ~/opt/dotfiles), detects
components that are already installed, and then opens a numbered menu with
missing or unverified components first:
Detected components are listed afterward, marked [installed], and default to
off; select one explicitly to rerun its installer. Detection is local and
best-effort. Source components are detected from their Git checkouts, while
command and application components are detected from their executable or app.
Explicit --preset and --with runs remain deterministic and do not filter
their selections through this interactive detection.
curl -fsSL https://gist.githubusercontent.com/Jamie-Cui/3c22bc591b4d372813b6ce26086e1c63/raw/setup-gist.sh | bashFor an unattended, reproducible run, pass a preset and explicitly accept the two confirmations:
curl -fsSL https://gist.githubusercontent.com/Jamie-Cui/3c22bc591b4d372813b6ce26086e1c63/raw/setup-gist.sh | \
bash -s -- --preset recommended --yesThe presets are minimal (prerequisites plus dotfiles), recommended (common
shell, font, editor, terminal, and Rime tools; plus AeroSpace on macOS), and
all. Individual components can be adjusted with repeatable, comma-separated
--with and --without arguments:
# Inspect without sudo, downloads, clone, generated files, or logs.
curl -fsSL https://gist.githubusercontent.com/Jamie-Cui/3c22bc591b4d372813b6ce26086e1c63/raw/setup-gist.sh | \
bash -s -- --preset minimal --with emacs --dry-run
# Prepare Emacs through configure; add --build-emacs to compile and install it.
curl -fsSL https://gist.githubusercontent.com/Jamie-Cui/3c22bc591b4d372813b6ce26086e1c63/raw/setup-gist.sh | \
bash -s -- --preset minimal --with emacs --yesComponents are shell, font, vim, nvim, emacs, ctags,
org-root, tdlib, kitty, flameshot, rime, x11, i3,
rofi, hyprland, waybar, dunst, mail, secrets, aerospace,
and borders. Dependencies are added automatically; explicitly excluding a
required dependency is an error. The clone-only ctags, org-root, and
tdlib components are selected only with --with or the all preset.
Software selection does not filter Stow packages: the complete macOS or Linux
dotfiles profile is always previewed and deployed.
The script inherits exported proxy variables without printing their values.
Export them before the initial curl so that the loader, Git, package managers,
and the proxy-only sudo environment see the same settings:
export http_proxy=http://127.0.0.1:10808
export https_proxy=$http_proxy
curl -fsSL https://gist.githubusercontent.com/Jamie-Cui/3c22bc591b4d372813b6ce26086e1c63/raw/setup-gist.sh | bashExisting configuration is never adopted or cleaned. A dirty/diverged clone or
Stow conflict stops safely. Optional application failures are collected while
independent components and dotfiles continue; expected GUI, authentication,
Rime, and logout steps are reported separately as pending work. Full logs are
written below ~/.local/state/dotfiles/ after the install is confirmed.
The Gist is a small loader; scripts/setup.sh in this repository remains the
source of truth. To inspect the loader before running it:
tmp=$(mktemp)
curl -fsSL https://gist.githubusercontent.com/Jamie-Cui/3c22bc591b4d372813b6ce26086e1c63/raw/setup-gist.sh -o "$tmp"
less "$tmp"
bash "$tmp"xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install stowsudo dnf install curl git make stowmkdir -p ~/opt
git clone https://github.com/Jamie-Cui/dotfiles.git ~/opt/dotfiles
cd ~/opt/dotfiles
make dry-run
make bootstrapOnly GPG ciphertext is managed by Git. The private key, its revocation
certificate, and plaintext credentials must remain outside this repository.
Install GnuPG with brew install gnupg on macOS or sudo dnf install gnupg2
on Fedora, then create the ciphertext yourself (replace the placeholder with
the fingerprint of an encryption-capable public key):
gpg --output packages/secrets/.authinfo.gpg \
--encrypt --recipient YOUR_ENCRYPTION_KEY_FINGERPRINT \
~/.authinfoThe secrets Stow package is selected automatically after the ciphertext
exists. Preview and deploy it, verify that your private key can decrypt it,
then securely remove or archive the old plaintext file:
make dry-run
make restow
gpg --decrypt ~/.authinfo.gpg >/dev/nullEmacs reads only ~/.authinfo.gpg through auth-source. On Linux, mbsync
decrypts that same file through gpg-agent. Import the private key from a
separate backup before deploying on a new machine.
The backup must be an armored OpenPGP secret key created by gpg, not an SSH
key or SSH fingerprint. Retrieve it from Bitwarden or another backup location
outside this repository, then import it into the local GnuPG keyring:
chmod 600 ~/Downloads/dotfiles-secrets-private.asc
gpg --import ~/Downloads/dotfiles-secrets-private.asc
gpg --list-secret-keys --with-subkey-fingerprintConfirm that the expected primary fingerprint is present and that it has an
encryption subkey marked [E]. Test decryption before deploying the profile:
cd ~/opt/dotfiles
gpg --decrypt packages/secrets/.authinfo.gpg >/dev/null
make dry-run
make bootstrapAfter the import and decryption test succeed, securely remove the downloaded
private-key export. GnuPG keeps the imported key in its own home directory
(normally ~/.gnupg); never copy that directory or the exported private key
into this repository.
Run make bootstrap once after installing the apps below.
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"sudo dnf install zsh curl util-linux
chsh -s "$(command -v zsh)"
RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"Log out and back in after changing the login shell.
brew install --cask font-maple-mono-nl-nf-cnsudo dnf install curl unzip fontconfig
mkdir -p ~/.local/share/fonts/maple-mono
curl -fL https://github.com/subframe7536/maple-font/releases/latest/download/MapleMonoNL-NF-CN-unhinted.zip -o /tmp/MapleMonoNL-NF-CN-unhinted.zip
unzip -o /tmp/MapleMonoNL-NF-CN-unhinted.zip -d ~/.local/share/fonts/maple-mono
fc-cache -fvVim (vim)
brew install vim # macOS
sudo dnf install vim-enhanced # FedoraNeovim (nvim)
brew install neovim # macOS
sudo dnf install neovim # FedoraEmacs (emacs)
The setup script’s emacs component installs the dependencies, shallow-clones
the emacs-31 source with depth 1 or safely fast-forwards an existing checkout,
and runs autogen.sh and configure. Compilation and installation remain
manual unless --build-emacs is supplied; that explicit mode uses at most four
jobs by default and requires 10 GiB of available space.
git clone --branch emacs-31 --single-branch --depth 1 https://github.com/emacs-mirror/emacs.git ~/opt/emacs-srcbrew install autoconf automake texinfo libgccjit gcc gnutls tree-sitter@0.25 pkg-config coreutils sqlite librsvg
cd ~/opt/emacs-src
export PATH="$(brew --prefix texinfo)/bin:$PATH"
export PKG_CONFIG_PATH="$(brew --prefix tree-sitter@0.25)/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
./autogen.sh
./configure --with-ns --with-native-compilation --with-tree-sitter --with-sqlite3 --with-rsvg --without-pop --without-mailutils
make -j"$(sysctl -n hw.logicalcpu)"
make install
cp -R nextstep/Emacs.app /Applications/
sudo mkdir -p /usr/local/bin
sudo ln -sf /Applications/Emacs.app/Contents/MacOS/Emacs /usr/local/bin/emacs
sudo ln -sf /Applications/Emacs.app/Contents/MacOS/bin/emacsclient /usr/local/bin/emacsclientsudo dnf install dnf-plugins-core gcc gcc-c++ make autoconf automake texinfo
sudo dnf builddep emacs
sudo dnf install libgccjit-devel tree-sitter-devel sqlite-devel librsvg2-devel gtk3-devel
cd ~/opt/emacs-src
./autogen.sh
./configure --with-pgtk --with-native-compilation --with-tree-sitter --with-sqlite3 --with-rsvg --without-pop --without-mailutils
make -j"$(nproc)"
sudo make installemacs --versionEdit the managed ~/.emacs.d/init.el and ~/.emacs.d/early-init.el sources for
Emacs settings.
Universal Ctags (ctags)
The ctags component shallow-clones the source with depth 1 into
~/opt/ctags. It does not configure, build, or install Universal Ctags.
scripts/setup.sh --preset minimal --with ctags --yesorg-root (org-root)
The org-root component clones the private repository with its full history
over SSH into ~/opt/org-root, which is the default path used by the managed
Emacs configuration. GitHub SSH access must already be configured.
scripts/setup.sh --preset minimal --with org-root --yesTDLib (tdlib)
The tdlib component shallow-clones the source with depth 1 into
~/opt/tdlib. It does not run CMake, build, or install TDLib.
scripts/setup.sh --preset minimal --with tdlib --yesFor all three clone-only components, an existing Git checkout is left exactly as-is; setup does not fetch, pull, or validate its origin. An existing non-Git path is reported as a component failure.
Kitty (kitty)
brew install --cask kitty # macOS
sudo dnf install kitty # FedoraFlameshot (flameshot)
Download the latest .dmg from Flameshot Releases, copy Flameshot to
/Applications, open it once, then enable Screen & System Audio Recording
permission. If macOS blocks the first launch:
xattr -rd com.apple.quarantine /Applications/flameshot.appsudo dnf install flameshot grimThe tracked configuration is deployed only by the Linux profile. It leaves the save directory to Flameshot instead of pinning a machine-specific path.
Rime (rime)
brew install --cask squirrel-appAdd Squirrel in System Settings → Keyboard → Input Sources. After make
bootstrap, choose Squirrel → Redeploy from the input-method menu; log out and
back in if Squirrel does not work in existing applications.
sudo dnf install fcitx5 fcitx5-rime imsettings im-chooser
im-chooserSelect Fcitx 5 in im-chooser, then log out and back in.
proxyctl (bin)
proxyctl init
source ~/.zshrcCodex skills (skills)
No setup beyond make bootstrap.
Run make bootstrap once after installing the apps needed by the chosen X11 or
Wayland session.
X11 (x11)
sudo dnf install xorg-x11-server-Xorg xorg-x11-xinit xorg-x11-xauthi3 (i3)
sudo dnf install i3 i3lock picom feh xclip dex-autostart network-manager-applet pulseaudio-utils ibus jq xss-lock setxkbmapi3blocks (i3blocks)
sudo dnf install i3blocks alsa-utils sysstat perlRofi (rofi)
sudo dnf install rofi firefoxHyprland (hypr)
sudo dnf install hyprland hyprlock hyprpaper xdg-desktop-portal-hyprland brightnessctl playerctl wireplumber xclipThe main configuration uses Hyprland’s native Lua API and requires Hyprland 0.55 or newer. Hyprlock and Hyprpaper continue to use their own Hyprlang configuration files.
Waybar (waybar)
sudo dnf install waybar jq playerctl blueman network-manager-applet NetworkManager-tui pavucontrol htop baobabDunst (dunst)
sudo dnf install dunstFcitx5 (fcitx5)
sudo dnf install fcitx5 fcitx5-rime fcitx5-gtk fcitx5-qtGTK 2 (gtk-2.0)
sudo dnf install gtk2GTK 3 (gtk-3.0)
sudo dnf install gtk3GTK 4 (gtk-4.0)
sudo dnf install gtk4imsettings (imsettings)
sudo dnf install imsettingsDavMail (davmail)
sudo dnf copr enable mguessan/davmail
sudo dnf install davmail java-latest-openjdk-headless
mkdir -p ~/.local/state/davmail
systemctl --user enable --now davmail.service
journalctl --user -fu davmail.serviceKeep the log open during the first mbsync run and complete the Microsoft
device-code prompt it prints.
isync (isync)
sudo dnf install isync maildir-utils gnupg2
openssl rand -hex 32
umask 077
touch ~/.authinfo
$EDITOR ~/.authinfo
# Encrypt it using the Encrypted secrets instructions, then deploy it.
mbsync outlook
mu indexUse the generated value as the same LOCAL_KEY in both entries; it is not the
Microsoft password:
machine 127.0.0.1 login you@outlook.com password LOCAL_KEY port 1143 machine 127.0.0.1 login you@outlook.com password LOCAL_KEY port 1025
Run make bootstrap after installing the app.
AeroSpace (aerospace)
brew install --cask nikitabobko/tap/aerospace
# Mission Control and Dock settings required by this layout.
defaults write com.apple.dock expose-group-apps -bool true
defaults write com.apple.dock autohide -bool true
defaults write com.apple.dock pinning -string start
killall DockJankyBorders is optional. The AeroSpace configuration starts it only when the
borders executable exists:
brew tap FelixKratz/formulae
brew install bordersThe setup script installs AeroSpace in the recommended macOS preset but does not install borders or change Dock/Mission Control defaults. It reports the commands above as pending work when the current values differ.
If macOS blocks the first launch:
xattr -d com.apple.quarantine /Applications/AeroSpace.appThe tracked bindings use ${HOME} for user-specific paths.