Skip to content

Repository files navigation

dot-files

Overview

Personal macOS development environment. mise is the only entry point: it installs every tool, applies dotfiles, and configures the machine through mise bootstrap. There is no Nix, no task runner, and no project-level mise config in this repo.

Quick Start

Prerequisites: macOS, Xcode CLI tools (xcode-select --install).

curl -fsSL https://raw.githubusercontent.com/djgoku/dot-files/main/setup.sh | zsh

Or clone and run locally:

mkdir -p ~/dev/github/djgoku && cd "$_"
git clone https://github.com/djgoku/dot-files.git
cd dot-files && ./setup.sh

setup.sh does only what cannot be declared in config: clone the repo and install mise. It then points mise at the config inside the clone with MISE_CONFIG_DIR and lets mise create ~/.dot-files and ~/.config/mise from its own [dotfiles] entries – no path is symlinked by hand – before running mise bootstrap --yes. It takes --no-clone (use the checkout already in place) and --prepare-only (stop before bootstrapping); CI uses both rather than reimplementing the setup. Once bootstrapped, re-apply at any time with:

mise bootstrap --yes

Project Structure

.
├── setup.sh                    # Fresh-machine bootstrap (3 steps, then hands off)
├── config/mise/                # Machine config -> symlinked to ~/.config/mise
│   ├── config.toml             #   [settings] [tools] [env] [dotfiles]
│   └── conf.d/
│       ├── 10-repos.toml       #   git clones (fzf-tab, tree-sitter-module)
│       ├── 20-files.toml       #   managed directories and generated files
│       ├── 30-macos.toml       #   Finder and NSGlobalDomain defaults
│       └── 90-hooks.toml       #   post-repos, post-tools
├── emacs/
│   ├── init.el                 # Emacs init
│   ├── main.el                 # Main configuration
│   ├── early-init.el
│   └── emacs-env/              # Environment selector
├── mise.toml                   # PROJECT config: this repo's tasks only
├── .github/
│   ├── PklProject              # pins com.github.actions (pkl-pantry)
│   └── workflows/              # *.pkl are the SOURCES; *.yml are generated
├── gnupg/gpg-agent.conf.tmpl   # Rendered to ~/.gnupg/gpg-agent.conf
├── macos/com.apple.Terminal.plist
└── zsh/.zshrc

Why config/mise/ and not mise/

mise auto-discovers mise/config.toml, .mise/conf.d/, and .config/mise/conf.d/ as project config. Any of those names would mean that cd-ing into this repo loads the machine config a second time – including its [bootstrap] stanzas, so [bootstrap.macos.defaults] would go live locally. config/mise/ matches no discovery rule, so the ~/.config/mise symlink is the only path by which it loads.

Bootstrap Stages

mise bootstrap runs stages in a fixed order:

plugins  packages  accounts  files  services  firewall  compose  repos
dotfiles  mise-shell-activate  macos-defaults  macos-launchd-agents
linux-systemd-units  user  tools  task  final-hook

=tools= is stage 15 of 17. Anything that shells out to an installed binary must run in post-tools or final, not earlier. Two entries here depend on that ordering:

  • ~/.gnupg/gpg-agent.conf interpolates mise which pinentry-curses. It renders at the dotfiles stage with a bare-name fallback so the stage cannot hard-fail, then post-tools re-renders it with the resolved absolute path.
  • The gpg-agent restart runs in post-tools, where gpgconf actually exists.

Inspect without changing anything:

mise bootstrap --dry-run

Run a single stage:

mise bootstrap --only files --yes

Note that bootstrap.directories is applied as part of the files stage; there is no --only directories. bootstrap.files does not create parent directories or mkdir -p, so each level is declared explicitly, parent first.

CI

GitHub Actions, in two tiers:

  • Validate runs on every push and PR. It installs nothing – it asserts the five config files load, that every bootstrap stage resolves under --dry-run, and that the workflow YAML still matches its Pkl source.
  • Bootstrap runs weekly and on workflow_dispatch. It runs setup.sh for real on a clean macOS runner, asserts the artifacts, and re-runs bootstrap to prove idempotency.

Workflow YAML is generated – do not hand-edit it

.github/workflows/*.yml is rendered from the .pkl file beside it using Pkl and the com.github.actions pkl-pantry package. Edit the .pkl, then:

mise run render-workflows

The validate job runs mise run check-workflows, which re-renders and then runs git diff --exit-code, so a hand-edited .yml fails CI.

Note this repo carries two mise configs with different jobs: mise.toml at the root is project config (tasks, and the pkl they need), while config/mise/ is machine config and is never loaded from here.

After changing .github/PklProject, re-resolve and commit the lockfile:

pkl project resolve .github/

Note pkl does not discover a PklProject in an ancestor directory, which is why the render task passes --project-dir .github/.

Caveats

  • macos-defaults writes to your real macOS preferences. A sandboxed HOME does not isolate them, because cfprefsd is keyed by uid. Use --dry-run to inspect.
  • com.apple.Terminal.plist is applied with mode = "copy", not symlink, because cfprefsd rewrites the file in place. Quit Terminal before applying or it will overwrite the copy again on quit.
  • bootstrap.repos entries have no ref, so mise never pulls – an existing clone with a matching origin counts as current. A dirty worktree fails the stage, so hide local additions with .git/info/exclude.

Troubleshooting

mise doctor

Check which config files mise is actually reading:

mise config ls

Links

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages