Problem or use case
Someone whose quota is full opens degu to free space. Today that takes three separate understandings before anything is freed.
Staging does not free quota. A confirmed degu clean moves findings into the staging trash, and README.md says plainly that staged data "still counts against quota until purged". So the obvious first command leaves the number that prompted the whole exercise unchanged. Space comes back from degu trash purge, from --purge, or from waiting out the seven-day expiry — a second step the person has to know exists.
The review tier is where the space usually is, and it is the hardest to act on. On an ML node the reclaimable gigabytes are model and compile caches, which are regenerable but costly, so degu correctly refuses to decide and leaves the judgement to the user. Expressing that judgement is the friction. --include-review takes every review finding at once. --review PATH takes exactly one, and scan prints that command only for the largest location. A policy is expressible — --include-review --min-size 5G --older-than 180 composes, and for scheduled cleanup that is the right shape — but a judgement that a rule cannot capture ("this model is coming back next week, that one is not") has to be recorded by transcribing paths out of a report that has already scrolled past.
Permanent removal is all or nothing. degu trash purge removes every entry; it has no --path. So a person who wants back the eight gigabytes sitting in one staged model directory, while keeping last week's other entries in reach of degu undo, cannot say that. The options are everything or patience.
None of these is a missing capability in the safety model — the tiers, the staging, the undo window and the confirmations are all doing their job. What is missing is a place to make the decisions they exist to protect.
Desired behavior
degu tui: an interactive surface for the decisions the printed report can only describe.
It presents the current scan and the current staging trash together, because that is where quota actually sits, and lets the reader decide per location:
- which Needs review findings join this clean,
- which staged entries are permanently removed now rather than left for undo or expiry.
It then previews the whole outcome — what will be staged, what will be permanently destroyed, what the trash will hold afterwards — and executes on confirmation. No command is typed to make it happen.
It is a wrapper over the CLI, structurally and not just in spirit. What the interface produces is the same argument set a person could have typed, handed to the same command implementation. It holds no scanning, admission, staging or deletion code of its own, so there is exactly one deletion path and no way to grow a second. The equivalent command line is shown before confirmation — not as something to type, but so that the next time the decision is a rule rather than a judgement, the reader already knows how to say it.
Three properties must not soften because the surface is graphical:
- Not managed is never selectable, and Needs review is still included one location at a time. Explicit becomes a keystroke instead of a transcribed path; it does not become a default or a bulk toggle.
- Permanent removal keeps its friction. The interface reuses the same confirmation the CLI uses, including typing the word for irreversible removal. A highlighted button is exactly what muscle memory triggers, which is the reason that friction exists.
- Preview matches execution, as
clean already promises. The preview is the same admission assessment execution re-verifies, and an explicit selection stays atomic: if one selected item fails preflight the whole batch is refused before anything is written.
A confirmed clean also permanently removes staging entries at least seven days old — docs/safety.md notes this happens even with an empty plan, because there is no background timer. The interface must show that alongside, and apart from, what the reader chose, so the two are never confused.
Example workflow or CLI
# today: read, transcribe, then discover that nothing was freed
degu scan
degu clean --include-review --path ~/.cache/huggingface/hub/models--a --path ~/.cache/torch/inductor
degu trash list
degu trash purge # all of it, or nothing
# proposed
degu tui
Selective permanent removal should exist on the command line first, so the interface has something to wrap:
degu trash purge --path ~/.local/state/degu/trash/...
Affected area or ecosystem
Cleanup and trash workflow, plus presentation; no adapter or ecosystem-specific behavior.
Current workaround or alternatives
Read the scan, copy the paths you decided to clean, assemble --include-review --path ... --path ..., run it, then run degu trash purge and accept that it takes everything. For decisions a rule can express, --include-review --min-size ... --older-than ... already works well and is the right answer for scheduled cleanup; this request is about the decisions a rule cannot express.
Safety and filesystem semantics
The interface must not carry deletion capability. It produces the arguments; admission, staging, purge and the mutation lock stay where they are, and the plan is re-verified at execution rather than trusted from when it was drawn.
Eligibility does not change. Not managed cannot be selected from any surface. Needs review is included per location by an explicit act. Ready to clean is unaffected.
Selective permanent removal is a new selector, not a new mechanism: plan_expired_trash already builds a purge plan from a subset chosen by a predicate, and captures and executes those entries through the same batch path as a full purge. Adding a path predicate reuses that; it does not introduce a second way to destroy data.
Irreversible operations keep the confirmation they have today, and the interface must refuse in the same places the CLI refuses — a non-terminal, a held mutation lock, an incomplete scan that makes the plan untrustworthy.
The read-only browser from #98 is a different thing and stays useful for a different case: a report exported from a cluster and read elsewhere, where the reader cannot act because they are not on that machine. Read-only is correct there. This is about the case where the reader is on the machine and the decision is the point.
Before submitting
Problem or use case
Someone whose quota is full opens degu to free space. Today that takes three separate understandings before anything is freed.
Staging does not free quota. A confirmed
degu cleanmoves findings into the staging trash, andREADME.mdsays plainly that staged data "still counts against quota until purged". So the obvious first command leaves the number that prompted the whole exercise unchanged. Space comes back fromdegu trash purge, from--purge, or from waiting out the seven-day expiry — a second step the person has to know exists.The review tier is where the space usually is, and it is the hardest to act on. On an ML node the reclaimable gigabytes are model and compile caches, which are regenerable but costly, so degu correctly refuses to decide and leaves the judgement to the user. Expressing that judgement is the friction.
--include-reviewtakes every review finding at once.--review PATHtakes exactly one, andscanprints that command only for the largest location. A policy is expressible —--include-review --min-size 5G --older-than 180composes, and for scheduled cleanup that is the right shape — but a judgement that a rule cannot capture ("this model is coming back next week, that one is not") has to be recorded by transcribing paths out of a report that has already scrolled past.Permanent removal is all or nothing.
degu trash purgeremoves every entry; it has no--path. So a person who wants back the eight gigabytes sitting in one staged model directory, while keeping last week's other entries in reach ofdegu undo, cannot say that. The options are everything or patience.None of these is a missing capability in the safety model — the tiers, the staging, the undo window and the confirmations are all doing their job. What is missing is a place to make the decisions they exist to protect.
Desired behavior
degu tui: an interactive surface for the decisions the printed report can only describe.It presents the current scan and the current staging trash together, because that is where quota actually sits, and lets the reader decide per location:
It then previews the whole outcome — what will be staged, what will be permanently destroyed, what the trash will hold afterwards — and executes on confirmation. No command is typed to make it happen.
It is a wrapper over the CLI, structurally and not just in spirit. What the interface produces is the same argument set a person could have typed, handed to the same command implementation. It holds no scanning, admission, staging or deletion code of its own, so there is exactly one deletion path and no way to grow a second. The equivalent command line is shown before confirmation — not as something to type, but so that the next time the decision is a rule rather than a judgement, the reader already knows how to say it.
Three properties must not soften because the surface is graphical:
cleanalready promises. The preview is the same admission assessment execution re-verifies, and an explicit selection stays atomic: if one selected item fails preflight the whole batch is refused before anything is written.A confirmed clean also permanently removes staging entries at least seven days old —
docs/safety.mdnotes this happens even with an empty plan, because there is no background timer. The interface must show that alongside, and apart from, what the reader chose, so the two are never confused.Example workflow or CLI
Selective permanent removal should exist on the command line first, so the interface has something to wrap:
degu trash purge --path ~/.local/state/degu/trash/...Affected area or ecosystem
Cleanup and trash workflow, plus presentation; no adapter or ecosystem-specific behavior.
Current workaround or alternatives
Read the scan, copy the paths you decided to clean, assemble
--include-review --path ... --path ..., run it, then rundegu trash purgeand accept that it takes everything. For decisions a rule can express,--include-review --min-size ... --older-than ...already works well and is the right answer for scheduled cleanup; this request is about the decisions a rule cannot express.Safety and filesystem semantics
The interface must not carry deletion capability. It produces the arguments; admission, staging, purge and the mutation lock stay where they are, and the plan is re-verified at execution rather than trusted from when it was drawn.
Eligibility does not change. Not managed cannot be selected from any surface. Needs review is included per location by an explicit act. Ready to clean is unaffected.
Selective permanent removal is a new selector, not a new mechanism:
plan_expired_trashalready builds a purge plan from a subset chosen by a predicate, and captures and executes those entries through the same batch path as a full purge. Adding a path predicate reuses that; it does not introduce a second way to destroy data.Irreversible operations keep the confirmation they have today, and the interface must refuse in the same places the CLI refuses — a non-terminal, a held mutation lock, an incomplete scan that makes the plan untrustworthy.
The read-only browser from #98 is a different thing and stays useful for a different case: a report exported from a cluster and read elsewhere, where the reader cannot act because they are not on that machine. Read-only is correct there. This is about the case where the reader is on the machine and the decision is the point.
Before submitting