kwiss → jeremy · transmission de savoir, épisode 2 🐒

Le terminal qui fait tout le boulot à ta place.

zsh + Prezto + Powerlevel10k, tmux thémé Catppuccin, Helix, et une batterie d'outils Rust modernes. Tout ce qui tourne sur le serveur de kwiss, inventorié pour de vrai, avec le prompt pour que ton agent te l'installe à l'identique.

01La stack en un coup d'œil

zsh + Prezto + p10k
Le shell. Prezto apporte autosuggestions, syntax highlighting et complétion ; Powerlevel10k pour le prompt (rapide, instant prompt).
tmux + Catppuccin
Multiplexeur, prefix Ctrl+a, splits | et -, navigation vim hjkl, thème frappé, clipboard OSC 52.
helix (hx)
L'éditeur. Modal comme vim mais LSP intégré, zéro plugin. EDITOR par défaut.
yazi
File manager TUI ultra-rapide, preview des fichiers, écrit en Rust.
atuin
Historique shell dans SQLite, recherche full-text avec Ctrl+R. La flèche haut reste classique (--disable-up-arrow).
zoxide
z montruc saute vers le dossier le plus fréquenté qui matche. Remplace cd à 90%.
eza · bat · fd · rg
Les remplaçants modernes : ls, cat (avec couleurs), find et grep. Aliasés dans le zshrc.
fzf
Fuzzy finder branché sur les keybindings zsh (Ctrl+T fichiers, Alt+C dossiers).
lazygit · gh
Git en TUI + GitHub CLI (qui sert aussi de credential helper git, zéro token à gérer).
direnv · btop · bun
Env vars par dossier (.envrc), monitoring joli, et bun comme runtime/package manager JS unique.

02Les détails malins

C'est là que le setup gagne sa vie — les trucs qu'on ne trouve pas dans les tutos.

Architecture Prezto par symlinks. Les dotfiles (~/.zshrc, ~/.zprofile…) sont des symlinks vers ~/.zprezto/runcoms/. La config custom vit dans runcoms/zshrc — un seul endroit à versionner, et une mise à jour de Prezto ne casse rien.
Clipboard OSC 52 à travers tmux + mosh. Copier dans tmux sur le serveur → ça atterrit dans le presse-papier de la machine locale, même via mosh. Le secret est une ligne terminal-overrides avec le préfixe c; qu'exige mosh 1.4 et un %p1%.0s qui satisfait la validation ncurses de tmux 3.4+. Cette ligne a coûté des heures, elle est dans le prompt.
Les pièges Ubuntu. Sur Ubuntu, bat s'installe comme batcat et fd comme fdfind — le zshrc crée les alias automatiquement, seulement s'il le faut. Pareil pour fzf : les keybindings se sourcent depuis /usr/share/doc/fzf/examples/.
Clipboard distant via Tailscale (optionnel, niveau boss). Un faux wl-copy dans ~/bin/ forwarde vers un serveur lemonade qui tourne sur le Mac, par le tailnet. Helix (avec clipboard-provider = "wayland") et yazi copient donc… dans le presse-papier du Mac, depuis un serveur headless. Marqué optionnel dans le prompt.
Le prompt Powerlevel10k ne se copie pas : le fichier ~/.p10k.zsh est généré par un assistant interactif. À la première ouverture de session zsh, lance p10k configure et réponds aux questions (2 minutes, avec aperçu en live). C'est le seul truc que l'agent ne fera pas pour toi.

03Le prompt à donner à Claude

Tous les fichiers de config sont embarqués verbatim dans le prompt (inventoriés depuis le vrai serveur) — l'agent n'a rien à inventer, juste à exécuter. Colle ça dans Claude Code sur ton serveur Ubuntu.

Installe et configure mon environnement terminal complet sur ce serveur Ubuntu. Procède étape par étape, vérifie chaque étape avant de passer à la suivante, et utilise les fichiers de config fournis VERBATIM à la fin de ce prompt (écris-les exactement tels quels, sauf mention contraire).

## Étape 1 : paquets apt
sudo apt update puis installe : zsh git curl unzip tmux fzf ripgrep bat fd-find btop direnv
Note Ubuntu : bat s'installe sous le nom batcat et fd sous fdfind — c'est normal, le zshrc fourni crée les alias.

## Étape 2 : outils modernes (hors apt)
- eza : via le repo officiel deb.gierens.de (instructions sur github.com/eza-community/eza), sinon cargo install eza
- zoxide : curl -sSf https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
- atuin : curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
- bun : curl -fsSL https://bun.sh/install | bash
- helix : sudo add-apt-repository ppa:maveonair/helix-editor && sudo apt install helix (sinon dernière release GitHub)
- yazi : dernière release GitHub (binaire x86_64-unknown-linux-musl), binaires yazi et ya dans ~/.local/bin
- lazygit : dernière release GitHub, binaire dans ~/.local/bin
- gh (GitHub CLI) : repo apt officiel de GitHub (cli.github.com), puis je ferai gh auth login moi-même
Vérifie chaque outil avec --version après installation.

## Étape 3 : zsh par défaut + Prezto + Powerlevel10k
1. git clone --recursive https://github.com/sorin-ionescu/prezto.git ~/.zprezto
2. Crée les symlinks runcoms (boucle standard Prezto) : pour chaque fichier zlogin zlogout zprofile zshenv zshrc dans ~/.zprezto/runcoms/, fais ln -s vers ~/.<nom> (supprime/sauvegarde les fichiers existants d'abord).
3. REMPLACE ensuite le contenu de ~/.zprezto/runcoms/zshrc par le fichier « zshrc » fourni plus bas (c'est le fichier réel derrière le symlink ~/.zshrc — c'est voulu, un seul endroit à maintenir).
4. Écris ~/.zpreztorc avec le fichier « zpreztorc » fourni plus bas. Le thème powerlevel10k est inclus dans Prezto, rien d'autre à installer.
5. chsh -s $(which zsh)
6. Dis-moi à la fin de lancer p10k configure à ma première connexion (config interactive, ne tente pas de la générer).

## Étape 4 : tmux + thème Catppuccin
1. mkdir -p ~/.tmux/plugins
2. git clone https://github.com/catppuccin/tmux ~/.tmux/plugins/tmux
3. git clone https://github.com/tmux-plugins/tmux-battery ~/.tmux/plugins/tmux-battery
4. Écris ~/.tmux.conf avec le fichier « tmux.conf » fourni plus bas, verbatim — surtout la ligne terminal-overrides Ms=\\E]52;… (avec les doubles backslashes) : elle fait marcher le presse-papier OSC 52 à travers tmux ET mosh, ne la « corrige » pas.

## Étape 5 : configs helix + yazi
1. Écris ~/.config/helix/config.toml avec le fichier « helix » fourni plus bas. ATTENTION : remplace la ligne clipboard-provider = "wayland" — elle ne sert que pour le setup lemonade optionnel (étape 7). Sans lemonade, supprime cette ligne (helix utilisera son fallback).
2. Écris ~/.config/yazi/yazi.toml avec le fichier « yazi » fourni plus bas.

## Étape 6 : git
git config --global user.name et user.email (demande-moi les valeurs), et configure gh comme credential helper : gh auth setup-git (après mon gh auth login).

## Étape 7 (OPTIONNEL — seulement si je le demande) : clipboard distant via Tailscale
Sur ma machine locale tourne un serveur lemonade (github.com/lemonade-command/lemonade). Sur ce serveur : installe lemonade (go install github.com/lemonade-command/lemonade@latest), crée ~/bin/wl-copy et ~/bin/wl-paste qui exec lemonade copy/paste --host <IP_TAILSCALE_DE_MA_MACHINE>, chmod +x. Helix (clipboard-provider = "wayland") et yazi les utiliseront automatiquement. Le zshrc fourni contient déjà le wrapper yazi() qui fake WAYLAND_DISPLAY.

## Étape 8 : vérification de bout en bout
1. zsh -ic 'echo ok' → aucune erreur au chargement
2. zsh -ic 'alias' → vérifie que ls/ll/la (eza), bat, fd, g/gs/gd sont définis
3. tmux new-session -d -s test && tmux kill-session -t test → aucune erreur (le thème catppuccin doit charger)
4. hx --health → pas d'erreur de config
5. atuin doctor (ou atuin status), zoxide --version, fzf --version, eza --version, rg --version, lazygit --version, btop --version, direnv --version, bun --version
6. Montre-moi un résumé : ce qui est installé, les versions, et ce qu'il me reste à faire à la main (chsh effectif à la prochaine connexion, p10k configure, gh auth login, atuin register si je veux la sync).

═══════════════════════════════════════════
FICHIERS DE CONFIG (VERBATIM)
═══════════════════════════════════════════

### zshrc → ~/.zprezto/runcoms/zshrc
─────────────────────────────────────
# Enable Powerlevel10k instant prompt. Keep near top of ~/.zshrc.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

# Source Prezto.
if [[ -s "${ZDOTDIR:-$HOME}/.zprezto/init.zsh" ]]; then
  source "${ZDOTDIR:-$HOME}/.zprezto/init.zsh"
fi

# ---- Editor ----
export EDITOR="hx"
export VISUAL="hx"
export PAGER="less"

# ---- PATH ----
export PATH="$HOME/.local/bin:$PATH"
export PATH="$HOME/bin:$PATH"

# Bun
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
[ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun"

# Cargo (if present)
[ -d "$HOME/.cargo/bin" ] && export PATH="$HOME/.cargo/bin:$PATH"

# Go (if present)
[ -d "/usr/local/go/bin" ] && export PATH="/usr/local/go/bin:$PATH"
[ -d "$HOME/go/bin" ] && export PATH="$HOME/go/bin:$PATH"

# ---- Tool integrations ----
# zoxide (smarter cd) — adds `z` and `zi`
command -v zoxide >/dev/null && eval "$(zoxide init zsh)"

# fzf keybindings + completion (Ubuntu paths)
[ -f /usr/share/doc/fzf/examples/key-bindings.zsh ] && source /usr/share/doc/fzf/examples/key-bindings.zsh
[ -f /usr/share/doc/fzf/examples/completion.zsh ] && source /usr/share/doc/fzf/examples/completion.zsh

# direnv
command -v direnv >/dev/null && eval "$(direnv hook zsh)"

# atuin (better history)
command -v atuin >/dev/null && eval "$(atuin init zsh --disable-up-arrow)"

# ---- Clipboard over Tailscale (lemonade) — OPTIONNEL, voir étape 7 ----
# Fake WAYLAND_DISPLAY makes yazi route clipboard through ~/bin/wl-copy,
# which forwards to the local machine's lemonade server over the tailnet.
yazi() { WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-lemonade}" command yazi "$@"; }

# ---- Aliases ----
# eza (modern ls)
if command -v eza >/dev/null; then
  alias ls="eza --group-directories-first"
  alias ll="eza -lh --group-directories-first --git --icons=auto"
  alias la="eza -lah --group-directories-first --git --icons=auto"
  alias lt="eza --tree --level=2 --icons=auto"
fi

# bat (cat with syntax highlighting) — Ubuntu installs as `batcat`
if command -v batcat >/dev/null && ! command -v bat >/dev/null; then
  alias bat="batcat"
fi

# fd (find) — Ubuntu installs as `fdfind`
if command -v fdfind >/dev/null && ! command -v fd >/dev/null; then
  alias fd="fdfind"
fi

# Git shortcuts
alias g="git"
alias gs="git status"
alias gd="git diff"
alias gl="git log --oneline --graph --decorate -20"
alias gco="git checkout"
alias gp="git pull"
alias gP="git push"

# Misc
alias ..="cd .."
alias ...="cd ../.."
alias rm="rm -i"

# ---- History ----
HISTSIZE=100000
SAVEHIST=100000
HISTFILE="$HOME/.zsh_history"
setopt SHARE_HISTORY HIST_IGNORE_ALL_DUPS HIST_IGNORE_SPACE HIST_REDUCE_BLANKS

# ---- Source p10k config if present ----
[[ -f ~/.p10k.zsh ]] && source ~/.p10k.zsh

# ---- Local overrides ----
[[ -f ~/.zshrc.local ]] && source ~/.zshrc.local

### zpreztorc → ~/.zpreztorc
─────────────────────────────────────
zstyle ":prezto:*:*" case-sensitive "no"
zstyle ":prezto:*:*" color "yes"
zstyle ":prezto:load" pmodule \
  "environment" \
  "terminal" \
  "editor" \
  "history" \
  "directory" \
  "spectrum" \
  "utility" \
  "completion" \
  "git" \
  "ssh" \
  "history-substring-search" \
  "autosuggestions" \
  "syntax-highlighting" \
  "prompt"
zstyle ":prezto:module:prompt" theme "powerlevel10k"
zstyle ":prezto:module:editor" key-bindings "emacs"
zstyle ":prezto:module:editor" dot-expansion "yes"
zstyle ":prezto:module:syntax-highlighting" highlighters \
  "main" "brackets" "pattern" "line" "cursor" "root"
zstyle ":prezto:module:autosuggestions:color" found "fg=8"
zstyle ":prezto:module:history-substring-search" color "yes"
zstyle ":prezto:module:ssh:load" identities "id_rsa" "id_ed25519"
zstyle ":prezto:module:terminal" auto-title "yes"
zstyle ":prezto:module:terminal:window-title" format "%n@%m: %~"
zstyle ":prezto:module:terminal:tab-title" format "%m: %s"

### tmux.conf → ~/.tmux.conf
─────────────────────────────────────
# ── General ──────────────────────────────────────────
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
set -g history-limit 50000
set -g escape-time 0
set -g focus-events off
set -g status-interval 5
set -g set-clipboard on
set -g allow-passthrough on

# ── OSC 52 clipboard (works through mosh) ─────────────
# Force the "c;" selection prefix that mosh 1.4.0 requires.
# %p1%.0s consumes tmux's selection param without printing it,
# satisfying ncurses validation in tmux 3.4+.
set -ag terminal-overrides ",xterm-256color:Ms=\\E]52;c%p1%.0s;%p2%s\\7"

# ── Copy-mode bindings (mouse + keyboard) ─────────────
# Do NOT auto-copy when mouse drag ends (we copy explicitly)
unbind -T copy-mode MouseDragEnd1Pane
# Clicking in copy-mode clears selection (does not exit copy-mode)
unbind -T copy-mode MouseDown1Pane
bind -T copy-mode MouseDown1Pane select-pane \; send-keys -X clear-selection
# Double/triple click: select word/line (both from root and copy-mode)
bind-key -T root DoubleClick1Pane select-pane -t = \; if-shell -F "#{||:#{pane_in_mode},#{mouse_any_flag}}" { send-keys -M } { copy-mode -H ; send-keys -X select-word }
bind-key -T root TripleClick1Pane select-pane -t = \; if-shell -F "#{||:#{pane_in_mode},#{mouse_any_flag}}" { send-keys -M } { copy-mode -H ; send-keys -X select-line }
bind -T copy-mode DoubleClick1Pane select-pane \; send-keys -X select-word
bind -T copy-mode TripleClick1Pane select-pane \; send-keys -X select-line
# Ctrl+Shift+C in copy-mode: copy selection to clipboard via OSC 52
bind -T copy-mode C-S-c send-keys -X copy-pipe-and-cancel
# 'r' toggles rectangular selection; 'R' refreshes pane content
bind -T copy-mode r send-keys -X rectangle-toggle
bind -T copy-mode R send-keys -X refresh-from-pane
# Visual: reverse video for selected text in copy-mode
setw -g mode-style "reverse"

# ── Key fixes ──────────────────────────────────────────
set -s extended-keys on
set -as terminal-features 'xterm*:extkeys'

# ── Prefix ───────────────────────────────────────────
# Ctrl+a instead of Ctrl+b (easier to reach)
unbind C-b
set -g prefix C-a
bind C-a send-prefix

# ── Splits ───────────────────────────────────────────
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"
bind x kill-pane

# ── Navigation (vim-style) ───────────────────────────
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# ── Resize panes ─────────────────────────────────────
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# ── Reload config ────────────────────────────────────
bind r source-file ~/.tmux.conf \; display "Config reloaded!"

# ── Catppuccin theme ─────────────────────────────────
# Options BEFORE loading the plugin
set -g @catppuccin_flavor "frappe"
set -g @catppuccin_window_status_style "slanted"
set -g @catppuccin_window_default_text " #W"
set -g @catppuccin_window_current_text " #W"
set -g @catppuccin_date_time_text " %d/%m %H:%M"
set -g @catppuccin_directory_text " #{pane_current_path}"
set -g @catppuccin_status_background "#{@thm_bg}"

# Load the plugin
run ~/.tmux/plugins/tmux/catppuccin.tmux

# Status bar (AFTER loading the plugin)
set -g status-position bottom
set -g status-left-length 100
set -g status-right-length 100
set -g status-left "#{E:@catppuccin_status_session}"

# Load battery plugin
run ~/.tmux/plugins/tmux-battery/battery.tmux
set -gF status-right "#{E:@catppuccin_status_directory}#{E:@catppuccin_status_battery}#{E:@catppuccin_status_date_time}"

### helix → ~/.config/helix/config.toml
─────────────────────────────────────
theme = "catppuccin_frappe"

[editor]
line-number = "relative"
mouse = false
bufferline = "multiple"
color-modes = true
cursorline = true
true-color = true
auto-save = true
clipboard-provider = "wayland"   # ← SUPPRIMER cette ligne sans le setup lemonade (étape 7)

[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "underline"

[editor.statusline]
left = ["mode", "spinner", "file-name", "file-modification-indicator"]
center = []
right = ["diagnostics", "selections", "position", "file-encoding", "file-line-ending", "file-type"]

[editor.lsp]
display-messages = true
display-inlay-hints = true

[editor.indent-guides]
render = true
character = "╎"

[editor.file-picker]
hidden = false

### yazi → ~/.config/yazi/yazi.toml
─────────────────────────────────────
[mgr]
show_hidden = true
sort_by = "natural"
sort_dir_first = true