tmux-shorten-path
May 29, 2026 · View on GitHub
Folder-aware path shortening for tmux status bars. Inspired by Powerlevel10k.
/Users/johndoe/myproject/server/api/middleware/auth.go
↓
~/myproject/s../api/mid../auth.go
anchor↑ ↑ ↑
long segments → shortest unique prefix among siblings
Demo

#{shorten_path} rendered in pane-border-format as the cwd changes, switches between panes, and moves across pre-made windows. See demo/ for the vhs tape and setup script.
Why
Long pane paths chew up the status bar. This plugin shortens them while keeping the project-relative part legible:
- Folder anchors — when a directory contains
.git,package.json,go.mod, etc., the path from that directory onwards is kept full (so you always see where you are inside the project). - Unique prefix truncation — segments before/around the anchor are shortened to the shortest prefix that doesn't collide with sibling directories, so
middlewarebecomesmid..only ifmigrationsexists alongside it; otherwise justm...
tmux has no built-in equivalent.
Install
Using TPM, add to ~/.tmux.conf:
set -g @plugin 'Amdhj22/tmux-shorten-path'
Then prefix + I to install.
Manual install:
git clone https://github.com/Amdhj22/tmux-shorten-path ~/.tmux/plugins/tmux-shorten-path
echo "run-shell ~/.tmux/plugins/tmux-shorten-path/shorten_path.tmux" >> ~/.tmux.conf
Usage
Use #{shorten_path} anywhere in status-left, status-right, window-status-format, window-status-current-format, or pane-border-format. The plugin rewrites it to a shell call at load time:
set -g status-left "#{shorten_path} | #S #I:#P "
Reload tmux config — the placeholder is replaced with the current pane's shortened path.
Options
Set before the run-shell (or set -g @plugin) line.
| Option | Default | Description |
|---|---|---|
@shorten_path_strategy | truncate_to_unique | One of truncate_to_unique, truncate_from_right, truncate_to_last, none. |
@shorten_path_seg_threshold | 5 | (truncate_to_unique) Only truncate segments longer than this. |
@shorten_path_seg_length | 1 | (truncate_from_right) Chars kept per non-last segment. Hidden dirs get +1. |
@shorten_path_markers | .git .hg .svn .bzr CVS _darcs Cargo.toml go.mod package.json composer.json stack.yaml CMakeCache.txt .terraform .shorten_folder_marker | (truncate_to_unique) Files that mark a directory as an anchor. Space-separated. |
@shorten_path_shell | auto | Worker shell: bash, zsh, or fish. Unset = auto-detect in order bash → zsh → fish. |
Example:
set -g @shorten_path_strategy truncate_to_unique
set -g @shorten_path_seg_threshold 3
set -g @shorten_path_markers ".git Makefile"
set -g @plugin 'Amdhj22/tmux-shorten-path'
To declare any directory as an anchor, drop a .shorten_folder_marker file in it:
touch ~/some/long/path/.shorten_folder_marker
The plugin ships three worker variants — scripts/shorten_path.bash, scripts/shorten_path.zsh, and scripts/shorten_path.fish — all producing identical output. At config-load time it picks whichever interpreter is installed and whose worker file is present, trying bash first. Set @shorten_path_shell to force a specific one. If none of the three is available the plugin disables itself gracefully: #{shorten_path} is left un-interpolated and no errors are raised. The worker runs as a subprocess via its shebang and has no relation to your login or interactive shell.
Strategies
All strategies collapse $HOME to ~.
| Strategy | What it does |
|---|---|
truncate_to_unique | (default) Folder-marker anchor + shortest unique prefix among siblings. See How it works below. |
truncate_from_right | Every non-last component → first N chars (@shorten_path_seg_length). Hidden dirs get +1. |
truncate_to_last | Only the basename. / stays as /. |
none | As-is (with $HOME collapsed to ~). |
Same path, different strategies:
input: ~/myproject/server/api/middleware/auth.go
truncate_to_unique → ~/myproject/s../api/mid../auth.go
truncate_from_right → ~/m/s/a/m/auth.go
truncate_from_right → ~/my/se/ap/mi/auth.go (seg_length=2)
truncate_to_last → auth.go
none → ~/myproject/server/api/middleware/auth.go
How it works (truncate_to_unique)
The algorithm runs on every status redraw:
- Find anchor. Walk components from root, looking for a directory containing any marker file. The shallowest match wins.
$HOMEand its ancestors are never considered anchors (otherwise a singlepackage.jsonin your home would defeat the whole purpose). - Before the anchor: truncate each component to 1 char (2 for hidden dirs starting with
.). - The anchor: kept full.
- After the anchor (middle segments): if length > threshold, replace with the shortest prefix that doesn't collide with any sibling entry, suffixed with
... - Last (current) segment: always kept full.
- No anchor: only the last component is kept full; everything else is one char.
Examples
Assume ~/myproject/.git exists (so ~/myproject is the anchor) and ~/myproject/server/api/ contains both middleware/ and migrations/:
| Full path | Shortened (truncate_to_unique) |
|---|---|
~/myproject | ~/myproject |
~/myproject/bin | ~/myproject/bin |
~/myproject/server/db | ~/myproject/s../db |
~/myproject/server/api | ~/myproject/s../api |
~/myproject/server/api/middleware/auth.go | ~/myproject/s../api/mid../auth.go |
~/.config/nvim/lua/plugins (no anchor) | ~/.c/n/l/plugins |
/usr/local/share/zsh/site-functions (no anchor) | /u/l/s/z/site-functions |
Requirements
- tmux 3.0+
- one of: bash 3.2+, zsh, or fish 3.1+ (for the worker script — independent of your login shell)
One
ls-style glob per middle segment per status redraw — negligible on local disks at the default 15sstatus-interval. For deep paths on network mounts, raisestatus-intervalto throttle.
License
MIT