English | 日本語
Dotfiles for setting up development machines and keeping them that way. One command installs the CLI toolchain and configures Claude Code, Codex, OpenCode, Cursor, and Gemini CLI.
Setting up a new machine is the easy half. The harder half is keeping several of them — work, personal, a host, a VPS, a throwaway sandbox — in a state worth trusting months later, without a human holding in their head what is installed where, what has gone stale, and where the environments have drifted apart. Updating is rarely difficult; remembering that something is due is what gets skipped.
So the goals are:
- Continuous maintenance, not just first-time setup. Automating the initial install is the smaller half of the problem; the environments that already exist have to stay maintainable for years.
- Updates that do not depend on memory. Whether an update exists is detected, not recalled. The machine says so; the human decides when to act on it.
- Reproducibility across machines. No machine chases upstream on its own. Versions are resolved once, centrally, and each machine follows that resolved state through Git and a lockfile — so two machines updated a week apart still land on the same thing.
- Frequent updates without blind trust. Raising the update frequency must not amount to trusting every new upstream release on sight. Staying current and staying deliberate is one tradeoff, not two independent goals.
The mechanisms below — a lockfile, checksums, a release-age delay, immutable references, a registry proxy — are the current answer to those goals, not the goals themselves.
curl -fsSL https://raw.githubusercontent.com/bmthd/dotfiles/main/install.sh | zshcurl -fsSL https://raw.githubusercontent.com/bmthd/dotfiles/main/install.sh | bashAfterwards, restart the shell or run source ~/.zshrc (source ~/.bashrc for bash) to put everything on PATH.
- CLI tools — node, bun, pnpm, uv, gh, ghq, jq, wrangler, and more (see
[tools]in.mise.toml) - Claude Code — the binary itself,
settings.json(merged into an existing one), and the status line - Agent skills — the same set installed for Claude Code, OpenCode, Cursor, Codex, and Gemini CLI
- Plugins — Codex, plus the official plugins (TypeScript LSP)
- npm registry — routed through Takumi Guard, a proxy that refuses known-malicious packages
- Global git hooks — trust mise configs in new worktrees and pin staged GitHub Actions references before commit, while preserving repository hooks and partial staging (
.dotfiles/git-hooks) - Shell startup — the mise activation and the update notice, written into
~/.zshrcand~/.bashrcas blocks mise owns and can rewrite ([bootstrap.mise_shell_activate]and[dotfiles]in.mise.toml)
The setup can be re-run at any time as a mise task.
mise run setup # full setup
mise tasks # list the individual tasksInteractive shells check main once a day — this repository and bmthd/skills, the two whose contents this setup installs.
If either has commits newer than the revision recorded at install time, you get a notice — nothing updates itself.
Update with /dotfiles apply.
It diffs against the installed revision and separates what to pull in from what to keep local (.agents/skills/dotfiles), and reinstalls the skills on the way through.
When only the skills moved, mise run setup:skills is the entire update: skills hold no per-machine state, so there is nothing to merge.
Re-running install.sh also updates the machine, and still overwrites ~/.claude/settings.json and ~/.claude/statusline.sh.
The mise config is no longer among them: the repository's copy goes to ~/.config/mise/conf.d/10-dotfiles.toml, and ~/.config/mise/config.toml is left to the machine — mise loads it after conf.d/, so a pin or a machine-only tool written there overrides the repository's copy and survives every re-run.
A machine installed before that split still has the repository's copy in config.toml.
install.sh and /dotfiles apply migrate it only when they can prove nothing was added locally — the file is identical either to the copy being installed or to the .mise.toml of the revision it was installed from.
Otherwise the file stays exactly where it is, so pins keep working, and both say what to do (review it and keep only the machine-local part, or DOTFILES_MIGRATE_MISE_CONFIG=1 to migrate anyway).
Third-party skill sources are deliberately not watched: they move on their own schedule, mostly for reasons unrelated to the skills installed from them. Update those with npx skills update. The Markdown it fetches goes straight into an agent's context, so review the diff before running it.
All of the setup logic lives in mise.
| File | Role |
|---|---|
install.sh |
Bootstrap only: install mise, place the config files, wire up the shell |
.mise.toml |
Tool definitions ([tools]) and setup tasks, each delegating to a script in .dotfiles/setup; installed to ~/.config/mise/conf.d/10-dotfiles.toml |
mise.lock |
The versions and checksums that actually get installed, installed to ~/.config/mise/mise.lock |
.agents/skills |
Skills specific to this repository; the general-purpose ones live in bmthd/skills |
renovate.json |
Update policy for GitHub Actions PRs |
.githooks |
A repository pre-commit hook guarding the [tools] block; the global dispatcher runs pinact first and then forwards here |
Tool versions move when the daily bump-tools.yml advances mise.lock, not through mise upgrade.
To get ahead locally: mise lock --bump --minimum-release-age 2d --global.
Resolving versions centrally and having every machine follow that result doubles as the supply-chain defense.
How it works, and the one-time setup for bump-tools.yml, are in docs/supply-chain.md.
MIT