feat(skills): add deva-clean workspace cleanup skill - #402
Conversation
There was a problem hiding this comment.
Pull request overview
Adds the first in-repo Claude Code skill under skills/ to guide mount-safe disk cleanup in deva workspaces, aiming to prevent accidental deletion of bind-mounted host repos and unpushed git work.
Changes:
- Add
skills/deva-clean/SKILL.mddocumenting a two-pass (dry-run then approved execute) cleanup procedure driven by/proc/mountsand git worktree triage. - Update
CHANGELOG.mdto record the new skill under Unreleased.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| skills/deva-clean/SKILL.md | New skill doc describing mount mapping, disk-pressure diagnosis, candidate inventory, git triage, and safe deletion workflow. |
| CHANGELOG.md | Notes the addition of the new deva-clean skill in the Unreleased section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Read `.deva` for declared VOLUME=host:container[:mode] lines, but treat | ||
| /proc/mounts as ground truth - .deva has comments and drift: | ||
|
|
||
| grep "$(pwd)" /proc/mounts | awk '{print $2}' | sort |
| Typical: trees from `git worktree add`, one-off clones, node_modules, | ||
| .pnpm-store, stray files from shell typos ("&1"). | ||
|
|
||
| du -sh <candidates> | sort -rh |
- map bind mounts from .deva + /proc/mounts before touching anything - locate disk pressure: host mount vs container overlay (shared-VM runtimes make overlay df lie) - git-triage local dirs: worktree type, dirty state, pushed test via branch -r --contains HEAD (upstream/ahead is a trap), ref freshness - tiered dry-run report; deletion is a second, approved pass using git worktree remove + prune, never rm -rf on linked worktrees Close #401 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ed010b80d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| ### 3. Inventory candidates | ||
|
|
||
| Candidates = dirs under the workspace that are not in the mount map. |
There was a problem hiding this comment.
Exclude mount ancestors from cleanup candidates
In a workspace where .deva mounts a separate repo below a local directory (for example VOLUME=/host/repo:/workspace/project/tmp/repo), this rule still makes /workspace/project/tmp a candidate because only paths equal to entries in the mount map are excluded. The Tier 1 path later allows rm -rf for plain dirs, and rm will traverse the nested bind mount, so an approved cleanup can delete files from the mounted host repo despite the “mounts are untouchable” rule. Build candidates by pruning any directory that is a mount point or contains a mount point before suggesting removal.
Useful? React with 👍 / 👎.
| Read `.deva` for declared VOLUME=host:container[:mode] lines, but treat | ||
| /proc/mounts as ground truth - .deva has comments and drift: | ||
|
|
||
| grep "$(pwd)" /proc/mounts | awk '{print $2}' | sort |
There was a problem hiding this comment.
Avoid grepping escaped /proc/mounts paths
When the workspace path contains whitespace, /proc/mounts encodes the mount target (for example spaces become \040), so grep "$(pwd)" returns no entries even though the workspace and child binds are mounted. In that environment the mount map can be empty and later steps may classify live .deva mounts as removable local directories; use a mount parser such as findmnt or decode /proc/mounts targets before comparing paths.
Useful? React with 👍 / 👎.
8ed010b to
01f6985
Compare
| Read `.deva` for declared VOLUME=host:container[:mode] lines, then take | ||
| ground truth from the kernel - config drifts, /proc/mounts does not: | ||
|
|
||
| grep "$(pwd)" /proc/mounts | awk '{print $2}' | sort |
| Overlay numbers can lie: on shared-VM runtimes (OrbStack and friends) | ||
| overlay df reports the whole VM disk. Container-local truth: | ||
|
|
||
| sudo du -xh -d1 / | sort -rh | head |
- scripts/triage.sh: read-only pass one - mount map from /proc/mounts, pressure check, candidate walk, four verdicts per dir, conservative tier proposal with exact commands; never deletes - verdict semantics encode the field traps: pushed test is live ls-remote SHA + merge ancestry (never upstream config), MERGED is monotonic so stale refs still prove it, absence against stale refs is UNVERIFIED not safe - script proposes, judgment disposes: SKILL.md keeps promotions, demotions, stray files, and the approval gate; execution criterion is now a triage rerun reporting empty tiers - shellcheck clean Refs #401 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| # --- step 2: locate the pressure -------------------------------------- | ||
| echo | ||
| echo "-- pressure" | ||
| df -h / "$WS" | awk 'NR==1 || $NF=="/" || $NF=="'"$WS"'"' |
|
|
||
| echo "== deva-clean triage: $WS" | ||
| echo "== mounts: ${#MOUNTS[@]} (off limits)" | ||
| is_mount "$WS" || echo "!! workspace root is not a bind mount - is this a deva workspace?" |
| parent=$(dirname "$(git -C "$d" rev-parse --path-format=absolute --git-common-dir)") | ||
| T1+=("$row"$'\n'" \$ git -C $parent worktree remove $d") | ||
| else | ||
| T1+=("$row"$'\n'" \$ rm -rf $d") | ||
| fi |
| if [[ -f $d/.git ]]; then type=linked | ||
| elif [[ -d $d/.git ]]; then type=standalone | ||
| else JUDGE+=("$size $d (no git evidence - judgment call)"); continue; fi |
| n=$(git -C "$m" worktree list --porcelain 2>/dev/null | grep -c '^prunable') || n=0 | ||
| [[ $n -gt 0 ]] && PRUNABLE+=("$m: $n stale entries -> \$ git -C $m worktree prune") |
| #!/usr/bin/env bash | ||
| # triage.sh - deva-clean pass one: read-only triage of a deva workspace. | ||
| # Emits a tiered dry-run plan on stdout. Never deletes anything. |
Closes #401
First entry in skills/: a Claude Code skill for cleaning deva workspaces without shooting a mounted repo or unpushed work.
The problem: workspace dirs look identical in ls, but split into .deva bind mounts (live host repos) and local dirs (git worktrees, node_modules, package stores). Agents doing naive disk cleanup rm -rf the wrong thing.
What the skill encodes:
Extracted from a real cleanup session that reclaimed ~5G and caught three worktrees holding unpushed branches that upstream config made look safe.
🤖 Generated with Claude Code