Files
command-center/agent/managed-skills/agenttrash-purger-invocation/SKILL.md
T

4.3 KiB

name, description
name description
agenttrash-purger-invocation Invoke the .AGENTTRASH purger (scripts/purge-agenttrash.sh) — plus its refusal traps (ENOSPC as a fake stale lock, unreadable dirs poisoning a root) and the per-root scope trap.

Purging .AGENTTRASH — invocation, and the traps that make it refuse or over-reach

scripts/purge-agenttrash.sh (serverAppConfigs, merged in PR #79 fad87aa) is the tool form of the fleet's deletion policy: files land in .AGENTTRASH, and an approved purge runs this instead of being improvised per session.

Invoke

sh scripts/purge-agenttrash.sh                      # plan only — prints, deletes nothing
sh scripts/purge-agenttrash.sh --execute             # perform the plan
sh scripts/purge-agenttrash.sh --execute /some/root  # scope to one root (default: $HOME)
  • --quiet silences per-line output; errors and the summary still print. --log PATH overrides the default ~/.AGENTTRASH-cleanup.log (one dated line per run — written even for a dry run).
  • Every printable line is fixed at plan time in $HOME/.agenttrash-purge.lock/plan, so dry-run and --execute output cannot drift. Exit 0 ok · 1 any refusal or failure · 2 usage.
  • Deleting a big staged item by hand (e.g. find <dir> -depth -delete) is the fallback only when the tool cannot run at all — see trap 1 — and the operator's purge approval covers exactly that.

Trap 0: the approval is per item, the scope is per root

The plan verb empty <root>/.AGENTTRASH means the whole trash directory, not the one item the operator approved. So before --execute, list the root and prove it holds only the approved staged item — ls -A <root>/.AGENTTRASH && du -sh <root>/.AGENTTRASH/* — and note that a second .AGENTTRASH deeper in the tree is also in scope (plan remove on it = it was empty, safe). Measured 2026-10-30 on dankserver: /mnt/entropy/.AGENTTRASH held exactly the approved 20261030-movies-monk (124 files, 32 G) plus an empty qwen38-w5nl64/.AGENTTRASH; plan → --execute /mnt/entropy reported removed=2 deleted=2 refused=0 and free space rose 187 G → 218 G.

Trap 1: a full filesystem makes it lie about a lock (measured 2026-10-30)

With 0 bytes free, three invocations refused with

purge-agenttrash: refused /home/<user>: exists and is not ours to reclaim

and no lock directory existed anywhere. The script writes its lock and its plan file before scanning; both hit ENOSPC, and the failure surfaced as the lock-reclaim message. There is nothing to reclaim — free space first (delete the staged item, move it to another volume, journalctl --vacuum-size=), then run plan + --execute. Never hunt a phantom lock because the message says so; check df first.

Trap 2: an unreadable directory spoils the whole root

collect_root turns any nonzero find status into a root refusal, so the plan is built from a partial scan and the root reports refused=1 even though find printed every .AGENTTRASH it found.

  • On the dev box the cause is uutils find (find --version → find 0.8.0), which exits 1 on ~/.local/share/containers/storage/**. Proof: find /home/blank -xdev -name .AGENTTRASH >/dev/null 2>&1; echo $? → 1, while a narrower root → 0.
  • On dankserver GNU find does the same, because rootless podman storage holds foreign-UID directories (overlay/*/diff/var/lib/mysql, valkey, calibre/plugins, apt/.../partial): find /home/dank -xdev -name .AGENTTRASH 2>&1 >/dev/null | head shows the denials.
  • Fix to land in the script (not to improvise around): prune ~/.local/share/containers from the scan — a .AGENTTRASH never lives inside container storage — or accept partial output and reserve refusal for a hard find failure. sh -n / shellcheck is the gate; bash -n is not.

Verified good path (dankserver, 2026-10-30)

After freeing space by hand: /tmp-scoped plan → --execute deleted the staged item and reported removed=1 deleted=1; a second --execute /mnt/entropy cleaned that volume's root (refused=0). A 32 G staged item on an 87 T volume scans + purges in ~90 s per pass (the scan, not the deletion, is the slow part). The cleanup log carries one dated line per run — both the dry run and the execute log the verb plan, so tell them apart by removed=; read it instead of re-deriving what happened.