Skip to content

The TUI ​

sh
bleach tui

Browse the scan, read the evidence behind each verdict, select what you want gone, then either write a plan or apply directly.

 bleach  4146 paths · 128G measured   47 selected · 12.8G
 CACHE-SAFE 12.8G · ORPHAN? 2.3G · REVIEW 65.4G · PROTECTED 50.3G · UNKNOWN 759M

 TIER       SIZE   AGE    WHERE          NAME
●CACHE-SAFE  1.4G  57d    xdg-cache      opencode
●CACHE-SAFE  1.1G  today  plugin:openco… opencode bin          ·opencode-sessions
 ORPHAN?     854M  20mo   app-support    com.isaacmarovitz.Whisky
·PROTECTED  15.2G  today  containers     com.docker.docker
·ORPHAN?     529M  3mo    sys-app-supp…  Autodesk/AcActivityInsights ⚿
────────────────────────────────────────────────────────────────────────────
 /Users/you/Library/Application Support/com.isaacmarovitz.Whisky
 owner: unresolved   files: 1204
   clean  noOwnerFound: no installed app claims "com.isaacmarovitz.Whisky"
   clean  stale: nothing modified inside for 617 days
 1/4146                space select · a all · t tier · / search · w plan · x apply

Keys ​

KeyAction
j k ↑ ↓move
ctrl-f ctrl-b PgUp PgDnpage
g Gfirst / last
spaceselect row
aselect everything selectable in this view
cclear selection
tcycle tier filter
/search name, path, or owner
wwrite a plan file and exit
x or Aapply now — opens the confirmation modal
?help
q Escquit

Reading the list ​

The leading glyph tells you whether a row is selectable:

GlyphMeaning
●selected
· (dim)cannot be selected
spaceselectable, not selected

Trailing markers explain why a row isn't selectable:

MarkerMeaning
⚿outside $HOME; needs sudo, so bleach won't act on it
⊂contains finer-grained rows — select those instead

Rows sourced from a plugin show the plugin name after the path, like ·opencode-sessions.

Pressing space on an unselectable row prints the reason in the status bar instead of silently doing nothing.

The detail pane ​

Always shows the full path, the resolved owner with the inventory sources that found it, and up to four evidence signals. Each is tagged:

  • keep — argues the path is in use
  • clean — argues it's abandoned
  • info — context, no weight

An owner that was identified but isn't actually installed is flagged explicitly: Slack — identified but not installed [installReceipt]. That's the stale-pkg-receipt case, and seeing it stated is the difference between trusting the verdict and guessing.

Applying ​

Press x. A modal states what will happen before it accepts anything:

   Apply to 47 paths · 12.8G

   ▸ quarantine     moved to ~/.local/state/bleach/quarantine — undo with `bleach restore`
     Trash          moved to Finder's Trash — undo from Finder, still using disk until emptied
     delete in place  unlinked immediately — NO undo

       1.4G   /Users/you/.cache/opencode
       1.1G   /Users/you/.local/share/opencode/bin
       1.0G   /Users/you/Library/Caches/lens-desktop-updater
     … 44 more

   Reversible: moved to ~/.local/state/bleach/quarantine — undo with `bleach restore`

 mode=quarantine                    m cycle mode · enter confirm · esc cancel

m cycles the disposal mode. Enter confirms, Esc cancels.

Choosing delete in place changes the modal: it turns red, states the byte count with no undo, and requires you to type the word delete in full. A single keystroke is too cheap for an irreversible action. Switching modes clears anything you've typed, because the word was consent for the previous mode.

What happens after you confirm ​

The TUI leaves the alternate screen and then re-runs full validation against live state before touching anything. The scan behind the screen may be many minutes old; processes start, directories grow. Confirmation is consent, not verification — those are separate steps on purpose.

Refusals are printed individually:

  mode: quarantine
  skip  1.2G   …/Library/Caches/JetBrains/IntelliJIdea2026.2 — a process is running from this path
  quarantined 46 paths · 11.6G

  batch 20260917-114203
  undo:    bleach restore 20260917-114203
  commit:  bleach quarantine --purge --all

bleach tui and bleach apply share one execution path, so validation, journalling and skip reporting cannot drift between them.

Selecting REVIEW rows ​

By default the TUI lets you select REVIEW rows, but apply refuses them. Pass --allow-review to permit them:

sh
bleach tui --allow-review

Worth doing deliberately rather than habitually — REVIEW is where bleach is telling you it isn't sure.

Notes ​

  • The terminal is restored on every exit path, including SIGINT, SIGTERM and SIGHUP, so a crash can't leave you in an alternate screen with an invisible cursor.
  • Resizing is handled: the layout re-queries terminal size on every frame.
  • The TUI needs a real terminal. Piped input exits with bleach tui needs a terminal.