Kitty is my default terminal on Kubuntu. Out of the box its shortcuts are Ctrl+Shift-heavy, so the first thing I do is give it tabs that work like a browser: Ctrl+T for a new tab, Ctrl+W to close, Ctrl+Tab to cycle. After years of Chrome and Firefox muscle memory, having the same shortcuts in my terminal just makes sense.
Other things I like:
- GPU-accelerated rendering (fast, smooth)
- Plain-text config file, with every option documented in the kitty.conf reference
- Splits built in (like tmux, but native)
- Its own keyboard protocol, which Claude Code uses, so Shift+Enter inserts a newline with no setup
- Claude Code sends desktop notifications through Kitty without extra configuration
Installation
Linux
Distro packages can lag behind upstream. I use the official binary installer, which puts everything in ~/.local/kitty.app and touches nothing else:
curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin
Then add it to your PATH and application menu (from Kitty’s binary install page):
ln -sf ~/.local/kitty.app/bin/kitty ~/.local/kitty.app/bin/kitten ~/.local/bin/
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/
sed -i "s|Icon=kitty|Icon=$(readlink -f ~)/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty*.desktop
sed -i "s|Exec=kitty|Exec=$(readlink -f ~)/.local/kitty.app/bin/kitty|g" ~/.local/share/applications/kitty*.desktop
echo 'kitty.desktop' > ~/.config/xdg-terminals.list
To update, run the installer command again.
If you’d rather have apt manage it, Ubuntu packages Kitty too. It usually trails upstream, but it updates with the rest of your system:
sudo apt install kitty
Noto fonts are worth adding either way (comprehensive Unicode coverage, prevents garbled characters when displaying web content, emojis, or international text):
sudo apt install fonts-noto fonts-noto-color-emoji
Mac
The same installer works and puts Kitty in /Applications/kitty.app:
curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin
Kitty’s macOS defaults already use Cmd+T and Cmd+W for tabs, so you may not need the tab mappings below.
Windows
Kitty doesn’t run on Windows (it supports Linux, macOS and the BSDs). If you’re on Windows, WezTerm and Windows Terminal both handle Claude Code’s Shift+Enter without setup.
Make It the Default on KDE
- Open System Settings → Default Applications and set Terminal emulator to kitty
- In System Settings → Keyboard → Shortcuts, find Konsole and clear its Ctrl+Alt+T
- Add kitty as an application there (the add button) and give it Ctrl+Alt+T
Now Ctrl+Alt+T opens Kitty from anywhere, and KDE apps that open a terminal use it too.
Config
Config lives in ~/.config/kitty/kitty.conf. Create the directory if it doesn’t exist. Kitty reloads the config when you save it (older builds need Ctrl+Shift+F5).
My kitty.conf:
# BEGIN_KITTY_THEME
# Gruvbox Dark
include current-theme.conf
# END_KITTY_THEME
# Keep colour enabled when Kitty inherits the NO_COLOR convention.
env NO_COLOR
# Keep application text readable against contrasting TUI fields.
text_fg_override_threshold 7 ratio
include selection-overrides.conf
# Use the same clipboard paste chord as GUI apps.
map ctrl+v paste_from_clipboard
# Browser-style tabs and splits
map ctrl+t new_tab
map ctrl+w close_window
map ctrl+shift+w close_tab
map ctrl+tab next_tab
map ctrl+shift+tab previous_tab
map ctrl+1 goto_tab 1
map ctrl+2 goto_tab 2
map ctrl+3 goto_tab 3
map ctrl+4 goto_tab 4
map ctrl+5 goto_tab 5
map ctrl+6 goto_tab 6
map ctrl+7 goto_tab 7
map ctrl+8 goto_tab 8
map ctrl+9 goto_tab 9
# Treat Ctrl+Enter like Shift+Enter in applications using Kitty's keyboard protocol.
map ctrl+enter send_text kitty \x1b[13;2u
map ctrl+shift+e combine : goto_layout splits : launch --cwd=current --location=vsplit
map ctrl+shift+h combine : goto_layout splits : launch --cwd=current --location=hsplit
map ctrl+shift+m detach_window ask
copy_on_select clipboard
And selection-overrides.conf, in the same folder:
# Preserve each cell's foreground colour when a theme sets a low-contrast
# selection foreground.
selection_foreground none
# Keep dimmed secondary text legible on light themes.
dim_opacity 0.9
# Keep plain drag-to-copy available when an application captures the mouse.
mouse_map left press grabbed mouse_selection normal
What each part does:
Theme block: Written by kitten themes, Kitty’s built-in theme picker. It copies the chosen theme to current-theme.conf and includes it. Run kitten themes to browse.
env NO_COLOR: Naming a variable with no value removes it from everything Kitty launches. If something in your desktop session sets NO_COLOR, this stops every CLI in the terminal going monochrome.
text_fg_override_threshold 7 ratio: Kitty nudges text lightness wherever an app picks colours that clash with the theme, until the contrast reaches 7:1 (the WCAG AAA level).
map ctrl+v paste_from_clipboard: Ctrl+V pastes, as in every other app (Ctrl+Shift+V still works). Dictation tools that paste with Ctrl+V, such as Handy, then work in the terminal too. See the Claude Code trade-off below.
Separate overrides file: The theme picker comments out colour settings in kitty.conf when you switch themes. Settings in a file included after the theme survive that and win any conflict.
selection_foreground none: Selected text keeps its own colour instead of the theme’s selection colour.
dim_opacity 0.9: Faint text is dimmed less than the default, which matters on light themes.
mouse_map ... grabbed: When a full-screen app captures the mouse, Kitty normally needs Shift+drag to select. This makes a plain drag select instead. The trade-off is that apps no longer see that drag.
copy_on_select clipboard: Selecting text with the mouse copies it to the clipboard.
Splits: Kitty calls panes “windows”. The split mappings switch to the splits layout and open a new pane in the current directory: vsplit puts it side by side, hsplit one above the other.
detach_window ask: Moves the current pane into a tab you pick, which is handy for merging two sessions into one tab.
Font: I leave Kitty on its default (your system’s monospace font). Run kitten choose-fonts to pick another.
Keybindings Summary
| Action | Shortcut |
|---|---|
| New tab | Ctrl+T |
| Close pane | Ctrl+W |
| Close tab | Ctrl+Shift+W |
| Next tab | Ctrl+Tab |
| Previous tab | Ctrl+Shift+Tab |
| Jump to tab N | Ctrl+1-9 |
| Split side by side | Ctrl+Shift+E |
| Split one above the other | Ctrl+Shift+H |
| Move pane to another tab | Ctrl+Shift+M |
| Paste | Ctrl+V or Ctrl+Shift+V |
| Scroll by page | Ctrl+Shift+PageUp / PageDown |
| Jump to top / bottom | Ctrl+Shift+Home / End |
| Reload config | Ctrl+Shift+F5 |
Day and Night Themes
I keep two custom themes in ~/.config/kitty/themes/ (Rosé Pine Dawn and Gruvbox Dark, each with muted pane borders) and switch between them on a schedule. A theme file there with the same name as a built-in theme overrides it.
The script, saved as ~/.local/bin/kitty-theme-schedule and made executable:
#!/bin/sh
now=$(date +%H%M)
if [ "$now" -ge 0930 ] && [ "$now" -lt 2230 ]; then
theme='Rosé Pine Dawn'
else
theme='Gruvbox Dark'
fi
exec "$HOME/.local/kitty.app/bin/kitten" themes \
--cache-age=-1 \
--reload-in=all \
"$theme"
--reload-in=all updates every open Kitty window, and --cache-age=-1 stops it checking online for new themes.
A systemd user timer runs it at each switch time and shortly after login. ~/.config/systemd/user/kitty-theme-schedule.service:
[Unit]
Description=Select Kitty theme for the current local time
[Service]
Type=oneshot
ExecStart=%h/.local/bin/kitty-theme-schedule
~/.config/systemd/user/kitty-theme-schedule.timer:
[Unit]
Description=Switch Kitty between Rosé Pine Dawn and Gruvbox Dark
[Timer]
OnCalendar=*-*-* 09:30:00
OnCalendar=*-*-* 22:30:00
OnStartupSec=10s
Persistent=true
AccuracySec=1s
Unit=kitty-theme-schedule.service
[Install]
WantedBy=timers.target
systemctl --user daemon-reload
systemctl --user enable --now kitty-theme-schedule.timer
If you’d rather follow your desktop’s light/dark setting, Kitty can do that natively: run kitten themes and save a theme for each of the light, dark and no-preference modes (details).
Claude Code in Kitty
Newlines: Shift+Enter inserts a newline in Claude Code with no setup. The ctrl+enter mapping above sends the same key code, so Ctrl+Enter works too. Ctrl+J also works in any terminal.
Notifications: Claude Code sends desktop notifications through Kitty by default, including from sessions over SSH.
Key clashes: Browser-style tabs take three keys Claude Code also uses. Kitty catches them first, so inside Claude Code you lose:
- Ctrl+T, which toggles Claude’s task checklist
- Ctrl+W, which deletes back to the previous space
- Ctrl+V, which pastes an image from the clipboard
If you miss one, either drop that line from kitty.conf or give the Claude Code action a new key with /keybindings.
External editor: Ctrl+G opens your prompt in $VISUAL for longer edits. I use Kate, and --block makes Claude Code wait until you close the file:
echo "export VISUAL='kate --block'" >> ~/.bashrc
Claude Code Status Line
This part works in any terminal. You can add a custom status line to Claude Code that shows context window usage with traffic-light colouring: green when you have plenty of room, yellow when you should start wrapping up, red when you need to park the session.
The display looks like: Ctx: 50k (5%) | Model: Opus | Session: 16m
The colour of the context indicator changes based on usage:
- Green (<30%): safe working zone
- Yellow (30–50%): start wrapping up
- Red (>50%): park now, before auto-compaction eats your context
Quick setup
Claude Code has a built-in /statusline command that generates a status line script and configures settings for you:
/statusline show model name and context percentage with traffic light colors
This creates the script and updates your settings.json automatically.
Manual setup
If you want full control over the script, or want to understand what /statusline generates:
Claude Code’s statusLine setting pipes session data (model, context usage, duration) as JSON to any script you point it at. The script below parses that JSON and outputs a colour-coded status line.
Requires jq for JSON parsing:
# Linux (Debian/Ubuntu)
sudo apt install jq
# Mac
brew install jq
Create the script at ~/.claude/statusline.sh:
#!/bin/bash
# Claude Code status line with traffic-light context display
# Green (<30%), Yellow (30-50%), Red (>50%)
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name // "Claude"')
PERCENT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
TOTAL=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
# Calculate used tokens from percentage
USED=$((TOTAL * PERCENT / 100))
# Format used tokens (e.g., 50k, 150k)
if [ "$USED" -ge 1000 ]; then
USED_FMT=$(awk "BEGIN {printf \"%.0fk\", $USED/1000}")
else
USED_FMT="$USED"
fi
# Format session duration
SESSION_SECS=$((DURATION_MS / 1000))
if [ "$SESSION_SECS" -lt 60 ]; then
DURATION="<1m"
elif [ "$SESSION_SECS" -lt 3600 ]; then
DURATION="$((SESSION_SECS / 60))m"
else
DURATION="$((SESSION_SECS / 3600))h$((SESSION_SECS % 3600 / 60))m"
fi
# Traffic-light colour coding
if [ "$PERCENT" -ge 50 ]; then
CTX="\033[31m${USED_FMT} (${PERCENT}%)\033[0m" # Red
elif [ "$PERCENT" -ge 30 ]; then
CTX="\033[33m${USED_FMT} (${PERCENT}%)\033[0m" # Yellow
else
CTX="\033[32m${USED_FMT} (${PERCENT}%)\033[0m" # Green
fi
echo -e "Ctx: ${CTX} | Model: ${MODEL} | Session: ${DURATION}"
Make it executable:
chmod +x ~/.claude/statusline.sh
Then add it to ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}
Windows note: Claude Code runs status line commands through Git Bash when it’s installed (so this script works unchanged), or PowerShell otherwise. See the status line docs for PowerShell examples.
Why the thresholds?
Claude Code auto-compacts the conversation when the context window fills up. Compaction loses detail: tool outputs get summarised, earlier reasoning gets trimmed. The traffic light gives you a glanceable signal to wrap up and save state before compaction happens, rather than discovering mid-thought that half your context just disappeared.