05. Commando — Multi-panel mode
Commando is the default mode. It opens when you launch dedcom without flags
(or explicitly with dedcom --commando). The alternative is the step-by-step
wizard dedcom --classic (§06).
This is a multi-panel navigator in the spirit of classic two-panel file managers: 2–4 independent panels, each showing something of its own (the files of a directory, duplicate groups, the files of a selected group, and so on). The main difference from those is that panels can be "watch" modes and switch automatically as the cursor moves in a neighbouring panel.
Screen anatomy
┌─ DedupCommando v0.9.0-beta.1 ──────────────────────── RAM 47.2M · CPU 3% ┐ ← header
│ Multi-panel mode ZFS: datasets 8 scan #5 · 2 h ago │ ← info line
├──────────────────────────┬──────────────────────────┬──────────────────────┤
│ /tank · files · name │ /tank · groups │ Group files #5 │
│ ▸ media/ │ #1 ●●●● 72.4M × 23 │ /tank/IMG_3120.HEIC│ ← 2–4 panels
│ backup/ │ #2 ●●●● 45.0M × 18 │ K /tank/IMG_canon.HEIC│
│ old/ │ ▸ #5 ●●● 25.7M × 10 │ H /tank/dup.HEIC │
│ iso/ │ #6 ●●● 18.9M × 8 │ H /tank/copy.HEIC │
│ .dedcom-quarantine/ │ ... │ ... │
├──────────────────────────┴──────────────────────────┴──────────────────────┤
│ Panel 1 · /tank · files: 5 · sort: name · v view · s sort · m layout │ ← status
│ 1Help 2Scan 3File 4Hash 5Hard 6Ref 7Keep 8Del 9Menu 10Exit 11Exec 12Sessions│ ← F-keys
└─────────────────────────────────────────────────────────────────────────────┘
- Header — the brand title, the version, and the process RAM/CPU badge.
- Info line — the mode, how many ZFS datasets the host reported (and how many
startup warnings, if any), and the active scan: its number and age,
(loading…)while its results load, orno scan for <folder> · F12 — select. - Panels — from 2 to 4; the ones that fit the window width are visible. If the window is narrow, the extra panels are "hidden", with a count in the status line.
- Status line — a short hint for the active panel plus the relevant single-character keys.
- F-key footer — the numbering (
1= F1, …,12= F12). The background color changes when the second layer is armed (see below).
Basic panel control
| Key | Action |
|---|---|
| Tab | Focus the next panel (cyclic) |
| Shift+Tab | Focus the previous panel |
| ← / → | Focus the previous / next panel |
| ↑ / ↓ or k / j | Cursor up / down |
| PgUp / PgDn | Cursor by ±15 rows |
| Home / End | Cursor to the start / end of the list |
| Enter | Enter a directory / open an entry (depends on the view) |
| Backspace | Go up to the parent directory |
Each panel's cursor is independent. Tab does not "reset" the cursors — they remember their positions.
Add and remove a panel
| Key | Action |
|---|---|
Shift+F3 or ` F3 | Add a panel (≤ 4) |
Shift+F4 or ` F4 | Remove a panel (≥ 2) |
If the window is too narrow for all panels, the hidden ones are shown as a "hidden panels: N — widen the window" note in the status line.
Change the panel root
| Key | Action |
|---|---|
Shift+F5 or ` F5 | Change the active panel's root (to the next ZFS dataset, cyclic) |
Useful for hopping between datasets quickly without cd by hand.
Synchronize and compare panels
| Key | Action |
|---|---|
Shift+F1 or ` F1 | All panels → the active panel's directory |
Shift+F2 or ` F2 | Compare the files and folders in the open panels |
| , (comma) | Side-by-side comparison (on/off, see below) |
Panel views (cycled with the v key)
Each panel chooses for itself what it shows. The views cycle with the
v / V key:
Files → DirsOnly → GroupList → GroupFiles → DuplicatesOfCursor → DirGroupList → DirGroupFiles → (Files)
| View | Header label | What it shows | Data source |
|---|---|---|---|
| Files | files | The ordinary navigator: files and subdirectories of the current dir | Real FS |
| DirsOnly | directories | Subdirectories only (no files) | Real FS |
| GroupList | groups | The duplicate groups of the whole loaded scan, sorted "by benefit" | Scan DB |
| GroupFiles | group files | The files of the group selected in the neighbouring GroupList (watch) | Scan DB |
| DuplicatesOfCursor | duplicates | Duplicates of the file under the cursor of the neighbouring Files panel (watch) | Scan DB |
| DirGroupList | directory groups | The list of groups of twin directories (see below) | Scan DB |
| DirGroupFiles | group directories | The directories of the group selected in the neighbouring DirGroupList (watch) | Scan DB |
When to use which view:
- Files + DuplicatesOfCursor (two neighbouring panels): "I walk through my directory and immediately see whether a file has duplicates anywhere else." One of the main working scenarios.
- GroupList + GroupFiles (two neighbouring): "I scroll groups by descending benefit and work through the large ones."
- Files + Files (two neighbouring): just a file browser for comparing two places.
- DirGroupList + DirGroupFiles: "I found folders with identical content and look at their full paths."
File and directory views: Files / DirsOnly
The ordinary navigator. Enter enters a subdirectory; Backspace goes up.
The panel header is the path, the view label (files / directories), and the
sort key.
┌─ /tank · files · name ───────────────────────────────────────────────┐
│ .. │
│ media/ │
│ backup/ │
│ old-photos/ │
│ ▸ vm-disks/ │
│ readme.txt │
│ .dedcom-quarantine/ │
└──────────────────────────────────────────────────────────────────────┘
File-duplicate views: GroupList / GroupFiles
After a scan, a panel can be switched to GroupList — showing all the duplicate groups of the loaded scan:
┌ 1 · groups (by savings) ─────────────────────────────────────────────┐
│▶ #0 2 files · 2 objects · 4.0 GiB │
│ guaranteed after quarantine purge: 4.0 GiB │
│ #1 2 files · 2 objects · 700.0 MiB │
│ guaranteed after quarantine purge: 700.0 MiB │
│ #2 3 files · 3 objects · 24.0 MiB │
│ guaranteed after quarantine purge: 48.0 MiB │
└──────────────────────────────────────────────────────────────────────┘
- The first line of a group: its rank (from
#0), the number of files, the number of separate copies of the data (objects; files already hardlinked to one another count once) and the size of one file. - The second line: the space guaranteed to come back once the copies are dealt with and the quarantine is purged. Groups are ordered by it, largest first.
The neighbouring panel on the right, switched to GroupFiles, automatically shows the files of the selected group — name first, then directory — with the marks saved for them:
┌ 2 · group files ─────────────────────────────────────────────────────┐
│guaranteed after quarantine purge: 48.0 MiB · links seen 3/unrecorded │
│▶ h IMG_3120.HEIC · /tank/backup/photo -> HARDLINK │
│ ★ IMG_3120.HEIC · /tank/media/photo/2021-11 (keeper) │
│ h IMG_3120.HEIC · /tank/old-copy -> HARDLINK │
└──────────────────────────────────────────────────────────────────────┘
The first column shows a file's saved mark: ★ keeper, h hardlink, c reflink,
x delete, = the same file on disk as the keeper. The marks themselves are set in
a Files panel (see "File marks" below); in GroupFiles the marking keys are refused,
and o opens the file's directory next to it (see below).
On very large groups, GroupFiles shows the first 200 files (a visual cap against freezes). This does not affect the bulk F11 actions. See §13.
The "duplicates of the cursor" view: DuplicatesOfCursor
The neighbouring panel on the right, switched to DuplicatesOfCursor, automatically shows the duplicates of the file under the cursor of the left Files panel:
┌─ /tank/photos · files ──┐ ┌─ Duplicates /tank/photos/IMG_3120.HEIC ────┐
│ .. │ │ /tank/backup/IMG_3120.HEIC │
│ IMG_3119.HEIC │ │ /tank/old-copy/IMG_3120.HEIC │
│ ▸ IMG_3120.HEIC │→ │ /tank/media/dup.HEIC │
│ IMG_3121.HEIC │ │ (4 copies in total, including the current) │
└─────────────────────────┘ └──────────────────────────────────────────────┘
The cursor moved in the left panel → the right one updated instantly (in the background, no freeze).
Directory-twin views: DirGroupList / DirGroupFiles
While scanning, DedupCommando builds directory signatures — two directories with identical signatures have identical content (recursively). Groups of such "twin directories" are available through the DirGroupList view:
┌─ Directory-twin groups (47 groups) ─────────────────────────────────┐
│ #1 45.2 GiB × 3 directories /tank/backup/2023-archive/ │
│ #2 12.7 GiB × 2 directories /tank/media/photo/canon-raw/ │
│ ▸ #3 8.9 GiB × 4 directories /tank/old/projects/ │
│ ... │
└──────────────────────────────────────────────────────────────────────┘
The neighbouring DirGroupFiles shows the full paths of all the directories in the selected group:
┌─ Group directories #3 (4) ──────────────────────────────────────────┐
│ /tank/old/projects/ │
│ /tank/archive/2022-projects/ │
│ /tank/backup/projects-bak/ │
│ /tank/restore-test/projects/ │
└──────────────────────────────────────────────────────────────────────┘
Which algorithm builds the signatures (default vs --merkle-dirs) — see
§07 Scanning.
The o key — a file's directory into the adjacent panel
In the GroupFiles and DuplicatesOfCursor views, the o / O
key opens the directory of the file under the cursor in the adjacent panel on the
right, in Files view, and the cursor there lands on that file immediately. This is
the way from a group to its files for marking (§04 Step 8).
If there is no right panel, o adds one, and the new panel takes the focus; a
narrow terminal or the panel limit puts the error text into the status line
instead. When the panel on the right already exists, the focus stays where it was.
In other views, o does nothing but set the status message "The «o» key works in
the «group files» and «duplicates» modes".
Watch modes: how panels "follow" one another
The GroupFiles, DuplicatesOfCursor, and DirGroupFiles views are "watch" modes. Each such panel looks at the cursor of the neighbouring panel on its left and updates automatically.
| Watch view | Source in the neighbour on the left |
|---|---|
| GroupFiles | GroupList — the selected group |
| DuplicatesOfCursor | Files / DirsOnly — the file under the cursor |
| DirGroupFiles | DirGroupList — the selected group |
If the neighbour has no suitable source (for example, it is in Files mode on a directory without duplicates), the watch panel shows "no data".
Watch updates in the background — navigating in the source does not "hang" on a DB query from the right.
Sorting entries (s / S)
The sort keys cycle with the s / S key in the active panel:
name → size → type → date → (name)
The panel header shows the current key.
File marks
A mark lives on the absolute path — moving to another directory does not lose it.
| Mark | Glyph | Key | Meaning |
|---|---|---|---|
| Keeper | K | F7 | The group's keeper file (one per group) |
| Hardlink | H | F5 | Replace with a hardlink to the keeper |
| Reflink | C | F6 | Replace with a reflink to the keeper (ZFS block_cloning) |
| Delete | D | F8 | Delete (to quarantine) |
| Selected | * | Space / Insert | An ephemeral batch (for the m layout) |
Space on an already-marked file removes the mark (by default it sets
Selected, but if there was a K/H/C/D it removes it).
Insert is the same as Space, for batch marking in the style of classic two-panel file managers.
The semantics of the actions (what exactly hardlink/reflink/delete do, and why a hardlink is better than a delete) — see §08 Actions.
F-keys — first layer
This is what is drawn on the footer. With no modifiers:
| F-key | Action |
|---|---|
| F1 or ? | Keyboard help (overlay) |
| F2 | Scan the active panel's directory |
| F3 | Info about the file under the cursor (the FileInfo overlay) |
| F4 | Compute the hash of the file under the cursor (in the background) |
| F5 | Mark as Hardlink |
| F6 | Mark as Reflink |
| F7 | Mark as Keeper |
| F8 | Mark as Delete |
| F9 | Menu (overlay) |
| F10 | Exit |
| F11 or x | Apply the marked actions (the confirmation overlay). Also in the F9 menu — most terminals eat F11 |
| F12 | Sessions and scan results (the ResumeScan overlay + the session list) |
F-keys — second layer
This is enabled by holding Shift when pressing an F-key OR by the prefix
key ` (grave accent) for the one next F press. The footer is highlighted in
yellow when the prefix is armed.
Why two mechanisms: the Proxmox web shell terminal (xterm.js) does not pass
Shift+F — the ` prefix is intended for it.
Key (Shift+F / ` F) | Footer label | Action |
|---|---|---|
| F1 | Sync | Synchronize all panels to the active panel's directory |
| F2 | Compare | Compare the files and folders between panels |
| F3 | +Panel | Add a panel (≤ 4) |
| F4 | -Panel | Remove a panel (≥ 2) |
| F5 | Root | Change the active panel's root (across datasets) |
| F6 | Size | Recompute the directory size (in the background) |
| F7, F8 | — | Unassigned |
| F9 | Wizard | Open the scan configuration wizard (ScanConfig) |
| F10, F11 | — | Unassigned |
| F12 | Board | Triage Board — the screen for laying out across 4 receivers (§09) |
The prefix is cleared:
- automatically after any key press;
- by pressing
`again (toggle); - by an F-key (the second layer handles it and clears).
The same prefix followed by the digit row reaches the FIRST layer, for terminals
that keep an F-key for themselves (F10 = menu, F11 = fullscreen in most of them):
` 1…9 = F1…F9, ` 0 = F10, ` - = F11, ` = = F12.
Execute also has the letter alias x. See
§13 Troubleshooting.
The F9 menu (14 items)
┌─ Menu — F9 ────────────────────────────────────────────────────────────┐
│ 1. Scan the active panel's directory │
│ 2. Configure and start a scan… │
│ 3. Sessions and scan results… │
│ 4. Execute marked actions (F11 or x) │
│ 5. Clear all marks │
│ 6. Reload scan data │
│ 7. Change panel mode (v) │
│ 8. Synchronize panels (Shift+F1) │
│ 9. Compare panels (Shift+F2) │
│ 10. Add a panel (Shift+F3) │
│ 11. Remove a panel (Shift+F4) │
│ 12. Change panel root (Shift+F5) │
│ 13. Recompute directory size (Shift+F6) │
│ 14. Keyboard help │
│ │
│ ↑↓ select Enter apply Esc cancel │
└────────────────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
| ↑ / ↓ | Cursor over the items |
| Enter | Apply the selected item |
| Esc or F9 | Close the menu without an action |
Item 2 = Shift+F9, item 3 = F12, item 4 executes the marked actions
(F11 or x), item 5 clears every saved mark of the scan after a question
(see "Clear all marks" below). Items 7–13 duplicate the hotkeys named in their
own labels (for those who do not yet remember them); item 6 has no key of its
own, and item 14 is the help screen.
Overlays
Besides the menu there are four more modal overlays:
F11 confirmation (Overlay::Confirm)
┌─ Confirmation — F11 ───────────────────────────────────────────────────┐
│ Summary Commands │
│ │
│ Actions to be executed: 9 │
│ By type: delete 2 · hardlink 7 │
│ guaranteed after quarantine purge: 232.0 MiB │
│ │
│ DELETE /tank/junk/duplicate.bin │
│ DELETE /tank/junk/duplicate-2.bin │
│ HARDLINK /tank/dup/IMG_4421.HEIC │
│ HARDLINK …/old-copy/IMG_4421.HEIC │
│ HARDLINK /tank/dup/IMG_4422.HEIC │
│ … and 4 more │
│ │
│ A ZFS snapshot for rollback is created before changes. │
│ │
│ [Tab] tab [S] save .sh [Y] execute [N]/[Esc] cancel │
└─────────────────────────────────────────────────────────────────────────┘
Summary reports the plan by composition, not just by total: the By type line
and up to five quoted targets. "Actions: 3" reads the same whether F7 or F8
landed on the copy, so the kinds and the paths are what catch a mis-marked
batch before Y. Long paths are elided from the left so the file name stays.
A short terminal gives things up in order — first the quoted paths, then the
spacing, then the snapshot note, then the size — so that the count, the
composition, the … and N more and the [Y]/[N] hint are always on screen.
The Commands tab shows the plan's shell script and scrolls: the script of a
large plan runs to thousands of lines, and the whole point of an audit view is
that it can be read to the end. The overlay title carries the position as
lines X-Y of N, or no script lines when there is nothing to show.
┌ Confirmation — F11 · lines 105-112 of 118 ──────────────────────────────┐
│ Summary Commands │
│ │
│ # 4. Actions: 3 total. │
│ dedcom_failed=0 │
│ # reflink (clone beside it, then the file to quarantine): /tank/dup/copy│
│ dedcom_reflink '/tank/dup/copy1.bin' '/tank/dup/orig.bin' '/tank/.dedcom│
│ # reflink (clone beside it, then the file to quarantine): /tank/dup/copy│
│ dedcom_reflink '/tank/dup/copy2.bin' '/tank/dup/orig.bin' '/tank/.dedcom│
│ # reflink (clone beside it, then the file to quarantine): /tank/dup/copy│
│ dedcom_reflink '/tank/dup/copy3.bin' '/tank/dup/orig.bin' '/tank/.dedcom│
│ │
│ ↑↓ · PgUp/PgDn · Home/End — scroll │
│ [Tab] tab [S] save .sh (whole script) [Y] execute [N]/[Esc] cancel │
└─────────────────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
| ↑ / ↓ | Scroll the script one line (Commands tab) |
| PgUp / PgDn | Scroll a screenful, one line of overlap |
| Home / End | First / last window of the script |
| Tab | Switch the tab: Summary ↔ Commands (the full shell script) |
| S | Save the plan as a .sh (audit trail; manual execution is possible) |
| Y | Execute — start applying |
| Enter | Nothing. Applying is destructive, so it costs a deliberate Y |
| N / Esc | Cancel |
S always writes the whole script, whatever part of it is on screen. On a
window too small for both hint lines the scrolling hint goes first — the
[Y]/[N] line stays.
Enter does not execute. It used to be a synonym for Y, which made the one irreversible step in the tool reachable by the key people press to dismiss a dialog they have not read. Enter is now ignored here: the confirmation stays open and the plan is untouched.
F3 file info (Overlay::FileInfo)
┌─ File — F3 · Esc to close ─────────────────────────────────────────────┐
│ Path: /tank/media/photo/IMG_3120.HEIC │
│ Size: 3.6 MiB │
│ Mtime: 2024-08-15 14:23:11 │
│ Device: 0x42 (zfs:tank) │
│ Inode: 12345678 │
│ Hash: a3f5... (from the last scan) │
│ Duplicates: 4 (including this one) │
└─────────────────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
| Enter / Esc / F3 | Close |
Resume — F2 (Overlay::ResumeScan)
On F2 (scan the active panel), if this root already has an unfinished or finished session, it asks what to do with it:
┌─ Scan roots — F2 ──────────────────────────────────────────────────────┐
│ Root: /tank │
│ │
│ Unfinished scan: 2026-05-20 14:15 (47% by volume, 1.2 TiB) │
│ Last completed: 2026-04-12 09:23 (12,437 groups) │
│ │
│ [R]/[Enter] resume │
│ [O] open completed │
│ [N] new scan │
│ [Esc] cancel │
└─────────────────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
| R | Resume the unfinished session (if any) |
| O | Open the result of the last completed scan |
| Enter | Equivalent to R, or O if there is no unfinished session |
| N | Ignore everything, start a new scan |
| Esc | Cancel (return to the commander without a scan) |
The check of saved scans runs in the background, as do the file info of F3 and the plan of F11. If something that takes the keys is in front when the answer arrives — the F9 menu or another F-key window, help, the Triage Board, a move waiting for its target panel — or you have left the commander, the answer opens nothing and starts no scan. Close what is in front and press the same key again. The status line says what arrived, except while a move waits for its panel: that line is the move's prompt then.
Opening a result with O (or Enter, when nothing is left to resume) takes a moment as well. If a window, the Triage Board or a waiting move is in front when it is ready, or you have left the commander, the scan opens but the screen stays where it is, and the status line names the scan: F12, then Enter on it in the list of scans shows its groups. Help does not hold it back — the groups open under it.
Clear all marks — F9, item 5 (Overlay::ClearMarks)
The F11 plan is built from every mark the database holds for the scan, marks set in an earlier session or in the classic interface included, and a files panel shows only the marks set while it was open. So item 5 clears them in the database, all of them, after a question that names the scan:
┌ Clear all marks — F9 ────────────────────────────────────────────────┐
│ Clear every saved mark of scan #1, keepers included? │
│ 1 file is marked for an action. │
│ Marks no panel shows go too: the F11 plan is built from all of them. │
│ │
│ [Y] yes · [N] no │
└──────────────────────────────────────────────────────────────────────┘
The count is of the files marked for an action; keepers are not in it and go
too. When that count is not known yet, the line is left out. On Y the
status line reads Marks cleared: N, N being the marks the database held, and
no panel or group shows a mark of that scan any more. Marks of other scans stay
in the database; a panel that still held one drops it. The selection made with
Space or Insert is not a mark and stays.
The item is refused in read-only mode, without a loaded scan, while a mark is still being saved or the marks are still being cleared, and while something that would open a window over the question or install another scan under it is still on its way — a plan being built (F11), a check of saved scans (F2), a file's info (F3), a scan opening, the lookup of a panel's scan, auto-select. The status line says which; ask again when it is done. If a scan is opened while the question is open, the same one again or another, or the database file is replaced under it, the question closes and nothing is cleared.
| Key | Action |
|---|---|
| Y | Clear every saved mark of the scan |
| N / Esc | Close; nothing is cleared |
| Enter | Nothing — as in F11, it costs a deliberate Y |
Side-by-side comparison (,)
The , (comma) key turns the CompareMode::SideBySide mode on/off for
neighbouring panels in the Files/DirsOnly views:
┌─ /tank/photos · files ──┐ ┌─ /tank/photos-bak · files ──┐
│ = IMG_3119.HEIC │ │ = IMG_3119.HEIC │
│ ≈ IMG_3120.HEIC │ │ ≈ IMG_3120.HEIC │
│ ~ IMG_3121.HEIC │ │ ~ IMG_3121.HEIC │
│ + IMG_3122.HEIC │ │ │
│ │ │ + IMG_extra.HEIC │
└──────────────────────────┘ └────────────────────────────────┘
Match glyphs:
=— identical (the same hash)≈— similar (close size/date)~— differs+— present only in this panel
Useful for an eyeball comparison of two "versions" of a directory — backup vs original.
Triage Board — laying out across 4 receivers
A separate screen for manually distributing files. It opens with Shift+F12
(or "start the layout" — the m key + a digit 1–4). This is not
deduplication — it is a "I brought a file here and sorted it into bins" tool.
Details — §09 Triage Board.
Other actions
| Key | Action |
|---|---|
| m / M | Start the layout: select files → a digit 1–4 = the receiver |
| u / U | Undo the last layout move (Undo) |
| q / Q | Exit |
What's next
- §06 Classic wizard — the step-by-step equivalent for those who find the multi-panel mode unwieldy.
- §07 Scanning — how to configure a scan that will later fill the GroupList/GroupFiles/etc. views.
- §09 Triage Board — laying out across 4 receivers.
- §14 Hotkeys reference — a printable table of all keys on a single page.
Published from docs/manual/05-commando.md at v0.9.2 · last changed 2026-09-28