dfzf redefines how you interact with windows in sway and i3, letting you switch windows with fzf, sorted by recency — no more cycling or losing your mind. Unlike traditional workspaces or tabbing, it frees you from relying on mental cartography, using name- and time-based navigation to keep access effortless, even with dozens of windows.
No more mental gymnastics. Just type to fuzzy-match and access recent windows first — eventually, you’ll rely solely on dfzf-windows for seamless navigation.
Click to expand description of the GIF
This GIF shows dfzf-windows in action:
- List the current windows, recent ones come first
- Inspect the windows previews, including terminal
- Mark the windows either as "urgent" or "important"
- Kills windows one by one until none are left
- Bonus: Notice a bit of "inception" in the
dfzf-windowspreview...
Using dfzf invites you to rethink how you use your window manager:
- No more tabs — Use
dfzf-windowsto manage windows efficiently, without relying on tabbed layouts. - No more workspaces — Replace static workspaces with a flexible color tagging system. Assign multiple tags to a single window for powerful cross-grouping and faster navigation.
- No more bars — Free up screen space and ditch the traditional bar. Invoke minimal, dedicated popups for clock, system monitor, system info, wifi, and more — only when needed.
These make your desktop cleaner, more dynamic, and easier to manage — with more pixels dedicated to what actually matters — always full-screen !
- ⏱️ Instant access — switch to any window instantly, regardless of how many are open.
- 🔍 Recent-first navigation — fuzzy-search windows by name, with recent ones prioritized.
- 🧠 Low cognitive load — remember what and when, not where.
dfzf relies on dfzf-daemon to track window focus changes via IPC, storing the order of recently used windows in their marks. It uses dfzf-mark to add or remove marks, such as "important" marks (shown in red). And don't worry if you're already using marks — dfzf won't interfere with your existing setup.
Just make sure the daemon is running when you try dfzf for the first time!
dfzf is more than a window switcher — it's a full toolkit for your desktop, built with speed, consistency, and minimalism in mind:
| Tool | Description | i3 | Sway |
|---|---|---|---|
dfzf-windows |
Navigate windows by title or time | ✅ | ✅ |
dfzf-scrollbacks |
Fuzzy-search within all your terminals at once | ✅ | ✅ |
dfzf-launcher |
Launch desktop apps or cmds in terminal | ✅ | ✅ |
dfzf-notify |
Browse past notifications | ❌ | ✅ |
dfzf-tasks |
Manage caldav tasks | ✅ | ✅ |
dfzf-clipboard |
Searchable clipboard with image/text preview | ✅ | ✅ |
dfzf-password |
Copy and preview entries from pass | ✅ | ✅ |
dfzf-mail |
View, preview and delete emails | ✅ | ✅ |
dfzf-exit |
Logout, reboot, suspend, hibernate | ❌ | ✅ |
dfzf-tools |
Clock, calendar, top, wifi, bluetooth, fetch popup | ✅ | ✅ |
dfzf-hub |
Invoke other dfzf commnands | ✅ | ✅ |
dfzf-term |
Terminal management (kill/new/toggle/scratchpad) | ✅ | ✅ |
dfzf-git |
Smart git repository lazygit toggle | ✅ | ✅ |
| Feature / Terminal | Kitty | Foot | Alacritty |
|---|---|---|---|
dfzf-windows Terminal Preview |
✅ Full | ❌ Not supported | ❌ Not supported |
dfzf-scrollbacks Support |
✅ Full | ❌ Not supported | ❌ Not supported |
dfzf-clipboard Image Preview |
✅ Full | 🔻 Degraded | |
Press escape to kill popup |
✅ Full | ||
| Everything else | ✅ Full | ✅ Full | ✅ Full |
Prerequisite
In general, dfzf needs:
- sway or i3, with default layout
tabbed - fzf
- kitty version >= 0.42.1 OR alacritty OR foot
- jq version >= 1.7
- nerdfonts to display the glyphs (see nerdfont section)
- lazygit (for
dfzf-git)
Moreover, each tool can have specific dependencies described in the Features section.
Also be sure fzf is accessible from sway/i3, by moving it to /usr/local/bin/ (instead of default ~/.cargo/bin place)
or setup sway/i3 path correctly
#~/.config/sway/config
set $PATH /usr/local/bin:/opt/bin:$PATH
Download the releases
- Download/copy the binaries into
/usr/local/bin/or anywhere in your PATH. - Download the deb package, and
sudo dpkg -iit on debian/ubuntu.
Build/install dfzf-daemon
cd dfzf-utils
curl https://sh.rustup.rs -sSf | sh
rustup update nightly
cargo +nightly build --release
find dfzf-utils -type f -executable -name "dfzf-*" |xargs -I@ sudo cp @ /usr/local/bin/Nerdfont
Glyph are used in some dfzf modules (windows, tasks). If you don't wan't them you can override the config that way:
#~/.config/dfzf/dfzf.conf
windows_glyph_rules_json='[{"glyph": ""}]'You can install nerdfont by running this script (source). Also snap apps cannot access to .local/share/fonts, reason I personally install them into ~/.fonts instead.
#!/bin/bash
declare -a fonts=(
BitstreamVeraSansMono
CascadiaCode
CodeNewRoman
DroidSansMono
FiraCode
FiraMono
Go-Mono
Hack
Hermit
JetBrainsMono
Meslo
Noto
Overpass
ProggyClean
RobotoMono
SourceCodePro
SpaceMono
Ubuntu
UbuntuMono
)
version=$(curl -s 'https://api.github.com/repos/ryanoasis/nerd-fonts/releases/latest' | jq -r '.name')
fonts_dir="${HOME}/.fonts"
if [[ ! -d "$fonts_dir" ]]; then
mkdir -p "$fonts_dir"
fi
for font in "${fonts[@]}"; do
zip_file="${font}.zip"
download_url="https://github.com/ryanoasis/nerd-fonts/releases/download/${version}/${zip_file}"
echo "Downloading $download_url"
wget "$download_url"
unzip "$zip_file" -d "$fonts_dir"
rm "$zip_file"
done
find "$fonts_dir" -name 'Windows Compatible' -delete
fc-cache -fvSway configuration
exec --no-startup-id dfzf-daemon # reboot to make the daemon running
exec --no-startup-id copyq
exec mako # for the dfzf-notifs
exec swaymsg workspace 1, layout tabbed
workspace_auto_back_and_forth no
# FOR FOOT OR ALACRITTY
#set $term foot
#set $term alacritty
#set $dfzf_term foot --app-id=dfzf-popup -e
#bindsym $mod+Tab exec --no-startup-id $dfzf_term dfzf-windows
#bindsym $mod+l exec --no-startup-id $dfzf_term dfzf-hub
# FOR KITTY
set $term kitty -1
exec --no-startup-id kitty -1 --start-as hidden
exec --no-startup-id kitty -1 --instance-group dfzf --start-as hidden -o 'map escape close_window' -o 'listen_on=unix:/tmp/kitty-dfzf'
bindsym $mod+Tab exec --no-startup-id kitty -1 --class=dfzf-popup -e dfzf-windows
bindsym $mod+l exec --no-startup-id kitty -1 --instance-group dfzf --class=dfzf-popup -e dfzf-hub
bindsym $mod+n exec dfzf-term scratchpad $term
bindsym ctrl+slash exec dfzf-term toggle $term
bindsym shift+ctrl+slash exec dfzf-term kill $term
bindsym $mod+g exec dfzf-git
for_window [app_id="^dfzf-popup$"] floating enable, sticky enable, border pixel 6, exec dfzf-resize 65
# optional: hide the tabs
font pango:monospace 0.001
default_border none
default_floating_border none
titlebar_padding 1
titlebar_border_thickness 0I3 configuration
exec --no-startup-id dfzf-daemon # reboot to make the daemon running
# make sure the workspace is tabbed by default
exec i3-msg workspace 1, layout tabbed
exec --no-startup-id copyq
workspace_auto_back_and_forth no
# FOR FOOT OR ALACRITTY
#set $term foot
#set $term alacritty
#set $dfzf_term foot --app-id=dfzf-popup -e
#bindsym $mod+Tab exec --no-startup-id $dfzf_term dfzf-windows
#bindsym $mod+l exec --no-startup-id $dfzf_term dfzf-hub
# FOR KITTY
set $term kitty -1
exec --no-startup-id kitty -1 --start-as hidden
exec --no-startup-id kitty -1 --instance-group dfzf --start-as hidden -o 'map escape close_window' -o 'listen_on=unix:/tmp/kitty-dfzf'
bindsym $mod+Tab exec --no-startup-id kitty -1 --class=dfzf-popup -e dfzf-windows
bindsym $mod+l exec --no-startup-id kitty -1 --instance-group dfzf --class=dfzf-popup -e dfzf-hub
bindsym $mod+n exec dfzf-term scratchpad $term
bindsym ctrl+slash exec dfzf-term toggle $term
bindsym shift+ctrl+slash exec dfzf-term kill $term
bindsym $mod+g exec dfzf-git
for_window [class="^dfzf-popup$"] floating enable, sticky enable, border pixel 6, exec dfzf-resize 65
# optional: hide the tabs
font pango:monospace 0
default_border none
default_floating_border none
# reset font for the bar
bar {
font pango:monospace 10 # needed
status_command i3status
}user configuration [optional]
you can override default configurations:
# ~/.config/dfzf/dfzf.conf
#kitty only: regexp to match the prompt
windows_prompt_pattern="^[>$%] "
#remove pattern from the window's title
windows_title_rm_pattern=' —[^—]*?— Mozilla Firefox'
# rename the application classes
windows_app_id_map_json='{"evolution": "mail", "kitty": "terminal", "jetbrains-idea-ce": "jetbrains"}'
# assign glyphs to application classes
windows_glyph_rules_json='[
{ "field": "name", "regex": "vim\\b", "glyph": " " },
{ "field": "app_id", "regex": "terminal", "glyph": " " },
{ "field": "app_id", "regex": "firefox", "glyph": " " },
{ "field": "app_id", "regex": "jetbrains", "glyph": " " },
{ "field": "app_id", "regex": "gimp", "glyph": " " },
{ "field": "app_id", "regex": "thunar|nautilus", "glyph": " " },
{ "field": "app_id", "regex": "thunderbird|evolution|geary|mailspring|k9mail|mail", "glyph": " " },
{ "glyph": " " }
]'
# override the exit list and respective commands
exit_options=(
"l: Lock (swaylock)"
"e: Restart GDM"
"s: Lock and Suspend"
"r: Reboot"
"S: Shutdown"
"h: Hibernate"
)
exit_cmd_l='swaylock -e -F -f -k -c 000000'
exit_cmd_e='sudo /usr/bin/systemctl restart gdm'
exit_cmd_s='swaylock -e -F -f -k -c 000000 && systemctl suspend'
exit_cmd_r='sudo reboot'
exit_cmd_S='shutdown now'
exit_cmd_h='sudo /bin/systemctl hibernate'
tools_clock_cmd="tty-clock -c -C 4 -s"
tools_calendar_cmd="~/.venv/3.11.6/bin/khal interactive"
tools_top_cmd="gotop"
# hub user customization
hub_options=(
"a: Audio"
"b: Bluetooth"
"c: Clipboard"
"d: Date"
"e: Exit"
"f: Fetch"
"g: Gotop"
"k: Calendar"
"l: Launcher"
"m: Mail"
"n: Notif"
"p: Password"
"s: Scrollback"
"t: Task"
"w: Wifi"
"i: Iotop"
"q: Pomatez"
)
# hub custom command mappings
hub_cmd_a='dfzf-exec exec pavucontrol'
hub_cmd_b='dfzf-tools bluetooth'
hub_cmd_c='dfzf-clipboard'
hub_cmd_d='dfzf-tools clock'
hub_cmd_e='dfzf-exit'
hub_cmd_f='dfzf-tools fetch'
hub_cmd_g='dfzf-tools top'
hub_cmd_k='dfzf-tools calendar'
hub_cmd_l='dfzf-launcher'
hub_cmd_m='dfzf-mail'
hub_cmd_n='dfzf-notifs'
hub_cmd_p='dfzf-password'
hub_cmd_s='dfzf-scrollbacks'
hub_cmd_t='dfzf-tasks'
hub_cmd_w='dfzf-tools wifi'
hub_cmd_i='TERM=xterm sudo /usr/sbin/iotop -o'
hub_cmd_q="pomatez || dfzf-windows-load|rg pomatez|sed -Ez 's/.*#([0-9]+).*/\1/'|xargs -I@ dfzf-exec '[con_id=@]' focus"Kitty configuration [optional]
#~/.config/kitty/kitty.conf
confirm_os_window_close 0
allow_remote_control yes
listen_on unix:/tmp/kittyWindows terminal preview in kitty:
the terminal preview compares the i3/sway window title with the kitty title. In some case there is duplicates, and we cannot determinate the right terminal. So the current hack is to add 2 random characters to the title so that they get unique. For that, you will have to disable kitty title handling and tweak the shell title. Here for zsh:
#~/.config/kitty/kitty.conf
shell_integration no-titletweak zsh:
# ~/.oh-my-zsh/lib/termsupport.zsh
case "$TERM" in
cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty*|st*|foot*|contour*)
print -Pn "\e]2;${2:q} /$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 2)\a" # set window name
print -Pn "\e]1;${1:q} /$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 2)\a" # set tab nameFirefox [optional]
Install the below extensions:
- tabs are windows
- hostname in windows title
I use this template
{title} - {href} —, together with this variable in dfzf config to bring perfect ff titles.
# remove pattern from the window's title
windows_title_rm_pattern=' —[^—]*?— Mozilla Firefox'Chromium [optional]
Install the below extensions:
- new-tab-new-window
- either URL in title or Title morph
Windows
- windows ordered by last access
- cycle previous window
- terminal scrollback preview (kitty only)
keybindings:
-
Return: focus window -
ctrl-b: toggle color blue -
ctrl-g: toggle color green -
ctrl-o: toggle color orange -
ctrl-r: toggle color red -
B: filter color blue -
G: filter color green -
O: filter color orange -
R: filter color red -
ctrl-k: kill window -
ctrl-u: toggle urgent (yellow color) -
ctrl-i: toggle important (red color) -
ctrl-j: preview windows -
escape: return to current windows (works after previews) -
ctrl-t: will toggle tilling to the multi-selected windowssudo apt install jq ripgrep
Scrollbacks
Scrollbacks let you fuzzy-search across all your terminal histories (Kitty only) and focus the right one — great for digging up lost work from vague command memories.
sudo apt install ripgrepHub
The hub lets you launch any dfzf command with a single keystroke — one keybinding to rule them all.
Clipboard
- list latest mails
- preview text mails
ctrl-j: preview html mails in the browser
sudo apt install jq himalayaNotifications
- list notification ordered
Return: notification actionctrl-k: kill notificationctrl-h: toggle notif history
sudo apt install jq mako-notifierTasks
Manage caldav tasks:
ctrl-t: new taskctrl-e: edit taskctrl-k: delete taskctrl-d: set status done for taskctrl-r: sync tasks with remote caldavctrl-l: choose the collection
pip install todoman vdirsyncerTools
Set of tools not related with fzf, but useful even to drop the sway bar.
- resource usage: top, htop, gotop ...
- calendar: khal, calcurse ...
- clock: tty-clock ...
- wifi
- bluetooth
- fetch: fastfetch
Terminal Management
dfzf-term provides two terminal integrations for different work contexts: project-specific tasks in companion terminals and general tasks in a shared global terminal.
Companion Terminals (project-specific work):
- One terminal per window, attached to any application (IDE, browser, etc.)
- Auto-detects working directory: JetBrains
[/path/to/project], Neovim- NVIMsuffix, Terminal path patterns, defaults to home - Toggles between split vertical and stacked layouts (stacked allows fullscreen switching between windows)
Ctrl + /- Toggle layout |Shift + Ctrl + /- Kill the companion- Automatically moves away any non-companion windows that might be added inadvertently during toggle operations
Global Terminal (general tasks):
- Single floating scratchpad terminal shared across workspaces
- 90% screen size, centered and floating
dfzf-term scratchpad [terminal_command]- Toggle visibility- Works across sway/i3, independent of companion terminals
Git Repository Management
`dfzf-git` provides intelligent git repository integration with lazygit in a scratchpad terminal.Smart Repository Detection:
- Automatically detects git repository from focused window context
- Extracts directory paths from window titles (JetBrains
[/path/to/project], Neovim- NVIMsuffix, etc.) - Recursively searches upward for
.gitfolder from detected directory - Falls back to current working directory if no git repository found from window context
Scratchpad Integration:
- Single floating lazygit terminal shared across workspaces
- 90% screen size, centered and floating
dfzf-git- Toggle lazygit in detected git repository- Automatically opens lazygit in the root of the detected git repository
- Works across sway/i3, uses
dfzf-gitapp_id to avoid conflicts with other terminals
Example Usage:
# Bind to a key (e.g., Alt+g)
bindsym $mod+g exec dfzf-gitdfzfis the combination ofdmenu andfzf- dfzf-daemon comes from i3-back
- dfzf-launcher comes from sway-launcher-desktop
- wofi-scripts has inspired dfzf-windows
- swayr: a window-switcher & more for sway
- i3-tools: switch to previous window
This project is licensed under the GNU General Public License v3.0.















