← Back to list

Wayland, starship, kitty: rebuilding a dev laptop on Ubuntu 26.04

I just rebuilt my dev laptop on a fresh Ubuntu 26.04 install. This post covers the foundation: distro, shell, and terminal. A second post…

Harpreet Dhillon · 2026-04-30 06:04 · 3 claps · 6.3 min read
#ubuntu-26 #wayland #developer-tools #developer-experience #kitty
Open on Medium ↗
Wiki topics: 🔓 · Open Source

Wayland, starship, kitty: rebuilding a dev laptop on Ubuntu 26.04

I just rebuilt my dev laptop on a fresh Ubuntu 26.04 install. This post covers the foundation: distro, shell, and terminal. A second post handles the Claude Code side.

Why Ubuntu 26.04

I only run LTS on my laptops and workstations. Five years of standard support (ten with Pro), no surprise upgrade cycles every six months, and a stable userland that other tooling can target. I’d been waiting for 26.04 since the start of the year, and “Resolute Raccoon” landed on April 23, 2026.

What pulled me in this cycle:

  • Linux 7.0 kernel, the first major version bump in a long time
  • GNOME 50 on a Wayland-only session (X11 GDM is gone; XWayland still handles legacy apps)
  • Toolchains: Python 3.14, GCC 15.2, OpenJDK 25
  • systemd 259, cgroup v1 removed entirely
  • sudo-rs (the Rust rewrite) replaces traditional sudo
  • TPM 2.0-backed full-disk encryption on by default
  • x86–64-v3 package variants for Haswell-and-newer CPUs, with measurable gains on compute-heavy work
  • Real-time kernel in main without Ubuntu Pro

The toolchain refresh and v3 binaries are the practical wins for me. The rest is good to know.

Shell foundation: from Oh My Zsh + Powerlevel10k to starship

I’ve been on Oh My Zsh + Powerlevel10k for years. P10k was the gold standard: fast, beautiful, configurable enough to disappear into the background. Active maintenance has tailed off though, and I’d been hearing for a while that starship was a faster Rust-based alternative. Single-digit milliseconds renders versus p10k’s 30 to 40 with comparable segments.

I switched on this rebuild and so far I’m loving it. Same visual style, faster cold start, one portable config file, no framework wrapping my dotfiles.

sudo apt install -y zsh
chsh -s "$(which zsh)"
curl -sS https://starship.rs/install.sh | sh

The skeleton of my ~/.zshrc:

export EDITOR="code -w"
export PATH="$HOME/.local/bin:$PATH"
export PATH="$PATH:$HOME/.cargo/bin"   # rust-installed CLI tools
# History
export HISTSIZE=100000
export SAVEHIST=$HISTSIZE
setopt SHARE_HISTORY HIST_IGNORE_ALL_DUPS HIST_IGNORE_SPACE INC_APPEND_HISTORY
# Sane defaults
setopt AUTO_CD AUTO_PUSHD EXTENDED_GLOB INTERACTIVE_COMMENTS
eval "$(starship init zsh)"   # always last

The $HOME/.cargo/bin line matters more than it looks. A lot of the best modern CLI utilities ship via cargo install and won't be on PATH without it. I had it commented out for ages and kept wondering why my newly-installed tools weren't being found.

The starship config

My ~/.config/starship.toml is a Powerlevel10k Classic clone: single-line powerline with directory, git branch, git status, optional kubernetes and python segments, and a right-aligned timestamp plus last-exit-code indicator. add_newline = false keeps it compact.

The pieces worth showing:

add_newline = false
format = """\
[](fg:#3B6E8F)$directory[](fg:#3B6E8F bg:#D7A93C)\
$git_branch$git_status[](fg:#D7A93C)\
$kubernetes$python$cmd_duration """
right_format = "$status$time"
[kubernetes]
disabled = false
symbol = "󱃾 "
contexts = [
  { context_pattern = ".*prod.*",    style = "bg:#BF616A fg:#FFFFFF bold" },
  { context_pattern = ".*staging.*", style = "bg:#D08770 fg:#FFFFFF bold" },
]
[python]
pyenv_version_name = true
detect_files = [".python-version", "requirements.txt", "pyproject.toml"]
[cmd_duration]
format = ' [⏱ $duration](fg:#EBCB8B)'
min_time = 2_000

Two segments earn their keep every shell:

  • The kubernetes segment turns red on any context matching .*prod.* and orange on .*staging.*. It's a visual circuit-breaker. I have to actively notice the colour before I run a destructive kubectl against the wrong cluster.
  • cmd_duration with min_time = 2_000 puts a clock on anything slower than two seconds. Not a hot take, but it makes slow build steps obvious without effort.

zsh plugins I keep

These do what Oh My Zsh’s framework used to do for me. Each one is a single git clone and one source line. No framework, no theme system, no startup-time tax for things I don't use.

mkdir -p ~/.my-custom-zsh && cd ~/.my-custom-zsh
git clone https://github.com/Aloxaf/fzf-tab
git clone https://github.com/zsh-users/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting
sudo apt install -y fzf direnv
cargo install zoxide atuin

Wired into .zshrc in this order (load order matters):

autoload -Uz compinit && compinit
# fzf-tab replaces zsh's tab menu with an fzf picker plus preview.
# Must load AFTER compinit and BEFORE syntax-highlighting / autosuggestions.
source ~/.my-custom-zsh/fzf-tab/fzf-tab.plugin.zsh
# Ghost-text completions from history; Ctrl+Space accepts.
source ~/.my-custom-zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
bindkey '^ ' autosuggest-accept
# Syntax highlighting must be sourced last among ZLE plugins
source ~/.my-custom-zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
eval "$(fzf --zsh)"                                # Ctrl+R, Ctrl+T, Alt+C
eval "$(atuin init zsh --disable-up-arrow)"        # SQLite history; keeps prefix-search on Up/Down
eval "$(zoxide init zsh)"                          # `z foo` smart cd
eval "$(direnv hook zsh)"                          # auto-load .envrc per directory
eval "$(starship init zsh)"                        # always last

What each one earns:

  • fzf-tab. Every tab completion becomes an fzf picker with a preview pane. cd <Tab> shows directory contents; kill <Tab> shows the process command; git checkout <Tab> shows file diffs. Once it's there, going back feels broken.
  • zsh-autosuggestions. Grey ghost completions from history as you type. Ctrl+Space accepts. Cuts out most Ctrl+R-then-edit cycles.
  • zsh-syntax-highlighting. Commands color as you type, so typos and missing files are visible before Enter.
  • atuin. Replaces zsh’s flat history file with SQLite, gives you a much richer Ctrl+R, and syncs across machines if you want. --disable-up-arrow keeps zsh's prefix-search Up/Down intact.
  • zoxide. z foo jumps to whichever directory you visit most that matches foo. After a week, plain cd feels archaic.
  • direnv. Per-project env vars in a checked-in .envrc. No more sourcing scripts by hand.

Kitty as the terminal

26.04 is Wayland-only by default. X11 GDM is gone. GNOME Terminal works fine, but kitty is built for this world and faster on every input that actually matters: scrolling long buffers, opening lots of panes, rendering ligatures and emoji. I spent some time tuning it on the new install. Here’s what that looked like.

Why kitty specifically:

  • GPU-accelerated rendering. Text goes through OpenGL, so scrollback stays smooth even on a 4K display.
  • Native Wayland. No XWayland round-trip; runs as a first-class client of the GNOME 50 / Wayland-exclusive session.
  • Splits and tabs in one process. No need for tmux for most workflows. kitty @ remote control lets scripts open new tabs in the running terminal.
  • Image protocol. Display PNGs, SVGs, charts inline with kitten icat plot.png. Useful for quick previews.
  • One plain-text config at ~/.config/kitty/kitty.conf, hot-reloadable with Ctrl+Shift+F5.

The optimization passes that mattered

Here’s the breakdown of what I tuned and why:

Highlights from ~/.config/kitty/kitty.conf

# Font
font_family       JetBrainsMono Nerd Font
font_size         12.0
disable_ligatures cursor
modify_font cell_height 1px
# Cursor
cursor_shape       beam
# Bell
enable_audio_bell    no
window_alert_on_bell yes
bell_on_tab          "🔔 "
# Scrollback
scrollback_lines              100000
scrollback_pager              less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER
scrollback_pager_history_size 10
# Clipboard / selection
copy_on_select clipboard
paste_actions  quote-urls-at-prompt,confirm-if-large,replace-dangerous-control-codes
# Wayland
linux_display_server wayland
# Performance
sync_to_monitor yes
repaint_delay   8
input_delay     2
# Splits inside a tab
enabled_layouts splits,stack,tall,fat,grid
# Shell integration
shell_integration    enabled
allow_remote_control yes
listen_on            unix:/tmp/kitty-${USER}
# Tabs and OS windows: every new spawn inherits cwd
map kitty_mod+t      new_tab_with_cwd
map kitty_mod+n      new_os_window_with_cwd
map kitty_mod+enter  launch --location=split  --cwd=current
map kitty_mod+\      launch --location=vsplit --cwd=current
map kitty_mod+-      launch --location=hsplit --cwd=current
# Pick any URL on screen via hint
map kitty_mod+e      open_url_with_hints
# Run rg via hyperlinked_grep (clickable file:line results)
map kitty_mod+r      kitten hyperlinked_grep
# Hot-reload + edit-in-place
map kitty_mod+f5     load_config_file
map kitty_mod+f2     edit_config_file
# Theme: managed by `kitten themes <name>`
# BEGIN_KITTY_THEME
# Catppuccin-Mocha
include current-theme.conf
# END_KITTY_THEME

What kitty’s shell integration buys you

This is the part that surprised me. With shell_integration enabled a fresh shell:

  • Ctrl+Shift+Z. Jumps the cursor to the previous prompt in scrollback.
  • Ctrl+Shift+X. Selects the entire output of the previous command.
  • Hold Ctrl and click any file path in the scrollback to open it in $EDITOR (mine is code -w). Same for line numbers, error stacks, URLs.
  • New tabs, splits, and OS windows inherit the shell’s current working directory automatically. The shell sends OSC 7; kitty reads it.

Combined, these make scrollback feel structured rather than like a dumb buffer.

Useful kittens (built-in, no extra install)

  • kitten themes. Browse and apply color schemes; writes to current-theme.conf and reloads in place.
  • kitten icat path/to/img.png. Inline images via the kitty graphics protocol.
  • kitten ssh user@host. Copies your kitty config and shell integration over SSH so remote shells feel like local ones.
  • kitten diff a b. Side-by-side diff with image support.
  • kitten clipboard. Read or write the system clipboard from any process: cat token | kitten clipboard.
  • kitten hyperlinked_grep. Wraps rg so output paths are clickable.

I’m running Catppuccin-Mocha (kitten themes Catppuccin-Mocha); it slots in nicely with the starship colour palette.

Dotfile management

Everything I’ve described is text: ~/.zshrc, ~/.config/starship.toml, ~/.config/kitty/kitty.conf, the ~/.my-custom-zsh/ plugin clones. I keep mine under chezmoi so the next clean install is fifteen minutes, not an afternoon. yadm and plain GNU stow are fine alternatives.

Things I deliberately don’t commit: secrets, anything that contains hostnames I don’t want public, and any state that the system regenerates on its own.

What I left behind

  • Oh My Zsh. Served me well for years. After the migration to starship plus a handful of standalone plugins, startup is faster and there’s no framework between me and my dotfiles. I don’t see myself going back.
  • Powerlevel10k. Same story: replaced by a starship.toml that does the same job in fewer lines and renders quicker.
  • GNOME Terminal. Fine if you want zero config. Kitty’s shell integration alone makes the switch worth it on 26.04’s Wayland-only stack.
  • bat, eza -l, tree without depth limits. Pretty in a terminal, noisy in a transcript when something is reading the output.

메타데이터
post_id
2f80de10bb2b
slug
wayland-starship-kitty-rebuilding-a-dev-laptop-on-ubuntu-26-04-2f80de10bb2b
url
https://medium.com/@harpreet.dhillon/wayland-starship-kitty-rebuilding-a-dev-laptop-on-ubuntu-26-04-2f80de10bb2b
canonical_url
https://medium.com/@harpreet.dhillon/wayland-starship-kitty-rebuilding-a-dev-laptop-on-ubuntu-26-04-2f80de10bb2b
author_url
https://medium.com/@harpreet.dhillon
status
ok
fetched_at
2026-06-24 18:57:25