developer tool
Linux engineering
dot-files
A reproducible Linux environment: the repo mirrors the filesystem, install converges with symlinks, and CI guards the installer and its own maintenance.
Bash · Git · Linux · GitHub Actions
This repository is more than a pile of dotfiles.
It treats $HOME as a filesystem that can be versioned, reproduced, and evolved through Git.
A new machine should converge toward the same working environment without copying configuration by hand.
The filesystem is the interface
home/ → $HOME
config/ → ~/.config
There is no second abstraction. The tree in Git is the tree Linux already exposes, so a path is discoverable from the filesystem itself.
.github/, install.sh, and repo scripts are not install targets.
Installation is a convergence operation
install.sh does not copy files. _link_one runs ln -s.
On conflict, the existing path is moved to ~/.dotfiles-backup/<timestamp>/, mirroring its original location. If the destination is already the correct symlink, the installer returns. A second run is a no-op besides an empty backup directory.
Special cases are narrower than the directory they live in:
.cursor: children are linked individually so Cursor-managed siblings are not replaced..gnupg: onlygpg.conf; the directory is0700, not a wholesale symlink..ssh: a whitelist (config.example,config.d, …). Keys never enter the install set.
--shell-only limits the run to git and bash files.
Why symlinks instead of copies?
copy: Git ──copy──► $HOME (two sources of truth)
symlink: Git ──link──► $HOME (one)
After a copy, the two trees diverge. A symlink keeps the live environment attached to the versioned tree.
The cost is coupling to the clone path. That is accepted: the machine is cattle for configuration, not for the repository location of last resort.
The .cursor problem
Replacing all of ~/.cursor would also replace paths Cursor itself manages.
~/.cursor/
├── (managed by Cursor)
├── skills → repository/home/.cursor/skills
└── rules → repository/home/.cursor/rules
Do not take ownership of a directory when you only need ownership of part of its contents.
Repository automation
The repo maintains itself.
| Workflow | What it actually runs |
|---|---|
| Lint | ShellCheck (-S error) and shfmt on install.sh, home/, and CI scripts |
| Install | Smoke + idempotent installer tests against a fake HOME |
| Agent skills | Drift check; on main, sync upstream skill sources and open reviewable PRs |
| Secret scan | gitleaks on full history |
Skill sync clones configured upstreams, rsyncs managed directories, and applies small overlays. Collision rule: first enabled source wins.
Safety
.bashrc.local and *.local are gitignored. .ssh is not installed as a tree. gitleaks runs on every push and PR.
Configuration is versioned. Credentials are not.
What this demonstrates
Linux path semantics, symlink-based configuration, safe state transitions, installer idempotency, and CI on the same repository that ships the environment.