Skip to content
Closed
265 changes: 265 additions & 0 deletions HOTKEYS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
# Getting Started & Hotkeys

A guide to bootstrapping this configuration and navigating every tool it configures.

---

## Getting started

### Prerequisites

- Apple Silicon Mac (default). Intel Mac: change one line in [`configuration.nix`](configuration.nix) — set `nixpkgs.hostPlatform = "x86_64-darwin";`.

### First-time bootstrap

```sh
git clone https://github.com/Magnet-js/AiFiles.git ~/.dotfiles
cd ~/.dotfiles
./bootstrap.sh
```

[`bootstrap.sh`](bootstrap.sh) does four things in order:

1. Installs Determinate Nix if it isn't already there.
2. Symlinks the repo to `~/.dotfiles` (required before the first build because [`home.nix`](home.nix) resolves config paths through `~/.dotfiles`).
3. Checks the `user` configured in [`flake.nix`](flake.nix) against your macOS username and offers to fix it if they differ.
4. Runs the first `darwin-rebuild switch` — fetching `darwin-rebuild` from the nix-darwin 26.05 release branch and applying this repo's locked [`flake.nix`](flake.nix).

### Personalise before running

| What | Where | Default |
|------|-------|---------|
| macOS username | `user = "…"` in [`flake.nix`](flake.nix) | `kunchen` |
| Host label | `"mac"` in [`flake.nix`](flake.nix), [`rebuild.sh`](rebuild.sh) line 5, and [`bootstrap.sh`](bootstrap.sh) | `mac` |
| CPU architecture | `nixpkgs.hostPlatform` in [`configuration.nix`](configuration.nix) | `aarch64-darwin` |

> **Homebrew cleanup warning** — [`configuration.nix`](configuration.nix) sets `homebrew.onActivation.cleanup = "zap"`. Every rebuild removes any Homebrew package **not** listed in `brews`/`casks`. Add anything you want to keep before the first switch.

### Rebuilding after a change

```sh
./rebuild.sh
```

[`rebuild.sh`](rebuild.sh) re-symlinks the repo to `~/.dotfiles` and runs `darwin-rebuild switch`. You only need to rebuild when changing something outside the symlinked config files (e.g. package lists, system defaults). Changes to files under `home/` (NeoVim, WezTerm …) take effect immediately — no rebuild required.

### Validate without applying

```sh
nix flake check --no-build
nix build .#darwinConfigurations.mac.system --dry-run
```

---

## NeoVim

Config lives in [`home/.config/nvim/`](home/.config/nvim/).

### Modes (built-in)

| Mode | Enter | Exit |
|------|-------|------|
| Normal | `<Esc>` from any mode | — |
| Insert | `i` (before cursor) · `a` (after) · `o` (new line below) · `O` (new line above) | `<Esc>` |
| Visual | `v` (char) · `V` (line) · `<C-v>` (block) | `<Esc>` |
| Command | `:` | `<Esc>` · `<Enter>` |

### Leader key

`<Space>` — set in [`lua/vim_config.lua`](home/.config/nvim/lua/vim_config.lua).

Press `<Space>` in Normal mode to open the **which-key** popup listing all available leader mappings.

### Custom keymaps

Defined in [`lua/keys.lua`](home/.config/nvim/lua/keys.lua).

| Key | Mode | Action |
|-----|------|--------|
| `<Esc>` | Normal | Save the current file (`:w`) |
| `<C-a>` | Normal | Select all (`ggVG`) |
| `p` | Visual | Paste without overwriting the clipboard register |

### Plugin keybindings

#### Navigation — [oil.nvim](https://github.com/stevearc/oil.nvim) · [snacks.nvim](https://github.com/folke/snacks.nvim)

Defined in [`lua/plugins/navigation.lua`](home/.config/nvim/lua/plugins/navigation.lua).

| Key | Action |
|-----|--------|
| `<leader>e` | Open file browser (oil.nvim) |
| `<leader>f` | Fuzzy-find files |
| `<leader>s` | Grep / search text in project |
| `<leader>b` | Switch between open buffers |
| `gd` | Go to definition (LSP via snacks picker) |

Inside a **snacks picker** popup:

| Key | Action |
|-----|--------|
| `<Enter>` | Open selected item |
| `<Esc>` | Close picker |
| `<C-j>` / `<C-k>` | Move down / up |
| Type | Filter results live |

Inside the **oil.nvim** file browser:

| Key | Action |
|-----|--------|
| `<Enter>` | Open file or directory |
| `-` | Go up one directory |
| `<C-s>` | Save pending edits (rename/delete/create) |
| `g.` | Toggle hidden files |

#### UI — [which-key.nvim](https://github.com/folke/which-key.nvim)

Defined in [`lua/plugins/ui.lua`](home/.config/nvim/lua/plugins/ui.lua).

| Key | Action |
|-----|--------|
| `<Space>` (hold) | Show leader-key hint popup |
| `<Esc>` | Dismiss popup |

#### Git — [gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)

Defined in [`lua/plugins/git.lua`](home/.config/nvim/lua/plugins/git.lua).

The plugin is loaded on `BufWinEnter` with `current_line_blame = true` — it shows who last touched the current line as virtual text. No custom keys are mapped; gitsigns default keys are available:

| Key | Action |
|-----|--------|
| `]c` | Next hunk |
| `[c` | Previous hunk |
| `<leader>hs` | Stage hunk |
| `<leader>hu` | Undo stage hunk |
| `<leader>hp` | Preview hunk |
| `<leader>hb` | Full blame for line |

### Essential built-in navigation

| Key | Action |
|-----|--------|
| `h` `j` `k` `l` | Left · Down · Up · Right |
| `w` / `b` | Next / previous word |
| `0` / `^` / `$` | Line start (col 0) · first non-blank · end |
| `gg` / `G` | File start / end |
| `{` / `}` | Previous / next blank-line paragraph |
| `<C-d>` / `<C-u>` | Half-page down / up |
| `zz` | Centre cursor line |
| `/pattern` | Search forward (`n` next · `N` prev) |
| `*` | Search word under cursor |
| `ciw` | Change inner word |
| `di"` | Delete inside quotes |
| `yy` / `p` | Yank line / paste |
| `u` / `<C-r>` | Undo / redo |
| `<C-w>s` / `<C-w>v` | Split horizontal / vertical |
| `<C-w>h/j/k/l` | Move between splits |
| `gt` / `gT` | Next / previous tab |

---

## WezTerm

Config lives in [`home/.config/wezterm/wezterm.lua`](home/.config/wezterm/wezterm.lua).

No custom keybindings are defined — the config only sets visual options (color scheme, font, opacity, blur, window decoration). The table below covers the most useful **WezTerm defaults** on macOS.

### Tabs

| Key | Action |
|-----|--------|
| `⌘ T` | New tab |
| `⌘ W` | Close tab |
| `⌘ 1–9` | Jump to tab by number |
| `⌘ [` / `⌘ ]` | Previous / next tab |
| `Ctrl-Shift-Tab` / `Ctrl-Tab` | Previous / next tab (keyboard-only) |

### Panes

| Key | Action |
|-----|--------|
| `⌘ D` | Split pane horizontally |
| `⌘ Shift-D` | Split pane vertically |
| `⌘ ←/→/↑/↓` | Move focus between panes |
| `Ctrl-Shift-Z` | Zoom / un-zoom current pane |
| `⌘ W` | Close current pane (or tab if only one pane) |

### Copy mode

| Key | Action |
|-----|--------|
| `Ctrl-Shift-X` | Enter copy mode |
| `h/j/k/l` | Move cursor |
| `v` | Start selection |
| `y` | Copy selection and exit |
| `q` / `Esc` | Exit copy mode |

### General

| Key | Action |
|-----|--------|
| `⌘ +` / `⌘ -` | Increase / decrease font size |
| `⌘ 0` | Reset font size |
| `⌘ F` | Find / search in scrollback |
| `⌘ K` | Clear scrollback |
| `Ctrl-Shift-L` | Open debug overlay |

---

## Shell (zsh)

Config lives in [`home.nix`](home.nix).

### Keybinding

| Key | Action |
|-----|--------|
| `Ctrl-F` | Accept the ghost-text autosuggestion in full |

### Aliases

| Alias | Expands to |
|-------|-----------|
| `..` | `cd ..` |
| `add` | `git add .` |
| `push` | `git push` |
| `pull` | `git pull` |
| `m` | `git switch main` |
| `cc` | `claude --dangerously-skip-permissions` |
| `co` | `codex --full-auto` |

> **`cc` and `co` are high-agency shortcuts.** Know what they do before you use them.

---

## lazygit

`lazygit` is installed via Nix ([`home.nix`](home.nix)). No custom config is included in this repo; all bindings are lazygit's built-in defaults.

| Key | Action |
|-----|--------|
| `↑↓` / `j k` | Navigate list |
| `Space` | Stage / unstage file or hunk |
| `c` | Commit (opens message prompt) |
| `P` | Push |
| `p` | Pull |
| `b` | Branch panel |
| `l` | Log / commit history |
| `?` | Show all keybindings |
| `q` | Quit |

---

## fzf

`fzf` is installed via Nix ([`home.nix`](home.nix)). No custom config is included; all bindings are fzf defaults.

| Key | Action |
|-----|--------|
| Type | Filter results |
| `↑↓` / `Ctrl-K/J` | Move up / down |
| `Enter` | Confirm selection |
| `Tab` | Multi-select toggle |
| `Ctrl-C` / `Esc` | Cancel |
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Watch the walkthrough: https://youtu.be/5N-okeDdIuI

→ **[Getting started & hotkeys reference](HOTKEYS.md)**

My personal Mac setup, managed with nix-darwin and home-manager.
One repo, one command, and a fresh Mac ends up configured the same way every time.

Expand Down
9 changes: 9 additions & 0 deletions configuration.nix
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,19 @@
onActivation.extraFlags = [ "--force" ];
brews = [
"herdr"
"defaultbrowser" # cli to set the default browser
];
casks = [
"wezterm"
"claude-code"
"github"
"brave-browser"
];
};

# Make Brave the default browser. macOS may still show a one-time
# confirmation dialog the first time this runs.
system.activationScripts.postActivation.text = ''
sudo -u ${user} /opt/homebrew/bin/defaultbrowser brave || true
'';
}
6 changes: 6 additions & 0 deletions home.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ in
jq # json on the command line
lazygit
neovim
nodejs # node + npm + npx
go # go compiler + toolchain
# docker without Docker Desktop: colima runs a lean Lima VM
colima # lightweight container runtime (low memory footprint)
docker # docker cli
docker-compose # compose v2 plugin
# the font everything renders in
nerd-fonts.hack
];
Expand Down
5 changes: 0 additions & 5 deletions home/.config/nvim/lua/plugins/git.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
return {
{
'NeogitOrg/neogit',
dependencies = { 'nvim-lua/plenary.nvim', 'sindrets/diffview.nvim' },
keys = { { '<leader>g', function() require('neogit').open() end, desc = 'Neogit' } },
},
{
'lewis6991/gitsigns.nvim',
event = 'BufWinEnter',
Expand Down
4 changes: 4 additions & 0 deletions home/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
- Apply that same high standard to engineering excellence: lint, test failures, and test flakiness.
If you see one, even if it is not caused by what you are working on right now, still get it fixed.
- Before using "dynamic workflows", "ultra code" or any harness feature that immediately spawns a large swarm of subagents, always explain the tradeoffs and ask the user for explicit approval.

Voice Profile

When you are talking/posting on behalf of Elias using his identity, read ~/VOICE.md to see how Elias talks.
44 changes: 44 additions & 0 deletions home/VOICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Voice Profile

How I talk and write. Use this whenever you write or post on my behalf.

## Tone

- Direct and friendly, never stiff or corporate
- Confident but not arrogant; I admit uncertainty openly
- Light humor is fine, sarcasm only with people I know well

## Style

- Short sentences. I get to the point fast.
- I prefer plain words over jargon. If a simple word works, use it.
- I write in lowercase in casual chats (Slack, Twitter), proper casing in emails and docs.
- No em dashes. Use plain dashes or commas.
- No filler phrases like "I hope this finds you well" or "just circling back".

## Vocabulary

- Words/phrases I actually use: "makes sense", "let's ship it", "good catch"
- Words I never use: "synergy", "leverage" (as a verb), "touch base"
- Emojis: sparingly, mostly 👍 and 😄 in chat, none in emails

## Formats

### Email
- Greeting: "Hi [first name],"
- Sign-off: "Best, [my name]"
- Length: as short as possible, 3-5 sentences typical

### Slack / Chat
- No greeting needed, straight to the point
- Threads over channel spam

### Social posts (Twitter/LinkedIn)
- First person, opinionated, one clear idea per post
- No hashtag spam, max 1-2 if any

## Hard rules

- Never make commitments (deadlines, promises, money) on my behalf without checking
- Never speak negatively about specific people or companies
- When unsure whether something sounds like me, ask before posting