Setup scripts, tool lists, and app settings for the owner's Macs and Linux hosts. AGENTS.md has the editing rules and the table of where each setting lives. DECISIONS.md explains the design.
mise.toml file links and shell checkouts for every host
mise.macos.toml Mac file links and macOS preferences
mise.linux.toml apt packages and the login shell for Linux
mise.<profile>.toml one file per machine: pro, air, container, vm
configs/<app>/ the settings files, one folder per app
Brewfile Homebrew formulae, casks, taps, and App Store apps
apps/ the app manifest, vendor-installed tools, login items
bin/ setup and repair scripts
macos/ the macOS defaults script and the telemetry login script
local/ ignored local files; only the examples are tracked
nvim/ the Neovim config, a separate repository
Most files in configs/ are links in HOME, so an app's change to its file is a
change in this repository. Commit it to share it with your other machines.
Agent, T3, and pnpm settings are the exception. These apps write private data
into their settings, so mise merges selected keys from configs/claude/,
configs/codex/, configs/t3/, and configs/pnpm/ into the live files.
./bin/save-settings copies your changes back without the private keys. See
Agent settings.
| Profile | Machine | Status |
|---|---|---|
pro |
MacBook Pro | Set up. |
air |
MacBook Air | Not set up yet. Setup stops before it changes anything. |
container |
NAS development container | Set up. |
vm |
Linux VM, planned on GCP | Not set up yet. Setup stops before it changes anything. |
Save the machine's profile in the ignored .miserc.local.toml. A Linux
container without this file uses container. DOTFILES_PROFILE=pro selects a
profile for one command.
printf 'env = ["pro"]\n' > .miserc.local.tomlEdit the file in configs/<app>/, or the [dotfiles] entry in a root mise
file, then preview and apply:
./bin/link-dotfiles --status
./bin/link-dotfiles --dry-run
./bin/link-dotfilesbin/link-dotfiles saves each file that it replaces in
~/.dotfiles-backups/links-<time>-*/. --status exits with 1 when an entry is
missing or differs. ~/.config/nvim waits until the nvim/ submodule is
checked out. --diff does not show the content of merged settings, because
those files can hold tokens.
These mise tasks run the same scripts from any folder, for the checkout in
$DOTFILES_ROOT or ~/development/dotfiles: dot:status, dot:diff,
dot:apply, dot:save, setup, update, packages, backup, restore,
and doctor. For example, run mise run dot:apply -- --dry-run.
Bun and pnpm require a four-day release age, except for oh-my-t3code,
agent-browser, agent-desktop, agent-device, and t3. Bun uses seconds
(345600), and pnpm uses minutes (5760). Project settings can override these
global defaults.
Bun defaults to linker = "isolated" so
globalStore = true takes effect.
A project can override the linker; the hoisted linker does not use the global
store. pnpm's
virtualStoreType: global
shares its virtual store across projects. pnpm uses
the isolated linker by default; a project with the hoisted linker does not
use a virtual store.
The shell sets XDG_CONFIG_HOME to ~/.config unless it is already set.
Bun reads ~/.config/.bunfig.toml, and pnpm reads
~/.config/pnpm/config.yaml with this default. pnpm's config is a regular
file because pnpm can write credentials into it. ./bin/link-dotfiles merges
the public defaults, and ./bin/save-settings saves only the keys in
configs/pnpm/sync-keys.
Claude Code, Codex, and T3 keep private data in ~/.claude/settings.json,
~/.codex/config.toml, and ~/.t3/userdata/settings.json. These files are
merges, not links. After you change a shared setting in an app, save it into
the repository and review the result:
./bin/save-settings --dry-run
./bin/save-settings
git diff configs/claude configs/codex configs/t3configs/<app>/sync-keys marks settings public or private. A public rule
names one setting, such as .theme. A private rule can name a whole section,
such as .projects. Each key in the repository file needs a public rule, so
add one when you add a key to a shared settings source. bin/save-settings
saves only the public settings. It counts settings on neither list and does not save
them. Run ./bin/save-settings --show-new to list them, add each one to the
list, then save again.
bin/save-settings leaves a file unchanged when one of its keys has no public
rule, or when a public setting has become a section or holds a local path, a
credential, or an email address. Its messages never show a value.
On the other machines, ./bin/link-dotfiles merges the saved keys and keeps
their own private keys. The last save replaces the saved values, so merge
before you change a setting: bin/save-settings refuses to save until this
machine has merged the current repository file. A merge never removes a key.
A key that you delete in an app stays on the other machines, and a later save
from one of them puts it back. Delete it on every machine, or mark it private.
T3 shares only the default Codex instance's driver and launch arguments.
The arguments keep the 60-second unload delay and select CLIProxyAPI. The
global Codex provider stays openai, so the desktop app can use ChatGPT
sign-in. Configure each host's private proxy URL and key before starting
Codex in T3. See the proxy setup.
T3's launchArgs is one string. A merge replaces the complete string, so keep
all shared arguments in it. Apply settings while no one changes them in T3.
T3 reloads the file, but existing Codex processes keep their startup arguments.
Start a fresh provider process to use changed arguments. The merge targets
the default T3 home; a custom T3CODE_HOME needs a matching file entry.
git pull --ff-only
./bin/link-dotfiles --dry-run
./bin/link-dotfilesThe repository's mise commands need mise 2026.10.22. If bin/repo-mise
reports an older mise, run ./bin/install-standalone mise first. After a pull
that moves files, bin/link-dotfiles points the old links at the new sources.
It also moves local files from the old layout, such as
home/.config/local/secrets.zsh, to local/.
dotfiles-update pulls, then runs the setup continuation without the general
macOS defaults. It does not upgrade every installed package. The shell's daily
background check only reports new commits. ./bin/prepare-sync compares the
live inventory with the repository and saves a Brewfile copy under
.sync-backups/.
On the old Mac, run ./bin/prepare-sync to report inventory drift and
./bin/file-backup to save portable state. Complete the Raycast export and
rerun ./bin/file-backup raycast to mirror it. Confirm the backups are
available before you erase the old Mac. See backup and restore.
Use a public macOS release. Setup stops if the active Apple or MDM catalog offers a macOS update, the update check is inconclusive, or macOS or Xcode appears to be a prerelease. Update in System Settings, restart if needed, and retry. Setup does not install OS updates or change beta enrollment.
mkdir -p ~/development
git clone https://github.com/gabimoncha/dotfiles.git ~/development/dotfiles
cd ~/development/dotfiles
printf 'env = ["pro"]\n' > .miserc.local.toml
./bin/setupRun setup as your normal user, not with sudo. If Git or setup opens the
Command Line Tools installer, finish it and retry the command.
Each phase asks twice for your password, or Touch ID, near its start. The
first prompt is for sudo. The second installs a temporary sudoers file at
/etc/sudoers.d/dotfiles-setup, so all your processes share one sudo
timestamp. Later steps, and a coding agent shell without a terminal, can then
use sudo without a prompt. The timestamp expires after 30 minutes without a
sudo command. Setup removes the file when it exits, also after a failure or
Ctrl-C. Preflight reports a file that a killed run left behind. Set
DOTFILES_SKIP_SUDO_GRANT=1 to skip the grant. Later sudo steps then ask in
the terminal.
The first phase installs the foundation tools: Homebrew, standalone mise, an isolated GitHub CLI, Codex CLI, Claude Code, Cursor Agent, and OpenCode v2. Then it stops:
- Sign in to the App Store app.
- In System Settings > Privacy & Security > App Management, allow the terminal app that runs setup. Approve access when macOS asks.
- Quit and reopen that terminal app, then continue:
./bin/setup --continueThis flag confirms the manual step. Setup cannot check permissions or the terminal restart. Some apps ask for consent only after they install.
The continuation checks the foundations again, logs in to GitHub, installs
packages, offers restores, and applies configuration. Pi installs here, after
mise provides Node and npm. GitHub API access gates the large mise install. An
SSH failure alone does not block it. The mobile step runs after every
interactive step and before telemetry. It installs Xcode from the App Store
without an Apple ID prompt. It also installs the Android SDK packages in
android-sdk.txt into ~/Library/Android/sdk and
accepts their licenses, so command-line Android builds need no Android Studio
step.
Setup exports the telemetry opt-outs in
telemetry.sh before installers run. A login job,
which mise installs from mise.macos.toml, sets the same values for GUI apps.
Reopen apps after setup.
./bin/configure-telemetry [--dry-run] applies them again. The
telemetry guide lists every control, the manual settings,
and the tools without an opt-out.
| Option | Effect |
|---|---|
--dry-run |
Run the preflight check and write private logs. List the other steps without running them. Add --continue to preview that phase. |
--skip-mobile-dev |
Skip Xcode, iOS support, Android Studio, the Android SDK, and apps/mobile.Brewfile. Mobile tools in the shared mise list still install. |
bin/setup lists the steps in order, and they run one at a time.
The foundation steps are required: preflight, the Command Line Tools, sudo
and its keepalive, Homebrew and its environment, mise, the GitHub CLI, the
links, and the Brewfile preparation (brewfiles). On Linux, the system
packages are required too. In the first macOS phase, so are the agent CLIs
and the permission handoff. When a required step fails, setup stops and
records the later steps as blocked. The other steps are marked --optional.
Each one checks what it needs, records its failure, and lets the run go on.
For example, the mise inventory runs only after the GitHub check passes. The
telemetry step runs even after a failure.
Setup also runs on Debian and Ubuntu, for example the NAS container in
remote development. Run it as your normal user.
It needs sudo for apt and the login shell.
mkdir -p ~/development
git clone https://github.com/gabimoncha/dotfiles.git ~/development/dotfiles
cd ~/development/dotfiles
./bin/setup --dry-run
./bin/setupLinux runs every step in one run. It has no App Store or restart step.
bin/linux-prerequisitesinstalls Ruby, Git, and curl with apt. Setup's diagnostics run on/usr/bin/ruby, as they do on macOS.- mise installs the system packages in
mise.linux.tomland the profile file, and makes zsh the login shell. - Setup installs the runtime tools, the agent CLIs, and T3
(
apps/standalone.tsv), then links the shared files.
Tools marked os = "macos" in configs/mise/global.toml stay on the Mac.
Entries in mise.macos.toml do not load on Linux.
Codex reads one global instructions file. On the container, mise renders
~/.codex/AGENTS.md from configs/agents/instructions.md and the host rules in
configs/agents/container.md. Claude reads the host rules from
~/.claude/rules/host.md. The container also turns off the Codex sandbox in
configs/codex/container.toml, because its kernel cannot start it.
DOTFILES_SKIP_GITHUB_AUTH=1 ./bin/setup defers the GitHub login. mise then
installs tools without a GitHub token. Log in later with ./bin/auth-setup.
The login asks for the workflow scope, so Git can push changes to GitHub
Actions files. On an existing login, ./bin/auth-setup --api-only adds a
missing scope. Linux uses Git over HTTPS with the GitHub CLI token, not an SSH
key. Agents on a headless host start without an SSH agent and cannot unlock a
protected key.
- Sign in to Apple, the App Store, iCloud, and the apps you use.
- Download one provider's backup copies in Finder. The first checklist reads metadata. It does not download the files or prove that the backup is valid.
- Grant app privacy access by hand when a feature needs it. Setup does not grant or check consent, and app settings and backups do not carry macOS permission grants.
- Complete the restore prompts. Raycast import needs its GUI and password. Existing Codex state is kept for comparison. See MACKUP.md.
- Complete the first launch of Android Studio, OrbStack, and the vendor apps
marked
manualin the app manifest. - Setup installs the Android SDK packages for command-line builds and the
Android Emulator, which the T3 Code device hub needs. To run an emulator,
install a system image with
sdkmanageror in Android Studio, and create a virtual device. - Personal skills need a reviewed
skillsCLI andDOTFILES_REVIEWED_SKILLS_REFset to a reviewed 40-character commit ofgabimoncha/skills. Without that commit, setup skips the step. With the commit but without the CLI, setup defers the step and returns nonzero. Skills and their lock file stay on the machine.
Missing optional restore inputs do not fail a run. A restore that runs and
fails does. A failed, blocked, or deferred step makes setup return nonzero. A
step that you turn off, with --skip-mobile-dev or a DOTFILES_SKIP_*
setting, does not.
./bin/app-state-doctor checks the managed app links, tmux plugins, Raycast,
Spotlight hotkeys, Touch ID, and disabled background jobs. It is not a complete
installation test.
To let a coding agent repair a failed step, ask it to follow
the setup repair guide. If preparation failed before the
permission step, rerun ./bin/setup. After that step, use
./bin/setup --continue. Setup reuses existing links and installs. Homebrew
installs use --no-upgrade. Setup replaces a mise older than the pin, and it
does not update a newer one. Between setup runs, mise updates itself because
the runtime config sets self_update.auto. The four-day release delay does not
apply to mise itself. Setup turns self-update off for its own run.
Each run prints its private .local/setup-runs/<run-id>/ folder:
summary.txt: one result line for each step, with a repair hint. Helpers add their own lines, such as one for each restore.setup.log: the output of the steps, with tokens removed. Steps that ask for a password or a login print to the terminal only. So do the steps that run in the setup shell, such asbrewfiles.
Git ignores the whole .local/ folder. Each new run keeps the latest three
run folders and removes older ones. A run that is still active stays until a
later run can remove it. Normal runs, dry runs, and helper commands share this
limit. Copy logs elsewhere before more runs if you need them longer.
Authentication output is omitted. Review logs before you share them.
| Command | Use |
|---|---|
./bin/preflight |
Check macOS updates and the repository prerequisites. |
./bin/link-dotfiles [--status | --diff | --dry-run] |
Apply, check, or preview the managed files. |
./bin/repo-mise bootstrap repos status |
Check the Oh My Zsh, plugin, and TPM checkouts. |
./bin/repo-mise bootstrap macos defaults status |
Compare macOS preferences with mise.macos.toml. |
./macos/defaults.sh |
Apply macOS preferences, input sources, the Dock, and display sleep. |
./bin/github-bootstrap install-gh |
Repair the isolated GitHub CLI install. |
./bin/auth-setup --api-only |
Repair the GitHub API login. |
./bin/auth-setup --ssh-only |
Repair the Git identity and SSH access. |
./bin/auth-setup --git-only |
Linux: repair the Git identity and Git over HTTPS. |
./bin/auth-setup --verify-mise |
Check the direct credential helper. |
./bin/check-mise-tools |
Check the installed tools without installing any. |
./bin/install-apps [--dry-run] |
Retry or preview the app manifest. |
./bin/install-standalone status |
Report the vendor-installed tools in apps/standalone.tsv. |
./bin/install-standalone [NAME...] |
Install or repair those tools. --dry-run previews. |
./bin/install-steam [--dry-run] |
Install Valve's verified ARM64 Steam bootstrapper. |
./bin/check-mobile-ready |
Check Xcode, iOS, Android Studio, the Android SDK and adb, and apps/mobile.Brewfile. |
./bin/install-mobile-dev [--dry-run] |
Install or repair Xcode, iOS support, Android Studio, the Android SDK, and the mobile formulae. |
./bin/sudo-grant --check |
Report a leftover sudo grant. --enable and --disable change it. |
./bin/setup-tmux |
Install missing TPM plugins and reload a running server. |
./bin/configure-app-settings |
Retry the login-item setup. |
./bin/configure-telemetry [--dry-run] |
Apply the telemetry opt-outs to installed tools. |
./bin/configure-screenshots |
Repair the PNG destination at ~/Screenshots. |
./bin/finder-sidebar-favorites |
Retry the development and screenshots favorites. |
./bin/setup-tokenburnmarket [--dry-run] |
Sign in to tokenburnmarket and install its sync daemon. A Linux host without systemd runs the daemon under bin/tokenburnmarket-supervise. A connected host with a current daemon is not changed. DOTFILES_SKIP_TOKENBURNMARKET=1 skips the setup step. |
./bin/configure-sudo-touch-id --check |
Inspect Touch ID for sudo. --enable and --disable change it. |
./bin/configure-background-jobs [--dry-run] |
Disable the jobs in macos/disabled-jobs.txt. --check reports drift, and --revert enables them. |
Tool checks and version probes stop after 10 seconds. Set
DOTFILES_TOOL_CHECK_TIMEOUT_SECONDS to change that. The macOS update probe
stops after 120 seconds (DOTFILES_SOFTWAREUPDATE_TIMEOUT_SECONDS).
Set DOTFILES_SKIP_SUDO_TOUCH_ID=1 to skip Touch ID setup, or
DOTFILES_SKIP_MACOS_DEFAULTS=1 to skip the general defaults. Screenshot
repair still runs. The general defaults run once per ~/.macos-defaults-applied
stamp.
Setup installs Xcode with sudo mas get 497799835. The App Store offers only
public releases and updates Xcode automatically, unless you turn that off in
the App Store settings. If the App Store cannot install Xcode, download the
public .xip from
Apple Developer Downloads, then run:
xcodes install <public-version> --path "/path/to/Xcode.xip" --select --experimental-unxip
./bin/setup --continueA passed screenshot step proves that the preferences were written, not that
captures work. Take a screenshot with Shift-Command-3 or 4 and check the file.
If needed, select ~/Screenshots in Shift-Command-5 > Options > Save to.
- The general defaults turn off display sleep on battery and on power.
- If Homebrew reports the Xcode app as too old, setup skips
bordersand does not retry it after Xcode installs. Rerun./bin/setup --continue. - A direct
./bin/install-mobile-devrun skips the macOS update check. It rejects only a prerelease Xcode. - Raycast backup can create missing provider folders. Confirm the cloud sync. The combined backup can exit zero when neither provider is ready.
- Finder failures can report success. Check the sidebar.
- The optional Postgres 18 Compose service uses a legacy data-volume target.
No script proves a fresh-Mac install. See the manual checks.
Add packages in this order: the Mac App Store, then mise, then Homebrew. The
agent CLIs and mise itself are vendor-installed exceptions in
apps/standalone.tsv. The T3 nightly desktop app is a Homebrew cask. Hex and
Scrawl come from their vendor taps, anomalyco/tap and kitlangton/tap.
vscode "publisher.extension" lines in the Brewfile select Cursor extensions.
~/.config/mise/mise.lock links to configs/mise/mise.lock. mise install
installs the locked versions, and mise up writes newer versions into the
tracked file. To add a tool, add it to configs/mise/global.toml, then run
mise lock --global, then commit the config, the lockfile, and the pipx lock
folder configs/mise/.mise/locks/. An older lockfile moves the tools back to
its versions.
After an interactive mise install or mise up, and after mise run update,
./bin/save-lock commits a changed lockfile and pushes it to main, so the
other machines get the same versions at their next pull. The commit holds only
the lock files. The script does nothing on another branch. It stops when
origin/main changed the lock too, and prints the commands that take that
lock. DOTFILES_SAVE_LOCK=0 turns it off. Every lock entry has a checksum for
both platforms, so a plain mise install leaves the lock unchanged.
./bin/install-standalone installs and repairs the vendor-installed tools and
reuses healthy installs. Run it for one tool, for example
./bin/install-standalone codex. harness update updates the installed tools
in parallel and reports every failure. --dry-run previews the commands, and
--installed-only skips absent tools. It skips mise, which updates itself, and
the Linux T3 server, which the T3 app updates. Each update stops after 30
seconds without new output (DOTFILES_HARNESS_IDLE_TIMEOUT_SECONDS). The
interactive zsh mise helper runs harness update --installed-only after a
successful mise install or mise up. Setup installs missing or broken
agents. It does not update healthy ones.
The T3 Code nightly app updates itself and its t3 launcher. Setup links
Homebrew's bin/t3 to ~/.t3/bin/t3. Open the app once to create the
launcher. ./bin/link-t3-command [--dry-run] repairs the link and keeps any
other t3 command. To adopt an existing app bundle, run
brew install --cask --adopt t3-code@nightly.
CLIProxyAPI has a separate Docker Compose example for the NAS. Its management UI owns provider logins and account selection. Codex uses OpenAI subscriptions, and Claude Code uses Anthropic subscriptions. Private client settings select the NAS endpoint through Tailscale. Normal dotfiles setup does not deploy the server. See NAS agent proxy.
bin/install-steam replaces the Intel-only Homebrew cask with Valve's ARM64
bootstrapper. It checks the checksum, the ARM64 code, Valve's signature, and
Gatekeeper before it replaces the app, and it keeps the old app under
~/.dotfiles-backups/. --verify-download checks a download without
installing it, and --check checks the installed app. Quit Steam before a
replacement. See DECISIONS.md.
Setup adds the apps in the login item list as login
items. This can ask for Automation access to System Events. After it adds T3
Code Nightly, it removes the /Applications/Codex.app login item. Run
./bin/configure-app-settings --dry-run to preview the changes. Privacy
permissions are manual for every app.
SHELL.md covers local secrets, GitHub account routing, command helpers, package runners, and Android paths. SECURITY.md lists the state that must stay out of Git.
Run bash -n on the changed scripts, ./bin/preflight, and git diff --check.
Run ./bin/link-dotfiles --dry-run for a config change, and
./bin/setup --dry-run or ./bin/setup --continue --dry-run for a setup
change. The setup previews query Apple's update catalog and write logs.