This guide uses this repository itself as the practice target for:
ushas the default interactive shell and.ushscript runtimetnixas the typed source-of-truth for generated runtime Nix- Nix,
nix-darwin, and Home Manager
Unless noted otherwise, run everything from the repository root.
The main files and directories in this repository are:
- flake entrypoint: flake.nix
- typed project config: tnix.config.tnix
- typed workspace entrypoint: src/tnix/workspace.tnix
- repo-local ambient declarations: src/tnix/types/dotfiles.d.tnix
- typed machine source: src/tnix/src/machine/default.tnix
- local machine override template: src/templates/machine.local.env.example
- typed shell source: src/tnix/src/home/shell.tnix
- typed Git source: src/tnix/src/home/git.tnix
- runtime Home Manager entrypoint: src/nix/home/default.nix
- runtime shell wrapper: src/nix/home/shell.nix
- runtime Git wrapper: src/nix/home/git.nix
- macOS system layer: src/nix/modules/darwin/core.nix
- GUI app exposure: src/nix/modules/darwin/desktop-apps.nix
- generated output sync: src/tnix/sync.sh
.ushcommand sources: src/ush- bootstrap-safe wrappers: _legacy
Script policy in this repository:
src/ush/is source-only and contains.ushimplementations- runnable shell entrypoints and compatibility wrappers live in _legacy
- every command in
_legacy/has a matching.ushsource undersrc/ush/ _legacy/bootstrap-macos.sh,_legacy/init-machine-config.sh, and_legacy/print-machine-env.shstay POSIXshas bootstrap-safe entrypoints- migrated helpers such as
_legacy/apply.sh,_legacy/clone.sh,_legacy/doctor.sh, and_legacy/init-repo.shdelegate intosrc/ush/*.ush
The normal workflow in this setup is:
- Explore with
eza,fd,rg, andbat - Inspect
.ushimplementations undersrc/ush/and typed Nix sources undersrc/tnix/src/ - Treat
src/ush/as source-only and use the matching_legacy/*.shwrapper when you need the current runnable entrypoint - Persist config changes in
.tnixwhen the source lives undersrc/tnix/src/ - Compile generated runtime Nix with
./src/tnix/sync.sh - Apply with
./_legacy/apply.sh - Verify with
./_legacy/doctor.sh
Move into the repository:
cd /path/to/originThis repository often has uncommitted changes. If nix prints a warning like
Git tree ... has uncommitted changes, that is not automatically a problem here.
This repo expects tnix at:
$HOME/Source/github.com/ubugeeei/tnixIf that checkout is missing, clone it before working on .tnix:
mkdir -p "$HOME/Source/github.com/ubugeeei"
if [ ! -d "$HOME/Source/github.com/ubugeeei/tnix/.git" ]; then
git clone git@github.com:ubugeeei/tnix.git "$HOME/Source/github.com/ubugeeei/tnix"
fieza -lah --git
eza --tree --level=3 src _legacy generatedWhat to notice:
ezais a nicerls--gitshows Git status inline--treeis great for quick structure discoverysrc/tnix/is the typed source-of-truthsrc/nix/is the runtime Nix layer imported byflake.nixsrc/ush/holds.ushsource-only command implementationsmachine/local.envis created on demand by./_legacy/init-machine-config.shgenerated/is gitignored build output produced by./src/tnix/sync.sh
This setup also defines these aliases:
l->eza -lah --gitlg->eza -lah --gitlt->eza --tree --level=2
Those aliases live in src/nix/home/default.nix.
fd -e tnix . src/tnix
fd -e nix . src/nix generated
fd doctor src/ush _legacyWhat to notice:
fdis usually much simpler thanfind- extension and name searches read naturally
- in this repo,
.tnixis usually the thing you want to edit first
rg 'programs\.' src/tnix/src src/nix
rg 'ush|shellAliases|clone|tnix' src/tnix src/ush _legacy src/nix/home/default.nixWhat to notice:
rgis the default codebase search tool here- it is a much better starting point than recursive
grep
bat src/tnix/src/home/shell.tnix --paging=never
bat src/nix/home/default.nix --paging=never
bat src/tnix/workspace.tnix --paging=never
bat src/ush/doctor.ush --paging=neverWhat to notice:
batis a bettercatfor source files- syntax highlighting makes config review much easier
- the repo keeps
.ushimplementations undersrc/ush/ - the repo keeps typed Nix source-of-truth under
src/tnix/src/
In this setup, cat is aliased to bat.
dust -d 1
duf
procs
btm
xh get https://httpbin.org/jsonWhat to notice:
dustis a friendlierdudufis a friendlierdfprocsis easier to read thanpsbtmgives you a useful terminal dashboardxhis a cleaner alternative tocurl
Notes:
- quit
btmwithq - this setup aliases
du -> dustanddf -> duf
printf 'home-manager\nhome shell\n' | sd 'home' 'HOME'
git diff -- src/tnix/src/home/shell.tnixWhat to notice:
sdis excellent for simple replacementsgit diffis rendered throughdeltain this setup
The delta integration source is in src/tnix/src/home/git.tnix, and the runtime wrapper is src/nix/home/git.nix.
This repository has two layers of Git shortcuts:
- shell aliases in src/nix/home/default.nix, such as
gsandgd - Git subcommand aliases in src/tnix/src/home/git.tnix, such as
git apandgit last
For day-to-day work, prefer the shell aliases where they exist.
Try these first:
gs
gd
ga src/tnix/src/home/shell.tnix
gm "test commit message"
git ds
git lastCommon shell shortcuts from this setup:
g->gitga->git addgaa->git add --allgam->git commit --amendgb->git branchgbda->git gbdagco->git checkoutgd->git diffgf->git fetchgl->git pullgm->git commit -mgp->git pushgs->git status -sbgsw->git switch
Useful Git-only aliases from this setup:
git ap->git add -pgit ds->git diff --stagedgit grm->git rm -rf --cachedgit last->git log -1 HEAD --statgit lg->git log --graph --decorate --oneline --allgit rb->git rebasegit ri->git rebase -igit unstage->git restore --staged
One detail to remember:
lgis already a shell alias foreza -lah --git, so usegit lgfor the Git log aliasgbdadeletes all local branches except the current one, so treat it as a cleanup command
This setup includes a clone helper that keeps GitHub and GitLab repositories under the
expected ~/Source/<host>/<owner-or-group>/... layout.
Try the built-in help first:
./_legacy/clone.sh --helpThen try a real clone:
./_legacy/clone.sh github your-user/origin tutorial
pwd
eza -lah ~/Source/github.com/your-userWhat to notice:
./_legacy/clone.sh github your-user/origin tutorialclones over SSH- the local directory becomes
~/Source/github.com/your-user/origin--tutorial - the extra
tutorialargument is an alias, so you can keep multiple local clones of the same repo - if you omit the alias, the directory name stays as the repository name
You can use the same flow with GitLab:
./_legacy/clone.sh gitlab my-group/platform/api qa
./_legacy/clone.sh git@gitlab.com:my-group/platform/api.git sandboxImportant behavior:
- only
github.comandgitlab.comare supported - only SSH inputs are accepted, so HTTPS remotes are rejected
- the command stops if the destination path already exists
The current bootstrap-time runnable entrypoint lives in _legacy/clone.sh,
and the implementation it delegates to lives in src/ush/clone.ush. After
./_legacy/apply.sh, the same behavior is also available as clone on PATH. The workspace layout
is documented in workspace.md.
This machine now uses ush as the default login shell. The relevant setup is in
src/nix/modules/darwin/core.nix,
src/tnix/src/home/shell.tnix,
and src/nix/home/default.nix.
ushIf you are on a machine that has not applied this repo yet, you can still run the pinned build with:
nix run .#ush -- -c 'pwd'bat src/tnix/src/home/shell.tnix --paging=never
bat src/nix/home/shell.nix --paging=never
bat src/nix/home/default.nix --paging=neverWhat to notice:
ushis installed as a normal CLI tool and the default login shell is set through nix-darwin- aliases are still defined centrally in
src/nix/home/default.nix src/tnix/src/home/shell.tnixis the source-of-truth, whilesrc/nix/home/shell.nixis the runtime wrapper imported by Home Manager- Home Manager writes
~/.config/ush/config.jsonand the macOSApplication Supportvariant from this repository
bat _legacy/doctor.sh --paging=never
bat _legacy/run-ush.sh --paging=never
bat src/ush/doctor.ush --paging=neverWhat to notice:
- the current shell wrapper lives in
_legacy/doctor.sh _legacy/run-ush.shprovides the sharedushfallback- the real implementation lives in
src/ush/doctor.ush
The same shape appears in other migrated helpers such as:
- _legacy/init-repo.sh
- _legacy/remove-unused-apple-apps.sh
- _legacy/set-default-browser.sh
- _legacy/fetch-github-profile-icon.sh
bat src/ush/doctor.ush --paging=never
bat src/ush/set-default-browser.ush --paging=neverWhat to notice:
use std::...imports fromushstandard modules- path and env helpers are used directly inside the script language
- external commands are still available through
capture(...)andshell (...)
nix run .#ush -- check src/ush/doctor.ush
nix run .#ush -- compile src/ush/doctor.ush | sed -n '1,40p'What to notice:
checkvalidates the.ushsourcecompileshows the generated shell code- the repo can validate
ushscripts even beforeushis on your PATH
./_legacy/doctor.sh
./_legacy/fetch-github-profile-icon.sh --help
./_legacy/set-default-browser.sh --helpWhat to notice:
_legacy/run-ush.shlets these commands fall back tonix run .#ush- the shell wrapper stays stable while the implementation moves underneath
exit- read the matching
.ushfile first when a helper has already been migrated - look in
_legacy/when you need the current shell entrypoint or want to compare implementations - use
nix run .#ush -- check ...andcompile ...while the migration is still in progress
This repository is flake-based, but the usual authoring layer is src/tnix/src/.
Before reading final flake outputs, get comfortable with the typed source layout.
./src/tnix/sync.sh
nix run "path:$HOME/Source/github.com/ubugeeei/tnix#tnix" -- check ./src/tnix/workspace.tnix
nix run "path:$HOME/Source/github.com/ubugeeei/tnix#tnix" -- check-project .What to notice:
./src/tnix/sync.shis the repo-native way to compile.tnixintogenerated/src/tnix/workspace.tnixis the typed workspace entrypoint- tracked files under
src/nix/are thin runtime wrappers so import paths stay stable
This repository is flake-based. Start by seeing what the flake exports.
nix flake show --no-write-lock-file .Expected takeaway:
- the main output here is
darwinConfigurations.workstation - machine-specific values come from
machine/local.envwhen you use the repo scripts
bat flake.nix --paging=neverWhat to notice:
inputscontainsnixpkgs,nix-darwin,home-manager, andushoutputsbuildsdarwinConfigurations.workstation- system modules and user modules are composed together
- the flake imports runtime paths from
src/nix/, while the typed source-of-truth stays undersrc/tnix/
bat src/tnix/workspace.tnix --paging=never
bat src/tnix/types/dotfiles.d.tnix --paging=never
bat src/tnix/src/machine/default.tnix --paging=neverWhat to notice:
src/tnix/workspace.tnixis a compact type-checked view of the reposrc/tnix/types/dotfiles.d.tnixis the local declaration surface that tellstnixabout this repo- machine defaults are authored in
.tnix, not by editing generated Nix directly
bat src/nix/modules/darwin/core.nix --paging=never
bat src/nix/modules/darwin/desktop-apps.nix --paging=neverWhat to notice:
- the login shell is
ush environment.shellsincludesbash,ush, andzsh- macOS defaults are managed declaratively
- GUI apps are exposed into
/Applications
bat src/nix/home/default.nix --paging=never
bat src/tnix/src/home/shell.tnix --paging=never
bat src/tnix/src/home/git.tnix --paging=never
bat src/nix/home/shell.nix --paging=neverWhat to notice:
src/nix/home/default.nixis the handwritten Home Manager entrypoint- leaf user modules are authored under
src/tnix/src/home/ - tracked
src/nix/home/*.nixfiles are thin wrappers around generated outputs home.packagesdefines user-facing CLI toolshome.shellAliasesdefines the shell aliasesprograms.git.settings.aliasdefines the Git subcommand aliasesprograms.fzf,programs.zoxide,programs.tmux, andprograms.starshiplive heredeltais wired into Git from src/tnix/src/home/git.tnix
nix eval --raw .#darwinConfigurations.workstation.config.networking.hostName
nix eval --raw .#darwinConfigurations.workstation.config.system.primaryUser
nix eval --raw .#darwinConfigurations.workstation.config.users.users.$(nix eval --raw .#darwinConfigurations.workstation.config.system.primaryUser).shell.name
nix eval --json .#darwinConfigurations.workstation.config.home-manager.users.$(nix eval --raw .#darwinConfigurations.workstation.config.system.primaryUser).home.sessionVariables | jqWhat to notice:
nix evallets you inspect final values directly- you can confirm your understanding of the module graph by evaluating it
Initial bootstrap:
./_legacy/bootstrap-macos.shApply config changes:
./src/tnix/sync.sh
./_legacy/apply.shRun a health check:
./_legacy/doctor.shWhat each script does:
bootstrap-macos.sh: initial machine setup when Nix is not ready yetapply.sh: compiles typed sources, then runsdarwin-rebuild switch --flake "path:$PWD#workstation" --impuredoctor.sh: checks whether the key tools are available
If you want the shortest full pass, run this:
cd /path/to/origin
eza -lah --git
fd -e tnix . src/tnix
rg 'ush|programs\.|shellAliases|tnix' src/tnix src/ush _legacy src/nix/home/default.nix
bat src/tnix/src/home/shell.tnix --paging=never
bat src/ush/doctor.ush --paging=never
./src/tnix/sync.sh
nix run .#ush -- check src/ush/doctor.ush
nix flake show --no-write-lock-file .
nix eval --raw .#darwinConfigurations.workstation.config.users.users.$(nix eval --raw .#darwinConfigurations.workstation.config.system.primaryUser).shell.name
./_legacy/doctor.shBy the end of this guide, you should be able to:
- naturally reach for replacements to
ls,find,grep,cat,du,df,ps, andcurl - explain how this repo separates
.ushsources insrc/ush/from runnable shell entrypoints in_legacy/ - explain how the SSH-first workspace clone flow maps repositories into
~/Source - explain how
.tnix,generated/, and runtime wrappers undersrc/nix/fit together in this repository - make a typed config change, compile it, apply it, and verify it
To make this stick, try these next:
- add one personal CLI tool to
src/tnix/src/home/shell.tnix - add one Git alias to
src/tnix/src/home/git.tnixor one shell alias tosrc/nix/home/default.nix - run
./src/tnix/sync.sh - run
nix run .#ush -- check src/ush/doctor.ush - run
./_legacy/apply.sh - run
./_legacy/doctor.sh - inspect the resulting diff with
git diff