A comprehensive guide to optimizing Arch Linux + Hyprland as an AI coding workstation for Claude Code and Codex power users
The essential keybinds and commands you need every day. Print this, tape it to your monitor, and burn it into muscle memory.
All tmux commands use the Ctrl + b prefix, then press the action key.
claude
Launch Claude Code in interactive mode in the current directory
claude -p "prompt"
Run a single prompt and exit; great for scripting and pipelines
/init
Create a CLAUDE.md with project context for better results
Shift+Tab
Accept all pending file changes at once
Esc
Stop the current generation mid-stream
# (in prompt)
Reference files, URLs, or other context in your message
codex
Launch Codex in interactive mode in the current directory
codex "prompt"
Run a single prompt directly from the command line
codex --full-auto
Let Codex run without manual approval for each step
codex --model MODEL
Choose a specific model for the session
btop
Beautiful resource monitor: CPU, memory, disks, network, processes
nvtop
GPU usage, temperature, VRAM, and running processes (NVIDIA/AMD/Intel)
journalctl -f
Stream system journal logs in real time; invaluable for debugging
systemctl --user status
Check status of user-level systemd services
A minimal, reproducible package selection for a Hyprland-powered AI development workstation. Install only what you need, keep it lean.
These are the essential packages for a functional Hyprland desktop. Install them first.
# Core Hyprland stack
sudo pacman -S --needed hyprland hyprpaper hyprlock hypridle \
waybar wofi dunst xdg-desktop-portal-hyprland
| Package | Role |
|---|---|
| hyprland | Dynamic tiling Wayland compositor -- the core of the setup |
| hyprpaper | Wallpaper daemon with per-monitor support |
| hyprlock | GPU-accelerated screen locker with custom widgets |
| hypridle | Idle daemon -- triggers lock/suspend on inactivity |
| waybar | Highly customizable status bar (workspaces, clock, tray, etc.) |
| wofi | Wayland-native application launcher (or use rofi-wayland from AUR for more theming) |
| dunst | Lightweight notification daemon (or swaync for a richer notification center) |
| xdg-desktop-portal-hyprland | Screen sharing, file dialogs, and app integration portal |
Your terminal is where you'll spend 90% of your time. Choose one.
# Recommended: Kitty (GPU-accelerated, splits, images, ligatures)
sudo pacman -S --needed kitty
# Alternative: Foot (lighter, simpler, still fast)
sudo pacman -S --needed foot
Kitty is the preferred choice for AI coding workflows. Its native split support means you can have Claude Code running in one pane and your editor in another without needing tmux for simple layouts. It also renders inline images, which is useful for reviewing generated charts and diagrams.
Many useful tools live in the AUR. You need a helper to build and install them.
# Install paru (recommended, Rust-based, fast)
sudo pacman -S --needed base-devel git
git clone https://aur.archlinux.org/paru.git
cd paru && makepkg -si
# Alternative: yay (Go-based, also popular)
git clone https://aur.archlinux.org/yay.git
cd yay && makepkg -si
Essential compilers, runtimes, and version managers for daily development work.
# Core development tools
sudo pacman -S --needed git base-devel
# Languages & runtimes
sudo pacman -S --needed nodejs npm python python-pip rustup go
# Initialize Rust toolchain
rustup default stable
The --needed flag tells pacman to skip packages that are already installed and up-to-date. This makes your install commands idempotent -- safe to re-run without reinstalling everything. Always use it in scripts and dotfiles.
Install the AI CLI tools that make this workstation special.
# Claude Code (Anthropic's CLI)
npm install -g @anthropic-ai/claude-code
# Codex CLI (OpenAI's CLI) -- via npm
npm install -g @openai/codex
# Codex CLI -- alternatively via pip
pip install openai-codex
# Verify installations
claude --version
codex --version
Both tools require API keys. Set ANTHROPIC_API_KEY for Claude Code and OPENAI_API_KEY for Codex in your shell profile (~/.zshrc or ~/.bashrc). Never commit these to git -- use a secrets manager or encrypted .env file.
Clipboard, screenshots, screen recording, and hardware control utilities for a complete Wayland desktop.
# System utilities for a complete Wayland workstation
sudo pacman -S --needed btop nvtop wl-clipboard cliphist \
grim slurp wf-recorder brightnessctl playerctl \
tailscale openssh
| Package | Role |
|---|---|
| btop | Resource monitor with CPU, RAM, disk, network graphs |
| nvtop | GPU monitor for NVIDIA, AMD, and Intel GPUs |
| wl-clipboard | Command-line clipboard access (wl-copy / wl-paste) |
| cliphist | Clipboard history manager -- search and reuse past copies |
| grim | Screenshot tool for Wayland compositors |
| slurp | Region selector for screenshots (pairs with grim) |
| wf-recorder | Screen recorder for Wayland (h264/h265 output) |
| brightnessctl | Backlight and LED brightness control |
| playerctl | MPRIS media player control from the command line |
Replace legacy Unix tools with modern alternatives that offer better defaults, color output, and AI-friendly features.
# Modern replacements for classic Unix tools
sudo pacman -S --needed eza bat ripgrep fd zoxide fzf \
git-delta starship atuin direnv dust procs tokei lazygit
| Modern Tool | Replaces | Why It's Better |
|---|---|---|
eza |
ls |
Icons, git status, tree view, color-coded file types |
bat |
cat |
Syntax highlighting, line numbers, git integration |
ripgrep |
grep |
10-50x faster, respects .gitignore, regex by default |
fd |
find |
Simpler syntax, respects .gitignore, parallel execution |
zoxide |
cd |
Frecency-based directory jumping (z project instead of cd ~/long/path/to/project) |
git-delta |
diff |
Side-by-side diffs, syntax highlighting, line numbers |
starship |
bash/zsh prompt | Cross-shell prompt with git, language, and context info |
atuin |
history |
Encrypted, searchable shell history synced across machines |
lazygit |
git (interactive) |
Full TUI git client with staging, branching, rebasing |
dust |
du |
Visual disk usage with tree chart |
# Shell aliases for muscle memory (add to ~/.zshrc)
alias ls='eza --icons'
alias ll='eza -la --icons --git'
alias tree='eza --tree --icons'
alias cat='bat --style=plain'
alias grep='rg'
alias find='fd'
alias top='btop'
alias du='dust'
alias ps='procs'
alias lg='lazygit'
# Initialize tools (add to ~/.zshrc)
eval "$(starship init zsh)"
eval "$(zoxide init zsh)"
eval "$(atuin init zsh)"
Add [core] pager = delta to your ~/.gitconfig and every git diff, git log -p, and git show gets syntax-highlighted side-by-side diffs automatically. Pair with [delta] side-by-side = true and line-numbers = true for maximum readability.
Good fonts are non-negotiable for a coding workstation. Nerd Fonts include programming ligatures and icon glyphs used by status bars and terminal prompts.
# Essential coding fonts + emoji support
sudo pacman -S --needed ttf-jetbrains-mono-nerd ttf-fira-code \
noto-fonts noto-fonts-emoji
JetBrains Mono Nerd is the best all-round terminal font. It has programming ligatures, excellent readability at small sizes, and the full Nerd Font icon set that waybar and starship use. Set it as your terminal font at 11-13px for optimal density.
For the impatient, here's everything from this section in a single copy-pasteable block.
# Complete base setup -- run after a fresh Arch install with base packages
sudo pacman -S --needed \
hyprland hyprpaper hyprlock hypridle \
waybar wofi dunst xdg-desktop-portal-hyprland \
kitty \
git base-devel nodejs npm python python-pip rustup go \
btop nvtop wl-clipboard cliphist \
grim slurp wf-recorder brightnessctl playerctl \
ttf-jetbrains-mono-nerd ttf-fira-code \
noto-fonts noto-fonts-emoji
# Initialize Rust
rustup default stable
# Install AI coding tools
npm install -g @anthropic-ai/claude-code
npm install -g @openai/codex
The heart of your workstation. Every line of this config is tuned for fast, distraction-free AI-assisted development.
# Hyprland reads its config from:
~/.config/hypr/hyprland.conf
# Create the directory if it doesn't exist
mkdir -p ~/.config/hypr
Hyprland watches its config file and reloads automatically when you save changes. No need to restart the compositor -- just save and see the results instantly. You can also force a reload with hyprctl reload.
Configure your displays. Hyprland supports per-monitor resolution, refresh rate, position, and scaling.
# === MONITORS ===
# Auto-detect single monitor (preferred resolution & refresh rate)
monitor=,preferred,auto,1
# Explicit single monitor (4K at 144Hz, no scaling)
monitor=DP-1,3840x2160@144,0x0,1
# Multi-monitor: laptop display + external monitor
monitor=eDP-1,1920x1080@60,0x0,1
monitor=DP-2,3440x1440@165,1920x0,1
# Multi-monitor: triple setup (center primary, flanking secondaries)
monitor=DP-1,2560x1440@165,0x0,1
monitor=DP-2,3840x2160@144,2560x0,1
monitor=DP-3,2560x1440@165,6400x0,1
Run hyprctl monitors to see connected displays with their names (DP-1, HDMI-A-1, eDP-1, etc.), supported resolutions, and current configuration.
These ensure Wayland compatibility across the entire desktop stack -- browsers, Qt apps, Electron apps, and screen sharing all need them.
# === ENVIRONMENT VARIABLES ===
# Core Wayland session
env = WAYLAND_DISPLAY,wayland-1
env = XDG_CURRENT_DESKTOP,Hyprland
env = XDG_SESSION_TYPE,wayland
env = XDG_SESSION_DESKTOP,Hyprland
# Application compatibility
env = MOZ_ENABLE_WAYLAND,1
env = QT_QPA_PLATFORM,wayland
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
env = GDK_BACKEND,wayland,x11
env = SDL_VIDEODRIVER,wayland
env = CLUTTER_BACKEND,wayland
# Cursor theme (set your preferred cursor here)
env = XCURSOR_SIZE,24
env = XCURSOR_THEME,Adwaita
# Electron apps (VS Code, Discord, etc.) -- Wayland on v28+
env = ELECTRON_OZONE_PLATFORM_HINT,auto
NVIDIA requires additional environment variables or you'll get flashing windows, login failures, and high CPU usage. Add these to your config:
# === NVIDIA-SPECIFIC (remove if AMD/Intel) ===
env = LIBVA_DRIVER_NAME,nvidia
env = __GLX_VENDOR_LIBRARY_NAME,nvidia
env = GBM_BACKEND,nvidia-drm
env = NVD_BACKEND,direct
env = WLR_NO_HARDWARE_CURSORS,1
# Force Vulkan backend for wgpu-based apps
env = WGPU_BACKEND,vulkan
Optimized for fast terminal typing. Higher repeat rate and lower delay mean less waiting when holding keys to navigate code.
# === INPUT ===
input {
# Keyboard layout (change to your locale)
kb_layout = us
# Remap Caps Lock to Escape -- essential for vim/neovim users
kb_options = caps:escape
# Fast key repeat for terminal navigation
# repeat_rate = keys per second after delay
# repeat_delay = ms before repeat kicks in
repeat_rate = 50
repeat_delay = 300
# Mouse / touchpad
follow_mouse = 1
sensitivity = 0
touchpad {
natural_scroll = true
tap-to-click = true
drag_lock = true
}
}
kb_options = caps:escape is the single most impactful keybind change you can make. Escape is used constantly in vim, tmux, and Claude Code (to interrupt). Moving it to Caps Lock saves your pinky finger thousands of reaches per day.
Gaps, borders, and layout behavior. Minimal gaps keep more code on screen while still providing visual separation between windows.
# === GENERAL ===
general {
# Gaps between windows and screen edges
gaps_in = 4
gaps_out = 8
# Border width and colors (thermal palette)
border_size = 2
# Active border: blue to teal gradient
col.active_border = rgba(6366f1ee) rgba(14b8a6ee) 45deg
# Inactive border: dark purple
col.inactive_border = rgba(2d1b6944)
# Layout algorithm
layout = dwindle
}
Visual effects for windows. Keep rounding minimal and shadows subtle -- this is a workstation, not a rice contest (well, mostly).
# === DECORATION ===
decoration {
# Rounded corners (subtle)
rounding = 6
# Shadow
shadow {
enabled = true
range = 12
render_power = 3
color = rgba(0a001088)
}
# Blur (for transparent terminals)
blur {
enabled = true
size = 6
passes = 2
new_optimizations = true
xray = false
}
}
Fast, snappy transitions optimized for productivity. Slow animations feel like lag when you're context-switching between AI sessions and editor panes.
# === ANIMATIONS ===
# Tuned for speed -- all transitions under 200ms
animations {
enabled = true
# Custom bezier curves
bezier = snappy, 0.25, 1, 0.5, 1
bezier = quick, 0.15, 0, 0.1, 1
# Window open/close
animation = windows, 1, 3, snappy, slide
animation = windowsOut, 1, 3, snappy, slide
# Fade for transparency changes
animation = fade, 1, 3, quick
# Workspace switching
animation = workspaces, 1, 3, snappy, slide
}
Per-application overrides for opacity, floating behavior, and workspace assignment. These rules keep your workspace organized automatically.
# === WINDOW RULES ===
# Terminal transparency (active 95%, inactive 85%)
windowrulev2 = opacity 0.95 0.85, class:^(kitty)$
windowrulev2 = opacity 0.95 0.85, class:^(foot)$
# Browser -- no transparency, slightly rounded
windowrulev2 = opacity 1.0 1.0, class:^(firefox)$
windowrulev2 = opacity 1.0 1.0, class:^(chromium)$
# File picker dialogs -- always float
windowrulev2 = float, title:^(Open File)$
windowrulev2 = float, title:^(Save As)$
windowrulev2 = float, title:^(Choose Files)$
# Pavucontrol (audio mixer) -- float, centered
windowrulev2 = float, class:^(pavucontrol)$
windowrulev2 = size 600 400, class:^(pavucontrol)$
windowrulev2 = center, class:^(pavucontrol)$
# Picture-in-picture -- small, always on top
windowrulev2 = float, title:^(Picture-in-Picture)$
windowrulev2 = pin, title:^(Picture-in-Picture)$
windowrulev2 = size 400 225, title:^(Picture-in-Picture)$
windowrulev2 = move 100%-410 100%-235, title:^(Picture-in-Picture)$
# Notification daemon -- suppress workspace change
windowrulev2 = float, class:^(dunst)$
The complete keybinding configuration. $mod is your Super/Windows/Meta key.
# === KEY BINDINGS ===
$mod = SUPER
# --- Core ---
bind = $mod, Return, exec, kitty
bind = $mod, Q, killactive
bind = $mod, M, exit
bind = $mod, D, exec, wofi --show drun
bind = $mod, F, fullscreen, 0
bind = $mod, V, togglefloating
# --- Focus ---
bind = $mod, left, movefocus, l
bind = $mod, right, movefocus, r
bind = $mod, up, movefocus, u
bind = $mod, down, movefocus, d
# --- Move windows ---
bind = $mod SHIFT, left, movewindow, l
bind = $mod SHIFT, right, movewindow, r
bind = $mod SHIFT, up, movewindow, u
bind = $mod SHIFT, down, movewindow, d
# --- Workspaces ---
bind = $mod, 1, workspace, 1
bind = $mod, 2, workspace, 2
bind = $mod, 3, workspace, 3
bind = $mod, 4, workspace, 4
bind = $mod, 5, workspace, 5
bind = $mod, 6, workspace, 6
bind = $mod, 7, workspace, 7
bind = $mod, 8, workspace, 8
bind = $mod, 9, workspace, 9
# --- Move to workspace ---
bind = $mod SHIFT, 1, movetoworkspace, 1
bind = $mod SHIFT, 2, movetoworkspace, 2
bind = $mod SHIFT, 3, movetoworkspace, 3
bind = $mod SHIFT, 4, movetoworkspace, 4
bind = $mod SHIFT, 5, movetoworkspace, 5
bind = $mod SHIFT, 6, movetoworkspace, 6
bind = $mod SHIFT, 7, movetoworkspace, 7
bind = $mod SHIFT, 8, movetoworkspace, 8
bind = $mod SHIFT, 9, movetoworkspace, 9
# --- Resize with mod + right-click drag ---
bindm = $mod, mouse:272, movewindow
bindm = $mod, mouse:273, resizewindow
# --- Screenshots ---
bind = , Print, exec, grim -g "$(slurp)" - | wl-copy
bind = SHIFT, Print, exec, grim - | wl-copy
# --- Clipboard history ---
bind = $mod, C, exec, cliphist list | wofi --dmenu | cliphist decode | wl-copy
# --- Volume control ---
binde = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
binde = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bind = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
# --- Brightness control ---
binde = , XF86MonBrightnessUp, exec, brightnessctl set +5%
binde = , XF86MonBrightnessDown, exec, brightnessctl set 5%-
Assign workspaces to specific monitors in multi-monitor setups. This keeps your mental model stable -- code is always on the center screen, browser always on the right, etc.
# === WORKSPACE RULES ===
# Assign workspaces to monitors (multi-monitor)
# Primary monitor: coding workspaces
workspace = 1, monitor:DP-2, default:true
workspace = 2, monitor:DP-2
workspace = 3, monitor:DP-2
# Left monitor: reference / docs
workspace = 4, monitor:DP-1, default:true
workspace = 5, monitor:DP-1
# Right monitor: browser / communication
workspace = 6, monitor:DP-3, default:true
workspace = 7, monitor:DP-3
# Scroll through workspaces on current monitor
bind = $mod, mouse_down, workspace, e+1
bind = $mod, mouse_up, workspace, e-1
Services and daemons that launch once when Hyprland starts. These are the background processes that make the desktop functional.
# === AUTOSTART ===
# Status bar
exec-once = waybar
# Notification daemon (pick one)
exec-once = dunst
# exec-once = swaync # alternative: richer notification center with panel
# Wallpaper (pick one)
exec-once = hyprpaper
# exec-once = swww-daemon # alternative: animated transitions + crossfade
# Clipboard listener (stores clipboard history)
exec-once = wl-paste --type text --watch cliphist store
exec-once = wl-paste --type image --watch cliphist store
# Idle daemon (lock after 5 min, suspend after 10 min)
exec-once = hypridle
# Authentication agent (for GUI sudo prompts)
exec-once = /usr/lib/polkit-kde-authentication-agent-1
# Optional: start tmux session on boot
# exec-once = kitty --class startup-term -e tmux new -s main
Use exec-once for daemons and background services -- they should only start one instance. Use exec (without -once) only for commands you want to re-run on every config reload, which is almost never what you want for services.
For a cleaner launch, use uwsm (Universal Wayland Session Manager) instead of raw exec Hyprland in your shell profile. uwsm ensures environment variables propagate correctly to systemd user units, which fixes issues where exec-once services can't see your WAYLAND_DISPLAY. Install with pacman -S uwsm, then start with uwsm start hyprland from your ~/.zprofile.
Everything above combined into a single ready-to-use hyprland.conf. Copy this to ~/.config/hypr/hyprland.conf and customize to taste.
# ~/.config/hypr/hyprland.conf
# Hyprland AI Workstation Configuration
# Optimized for Claude Code + Codex power users
# --- Monitors ---
monitor=,preferred,auto,1
# --- Environment ---
env = XDG_CURRENT_DESKTOP,Hyprland
env = XDG_SESSION_TYPE,wayland
env = XDG_SESSION_DESKTOP,Hyprland
env = MOZ_ENABLE_WAYLAND,1
env = QT_QPA_PLATFORM,wayland
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
env = GDK_BACKEND,wayland,x11
env = XCURSOR_SIZE,24
# --- Input ---
input {
kb_layout = us
kb_options = caps:escape
repeat_rate = 50
repeat_delay = 300
follow_mouse = 1
sensitivity = 0
touchpad {
natural_scroll = true
tap-to-click = true
}
}
# --- General ---
general {
gaps_in = 4
gaps_out = 8
border_size = 2
col.active_border = rgba(6366f1ee) rgba(14b8a6ee) 45deg
col.inactive_border = rgba(2d1b6944)
layout = dwindle
}
# --- Decoration ---
decoration {
rounding = 6
shadow {
enabled = true
range = 12
render_power = 3
color = rgba(0a001088)
}
blur {
enabled = true
size = 6
passes = 2
new_optimizations = true
}
}
# --- Animations ---
animations {
enabled = true
bezier = snappy, 0.25, 1, 0.5, 1
bezier = quick, 0.15, 0, 0.1, 1
animation = windows, 1, 3, snappy, slide
animation = windowsOut, 1, 3, snappy, slide
animation = fade, 1, 3, quick
animation = workspaces, 1, 3, snappy, slide
}
# --- Window Rules ---
windowrulev2 = opacity 0.95 0.85, class:^(kitty)$
windowrulev2 = opacity 1.0 1.0, class:^(firefox)$
windowrulev2 = float, title:^(Open File)$
windowrulev2 = float, title:^(Save As)$
windowrulev2 = float, class:^(pavucontrol)$
windowrulev2 = size 600 400, class:^(pavucontrol)$
windowrulev2 = center, class:^(pavucontrol)$
# --- Key Bindings ---
$mod = SUPER
bind = $mod, Return, exec, kitty
bind = $mod, Q, killactive
bind = $mod, M, exit
bind = $mod, D, exec, wofi --show drun
bind = $mod, F, fullscreen, 0
bind = $mod, V, togglefloating
bind = $mod, left, movefocus, l
bind = $mod, right, movefocus, r
bind = $mod, up, movefocus, u
bind = $mod, down, movefocus, d
bind = $mod SHIFT, left, movewindow, l
bind = $mod SHIFT, right, movewindow, r
bind = $mod SHIFT, up, movewindow, u
bind = $mod SHIFT, down, movewindow, d
bind = $mod, 1, workspace, 1
bind = $mod, 2, workspace, 2
bind = $mod, 3, workspace, 3
bind = $mod, 4, workspace, 4
bind = $mod, 5, workspace, 5
bind = $mod, 6, workspace, 6
bind = $mod, 7, workspace, 7
bind = $mod, 8, workspace, 8
bind = $mod, 9, workspace, 9
bind = $mod SHIFT, 1, movetoworkspace, 1
bind = $mod SHIFT, 2, movetoworkspace, 2
bind = $mod SHIFT, 3, movetoworkspace, 3
bind = $mod SHIFT, 4, movetoworkspace, 4
bind = $mod SHIFT, 5, movetoworkspace, 5
bind = $mod SHIFT, 6, movetoworkspace, 6
bind = $mod SHIFT, 7, movetoworkspace, 7
bind = $mod SHIFT, 8, movetoworkspace, 8
bind = $mod SHIFT, 9, movetoworkspace, 9
bindm = $mod, mouse:272, movewindow
bindm = $mod, mouse:273, resizewindow
bind = , Print, exec, grim -g "$(slurp)" - | wl-copy
bind = SHIFT, Print, exec, grim - | wl-copy
bind = $mod, C, exec, cliphist list | wofi --dmenu | cliphist decode | wl-copy
binde = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
binde = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bind = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
binde = , XF86MonBrightnessUp, exec, brightnessctl set +5%
binde = , XF86MonBrightnessDown, exec, brightnessctl set 5%-
# --- Autostart ---
exec-once = waybar
exec-once = dunst
exec-once = hyprpaper
exec-once = wl-paste --type text --watch cliphist store
exec-once = wl-paste --type image --watch cliphist store
exec-once = hypridle
Your terminal is the cockpit of the AI workstation. Choose the right emulator, configure it for maximum output density, and set up multiplexing for multi-agent workflows.
Three terminals dominate the Wayland AI coding landscape. Each has a distinct philosophy and sweet spot.
| Terminal | Rendering | Multiplexing | Config Format | Best For |
|---|---|---|---|---|
| kitty | GPU (OpenGL) fastest | Built-in splits, tabs, kitty @ IPC |
Custom (kitty.conf) |
Power users who want everything in one app |
| foot | CPU (Wayland-native) | None (pair with tmux) | INI (foot.ini) |
Minimalists, tmux-centric workflows |
| alacritty | GPU (OpenGL/Vulkan) | None (pair with tmux) | TOML (alacritty.toml) |
Cross-platform users, simple setups |
kitty is the optimal choice for AI coding on Hyprland. Its built-in multiplexing means you can split panes without tmux for simple layouts, the kitty @ IPC lets you script pane creation from the shell, and its image protocol renders inline graphics from AI tools. For multi-agent orchestration, pair any terminal with tmux.
A battle-tested ~/.config/kitty/kitty.conf tuned for long AI output sessions, fast rendering, and Wayland integration.
# --- Typography ---
font_family JetBrainsMono Nerd Font
font_size 13.0
bold_font auto
italic_font auto
# --- Thermal-Inspired Colors ---
background #0a0010
foreground #c4b5fd
selection_background #22143d
selection_foreground #e9e0ff
cursor #22c55e
cursor_shape beam
# --- Performance ---
repaint_delay 6
input_delay 1
sync_to_monitor yes
# --- Scrollback for Long AI Outputs ---
scrollback_lines 50000
scrollback_pager_history_size 100
# --- Window Management ---
enabled_layouts splits,stack
window_padding_width 8
hide_window_decorations yes
# --- Wayland-Specific ---
wayland_titlebar_color background
linux_display_server wayland
# --- Quick Splits (use instead of tmux for simpler setups) ---
map ctrl+shift+enter new_window_with_cwd
map ctrl+shift+] next_window
map ctrl+shift+[ previous_window
map ctrl+shift+f toggle_layout stack
When running multiple AI agents simultaneously, tmux provides the session persistence and scriptable pane management you need. This config is tuned for Wayland clipboard integration and thermal-colored UI.
# --- Core Settings ---
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",*:RGB"
set -g mouse on
set -g history-limit 100000
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
# --- Fast Escape for Vim/Neovim ---
set -sg escape-time 0
# --- Wayland Clipboard Integration ---
set -g copy-command 'wl-copy'
bind -T copy-mode-vi y send -X copy-pipe-and-cancel 'wl-copy'
bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel 'wl-copy'
# --- Paste from Wayland Clipboard ---
bind p run 'wl-paste | tmux load-buffer - && tmux paste-buffer'
# --- Status Bar (Thermal Theme) ---
set -g status-style 'bg=#120822 fg=#7c6faa'
set -g status-left '#[fg=#22c55e,bold][ #S ] '
set -g status-right '#[fg=#6366f1]#(date +"%H:%M") #[fg=#14b8a6]| #H'
set -g status-left-length 30
# --- Pane Borders (Thermal Colors) ---
set -g pane-border-style 'fg=#2d1b69'
set -g pane-active-border-style 'fg=#14b8a6'
# --- AI Coding Layout Shortcut ---
# Ctrl+b then A = create AI coding layout
bind A split-window -h -p 40 \; \
split-window -v -p 50 \; \
select-pane -t 0 \; \
send-keys 'claude' Enter \; \
select-pane -t 1 \; \
send-keys 'nvim .' Enter \; \
select-pane -t 2 \; \
send-keys 'btop' Enter
AI agents produce massive output -- a single Claude Code session can easily generate thousands of lines of code, diffs, and explanations. Setting history-limit to 100000 ensures you can scroll back through an entire coding session without losing context. The memory cost is negligible on a modern workstation.
Pre-built tmux session recipes for common AI coding scenarios. Copy these into shell scripts or aliases for instant workspace setup.
Run Claude Code and Codex side-by-side to compare approaches on the same task.
#!/bin/bash
# Dual Agent Session -- Claude Code (left) + Codex (right)
tmux new-session -d -s agents -n compare
tmux send-keys -t agents:compare 'cd ~/project && claude' Enter
tmux split-window -h -t agents:compare
tmux send-keys -t agents:compare.1 'cd ~/project && codex' Enter
tmux attach -t agents
Main pane for the AI agent, bottom panes for git log and system monitoring.
#!/bin/bash
# Monitor Session -- Agent (top) + Git log (bottom-left) + Watcher (bottom-right)
tmux new-session -d -s monitor -n dev
tmux send-keys -t monitor:dev 'cd ~/project && claude' Enter
tmux split-window -v -p 30 -t monitor:dev
tmux send-keys -t monitor:dev.1 'watch -n2 git log --oneline -20' Enter
tmux split-window -h -t monitor:dev.1
tmux send-keys -t monitor:dev.2 'cd ~/project && npm run test:watch' Enter
tmux select-pane -t monitor:dev.0
tmux attach -t monitor
Four-pane layout covering agent, editor, server, and tests.
#!/bin/bash
# Full Stack -- Agent | Editor / Server | Tests
tmux new-session -d -s fullstack -n work
tmux send-keys -t fullstack:work 'cd ~/project && claude' Enter
tmux split-window -h -p 50 -t fullstack:work
tmux send-keys -t fullstack:work.1 'cd ~/project && nvim .' Enter
tmux split-window -v -p 40 -t fullstack:work.0
tmux send-keys -t fullstack:work.2 'cd ~/project && npm run dev' Enter
tmux split-window -v -p 50 -t fullstack:work.1
tmux send-keys -t fullstack:work.3 'cd ~/project && npm test -- --watch' Enter
tmux select-pane -t fullstack:work.0
tmux attach -t fullstack
AI agents produce orders of magnitude more terminal output than manual coding. These techniques keep that output accessible and searchable.
prefix + [ then /
Enter tmux copy mode and search backward through output with regex
tmux pipe-pane -o 'cat >> ~/logs/agent-$(date +%Y%m%d).log'
Record all output from the current pane to a timestamped log file
ctrl+shift+h
Open scrollback in less or nvim for comfortable searching through long output
tmux clear-history
Flush scrollback buffer when it gets too large and slows down search
When running autonomous agents, always pipe output to a log file. If an agent makes a wrong turn at 3 AM, you need the full transcript to understand what happened. Use tmux pipe-pane or script -a ~/logs/session.log as a safety net.
Claude Code is the heart of this workstation. These configuration patterns and workflows will dramatically improve your output quality, speed, and autonomy.
CLAUDE.md is a special Markdown file that Claude Code reads at the start of every session. It gives the agent persistent context about your project -- architecture, conventions, build commands, and domain knowledge that would otherwise be lost between conversations.
| Location | Scope | Use Case |
|---|---|---|
| ./CLAUDE.md | Project-level (committed to git) | Shared conventions, build commands, architecture overview |
| ~/.claude/CLAUDE.md | User-level (all projects) | Personal preferences, global tool configs, coding style |
| ./src/CLAUDE.md | Directory-level (monorepo sections) | Subsystem-specific patterns, local conventions |
# Project Name
## Architecture
- Frontend: React + TypeScript in /src/client
- Backend: Express API in /src/server
- Database: PostgreSQL via Prisma ORM
## Build & Test
- Build: `npm run build`
- Test: `npm test` (Jest, run from root)
- Lint: `npm run lint` (ESLint + Prettier)
- Dev server: `npm run dev` (port 3000)
## Conventions
- Use named exports, not default exports
- All API routes return { data, error } shape
- Use Zod for runtime validation
- Database migrations in /prisma/migrations
## Common Patterns
- Error handling: wrap async handlers with catchAsync()
- Auth: JWT in httpOnly cookies, middleware in /src/server/auth
- Tests: colocate test files as *.test.ts next to source
Run /init inside Claude Code to auto-generate a starter CLAUDE.md from your project structure. Then refine it manually -- the more specific your context, the fewer mistakes the agent makes.
Claude Code has a finite context window. Every file, every conversation turn, every tool output consumes tokens. Managing context is the single most impactful skill for productive AI coding.
/compact
Compress the conversation history when context gets large, preserving key decisions and losing verbose output
# filename.ts
Reference a file in your prompt to pull it into context without reading it manually
# https://docs.example.com/api
Pull documentation or web content directly into context for reference
/clear
Reset the conversation entirely when context is polluted or you are changing tasks
Create a .claudeignore file (same syntax as .gitignore) to prevent large or irrelevant files from being pulled into context.
# Dependencies
node_modules/
vendor/
.venv/
# Build artifacts
dist/
build/
*.min.js
*.min.css
# Large data files
*.sql
*.csv
*.sqlite
# Media
*.mp4
*.png
*.jpg
Claude Code asks permission before running commands or modifying files. For trusted workflows, allowlists let you pre-approve specific tools so the agent can work autonomously.
| Mode | Flag | Behavior |
|---|---|---|
| Default | (none) | Ask permission for every tool use -- safest, most interactive |
| Allowlist | --allowedTools |
Pre-approve specific tools, ask for the rest -- best balance |
| Full Auto | --dangerously-skip-permissions |
Skip all permission checks -- use only in disposable sandboxes |
claude --allowedTools "Read,Write,Edit,Glob,Grep,Bash(git *),Bash(npm test),Bash(npm run *)"
claude --allowedTools "Read,Write,Edit,Glob,Grep,Bash(git *),Bash(npm *),Bash(cargo *),Bash(python *),Agent"
--dangerously-skip-permissions means Claude can run any shell command without asking. Only use this inside Docker containers, disposable VMs, or CI pipelines where the worst case is a rebuild. On your workstation, use allowlists instead.
Hooks let you run custom commands before or after Claude Code uses a tool. Use them for auto-formatting, linting, notifications, and custom integrations.
Get a dunst notification when a long-running agent task finishes.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Stop",
"command": "notify-send 'Claude Code' 'Agent finished working' --icon=terminal --urgency=normal"
}
]
}
}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
}
Hooks run synchronously -- they block Claude from proceeding until the command finishes. Keep hook commands fast (under 2 seconds). For slow operations like full test suites, trigger them asynchronously with & at the end of the command.
The Model Context Protocol (MCP) extends Claude Code with external tool servers. MCP servers give the agent access to databases, APIs, file systems, and custom tools beyond its built-in capabilities.
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here"
}
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
}
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/docs"]
}
}
}
@modelcontextprotocol/server-github
Create PRs, read issues, search repos, manage branches directly from Claude
@modelcontextprotocol/server-postgres
Query databases, inspect schemas, run migrations with natural language
@modelcontextprotocol/server-filesystem
Give Claude access to directories outside the project root (docs, configs)
Claude Code supports multiple models with different cost/capability tradeoffs. Switch models mid-conversation with /model to match the complexity of each sub-task.
| Model | Thermal Rating | Best For | Context |
|---|---|---|---|
| Opus | searing | Complex architecture, large refactors, multi-file changes, subtle bugs | 200K tokens |
| Sonnet | warm | Routine coding, quick edits, test writing, documentation | 200K tokens |
| Haiku | cool | Simple lookups, explanations, formatting, boilerplate generation | 200K tokens |
/model
/config
Start complex tasks with Opus for the architecture and design phase, then switch to Sonnet for implementation. Use /compact before switching models to avoid wasting the expensive model's tokens on stale context. This hybrid approach can cut API costs by 50%+ while maintaining quality where it matters.
Run multiple AI agents in parallel on the same codebase. Git worktrees isolate each agent's changes, tmux manages the sessions, and disciplined branching keeps everything mergeable.
OpenAI's Codex CLI is a terminal-native coding agent. It complements Claude Code by offering a different model family and a sandbox-first approach to file modifications.
# Install globally via npm
npm install -g @openai/codex
# Verify installation
codex --version
# Set your API key (add to ~/.zshrc)
export OPENAI_API_KEY="sk-your-key-here"
| Mode | Flag | Behavior |
|---|---|---|
| Suggest | (default) | Shows proposed changes, asks for approval before applying |
| Auto-Edit | --auto-edit |
Applies file edits automatically, asks before shell commands |
| Full Auto | --full-auto |
Runs everything in a sandbox without asking -- network disabled |
# Use GPT-4.1 for complex tasks
codex --model gpt-4.1 "refactor the auth module to use JWT"
# Use o4-mini for quick edits (faster, cheaper)
codex --model o4-mini "add error handling to the API routes"
# Codex reads these files for project context (similar to CLAUDE.md)
# Create one of these in your project root:
~/.codex/instructions.md # Global instructions
./codex.md # Project-level instructions
./.codex/instructions.md # Project-level (alternative)
The key insight: each agent needs its own working directory to avoid file conflicts. If two agents edit the same file simultaneously, you get corruption. Git worktrees solve this elegantly.
# From your main project directory
cd ~/project
# Create worktrees for parallel agents
git worktree add ../project-claude -b feature/claude-refactor
git worktree add ../project-codex -b feature/codex-tests
# Launch agents in separate tmux panes
tmux new-session -d -s parallel -n agents
tmux send-keys -t parallel:agents 'cd ~/project-claude && claude' Enter
tmux split-window -h -t parallel:agents
tmux send-keys -t parallel:agents.1 'cd ~/project-codex && codex --full-auto' Enter
tmux attach -t parallel
Two agents in the same directory will overwrite each other's changes. Always use separate worktrees or separate clones. This is the number one mistake in multi-agent setups -- it looks like it works until you lose an hour of agent output to a silent conflict.
Git worktrees let you check out multiple branches simultaneously in different directories, all sharing the same .git history. This is the foundation of parallel agent workflows.
git worktree add <path> -b <branch>
Create a new worktree at the given path with a new branch
git worktree list
Show all worktrees with their paths, branches, and HEAD commits
git worktree remove <path>
Clean up a worktree after merging the agent's branch
git worktree prune
Remove worktree references for directories that no longer exist
#!/bin/bash
# 1. Create worktrees for two parallel features
git worktree add ../project-auth -b feature/auth-refactor
git worktree add ../project-tests -b feature/test-coverage
# 2. Run agents (in separate tmux panes or terminals)
# Pane 1:
cd ../project-auth && claude "refactor auth to use JWT with refresh tokens"
# Pane 2:
cd ../project-tests && codex --full-auto "add unit tests for all API routes, aim for 80% coverage"
# 3. When agents finish, review and merge
cd ~/project
git merge feature/auth-refactor
git merge feature/test-coverage
# 4. Clean up worktrees
git worktree remove ../project-auth
git worktree remove ../project-tests
git branch -d feature/auth-refactor feature/test-coverage
Git prevents the same branch from being checked out in multiple worktrees simultaneously. This is a feature, not a bug -- it prevents the exact kind of conflicts that would corrupt your work. Each agent gets its own branch, always.
Strategic patterns for dividing work across agents. The right pattern depends on task decomposability and how much the subtasks overlap in files.
| Pattern | Agents | When to Use | Merge Risk |
|---|---|---|---|
| Divide & Conquer | 2-4 agents on independent modules | Features touch different files/directories | low |
| Review Chain | Agent 1 writes → Agent 2 reviews | High-stakes code that needs a second opinion | low |
| Research + Implement | Sonnet researches → Opus implements | Unfamiliar domains where you need to explore first | low |
| Parallel Features | Each agent on a separate feature branch | Sprint-style work with multiple independent stories | medium |
| Competitive | 2 agents solve the same problem differently | Architecture decisions where you want to compare approaches | none (pick one) |
Claude Code's Agent tool spawns subagents within a single session for parallel work. Use it for tasks like "search the codebase for all uses of X while I continue editing Y." Add Agent to your allowlist to enable it: --allowedTools "...,Agent".
When two agents touch overlapping files, merge conflicts are inevitable. The key is minimizing their frequency and having a clean resolution strategy.
# After a failed merge, let Claude resolve it
git merge feature/agent-2
# CONFLICT in src/api/routes.ts
# Open Claude in the conflicted repo
claude "resolve the merge conflicts in all files. Read both versions \
carefully and combine the best from each approach. Run tests after resolving."
# See all conflicted files
git diff --name-only --diff-filter=U
# For each file, review both sides
git diff --merge HEAD...feature/agent-2 -- src/api/routes.ts
# After resolving
git add -A
git commit -m "merge: combine auth refactor and test improvements"
A side-by-side comparison to help you decide which agent to deploy for each task.
| Feature | Claude Code | Codex CLI |
|---|---|---|
| Provider | Anthropic | OpenAI |
| Models | Opus, Sonnet, Haiku | GPT-4.1, o4-mini, o3 |
| Install | npm i -g @anthropic-ai/claude-code |
npm i -g @openai/codex |
| Project Context | CLAUDE.md |
codex.md or instructions.md |
| Sandbox | Permission allowlists | Full sandbox (network disabled in full-auto) |
| Tool Use | Read, Write, Edit, Bash, Glob, Grep, Agent, MCP | Shell commands, file I/O (sandboxed) |
| MCP Support | Yes (extensible via MCP servers) | No |
| Subagents | Yes (Agent tool) | No |
| Mid-Session Model Switch | Yes (/model) |
No (set at launch) |
| Hooks | Yes (pre/post tool use) | No |
| Best Strength | Complex multi-file refactors, architecture | Fast sandboxed edits, autonomous batch jobs |
These tools are complementary, not competing. Use Claude Code as your primary agent for architecture, complex reasoning, and interactive development. Deploy Codex for batch tasks, quick autonomous fixes, and as a second opinion. The dual-agent tmux layout from Section 04 makes this workflow seamless.
Organize your Hyprland workspaces into dedicated zones for coding, browsing, communication, and monitoring. A disciplined workspace model eliminates context-switching friction and keeps your agents front and center.
Dedicate each Hyprland workspace to a single concern. This keeps your primary coding environment distraction-free while giving every tool a predictable home.
| Workspace | Name | Purpose |
|---|---|---|
| SUPER+1 | code | Primary editor / agent workspace — this is where Claude Code lives |
| SUPER+2 | agent | Second agent or Codex CLI on a worktree |
| SUPER+3 | web | Firefox / Chromium for docs, PRs, API references |
| SUPER+4 | comm | Slack, Discord, email |
| SUPER+5 | mon | btop, nvtop, journalctl, waybar dashboard |
| SUPER+6 | scratch | Throwaway terminals, quick tests, file managers |
# Workspace assignments
windowrulev2 = workspace 3 silent, class:^(firefox)$
windowrulev2 = workspace 3 silent, class:^(chromium)$
windowrulev2 = workspace 4 silent, class:^(Slack)$
windowrulev2 = workspace 4 silent, class:^(discord)$
# Workspace names (for waybar)
workspace = 1, name:code
workspace = 2, name:agent
workspace = 3, name:web
workspace = 4, name:comm
workspace = 5, name:mon
workspace = 6, name:scratch
Waybar is the de-facto status bar for Hyprland. Configure it to show workspace names, system metrics, and thermal readings at a glance.
{
"layer": "top",
"position": "top",
"height": 32,
"modules-left": ["hyprland/workspaces", "hyprland/window"],
"modules-center": ["clock"],
"modules-right": ["cpu", "memory", "temperature", "network", "pulseaudio", "tray"],
"hyprland/workspaces": {
"format": "{icon}",
"format-icons": {
"1": "code",
"2": "agent",
"3": "web",
"4": "comm",
"5": "mon",
"6": "misc"
}
},
"cpu": { "format": "CPU {usage}%" },
"memory": { "format": "RAM {percentage}%" },
"temperature": { "format": "{temperatureC}°C" }
}
/* Waybar styling matched to thermal design system */
* {
font-family: 'JetBrainsMono Nerd Font', monospace;
font-size: 13px;
}
window#waybar {
background: #0a0010;
border-bottom: 2px solid #2d1b69;
}
#workspaces button {
color: #7c6faa;
padding: 0 8px;
}
#workspaces button.active {
color: #22c55e;
border-bottom: 2px solid #14b8a6;
}
#cpu, #memory { color: #14b8a6; }
#temperature { color: #f59e0b; }
#temperature.critical { color: #ef4444; }
You have two good choices: dunst (lightweight, config-file driven) or swaync (richer notification center with a slide-out panel and Do Not Disturb). Both work well for agent completion alerts.
# Option A: dunst (lightweight, simple)
sudo pacman -S --needed dunst
# Option B: swaync (notification center with panel)
sudo pacman -S --needed swaync
# Bind notification center toggle in hyprland.conf:
# bind = SUPER, N, exec, swaync-client -t -sw
[global]
monitor = 0
follow = keyboard
width = 350
offset = 20x20
origin = top-right
font = Rajdhani 12
frame_color = "#14b8a6"
separator_color = frame
background = "#120822"
foreground = "#c4b5fd"
[urgency_low]
background = "#120822"
foreground = "#7c6faa"
frame_color = "#2d1b69"
[urgency_normal]
background = "#120822"
foreground = "#c4b5fd"
frame_color = "#14b8a6"
[urgency_critical]
background = "#120822"
foreground = "#ef4444"
frame_color = "#ef4444"
Pair dunst with a simple wrapper script: when Claude Code exits, fire notify-send "Claude Code" "Task complete on $(pwd)". This way you can context-switch to workspace 4 (comms) without losing track of agent progress.
Go beyond basic SUPER+N workspace switching with scratchpads and quick-toggle binds.
# Special workspace (scratchpad) for quick terminal
bind = SUPER, grave, togglespecialworkspace, scratchpad
bind = SUPER SHIFT, grave, movetoworkspace, special:scratchpad
# Move focused window to another workspace
bind = SUPER SHIFT, 1, movetoworkspace, 1
bind = SUPER SHIFT, 2, movetoworkspace, 2
bind = SUPER SHIFT, 3, movetoworkspace, 3
# Named special workspaces for persistent tools
bind = SUPER, F1, togglespecialworkspace, btop
bind = SUPER, F2, togglespecialworkspace, notes
# Workspace overview (requires hyprland plugins or hyprexpo)
bind = SUPER, Tab, hyprexpo:expo, toggle
Wayland replaces X11's clipboard model entirely. Master wl-clipboard, cliphist, and screenshot tooling to keep data flowing smoothly between your agents, browser, and terminal.
wl-copy and wl-paste are the core Wayland clipboard tools. They replace xclip and xsel from the X11 era.
cat file.txt | wl-copy
Pipe file contents to clipboard
wl-paste > output.txt
Paste clipboard to file
ls -la | wl-copy
Copy command output
wl-copy < ~/.ssh/id_ed25519.pub
Copy file contents directly
wl-copy --primary
Copy to primary selection (middle-click)
wl-paste --primary
Paste from primary selection
cliphist watches your clipboard and stores a searchable history. Paired with wofi, it gives you a visual clipboard manager accessible via a single keybind.
# Start clipboard watcher on login
exec-once = wl-paste --watch cliphist store
# Bind clipboard history to SUPER+C
bind = SUPER, C, exec, cliphist list | wofi --dmenu | cliphist decode | wl-copy
cliphist list
Show all clipboard history entries
cliphist wipe
Clear entire clipboard history
cliphist list | head -5
Show 5 most recent entries
cliphist supports images in addition to text. Screenshots copied via grim are stored in history and can be re-pasted later. The default max history is 750 entries — adjust with cliphist store --max-items 1500 if you need more.
grim captures screenshots and slurp provides interactive region selection. Together they replace the full-featured screenshot tools from desktop environments.
# Full screen → clipboard
grim - | wl-copy
# Region select → clipboard
grim -g "$(slurp)" - | wl-copy
# Region select → file
grim -g "$(slurp)" ~/screenshots/$(date +%Y%m%d-%H%M%S).png
# Active window only
grim -g "$(hyprctl activewindow -j | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')" - | wl-copy
bind = , Print, exec, grim - | wl-copy
bind = SHIFT, Print, exec, grim -g "$(slurp)" - | wl-copy
bind = SUPER, Print, exec, grim -g "$(slurp)" ~/screenshots/$(date +%Y%m%d-%H%M%S).png
wf-recorder captures Wayland screen output to video files. Essential for recording agent sessions, creating demos, and debugging visual issues.
wf-recorder -f recording.mp4
Record full screen
wf-recorder -g "$(slurp)" -f recording.mp4
Record a selected region
wf-recorder --audio -f recording.mp4
Record with audio capture
pkill -INT wf-recorder
Stop recording gracefully
Practical patterns for moving data between agents, browsers, and terminals using the Wayland clipboard as glue.
wl-paste | claude -p "explain this code"
Pipe clipboard contents into Claude for quick analysis
wl-paste | claude -p "fix this error" | wl-copy
Round-trip: clipboard → agent → clipboard
wl-paste > /tmp/debug.txt
Dump clipboard to file for agent context
Copy an error from your browser console, switch to workspace 1, and run wl-paste | claude -p "explain this error and suggest a fix". The Wayland clipboard persists across workspaces, making cross-app data flow seamless without touching a mouse.
AI agents are resource-intensive processes. Tune memory, CPU scheduling, GPU compositing, and storage I/O to keep your workstation responsive even when multiple agents are hammering the API and processing large codebases.
AI agents are memory-hungry — each Claude Code session runs Node.js processes that can consume 1-4 GB of RAM. Running two agents with a browser and monitoring tools easily exceeds 16 GB.
# Install zram for compressed swap
sudo pacman -S zram-generator
# Configure compressed swap
[zram0]
zram-size = ram / 2
compression-algorithm = zstd
swap-priority = 100
zram compresses swap in RAM using zstd, which is dramatically faster than paging to disk. For AI workloads that allocate and release large buffers frequently, zram keeps the system responsive without SSD wear.
# Keep agent processes in RAM -- prefer compressing over swapping
sudo sysctl vm.swappiness=10
# Make persistent
echo "vm.swappiness=10" | sudo tee /etc/sysctl.d/99-swappiness.conf
A system with no swap and 16 GB RAM will hit the OOM killer when running two agents, a browser with 20 tabs, and btop simultaneously. The kernel will kill your agent mid-task with no warning. Always configure at least zram — it costs nothing and prevents catastrophic process termination.
Hyprland uses the GPU for compositing. Monitor GPU utilization to ensure smooth rendering alongside any local model inference.
nvtop
Interactive GPU monitor (NVIDIA, AMD, Intel)
intel_gpu_top
Intel integrated graphics monitor
radeontop
AMD GPU utilization monitor
hyprctl monitors -j | jq '.[].name'
List connected monitors
# Check GPU usage
nvtop
# Hyprland GPU info
hyprctl monitors -j | jq '.[].name'
# Force specific GPU (multi-GPU setups)
env WLR_DRM_DEVICES=/dev/dri/card1 hyprland
Give AI agents priority CPU access so they respond instantly to API results, and pin them to specific cores to avoid contention with the compositor.
# Run Claude Code with higher priority
nice -n -5 claude
# Real-time scheduling for responsive UI
sudo renice -n -10 -p $(pgrep hyprland)
# CPU affinity -- pin agents to specific cores
taskset -c 0-3 claude
taskset -c 4-7 codex
Setting negative nice values (higher priority) requires root or CAP_SYS_NICE. For a persistent setup, add your_user hard nice -10 to /etc/security/limits.conf so you can prioritize agents without sudo. Be careful not to starve system processes.
Use systemd cgroups v2 to set hard resource limits on agent processes, preventing any single runaway agent from consuming all system resources.
[Service]
MemoryMax=8G
CPUQuota=400%
IOWeight=200
# Run Claude with a 4 GB memory ceiling
systemd-run --user --scope -p MemoryMax=4G claude
# Run Codex with CPU and memory limits
systemd-run --user --scope -p MemoryMax=4G -p CPUQuota=200% codex
| Property | Example | Effect |
|---|---|---|
MemoryMax |
8G |
Hard memory limit — OOM kills the process if exceeded |
CPUQuota |
400% |
Max 4 CPU cores worth of time (percentage of one core) |
IOWeight |
200 |
I/O priority relative to default (100). Higher = more bandwidth |
MemoryHigh |
6G |
Soft limit — throttles I/O before hitting MemoryMax |
Both Claude Code and Codex are API-heavy — every keystroke can trigger network requests. Optimize DNS resolution, connection reuse, and bandwidth monitoring to minimize latency.
# Enable and start systemd-resolved
sudo systemctl enable --now systemd-resolved
# Verify DNS caching is active
resolvectl statistics
# Monitor network per-process
sudo bandwhich
# Check API latency
curl -w "%{time_total}s\n" -o /dev/null -s https://api.anthropic.com/v1/messages
curl -w "%{time_total}s\n" -o /dev/null -s https://api.openai.com/v1/chat/completions
bandwhich
Per-process bandwidth monitor with TUI
nethogs
Lightweight per-process network usage
resolvectl statistics
DNS cache hit rate and stats
Git operations on large repos, agent file I/O, and build artifacts all benefit from fast storage. An NVMe SSD is essential — spinning disks will bottleneck every agent interaction.
# Mount tmpfs for fast builds
sudo mount -t tmpfs -o size=4G tmpfs /tmp/build
# Or add to /etc/fstab for persistence
tmpfs /tmp/build tmpfs size=4G,mode=1777 0 0
# Add noatime to your root partition to reduce write overhead
# Before:
UUID=xxxx / ext4 defaults 0 1
# After:
UUID=xxxx / ext4 defaults,noatime 0 1
| Optimization | Impact | Risk |
|---|---|---|
noatime mount option |
Eliminates access-time writes on every file read | None |
tmpfs for /tmp/build |
RAM-speed builds, zero SSD wear | Data lost on reboot |
| NVMe over SATA SSD | 3-7x sequential, 10x random I/O improvement | None |
| btrfs compression | Smaller on-disk size, slight CPU overhead | Marginal CPU cost |
AI workloads generate significant disk I/O — constant git operations, file writes, and log output. Monitor your NVMe health with sudo smartctl -a /dev/nvme0n1 and check the Percentage Used field monthly. Most NVMe drives handle 600 TBW+ but heavy agent use can accelerate wear.
Your workstation is only as good as your ability to recreate it. Dotfile management turns a fragile snowflake into a reproducible, version-controlled machine definition.
Three dominant strategies exist for tracking and syncing your configuration files. Each trades off simplicity against power.
| Approach | Pros | Cons | Best For |
|---|---|---|---|
| chezmoi | Templates, secrets management, multi-machine support | Learning curve, Go dependency | Multi-device power users |
| GNU Stow | Simple symlinks, no dependencies, composable | No templating, manual sync | Single-machine, Unix purists |
| Bare Git Repo | No extra tools, pure git | Awkward commands, easy to make mistakes | Minimalists |
chezmoi is the most capable dotfile manager — it supports templates for machine-specific values, encrypted secrets, and one-command apply across multiple machines.
# Install chezmoi
sudo pacman -S chezmoi
# Initialize (creates ~/.local/share/chezmoi/)
chezmoi init
# Add your Hyprland workstation configs
chezmoi add ~/.config/hypr/hyprland.conf
chezmoi add ~/.config/kitty/kitty.conf
chezmoi add ~/.config/waybar/config.jsonc
chezmoi add ~/.config/waybar/style.css
chezmoi add ~/.config/dunst/dunstrc
chezmoi add ~/.tmux.conf
chezmoi add ~/.claude/settings.json
# Edit a managed file (opens in $EDITOR)
chezmoi edit ~/.config/hypr/hyprland.conf
# Apply changes to home directory
chezmoi apply
# Push to your dotfiles repo
chezmoi cd && git add -A && git commit -m "update configs" && git push
# Machine-specific values used in templates
monitor_primary: "DP-1"
monitor_scale: "1.5"
gpu_driver: "nvidia"
In your Hyprland config template, reference these with {{ .monitor_primary }} and chezmoi will substitute the correct value per machine.
If you prefer zero-magic simplicity, GNU Stow manages dotfiles via symlinks. Each package is a directory tree that mirrors your home directory structure.
# Create package directories mirroring home structure
mkdir -p ~/dotfiles/{hypr,kitty,waybar,tmux,claude}/.config
# Stow each package (creates symlinks into ~)
cd ~/dotfiles
stow hypr # Creates ~/.config/hypr → ~/dotfiles/hypr/.config/hypr
stow kitty
stow waybar
stow tmux
stow claude
# Remove symlinks for a package
stow -D kitty
# Re-stow (remove + re-create, useful after restructuring)
stow -R kitty
A single script that takes a bare Arch install to a fully configured Hyprland AI workstation. Run it once on a fresh machine, or use it as a reference for what to install.
#!/usr/bin/env bash
# bootstrap.sh — Hyprland AI Workstation Setup
set -euo pipefail
echo "[*] Installing core packages..."
sudo pacman -S --needed --noconfirm \
hyprland hyprpaper hyprlock hypridle \
waybar wofi dunst \
xdg-desktop-portal-hyprland \
kitty tmux \
git base-devel \
nodejs npm python python-pip \
btop wl-clipboard cliphist grim slurp \
ttf-jetbrains-mono-nerd noto-fonts \
zram-generator brightnessctl
echo "[*] Installing paru (AUR helper)..."
if ! command -v paru &>/dev/null; then
git clone https://aur.archlinux.org/paru-bin.git /tmp/paru
cd /tmp/paru && makepkg -si --noconfirm
fi
echo "[*] Installing AUR packages..."
paru -S --needed --noconfirm \
nvtop wf-recorder bandwhich
echo "[*] Installing AI tools..."
npm install -g @anthropic-ai/claude-code
npm install -g @openai/codex
echo "[*] Applying dotfiles..."
chezmoi init --apply https://github.com/YOUR_USER/dotfiles.git
echo "[*] Enabling services..."
sudo systemctl enable --now systemd-resolved
systemctl --user enable --now pipewire pipewire-pulse wireplumber
echo "[*] Setup complete! Reboot and launch Hyprland."
Every config file covered in this guide, mapped to its purpose and the section where it was introduced. Track all of these in your dotfile repo.
| File | Purpose | Section |
|---|---|---|
~/.config/hypr/hyprland.conf |
Window manager config | §03 |
~/.config/kitty/kitty.conf |
Terminal emulator | §04 |
~/.tmux.conf |
Terminal multiplexer | §04 |
~/.config/waybar/config.jsonc |
Status bar | §07 |
~/.config/waybar/style.css |
Status bar styling | §07 |
~/.config/dunst/dunstrc |
Notifications | §07 |
~/.claude/settings.json |
Claude Code settings | §05 |
~/.claude/CLAUDE.md |
Global Claude context | §05 |
project/CLAUDE.md |
Project Claude context | §05 |
.claudeignore |
Claude file exclusions | §05 |
/etc/systemd/zram-generator.conf |
Swap config | §09 |
The fastest path from bare Arch install to full AI workstation: enable SSH immediately, then let Claude Code on another device do the heavy lifting over the network.
# Phase 1: On the fresh Arch box (TTY only)
sudo pacman -S --needed openssh tailscale
sudo systemctl enable --now sshd
sudo systemctl enable --now tailscaled
sudo tailscale up
# Phase 2: From your other device (laptop, phone, etc.)
ssh builder@arch-box # or use Tailscale IP/hostname
# Phase 3: Clone dotfiles and bootstrap
git clone https://github.com/YOUR_USER/dotfiles.git ~/dotfiles
cd ~/dotfiles && ./bootstrap.sh
# Phase 4: Build any custom components
cargo build --release # if you have Rust desktop tools
# Phase 5: Reboot into Hyprland
sudo reboot
You can bootstrap an entire Hyprland desktop from your phone using Termux or PocketForge over Tailscale + SSH. Install Arch to a TTY, enable SSH + Tailscale, then run Claude Code from your phone to install packages, write configs, and build everything remotely. The phone becomes a remote control for AI-driven system building.
Tailscale creates a WireGuard mesh network between your devices with zero configuration. No port forwarding, no dynamic DNS, no firewall rules. Your phone and desktop are always one hop away on any network. Install it on every device in your toolkit.
Dotfiles without version control are just text files waiting to be lost. Treat your configs with the same discipline as production code.
# Keep dotfiles in a dedicated repo
chezmoi cd
git init
git remote add origin git@github.com:YOUR_USER/dotfiles.git
# Use branches for different machines
git checkout -b laptop
git checkout -b desktop
git checkout -b server
# Tag stable configs before major changes
git tag -a v1.0-hyprland "stable hyprland + claude setup"
git tag -a v1.1-waybar "waybar GPU module added"
# Include a README documenting each config's purpose
# Sensitive data: use chezmoi's encryption with age/gpg
chezmoi age encrypt ~/.config/secrets/api-keys.env
Always test config changes in a VM or container before applying to your production machine. A broken Hyprland config can leave you at a TTY with no graphical environment. Keep a known-good config tagged in git so you can roll back quickly.
Your ANTHROPIC_API_KEY, OPENAI_API_KEY, and any other secrets must never appear in your dotfiles repo. Use chezmoi’s built-in encryption (age or gpg), environment variables loaded from an untracked .env file, or a dedicated secrets manager like pass or 1password-cli. A single leaked key can result in thousands of dollars of unauthorized API usage within hours.