CommanderTUI
Dual-pane terminal file manager: compare two folders, sync them, or move files/folders between them (and to USB/SMB/any mounted path) — with a phosphor-green 80s-terminal look and a short modem-style boot animation.
Status: v1.3.1 — 127/127 tests passing. MIT licensed.
Why this exists
A safe, simple alternative to heavier dual-pane file managers. It was written after an earlier attempt of the same idea had to be scrapped for running an unauthenticated local HTTP server. This project deliberately:
- Never opens a network port. Pure terminal UI (Textual), no HTTP server (the only outgoing request is the update check on startup, which you can turn off), no webview.
- Never does a raw
rm -rf. Deletes always go through the desktop trash (send2trash→gio trash→ manual move into~/.local/share/Trash, in that order). - Never overwrites in place. Copies stream into a hidden
.tmpfile next to the destination and are committed withos.replace— a crash or Ctrl+C never leaves a half-written file. - Never guesses on a conflict. Two-way sync copies each side's exclusive files automatically, but a file changed on both sides is always shown to you, never auto-resolved.
Install
Arch Linux / Omarchy. An AUR package is on the way (yay -S commandertui).
Until then, build it from the PKGBUILD in this repo. makepkg pulls in
everything it needs:
git clone https://github.com/juniorbarchini-oss/commandertui.git
cd commandertui/packaging/arch
makepkg -si
Remove it with sudo pacman -R commandertui.
PyPI (Linux / macOS / WSL). It is a standard package on PyPI (Python 3.11+). Recommended via pipx:
pipx install commandertui
Or inside an activated virtual environment:
pip install commandertui
macOS. Same Python package (pipx install commandertui), plus
kitty for the standalone window. Places
lists the volumes under /Volumes (system volumes such as Recovery and
Preboot are hidden) and FUSE mounts inside your home folder. To get a
double-clickable app with the CommanderTUI icon:
packaging/macos/build_app.sh # builds packaging/macos/CommanderTUI.app
packaging/macos/build_app.sh --install # also copies it to /Applications
The app opens kitty at 1174x637 px and runs commandertui. It looks for the
command in ~/.local/bin (pipx), Homebrew, /usr/local/bin, your PATH,
and a source checkout's .venv. Tested by the author on macOS with a Time
Machine volume, Google Drive and OneDrive mounts.
From a source checkout (development):
python3 -m venv .venv && .venv/bin/pip install -e . -r requirements-dev.txt
bin/commandertui [left-dir] [right-dir]
Run
| Command | What it does |
|---|---|
cmdrtui |
Opens it in its own terminal window. This is also what the CommanderTUI app-launcher entry runs |
commandertui |
Runs it inside the terminal you are in |
commandertui DIR1 DIR2 |
Opens with those two folders side by side |
cmdrtui uses your desktop's default terminal (xdg-terminal-exec). If that
isn't available it tries foot, alacritty, kitty and ghostty. The window
always gets the app-id/class commandertui, so a window-manager rule can
float it. It needs about 1174x637 px to fit every key hint. On Hyprland:
# hyprland.conf
windowrulev2 = float, class:^(commandertui)$
windowrulev2 = size 1174 637, class:^(commandertui)$
windowrulev2 = center, class:^(commandertui)$
-- Omarchy Lua config (~/.config/hypr/hyprland.lua)
o.window("^commandertui$", { float = true, center = true, size = { 1174, 637 } })
Keys
| Key | Action |
|---|---|
Tab |
Switch active pane |
↑/↓, Enter |
Navigate, open directory |
Backspace |
Go to parent directory |
Space |
Mark/unmark item under cursor |
F2 |
Rename the item under the cursor (never overwrites an existing name) |
F4 |
Edit the file under the cursor with $VISUAL / $EDITOR (falls back to nano, vim or vi); CommanderTUI pauses and comes back when you close the editor |
F5 |
Copy marked (or item under cursor) to the other pane |
F6 |
Move marked to the other pane |
F7 |
Create a folder in the active pane |
F8 / Delete |
Delete marked (to trash) |
/ |
Filter the active pane by name (contains, ignores case) as you type; Enter keeps it, Esc clears it |
+ / - / * |
Mark / unmark by pattern (*.iso, or plain text = contains) / invert marks, over the rows shown |
u |
Check for updates now (also the Updates button): asks PyPI right away and offers the new version if there is one |
i |
Size: file/folder count and total bytes of marked items (background, Esc stops it) |
h |
Show/hide hidden (dot) files in both panes |
t |
Color theme: Phosphor green (default), Phosphor amber, Nord, Gruvbox, Dracula, Tokyo Night, Catppuccin Mocha, Solarized Dark, Monokai, Textual Dark. Previews as you move, Enter keeps it (saved in ~/.config/commandertui/settings.json), Esc goes back |
p |
Places: jump to a mounted drive (USB/SMB/rclone), saved bookmark or saved network location. Inside: a add a network location, s save the active pane's folder as a bookmark, d delete a saved one |
c |
Compare: full recursive diff between the two panes' current folders, with size and date of both sides (and which is newer when a file changed) |
r |
Refresh both panes |
q |
Quit |
While a copy/move runs, the progress window shows two bars (current file
and whole job, by bytes) plus speed in Mb/s and time left. Esc asks to
cancel: finished files stay, the file in progress is discarded (never left
half-written), and a move never removes a source it didn't fully copy.
Places lists only what is mounted right now: USB drives
(/run/media, /media, /mnt — checked with ismount, so an empty
on-demand mount point doesn't show), GVFS/Nautilus network shares, FUSE
mounts inside $HOME (e.g. rclone mount), and saved bookmarks.
Network locations (Linux, needs gio/GVFS): in Places press a, pick
SMB, SFTP or FTP and type the server's IP or name. For SMB the app lists the
shares on the server and you pick one; SFTP/FTP connect straight in. The
location is saved in ~/.config/commandertui/network.json (protocol, host
and share only -- never a password) and reappears in Places, mounting itself
when picked. If the server asks for a login, gio asks for it in the
terminal and can remember it in the system keyring, exactly like Nautilus.
Every key also has a clickable box on the bottom bar: one row on wide windows (168+ columns), two rows when narrower (120 columns is the practical minimum). The active pane has the thick border and the inverted path bar; each path bar shows the free space of that disk, and the marked count and total size.
Updates
On every launch, in the background while the start-up animation plays (its
CHECKING UPDATES line shows the result), the app
asks PyPI for the latest version (a plain GET, nothing about you is sent). If
a newer one exists you get a dialog -- Update now / Later / Skip this
version -- and the header keeps saying update X available (press u).
It never installs on its own. Update now hands the terminal over and runs
the command that matches how it was installed:
| Installed as | Update runs |
|---|---|
Arch package (makepkg) |
rebuilds from the release's PKGBUILD with makepkg -si (your sudo password is typed in the terminal, never read by the app) |
| pipx | pipx upgrade commandertui |
| pip | pip install --upgrade commandertui |
| git checkout | no button: the dialog tells you to git pull |
Turn the check off with commandertui --no-update-check or by setting
COMMANDERTUI_NO_UPDATE_CHECK=1. COMMANDERTUI_FAKE_LATEST=9.9.9 shows the
dialog without a real release, to see how it looks. The logic lives in one
self-contained file, commandertui/updater.py, written to be copied into
other apps.
Inside Compare:
| Key | Action |
|---|---|
m |
Mirror: make right identical to left |
u |
Update: copy new/changed left → right, never deletes |
b |
Two-way: propagate each side's exclusive changes; conflicts (changed on both sides) are listed, never guessed |
Space |
Mark a row for manual handling |
c |
Copy marked rows in whichever direction they diverge |
Esc |
Back to the panes |
Every bulk or destructive action shows a plain-language summary (count of
operations, total bytes) and requires y to confirm.
Architecture
commandertui/
├── models.py # FileEntry, DiffEntry, OperationQueue, QueuedOp
├── scanner.py # os.scandir recursive tree walk
├── diff.py # pure comparison: left-only / right-only / modified / identical
├── plan.py # diff -> OperationQueue (mirror / update / two-way)
├── sync.py # atomic copy/move (streamed, tmp+replace), checksum verify
├── trash.py # 3-layer safe delete (send2trash / gio trash / manual)
├── executor.py # runs an OperationQueue against the filesystem
├── bookmarks.py # detected mounts (USB/SMB/rclone) + saved places
├── netlocations.py # SMB/SFTP/FTP locations via gio (list shares, mount, save)
├── theme.py # phosphor green/amber themes + the stylesheet (Textual theme variables)
├── settings.py # saved settings (color theme)
├── boot.py # startup "modem" reveal animation
├── widgets.py # FilePanel: one pane's directory listing
├── modals.py # Confirm / Places / Input / Size / Message screens
├── progress_screen.py # two-bar transfer progress + cancel
├── run_queue.py # confirm -> run queue in a worker thread
├── compare_screen.py # full diff view + bulk/manual sync actions
├── app.py # CommanderApp: wires panes + keybindings
└── cli.py # argument parsing, entrypoint
Tests
pip install -r requirements-dev.txt
pytest
black commandertui tests # formatter, line length set in pyproject.toml
Engine (scanner/diff/plan/sync/executor) is fully unit tested against a real
filesystem (tmp_path). The UI has smoke tests via Textual's Pilot
(boot sequence dismisses, pane switching, mark→copy→confirm end to end).
Not in scope
No file preview, no deduplication engine, no desktop GUI wrapper — those are different problems.
Credits
Designed and tested by Humberto Barchini. The code was written together with Claude (Anthropic) through Claude Code: Claude Sonnet 5 built the first version, Claude Opus 5.5 did most of v0.2 and the v1.0 packaging.
License
MIT — see LICENSE.
Metadata
Release files for commandertui 1.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| commandertui-1.3.1.tar.gz | 61.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| commandertui-1.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 113.1 kB
Release files / commandertui-1.3.1.tar.gz
| Download URL | commandertui-1.3.1.tar.gz |
|---|---|
| Size | 61.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8eecb6be6a5e75a9a4cdc37e45ab5cb78c7fdb8e2addc32e4e790c54a67adb5b
|
|
BLAKE2b-256 checksum How to use checksums |
8f244e2aca46f6a82dffcc1bb3906659abe2da1a1ced6c83f093eaf11ed9ee65
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / commandertui-1.3.1-py3-none-any.whl
| Download URL | commandertui-1.3.1-py3-none-any.whl |
|---|---|
| Size | 51.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
81914ce6f9387e98e9c111ef53b230a92b7a0c2e64ecfcb34d54e23c11e8784c
|
|
BLAKE2b-256 checksum How to use checksums |
40e3d5a3be70d42cc9fe158c646a867697cf0fdbd13da1d99136ee1069ce7a83
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for commandertui 1.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for commandertui-1.3.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.