Skip to content

Latest commit

 

History

History
558 lines (403 loc) · 17.4 KB

File metadata and controls

558 lines (403 loc) · 17.4 KB

Start Here: ush, tnix, and nix

This guide uses this repository itself as the practice target for:

  • ush as the default interactive shell and .ush script runtime
  • tnix as the typed source-of-truth for generated runtime Nix
  • Nix, nix-darwin, and Home Manager

Unless noted otherwise, run everything from the repository root.

Big Picture

The main files and directories in this repository are:

Script policy in this repository:

  • src/ush/ is source-only and contains .ush implementations
  • runnable shell entrypoints and compatibility wrappers live in _legacy
  • every command in _legacy/ has a matching .ush source under src/ush/
  • _legacy/bootstrap-macos.sh, _legacy/init-machine-config.sh, and _legacy/print-machine-env.sh stay POSIX sh as bootstrap-safe entrypoints
  • migrated helpers such as _legacy/apply.sh, _legacy/clone.sh, _legacy/doctor.sh, and _legacy/init-repo.sh delegate into src/ush/*.ush

The normal workflow in this setup is:

  1. Explore with eza, fd, rg, and bat
  2. Inspect .ush implementations under src/ush/ and typed Nix sources under src/tnix/src/
  3. Treat src/ush/ as source-only and use the matching _legacy/*.sh wrapper when you need the current runnable entrypoint
  4. Persist config changes in .tnix when the source lives under src/tnix/src/
  5. Compile generated runtime Nix with ./src/tnix/sync.sh
  6. Apply with ./_legacy/apply.sh
  7. Verify with ./_legacy/doctor.sh

0. Setup

Move into the repository:

cd /path/to/origin

This 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/tnix

If 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"
fi

1. Modern Unix Hands-on

1-1. List files and understand structure

eza -lah --git
eza --tree --level=3 src _legacy generated

What to notice:

  • eza is a nicer ls
  • --git shows Git status inline
  • --tree is great for quick structure discovery
  • src/tnix/ is the typed source-of-truth
  • src/nix/ is the runtime Nix layer imported by flake.nix
  • src/ush/ holds .ush source-only command implementations
  • machine/local.env is created on demand by ./_legacy/init-machine-config.sh
  • generated/ is gitignored build output produced by ./src/tnix/sync.sh

This setup also defines these aliases:

  • l -> eza -lah --git
  • lg -> eza -lah --git
  • lt -> eza --tree --level=2

Those aliases live in src/nix/home/default.nix.

1-2. Find files

fd -e tnix . src/tnix
fd -e nix . src/nix generated
fd doctor src/ush _legacy

What to notice:

  • fd is usually much simpler than find
  • extension and name searches read naturally
  • in this repo, .tnix is usually the thing you want to edit first

1-3. Search text

rg 'programs\.' src/tnix/src src/nix
rg 'ush|shellAliases|clone|tnix' src/tnix src/ush _legacy src/nix/home/default.nix

What to notice:

  • rg is the default codebase search tool here
  • it is a much better starting point than recursive grep

1-4. Read files

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=never

What to notice:

  • bat is a better cat for source files
  • syntax highlighting makes config review much easier
  • the repo keeps .ush implementations under src/ush/
  • the repo keeps typed Nix source-of-truth under src/tnix/src/

In this setup, cat is aliased to bat.

1-5. Disk, processes, and HTTP

dust -d 1
duf
procs
btm
xh get https://httpbin.org/json

What to notice:

  • dust is a friendlier du
  • duf is a friendlier df
  • procs is easier to read than ps
  • btm gives you a useful terminal dashboard
  • xh is a cleaner alternative to curl

Notes:

  • quit btm with q
  • this setup aliases du -> dust and df -> duf

1-6. Replace text and inspect diffs

printf 'home-manager\nhome shell\n' | sd 'home' 'HOME'
git diff -- src/tnix/src/home/shell.tnix

What to notice:

  • sd is excellent for simple replacements
  • git diff is rendered through delta in this setup

The delta integration source is in src/tnix/src/home/git.tnix, and the runtime wrapper is src/nix/home/git.nix.

1-7. Use the Git shortcuts in this setup

This repository has two layers of Git shortcuts:

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 last

Common shell shortcuts from this setup:

  • g -> git
  • ga -> git add
  • gaa -> git add --all
  • gam -> git commit --amend
  • gb -> git branch
  • gbda -> git gbda
  • gco -> git checkout
  • gd -> git diff
  • gf -> git fetch
  • gl -> git pull
  • gm -> git commit -m
  • gp -> git push
  • gs -> git status -sb
  • gsw -> git switch

Useful Git-only aliases from this setup:

  • git ap -> git add -p
  • git ds -> git diff --staged
  • git grm -> git rm -rf --cached
  • git last -> git log -1 HEAD --stat
  • git lg -> git log --graph --decorate --oneline --all
  • git rb -> git rebase
  • git ri -> git rebase -i
  • git unstage -> git restore --staged

One detail to remember:

  • lg is already a shell alias for eza -lah --git, so use git lg for the Git log alias
  • gbda deletes all local branches except the current one, so treat it as a cleanup command

1-8. Clone into the workspace layout

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 --help

Then try a real clone:

./_legacy/clone.sh github your-user/origin tutorial
pwd
eza -lah ~/Source/github.com/your-user

What to notice:

  • ./_legacy/clone.sh github your-user/origin tutorial clones over SSH
  • the local directory becomes ~/Source/github.com/your-user/origin--tutorial
  • the extra tutorial argument 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 sandbox

Important behavior:

  • only github.com and gitlab.com are 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.

2. ush and .ush Script Hands-on

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.

2-1. Enter ush

ush

If 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'

2-2. Inspect the shell setup

bat src/tnix/src/home/shell.tnix --paging=never
bat src/nix/home/shell.nix --paging=never
bat src/nix/home/default.nix --paging=never

What to notice:

  • ush is 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.tnix is the source-of-truth, while src/nix/home/shell.nix is the runtime wrapper imported by Home Manager
  • Home Manager writes ~/.config/ush/config.json and the macOS Application Support variant from this repository

2-3. Inspect the wrapper and implementation split

bat _legacy/doctor.sh --paging=never
bat _legacy/run-ush.sh --paging=never
bat src/ush/doctor.ush --paging=never

What to notice:

  • the current shell wrapper lives in _legacy/doctor.sh
  • _legacy/run-ush.sh provides the shared ush fallback
  • the real implementation lives in src/ush/doctor.ush

The same shape appears in other migrated helpers such as:

2-4. Read a real .ush script

bat src/ush/doctor.ush --paging=never
bat src/ush/set-default-browser.ush --paging=never

What to notice:

  • use std::... imports from ush standard modules
  • path and env helpers are used directly inside the script language
  • external commands are still available through capture(...) and shell (...)

2-5. Check and compile a .ush script

nix run .#ush -- check src/ush/doctor.ush
nix run .#ush -- compile src/ush/doctor.ush | sed -n '1,40p'

What to notice:

  • check validates the .ush source
  • compile shows the generated shell code
  • the repo can validate ush scripts even before ush is on your PATH

2-6. Run the migrated helpers

./_legacy/doctor.sh
./_legacy/fetch-github-profile-icon.sh --help
./_legacy/set-default-browser.sh --help

What to notice:

  • _legacy/run-ush.sh lets these commands fall back to nix run .#ush
  • the shell wrapper stays stable while the implementation moves underneath

2-7. Exit ush

exit

2-8. The main ush mindset in this repo

  • read the matching .ush file 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 ... and compile ... while the migration is still in progress

3. tnix and Nix Hands-on

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.

3-0. Check and compile the typed project

./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.sh is the repo-native way to compile .tnix into generated/
  • src/tnix/workspace.tnix is 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.env when you use the repo scripts

3-1. Read the flake

bat flake.nix --paging=never

What to notice:

  • inputs contains nixpkgs, nix-darwin, home-manager, and ush
  • outputs builds darwinConfigurations.workstation
  • system modules and user modules are composed together
  • the flake imports runtime paths from src/nix/, while the typed source-of-truth stays under src/tnix/

3-2. Read the typed workspace layer

bat src/tnix/workspace.tnix --paging=never
bat src/tnix/types/dotfiles.d.tnix --paging=never
bat src/tnix/src/machine/default.tnix --paging=never

What to notice:

  • src/tnix/workspace.tnix is a compact type-checked view of the repo
  • src/tnix/types/dotfiles.d.tnix is the local declaration surface that tells tnix about this repo
  • machine defaults are authored in .tnix, not by editing generated Nix directly

3-3. Read the system layer

bat src/nix/modules/darwin/core.nix --paging=never
bat src/nix/modules/darwin/desktop-apps.nix --paging=never

What to notice:

  • the login shell is ush
  • environment.shells includes bash, ush, and zsh
  • macOS defaults are managed declaratively
  • GUI apps are exposed into /Applications

3-4. Read the user layer

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=never

What to notice:

  • src/nix/home/default.nix is the handwritten Home Manager entrypoint
  • leaf user modules are authored under src/tnix/src/home/
  • tracked src/nix/home/*.nix files are thin wrappers around generated outputs
  • home.packages defines user-facing CLI tools
  • home.shellAliases defines the shell aliases
  • programs.git.settings.alias defines the Git subcommand aliases
  • programs.fzf, programs.zoxide, programs.tmux, and programs.starship live here
  • delta is wired into Git from src/tnix/src/home/git.tnix

3-5. Evaluate concrete values

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 | jq

What to notice:

  • nix eval lets you inspect final values directly
  • you can confirm your understanding of the module graph by evaluating it

3-6. Day-to-day operational commands

Initial bootstrap:

./_legacy/bootstrap-macos.sh

Apply config changes:

./src/tnix/sync.sh
./_legacy/apply.sh

Run a health check:

./_legacy/doctor.sh

What each script does:

  • bootstrap-macos.sh: initial machine setup when Nix is not ready yet
  • apply.sh: compiles typed sources, then runs darwin-rebuild switch --flake "path:$PWD#workstation" --impure
  • doctor.sh: checks whether the key tools are available

4. Fastest 30-Minute Path

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.sh

5. Learning Goals

By the end of this guide, you should be able to:

  1. naturally reach for replacements to ls, find, grep, cat, du, df, ps, and curl
  2. explain how this repo separates .ush sources in src/ush/ from runnable shell entrypoints in _legacy/
  3. explain how the SSH-first workspace clone flow maps repositories into ~/Source
  4. explain how .tnix, generated/, and runtime wrappers under src/nix/ fit together in this repository
  5. make a typed config change, compile it, apply it, and verify it

6. Good Next Exercises

To make this stick, try these next:

  1. add one personal CLI tool to src/tnix/src/home/shell.tnix
  2. add one Git alias to src/tnix/src/home/git.tnix or one shell alias to src/nix/home/default.nix
  3. run ./src/tnix/sync.sh
  4. run nix run .#ush -- check src/ush/doctor.ush
  5. run ./_legacy/apply.sh
  6. run ./_legacy/doctor.sh
  7. inspect the resulting diff with git diff