docs: move prose documentation into docs/ so the docs site publishes it
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m21s
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m21s
The docs-site build syncs this repo's README.md and docs/ into the site tree; nothing else is copied. All prose apart from the README therefore lived outside the sync and never appeared on https://docs.lyrapup.pet/nixfiles/, and the one page that did publish carried 18 link targets that resolved to nothing. Moves: home/README.md -> docs/shell.md home/KEYBINDINGS.md -> docs/keybindings.md hosts/<Name>/README.md -> docs/hosts/<name>.md docs/.pages and docs/hosts/.pages give the awesome-pages plugin an explicit order; new pages are picked up by the trailing '...' without an edit. Links are rewritten so a single URL is correct in both Gitea and the published site: absolute Gitea source URLs for .nix files and directories, relative links between pages under docs/, and absolute docs.lyrapup.pet URLs from the root README, which the build republishes at a different depth from the rest of the tree. In-code comments that pointed at a moved README are updated to the new path. The README gains a Documentation section covering the sync contract and the linking rules, and CLAUDE.md carries the short version so future edits do not reintroduce unsynced pages or dead links. Verified by reproducing the docs-site assembly locally against its pinned toolchain (mkdocs 1.6.1, mkdocs-material 9.7.7, awesome-pages 2.10.1): pages render at the URLs used above and in the declared order.
This commit is contained in:
@@ -1,217 +0,0 @@
|
||||
# Keybindings reference
|
||||
|
||||
Every keyboard shortcut configured across this desktop, and where it is defined.
|
||||
Everything here is managed declaratively through Nix — edit the listed file and
|
||||
rebuild, never the generated dotfiles.
|
||||
|
||||
| Area | Defined in |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| Sway (compositor) | [`sway.nix`](./sway.nix) `config.keybindings` + `config.modes`, plus the home-manager Sway module's built-in defaults |
|
||||
| tmux | [`shell.nix`](./shell.nix) `programs.tmux` |
|
||||
| zsh line editor | [`shell.nix`](./shell.nix) `programs.zsh.historySubstringSearch` |
|
||||
| Neovim | [`editor.nix`](./editor.nix) `programs.nixvim` |
|
||||
| foot (terminal) | foot package defaults — only colours are themed (in `sway.nix`) |
|
||||
|
||||
**Conventions**
|
||||
|
||||
- **Super** is the `Mod4` / logo (Windows/Command) key; **Alt** is `Mod1`.
|
||||
- Letter keys are **keysyms** (the character produced), not physical positions.
|
||||
The keyboard is **Dvorak** (`us`/`dvorak`), so e.g. "Super+s" is whatever key
|
||||
types `s` in Dvorak.
|
||||
- Shortcuts apply to every Sway host (MBP, T400, Mac Pro); brightness keys are
|
||||
laptop-only, as noted.
|
||||
|
||||
---
|
||||
|
||||
## Sway
|
||||
|
||||
### Applications & session
|
||||
|
||||
| Shortcut | Action |
|
||||
| ------------------- | ------------------------------------------------------- |
|
||||
| `Super`+`Return` | Open a terminal (foot) |
|
||||
| `Super`+`Space` | App launcher (sway-launcher-desktop in a floating foot) |
|
||||
| `Super`+`d` | App launcher (same as above; module default) |
|
||||
| `Super`+`e` | File manager (nemo) |
|
||||
| `Super`+`c` | Clipboard history picker (clipman → fuzzel) |
|
||||
| `Super`+`l` | Lock screen (swaylock) |
|
||||
| `Super`+`Shift`+`q` | Close the focused window |
|
||||
| `Super`+`Shift`+`c` | Reload the Sway config |
|
||||
| `Super`+`Shift`+`e` | Exit Sway (asks for confirmation) |
|
||||
|
||||
### Focus
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------------------- | ---------------------------------------- |
|
||||
| `Super`+`←`/`↓`/`↑`/`→` | Move focus by direction |
|
||||
| `Super`+`h`/`j`/`k` | Move focus left / down / up (vim-style) |
|
||||
| `Super`+`a` | Focus the parent container |
|
||||
| `Super`+`Alt`+`Space` | Toggle focus between tiling and floating |
|
||||
|
||||
> Note: vim focus-right would be `Super`+`l`, but that is bound to **lock** here;
|
||||
> use `Super`+`→`.
|
||||
|
||||
### Moving windows
|
||||
|
||||
| Shortcut | Action |
|
||||
| ------------------------------- | ---------------------------------------- |
|
||||
| `Super`+`Shift`+`←`/`↓`/`↑`/`→` | Move the window by direction |
|
||||
| `Super`+`Shift`+`h`/`j`/`k`/`l` | Move the window left / down / up / right |
|
||||
| `Super`+`Shift`+`Space` | Toggle the window floating |
|
||||
|
||||
Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
|
||||
|
||||
### Layout
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------- | -------------------------------------------------------------------------------------- |
|
||||
| `Super`+`b` | Split horizontally |
|
||||
| `Super`+`v` | Split vertically |
|
||||
| `Super`+`s` | Stacking layout |
|
||||
| `Super`+`w` | Tabbed layout |
|
||||
| `Super`+`f` | Toggle fullscreen |
|
||||
| `Super`+`y` | **Layout submenu**: `s` stacking · `w` tabbed · `e` toggle split · `Return`/`Esc` exit |
|
||||
|
||||
> The layout submenu's `e` (toggle split) is the home for that action since
|
||||
> `Super`+`e` now opens the file manager.
|
||||
|
||||
### Workspaces
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------------------- | --------------------------------- |
|
||||
| `Super`+`1`…`0` | Switch to workspace 1…10 |
|
||||
| `Super`+`Shift`+`1`…`0` | Move the window to workspace 1…10 |
|
||||
| `Super`+`z` | Previous workspace |
|
||||
| `Super`+`x` | Next workspace |
|
||||
|
||||
### Scratchpad
|
||||
|
||||
| Shortcut | Action |
|
||||
| ------------------- | --------------------------------- |
|
||||
| `Super`+`Shift`+`-` | Move the window to the scratchpad |
|
||||
| `Super`+`-` | Show / cycle the scratchpad |
|
||||
|
||||
### Modes (submenus)
|
||||
|
||||
| Shortcut | Action |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `Super`+`r` | **Resize mode**: arrow keys resize; `Return`/`Esc` exit |
|
||||
| `Super`+`y` | **Layout mode** (see Layout above) |
|
||||
| `Super`+`Shift`+`x` | **Power menu**: `l` lock · `e` log out · `s` sleep · `r` reboot · `Shift`+`s` shutdown · `Return`/`Esc` exit |
|
||||
|
||||
### Screenshots
|
||||
|
||||
| Shortcut | Action |
|
||||
| --------------- | ---------------------------------------- |
|
||||
| `Print` | Select a region → swappy (annotate/save) |
|
||||
| `Shift`+`Print` | Focused window → swappy |
|
||||
|
||||
### Audio & media
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------------------------------------------- | ---------------------- |
|
||||
| `XF86AudioRaiseVolume` / `XF86AudioLowerVolume` | Volume ±5% (wpctl) |
|
||||
| `XF86AudioMute` | Toggle output mute |
|
||||
| `XF86AudioMicMute` | Toggle microphone mute |
|
||||
| `XF86AudioPlay` | Play/pause (playerctl) |
|
||||
| `XF86AudioNext` / `XF86AudioPrev` | Next / previous track |
|
||||
|
||||
### Brightness — laptops only
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------------------------------------------- | ----------------------------- |
|
||||
| `XF86MonBrightnessUp` / `XF86MonBrightnessDown` | Backlight ±5% (brightnessctl) |
|
||||
|
||||
Present only on portable hosts (T400, MBP); desktops have no internal backlight.
|
||||
|
||||
---
|
||||
|
||||
## tmux
|
||||
|
||||
Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys.
|
||||
|
||||
| Shortcut | Action |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `Ctrl`+`b` then `v` | Split into left/right panes |
|
||||
| `Ctrl`+`b` then `s` | Split into top/bottom panes |
|
||||
| `Ctrl`+`h`/`j`/`k`/`l` | Move between panes — and into/out of vim splits — seamlessly (vim-tmux-navigator, no prefix) |
|
||||
| `Alt`+`←`/`→`/`↑`/`↓` | Switch pane by direction (no prefix needed) |
|
||||
| `Ctrl`+`b` then `[` | Enter copy mode (then vi motions; `Space`/`Enter` to select/copy) |
|
||||
| `Ctrl`+`b` then `z` | Zoom / unzoom the focused pane |
|
||||
| `Ctrl`+`b` then `c` | New window |
|
||||
| `Ctrl`+`b` then `n` / `p` | Next / previous window |
|
||||
| `Ctrl`+`b` then `d` | Detach |
|
||||
| `Ctrl`+`b` then `Ctrl`+`s` / `Ctrl`+`r` | Save / restore the session (resurrect; continuum also auto-saves and restores on start) |
|
||||
| Mouse | Enabled — click to focus, drag borders, scroll, select |
|
||||
|
||||
> The stock split keys `%` and `"` are unbound; use `v` / `s` above. `Ctrl`+`b`
|
||||
> then `s` is therefore a split, not the session tree.
|
||||
>
|
||||
> Sessions persist across reboots (resurrect + continuum). Terminals auto-start
|
||||
> tmux; `NO_TMUX=1 <terminal>` opens a bare shell instead.
|
||||
|
||||
---
|
||||
|
||||
## foot (terminal)
|
||||
|
||||
Only colours are themed; these are foot's default key bindings.
|
||||
|
||||
| Shortcut | Action |
|
||||
| --------------------------------------- | ----------------------------- |
|
||||
| `Ctrl`+`Shift`+`c` / `Ctrl`+`Shift`+`v` | Copy / paste (clipboard) |
|
||||
| `Shift`+`Insert` | Paste primary selection |
|
||||
| `Ctrl`+`Shift`+`r` | Search scrollback |
|
||||
| `Ctrl`+`+` / `Ctrl`+`-` / `Ctrl`+`0` | Font larger / smaller / reset |
|
||||
| `Ctrl`+`Shift`+`u` | URL mode (jump to/open links) |
|
||||
| `Ctrl`+`Shift`+`n` | Spawn a new terminal |
|
||||
| `Shift`+`PageUp` / `Shift`+`PageDown` | Scroll back / forward |
|
||||
|
||||
---
|
||||
|
||||
## Neovim
|
||||
|
||||
Leader is **`Space`**. `Ctrl`+`h/j/k/l` is shared with tmux (see above): it moves
|
||||
across vim splits and tmux panes seamlessly. Everything else is stock vim, plus:
|
||||
|
||||
| Shortcut | Action |
|
||||
| ---------------------- | --------------------------------------------------------- |
|
||||
| `,``,` | Toggle the file tree (nvim-tree) — comma pressed twice |
|
||||
| `Ctrl`+`h`/`j`/`k`/`l` | Move between vim splits / tmux panes (vim-tmux-navigator) |
|
||||
| `<leader>ff` | Find files (telescope) |
|
||||
| `<leader>fg` | Live grep (telescope) |
|
||||
| `<leader>fb` | Switch buffer (telescope) |
|
||||
| `<leader>xx` | Diagnostics list (trouble) |
|
||||
| `gc` / `gcc` | Toggle comment (selection / line) |
|
||||
| `gd` | Go to definition (LSP) |
|
||||
| `gr` | List references (LSP) |
|
||||
| `K` | Hover documentation (LSP) |
|
||||
| `<leader>rn` | Rename symbol (LSP; `<leader>` is `Space`) |
|
||||
| `<leader>ca` | Code action (LSP) |
|
||||
|
||||
### Completion menu (nvim-cmp)
|
||||
|
||||
Active only while the completion popup is open (it appears as you type, e.g.
|
||||
file paths):
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------------------- | ------------------------------------------------------------------ |
|
||||
| `Tab` / `Shift`+`Tab` | Select next / previous item |
|
||||
| `Ctrl`+`n` / `Ctrl`+`p` | Select next / previous item |
|
||||
| `Ctrl`+`Space` | Open the completion menu |
|
||||
| `Enter` | Confirm the highlighted item (no auto-select; otherwise a newline) |
|
||||
| `Ctrl`+`e` | Dismiss the menu |
|
||||
|
||||
LSP covers Nix, Lua, Python and Terraform (the work box adds C# and Helm).
|
||||
Files are formatted on save (conform-nvim). `:Git` opens fugitive; gitsigns
|
||||
shows gutter signs. which-key pops up after `<leader>` to show the rest.
|
||||
|
||||
---
|
||||
|
||||
## zsh
|
||||
|
||||
| Shortcut | Action |
|
||||
| --------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `↑` / `↓` | History **substring** search — type a fragment first, then the arrows cycle matching past commands |
|
||||
|
||||
Bound for both CSI and SS3 cursor sequences, so it works in foot, iTerm2 and
|
||||
the Linux TTY alike.
|
||||
-360
@@ -1,360 +0,0 @@
|
||||
# Interactive shell environment
|
||||
|
||||
Everything the shell, terminal multiplexer, git and ssh do beyond their defaults,
|
||||
and where each is defined. All of it is managed declaratively through
|
||||
home-manager — edit the listed file and rebuild, never the generated dotfiles.
|
||||
|
||||
Keyboard shortcuts have their own reference: [`KEYBINDINGS.md`](./KEYBINDINGS.md).
|
||||
|
||||
| Area | Defined in |
|
||||
| -------------------------------------- | ----------------------------------------------------- |
|
||||
| zsh, CLI tools, tmux, ssh, auto-tmux | [`shell.nix`](./shell.nix) |
|
||||
| git (+ delta, commitizen) | [`git.nix`](./git.nix) |
|
||||
| Neovim (nixvim) + LSP | [`editor.nix`](./editor.nix) |
|
||||
| Claude Code (CLAUDE.md, style, memory) | [`claude.nix`](./claude.nix) |
|
||||
| GUI apps, GTK/Firefox theming, cursor | [`desktop.nix`](./desktop.nix) (graphical hosts only) |
|
||||
|
||||
Shared by every host via [`default.nix`](./default.nix); the work box also layers
|
||||
[`work.nix`](../users/emmathorpe/work.nix) on top (its own ssh config, extra
|
||||
packages, kubecolor, and the C#/Helm language servers). The committer identity (name, email,
|
||||
signing key) comes from the user registry
|
||||
([`../users/registry.nix`](../users/registry.nix)), not this module.
|
||||
|
||||
---
|
||||
|
||||
## zsh
|
||||
|
||||
| Feature | Notes |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| oh-my-zsh | plugins `git`, `man`, `sudo` (Esc-Esc to prepend sudo), `colored-man-pages`, `extract`; theme `robbyrussell` |
|
||||
| Autosuggestion | fish-style history suggestions as you type (→ to accept) |
|
||||
| Syntax highlighting | commands coloured by validity as you type |
|
||||
| Completion | menu completion; the dump is rebuilt on every activation (see Maintenance) |
|
||||
| History | 100k in-memory/on-disk, deduped, space-prefixed commands ignored, timestamped, **shared live across sessions**; file stays at `~/.zsh_history` |
|
||||
| Dotfiles location | `dotDir` is `~/.config/zsh` (XDG) — `.zshrc`/`.zshenv`/`.zcompdump` live there; `~/.zshenv` only bootstraps `$ZDOTDIR` |
|
||||
| History substring search | type a fragment, then ↑/↓ cycles matching past commands — works in foot, iTerm2 and the Linux TTY (both CSI and SS3 arrow encodings bound) |
|
||||
| Prompt | hostname is prefixed when over SSH |
|
||||
|
||||
**Aliases:** `ls`/`ll`/`la`/`lt` → `eza` (icons + git), `cls` → `clear`,
|
||||
`cat`/`du`/`df`/`ps` → their modern equivalents (see "Replacing the classics").
|
||||
git aliases live in git.nix (below).
|
||||
|
||||
## CLI tools
|
||||
|
||||
| Tool | What it gives you |
|
||||
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `fzf` | `Ctrl-R` fuzzy history, `Ctrl-T` file picker, `Alt-C` fuzzy cd (Catppuccin-themed) |
|
||||
| `zoxide` | `z <fragment>` jumps to frecent directories |
|
||||
| `direnv` + `nix-direnv` | per-project environments auto-loaded on `cd` (cached Nix dev shells) |
|
||||
| `eza` | modern `ls` (drives the ls aliases) |
|
||||
| `bat` | syntax-highlighting pager (Catppuccin Mocha theme); behaves like `cat` when piped; also the `MANPAGER` |
|
||||
| `ripgrep` / `fd` | fast search (`rg`) and find (`fd`); also back `fzf` |
|
||||
| `jq` | JSON processor |
|
||||
| `gh` / `tea` | GitHub and Gitea (`code.emmathe.dev`) CLIs; `gh` uses SSH |
|
||||
| `nix-index` | `command-not-found`: an unknown command tells you which Nix package provides it (prebuilt DB, no manual indexing) |
|
||||
| `comma` (`,`) | run an uninstalled program once: `, cowsay hi` |
|
||||
| `nh` | nicer `nixos-rebuild`/`home-manager` with diffs; `$NH_FLAKE` set to the repo. No scheduled GC (it could reap paths a running generation still references) — collect garbage manually with `nh clean all` / `nix-collect-garbage -d` |
|
||||
| `btop` | resource monitor, themed Catppuccin Mocha (vendored theme) |
|
||||
| `lazygit` | git TUI for staging/rebasing, themed to match (`git.nix`) |
|
||||
| `hyperfine` / `sd` | command-line benchmarking; saner find-and-replace than sed |
|
||||
| `tldr` (tealdeer) | worked examples for a command, alongside `man`; the page cache is refreshed by a `tldr-update` user timer |
|
||||
| `jnv` / `fq` | interactive jq-filter builder for JSON; jq syntax over binary formats (ELF, PNG, gzip, mp4…) |
|
||||
| `hexyl` | hex viewer, coloured by byte class |
|
||||
| `ouch` | one command for every archive format (`ouch d`/`c`/`l`) |
|
||||
| `dust` `dysk` `procs` | `du` / `df` / `ps` replacements — aliased over the originals, see below |
|
||||
| `trash-cli` `doggo` `xh` | `rm` (to the XDG trash) / `dig` / `curl` replacements — **not** aliased, see below |
|
||||
|
||||
**Theming:** `fzf`, `bat`, `btop`, `lazygit` and `git`'s `delta` pager are all
|
||||
Catppuccin Mocha, driven from the shared `../lib/catppuccin-mocha.nix` palette / the
|
||||
catppuccin upstream themes.
|
||||
|
||||
**Env & defaults:** `xdg.enable` on; `PAGER`/`MANPAGER` (bat) set in `default.nix`
|
||||
(the editor owns `$EDITOR`/`$VISUAL`); `xdg.mimeApps` maps web→Firefox,
|
||||
directories→nemo (`desktop.nix`).
|
||||
|
||||
## Replacing the classics
|
||||
|
||||
Muscle memory is the expensive part of this, not the packages. Four commands are
|
||||
**shadowed** — the old name now runs a new tool. Everything else keeps a new
|
||||
name, so the original is never displaced.
|
||||
|
||||
### Shadowed by an alias
|
||||
|
||||
| You type | You now run | The original is still `command <name>` / `\<name>` |
|
||||
| -------- | -------------------- | -------------------------------------------------- |
|
||||
| `cat` | `bat --paging=never` | `command cat` |
|
||||
| `du` | `dust` | `command du` |
|
||||
| `df` | `dysk` | `command df` |
|
||||
| `ps` | `procs` | `command ps` |
|
||||
|
||||
Only read-only commands are shadowed, so the worst case of a wrong flag is a
|
||||
retype rather than lost data. `rm`, `grep`, `curl` and `find` are deliberately
|
||||
left alone — see "Left alone on purpose" below.
|
||||
|
||||
**Where the aliases apply.** They are written into `~/.config/zsh/.zshrc`, so
|
||||
they exist only in an **interactive zsh**:
|
||||
|
||||
- shell scripts, `Makefile` recipes and anything another program `exec`s get the
|
||||
real coreutils binary — nothing that parses output can break;
|
||||
- `sudo du -sh /var` runs the real `du`: zsh does not expand an alias after
|
||||
`sudo`;
|
||||
- `KUBECONFIG=… kubectl …` **does** expand — zsh expands aliases after a
|
||||
variable-assignment prefix. That is what makes the kubecolor alias on the work
|
||||
box (below) useful rather than a special case you have to remember.
|
||||
|
||||
### Flag gotchas
|
||||
|
||||
These replacements are not drop-in. The two marked **silent** are the dangerous
|
||||
ones — they succeed and answer a different question than the one you asked.
|
||||
Everything else fails loudly.
|
||||
|
||||
| Old habit | What happens now | Do this instead |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| `du -sh dir` | dust prints its usage and exits non-zero — `-h` is not a dust flag | `dust dir` (units are human by default; the total is the last row) |
|
||||
| `du -s dir` | **silent**: dust's `-s` is `--apparent-size`, not `--summarize` | `dust -d 0 dir` for a single total line |
|
||||
| `du --max-depth=2` | not recognised | `dust -d 2` |
|
||||
| `df -h` | dysk rejects `-h` | `dysk` (SI units by default; `-u binary` for 1024-based) |
|
||||
| `df -i` | not recognised | `dysk -c +inodes` |
|
||||
| `df -a` | works, same meaning (all mount points) | — |
|
||||
| `df /some/path` | works, same meaning (the device holding that path) | — |
|
||||
| `ps aux` | **silent**: `aux` is read as a search keyword, so you get only processes whose command line contains the string "aux" | `procs` lists everything; `procs <pattern>` filters |
|
||||
| `ps -ef` | `error: unexpected argument '-e'` | `procs` |
|
||||
| `ps -p 1234` | not recognised | `procs 1234` |
|
||||
| `procs -a` | **silent**: `-a` is `--and` (combine search keywords), not "all" | drop it — `procs` already shows everything |
|
||||
| `cat -v` / `cat -e` | `error: unexpected argument` | `cat -A` does work (bat implements show-all); else `command cat -v` |
|
||||
| `cat -n` | works, but bat's number column, not coreutils' layout | fine to read; `command cat -n` when the exact layout matters |
|
||||
| `cat <binary>` | prints `<BINARY>` to a terminal instead of dumping the bytes | `hexyl <file>`, or `command cat` to dump |
|
||||
|
||||
Useful new capabilities in the same tools: `procs --tree`, `procs --watch`,
|
||||
`dust -r` (largest at the top), `dysk -s size`, `dysk -f 'type=ext4'`.
|
||||
|
||||
**Piping is safe for `cat`.** bat drops all decoration and colour when stdout is
|
||||
not a terminal, so `cat f | sha256sum` is byte-for-byte what coreutils `cat`
|
||||
would have given. The others are TUI-shaped tables with no stable format — if
|
||||
something needs to parse them, use `dysk --json`/`--csv`, `procs --json`, or the
|
||||
original binary.
|
||||
|
||||
### Renamed, not shadowed
|
||||
|
||||
| Instead of | Use | Notes |
|
||||
| --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `rm` | `trash` | Moves to the XDG trash. `trash-list`, `trash-restore` (interactive picker), `trash-empty [days]`. It never deletes in place: if it cannot create a trash directory on that filesystem it errors out. |
|
||||
| `dig` / `nslookup` | `doggo` | `doggo example.com MX @1.1.1.1`; `--json` for scripting. Not aliased — `dig` (from the `bind` closure that other modules pull in) stays where scripts expect it. |
|
||||
| `curl` (interactive poking) | `xh` | HTTPie syntax: `xh POST api.example/x name=lyra`. `xhs` is `xh --https`. **curl stays installed and unaliased** — it is what scripts and CI use. |
|
||||
| `tar` / `unzip` / `7z` | `ouch` | `ouch d file.<anything>`, `ouch c out.tar.zst src/`, `ouch l archive`. Format is inferred from the extension. The oh-my-zsh `extract` function still works too. |
|
||||
| `jq` (exploring a payload) | `jnv` | Interactive filter builder over a JSON file; it prints the jq expression you built. `jq` remains the scripting tool. |
|
||||
| `hexdump -C` / `xxd` | `hexyl` | `hexyl -n 256 -s 0x40 file` for a window into a large file. |
|
||||
| `strings` on a known format | `fq` | jq syntax over binary formats: `fq -d elf '.sections[].name' ./bin`. |
|
||||
| skimming a man page | `tldr` | Worked examples. `man` is untouched (and still rendered through bat). |
|
||||
|
||||
### Left alone on purpose
|
||||
|
||||
- **`grep`** is not aliased to `rg`. ripgrep is recursive by default, skips
|
||||
gitignored and hidden files, and uses a different regex dialect (no
|
||||
backreferences, no POSIX classes in the same form). A `grep` habit silently
|
||||
producing fewer matches is a worse failure than typing three characters. Type
|
||||
`rg`.
|
||||
- **`rm`** is not aliased to `trash-put`. Retraining `rm` to mean "recoverable"
|
||||
is a habit that follows you onto every machine where it is not — remote hosts,
|
||||
root shells, containers, CI. Type `trash`.
|
||||
- **`find`** is not aliased to `fd`; the `-exec`/`-print0` vocabulary has no
|
||||
equivalent and scripts lean on it. Type `fd`.
|
||||
- **`sed`** is not aliased to `sd`; `sd` takes real regex and literal
|
||||
replacements, not sed's expression language. Type `sd`.
|
||||
- **coreutils itself** is not swapped for `uutils-coreutils`. It is packaged and
|
||||
tempting, but every Nix builder and shell script on these hosts is written
|
||||
against GNU behaviour, including its forty-year-old edge cases.
|
||||
|
||||
### Work box only: kubectl → kubecolor
|
||||
|
||||
On EDaaS (`work.nix`) `kubectl` is aliased to **kubecolor**, which runs the real
|
||||
kubectl underneath and colourises what comes back. Nothing to relearn: every
|
||||
flag, subcommand and plugin passes straight through, unrecognised output is
|
||||
printed verbatim, and colour is dropped automatically when stdout is not a
|
||||
terminal — so `kubectl get -o json … | jq` is unchanged. The alias also applies
|
||||
to `KUBECONFIG=prodconfig kubectl …`, per the alias-expansion note above.
|
||||
Completions are kubectl's own (`compdef kubecolor=kubectl`). Escape hatch as
|
||||
ever: `command kubectl`.
|
||||
|
||||
### sudo → sudo-rs
|
||||
|
||||
Every NixOS host now uses **sudo-rs**, the memory-safe reimplementation, in
|
||||
place of `sudo` (`modules/common-nixos.nix`; the macOS host keeps Apple's sudo
|
||||
with Touch ID). Day to day there is nothing to learn — `sudo`, `sudo -i`,
|
||||
`sudo -u`, `sudo -l`, `sudoedit` and `visudo` all behave as before against this
|
||||
fleet's stock "wheel, with a password" policy. What it does **not** implement:
|
||||
host aliases, LDAP/SSSD sudoers, `sudoreplay`, and most `Defaults` settings.
|
||||
Needing any of those means reverting to `security.sudo`.
|
||||
|
||||
If a host ever refuses to escalate, get a root shell that does not go through
|
||||
sudo (`wsl -u root -d NixOS` on the work box; the console or a serial/HDMI login
|
||||
elsewhere) and roll back with `nixos-rebuild switch --rollback`, or pick the
|
||||
previous generation from the boot menu.
|
||||
|
||||
## tmux
|
||||
|
||||
**Auto-start:** opening any interactive terminal — foot, iTerm2, the WSL shell, the
|
||||
Linux console — drops you straight into a tmux session named `main` (attach if it
|
||||
exists, else create). Panes run a plain non-login zsh. It deliberately does **not**
|
||||
fire for SSH sessions, VS Code's integrated terminal, already-inside-tmux, or
|
||||
non-interactive shells. Escape hatch: `NO_TMUX=1 <terminal>` opens a bare shell.
|
||||
|
||||
| Setting | Value |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Mode keys | vi |
|
||||
| Mouse | on |
|
||||
| Scrollback | 500000 lines |
|
||||
| `escape-time` | 10ms (the 500ms default lagged vim's ESC) |
|
||||
| `focus-events` | on (vim autoread) |
|
||||
| `base-index` / `pane-base-index` | 1 |
|
||||
| Splits | `prefix s` vertical, `prefix v` horizontal (stock `%`/`"` unbound) |
|
||||
| Pane nav | `Alt`+arrows (no prefix) |
|
||||
| Terminal | `default-terminal tmux-256color`; truecolor advertised per outer terminal (`foot*`, `xterm-256color`/iTerm2) via `terminal-features … RGB` |
|
||||
| Clipboard | `set-clipboard on`; foot `terminal-features` advertise truecolor/sync/OSC52/title/cursor |
|
||||
|
||||
**Plugins:** `sensible`, `vim-tmux-navigator` (Ctrl-h/j/k/l across vim ↔ tmux),
|
||||
`yank`, `extrakto` (`prefix`+`Tab`: fzf-grab paths/URLs/text from the pane into
|
||||
the prompt), `catppuccin` (Mocha statusline), `resurrect` + `continuum`
|
||||
(sessions auto-save and restore across reboots). The statusline draws Nerd-Font
|
||||
glyphs — see Fonts.
|
||||
|
||||
## Fonts
|
||||
|
||||
**JetBrainsMono Nerd Font**, **Noto Sans** and **Noto Color Emoji** are
|
||||
installed on every host (in `common-nixos.nix`, because tmux/terminals run
|
||||
everywhere; the Mac installs the Nerd Font to `/Library/Fonts` via the Darwin
|
||||
config). `fonts.fontconfig.defaultFonts` maps the generic families so anything
|
||||
asking for `monospace` gets the Nerd Font (with emoji fallback) — this also
|
||||
gives the WSL box emoji/sans coverage it otherwise lacked. foot uses the Nerd
|
||||
Font as its main font automatically. iTerm2's font is a GUI setting — set it to
|
||||
_JetBrainsMono Nerd Font_ (Settings → Profiles → Text → Font) so the tmux
|
||||
statusline glyphs render instead of `?`.
|
||||
|
||||
## Editor (Neovim)
|
||||
|
||||
`nvim` — aliased to `vi`/`vim`, and set as `$EDITOR`/`$VISUAL` — is configured
|
||||
declaratively with **nixvim**, so the same plugins and config are baked in on
|
||||
every host. Migrated from plain vim; the practical gain is a real LSP stack in
|
||||
place of the old (inert) ALE.
|
||||
|
||||
| Feature | Notes |
|
||||
| -------------- | ----------------------------------------------------------------------------------------- |
|
||||
| Colorscheme | Catppuccin Mocha (matches the terminal and the rest of the desktop) |
|
||||
| File tree | nvim-tree, toggled with `,,` (comma twice; was nerdtree) |
|
||||
| Fuzzy finder | telescope (+fzf-native): `<leader>ff` files, `<leader>fg` grep, `<leader>fb` buffers |
|
||||
| Format on save | conform-nvim (nixfmt, stylua, ruff, shfmt, prettier, gofumpt; LSP fallback otherwise) |
|
||||
| Git | fugitive (`:Git …`) + gitsigns gutter signs/blame |
|
||||
| Diagnostics | inline + trouble list (`<leader>xx`) |
|
||||
| Completion | nvim-cmp (LSP/buffer/path) with luasnip snippet expansion |
|
||||
| Indent guides | indent-blankline, on by default (was vim-indent-guides) |
|
||||
| Statusline | lualine (Catppuccin theme) |
|
||||
| Editing | which-key hints, comment (`gc`/`gcc`), autopairs, treesitter textobjects |
|
||||
| Pane nav | vim-tmux-navigator — `Ctrl`+`h/j/k/l` moves across vim splits and tmux panes |
|
||||
| Syntax | tree-sitter (nix, lua, bash, markdown, groovy, c#, python, terraform, yaml) |
|
||||
| LSP | nvim-cmp completion + servers `nil_ls` (Nix), `lua_ls`, `pyright` (Python), `terraformls` |
|
||||
| Indentation | 2-wide hard tabs (`noexpandtab`, `tabstop`/`shiftwidth` = 2); line numbers on |
|
||||
| Filetypes | `*Jenkinsfile` → groovy |
|
||||
|
||||
Leader is `Space`. LSP keymaps (`gd`, `gr`, `K`, `<leader>rn`, `<leader>ca`) and
|
||||
the file-tree toggle are listed in
|
||||
[`KEYBINDINGS.md`](./KEYBINDINGS.md#neovim). Add a universal language server by
|
||||
enabling it under `programs.nixvim.plugins.lsp.servers` in `editor.nix`;
|
||||
host-specific ones go in that host's module — the work box (`work.nix`) adds
|
||||
`omnisharp` (C#) and `helm_ls` (Helm), kept off the personal machines.
|
||||
|
||||
## git
|
||||
|
||||
Pager is **delta**. **commitizen** is installed on every host; `cz` defaults to
|
||||
Conventional Commits. **lazygit** (themed) is the TUI. The commit-graph is kept
|
||||
current (`gc`/`fetch.writeCommitGraph`) so `lg` stays fast.
|
||||
|
||||
| Aliases | |
|
||||
| ------------------------ | ------------------------------------------------------------------------- |
|
||||
| `st` `co` `sw` `br` `ci` | status / checkout / switch / branch / commit |
|
||||
| `last` `unstage` | last commit / unstage |
|
||||
| `amend` `fixup` `undo` | amend-no-edit / `commit --fixup` / soft-reset HEAD~1 (keep staged) |
|
||||
| `lg` | graph log, all branches |
|
||||
| `cz` `cc` | `git cz <sub>` (e.g. `git cz c`) and `git cc` → commitizen prompt |
|
||||
| `dft` | structural (syntax-aware) diff via difftastic; takes `git diff` arguments |
|
||||
|
||||
**`git dft` vs `git diff`.** delta stays the default renderer for everything;
|
||||
`diff.external` is deliberately **not** set, so `git diff`, `git show` and
|
||||
anything parsing their output are unchanged. Reach for `dft` when a refactor
|
||||
moved code around and a line-based diff is noise. One wrinkle: `dft` is a
|
||||
`!`-shell alias, and git runs those from the repository root — pass pathspecs
|
||||
relative to the root, not to your current directory.
|
||||
|
||||
| Behaviour | |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Pulls | rebase, with autostash + autosquash |
|
||||
| Fetch | prune deleted remote branches |
|
||||
| Conflicts | `zdiff3` (shows the common ancestor) |
|
||||
| Diffs | histogram algorithm, colour-moved |
|
||||
| `rerere` | remembers + replays conflict resolutions |
|
||||
| Commit editor | full diff shown (`commit.verbose`) |
|
||||
| Misc | branches sorted by date, `column.ui = auto`, `help.autocorrect = prompt`, `push.autoSetupRemote` |
|
||||
| Global ignores | `result`, `result-*`, `.direnv`, `*.swp`, `.DS_Store` |
|
||||
| Signing | SSH commit + tag signing (`mkDefault`, so a host without the key in its agent can disable it). Name, email and signing key all come from the per-user `identity` (the user registry, `../users/registry.nix`). |
|
||||
|
||||
## ssh
|
||||
|
||||
| Feature | Notes |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ssh-agent | runs on Linux (launchd on macOS); keys added on **first use** so the passphrase is typed once per login session — this also feeds git commit signing |
|
||||
| macOS | `UseKeychain` caches the passphrase in the login keychain (guarded by `IgnoreUnknown`, so a non-Apple `ssh` skips it instead of erroring) |
|
||||
| Gitea remote | `code.emmathe.dev` → `HostName 10.187.1.76` (DNS-override), `Port 30009`, user `git`, dedicated key, `identitiesOnly` |
|
||||
| Defaults | the module's deprecated default block is opted out; equivalents kept under `settings."*"` |
|
||||
|
||||
The **work box keeps its own `~/.ssh/config`** (home-manager's `programs.ssh` is
|
||||
forced off there) but still runs the agent.
|
||||
|
||||
## Claude Code
|
||||
|
||||
Managed declaratively by [`claude.nix`](./claude.nix) on every host whose CPU
|
||||
can run it (the CLI is `pkgs.claude-code`, tracked to unstable via the flake
|
||||
overlay).
|
||||
|
||||
**Capability gate.** The module installs nothing — CLI or files — when
|
||||
`osConfig.features.claudeCode.enable` is off. That flag is derived fleet-wide
|
||||
from the host's declared CPU level (see "CPU capability gating" in the root
|
||||
README): the Node runtime needs SSE4.2/POPCNT, so anything below x86-64-v2 (the
|
||||
Mac Pro 3,1) is excluded. Hosts that do not define the option — the Darwin host
|
||||
and the standalone `homeConfigurations` — keep it enabled.
|
||||
|
||||
| Managed (static, from Nix) | Left mutable (runtime state) |
|
||||
| --------------------------------------------------- | ------------------------------------------------------ |
|
||||
| `~/.claude/CLAUDE.md` (persona + memory workflow) | `settings.json` (permissions, model, theme, `/config`) |
|
||||
| `~/.claude/output-styles/soviet-engineer.md` | `.credentials.json`, history, caches |
|
||||
| `~/.claude/memory/` (read-only symlink to the repo) | |
|
||||
|
||||
`settings.json` is intentionally **not** managed: Claude rewrites it at runtime
|
||||
(interactive permission grants, `/config`), which a read-only store symlink would
|
||||
break.
|
||||
|
||||
**Memory is sourced from this repo.** The files in
|
||||
[`claude/memory/`](./claude/memory) are the source of truth; they are symlinked
|
||||
read-only into `~/.claude/memory`, so recall works but the runtime "save a
|
||||
memory" path does not. To add/change/remove a memory, edit `claude/memory/`
|
||||
(one file per memory + the `MEMORY.md` index) and rebuild — `CLAUDE.md` tells
|
||||
Claude to route new memories there.
|
||||
|
||||
## Maintenance behaviours
|
||||
|
||||
- **zcompdump reset** — `~/.config/zsh/.zcompdump*` (plus legacy `~/.zcompdump*`
|
||||
and the cache copy) is removed on every activation, so a stale
|
||||
dump (pointing at `/nix/store` paths a rebuild or a manual GC removed) can't
|
||||
break completion with `_git: function definition file not found`.
|
||||
- **GC** — no scheduled timer; collect garbage deliberately (`nh clean all` /
|
||||
`nix-collect-garbage -d`) when no important session is running.
|
||||
|
||||
## Per-host differences
|
||||
|
||||
| | Personal Linux (sway) | macOS | Work WSL (EDaaS) |
|
||||
| --------------------------- | --------------------- | --------------------- | --------------------------- |
|
||||
| Auto-tmux | yes (foot/TTY) | yes (iTerm2) | yes (WSL shell) |
|
||||
| `kubectl` → kubecolor | no (no kubectl) | no | yes (work module) |
|
||||
| `sudo` implementation | sudo-rs | Apple sudo + Touch ID | sudo-rs |
|
||||
| git email | `iam@emmathe.dev` | `iam@emmathe.dev` | `…@citrix.com` (work) |
|
||||
| ssh config managed | yes | yes | no (keeps corporate config) |
|
||||
| ssh-agent | yes | launchd | yes (work module) |
|
||||
| GUI / theming (desktop.nix) | yes | no | no |
|
||||
+2
-2
@@ -31,7 +31,7 @@ in
|
||||
# are aliased over the original name (see shellAliases below); the rest keep
|
||||
# their own name so nothing changes shape under a script's feet. The alias
|
||||
# map and the flag-compatibility differences are documented in
|
||||
# ./README.md, "Replacing the classics".
|
||||
# ../docs/shell.md, "Replacing the classics".
|
||||
pkgs.dust # du: tree-shaped, size-sorted disk usage
|
||||
pkgs.dysk # df: mounted filesystems (duf is unmaintained upstream)
|
||||
pkgs.procs # ps: process list with tree, ports and container columns
|
||||
@@ -165,7 +165,7 @@ in
|
||||
# Shadow the classics with their modern equivalents. Only read-only
|
||||
# commands are shadowed: a wrong flag costs a retype, never data. The
|
||||
# flag vocabularies are NOT compatible (`du -sh`, `df -h`, `ps aux` all
|
||||
# fail here) -- see ./README.md, "Replacing the classics".
|
||||
# fail here) -- see ../docs/shell.md, "Replacing the classics".
|
||||
#
|
||||
# Blast radius is bounded by where these live: shellAliases lands in
|
||||
# .zshrc, so only interactive zsh sees them. Scripts, `sudo <cmd>` and
|
||||
|
||||
Reference in New Issue
Block a user