Skip to content

Repository files navigation

dotfiles

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:10808

Contents

Quick setup

scripts/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 | bash

For 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 --yes

The 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 --yes

Components 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 | bash

Existing 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"

Prerequisites

macOS

xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install stow

Fedora

sudo dnf install curl git make stow

Deploy

mkdir -p ~/opt
git clone https://github.com/Jamie-Cui/dotfiles.git ~/opt/dotfiles
cd ~/opt/dotfiles
make dry-run
make bootstrap

Encrypted secrets

Only 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 \
    ~/.authinfo

The 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/null

Emacs 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.

Import the GPG key 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-fingerprint

Confirm 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 bootstrap

After 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.

Cross-platform apps

Run make bootstrap once after installing the apps below.

macOS

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Fedora

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.

macOS

brew install --cask font-maple-mono-nl-nf-cn

Fedora

sudo 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 -fv

Vim (vim)

brew install vim                 # macOS
sudo dnf install vim-enhanced    # Fedora

Neovim (nvim)

brew install neovim              # macOS
sudo dnf install neovim          # Fedora

Emacs (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-src

macOS

brew 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/emacsclient

Fedora

sudo 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 install

Configure

emacs --version

Edit the managed ~/.emacs.d/init.el and ~/.emacs.d/early-init.el sources for Emacs settings.

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 --yes

org-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 --yes

TDLib (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 --yes

For 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           # Fedora

Flameshot (flameshot)

macOS

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.app

Fedora

sudo dnf install flameshot grim

The 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)

macOS

brew install --cask squirrel-app

Add 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.

Fedora

sudo dnf install fcitx5 fcitx5-rime imsettings im-chooser
im-chooser

Select Fcitx 5 in im-chooser, then log out and back in.

proxyctl (bin)

proxyctl init
source ~/.zshrc

Codex skills (skills)

No setup beyond make bootstrap.

GNU/Linux (Fedora) apps

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-xauth

i3 (i3)

sudo dnf install i3 i3lock picom feh xclip dex-autostart network-manager-applet pulseaudio-utils ibus jq xss-lock setxkbmap

i3blocks (i3blocks)

sudo dnf install i3blocks alsa-utils sysstat perl

Rofi (rofi)

sudo dnf install rofi firefox

Hyprland (hypr)

sudo dnf install hyprland hyprlock hyprpaper xdg-desktop-portal-hyprland brightnessctl playerctl wireplumber xclip

The 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 baobab

Dunst (dunst)

sudo dnf install dunst

Fcitx5 (fcitx5)

sudo dnf install fcitx5 fcitx5-rime fcitx5-gtk fcitx5-qt

GTK 2 (gtk-2.0)

sudo dnf install gtk2

GTK 3 (gtk-3.0)

sudo dnf install gtk3

GTK 4 (gtk-4.0)

sudo dnf install gtk4

imsettings (imsettings)

sudo dnf install imsettings

DavMail (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.service

Keep 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 index

Use 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

MacOS apps

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 Dock

JankyBorders is optional. The AeroSpace configuration starts it only when the borders executable exists:

brew tap FelixKratz/formulae
brew install borders

The 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.app

The tracked bindings use ${HOME} for user-specific paths.

About

Personal configuration for Linux and macOS desktops.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages