Add macos-provenance-xattr-deletion skill
This commit is contained in:
parent
44883ab6a8
commit
0d3916f806
1 changed files with 102 additions and 0 deletions
102
dot_claude/skills/macos-provenance-xattr-deletion/SKILL.md
Normal file
102
dot_claude/skills/macos-provenance-xattr-deletion/SKILL.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
name: macos-provenance-xattr-deletion
|
||||
description: |
|
||||
Fix for "Permission denied" when deleting empty directories on macOS created by
|
||||
sandboxed processes (e.g., Claude Code agents, git worktrees from sandboxed tools).
|
||||
Use when: (1) rm -rf fails with "Permission denied" on an empty directory,
|
||||
(2) chmod and xattr -d don't help, (3) the directory has com.apple.provenance
|
||||
extended attribute, (4) git worktree remove fails with "is not a .git file".
|
||||
Root cause: macOS sandbox provenance tracking marks directories as immutable
|
||||
to the sandboxed process. Only an unsandboxed terminal can delete them.
|
||||
author: Claude Code
|
||||
version: 1.0.0
|
||||
date: 2026-02-21
|
||||
---
|
||||
|
||||
# macOS com.apple.provenance Blocking Directory Deletion
|
||||
|
||||
## Problem
|
||||
Directories created by sandboxed macOS processes (like Claude Code subagents
|
||||
running in git worktrees) acquire a `com.apple.provenance` extended attribute.
|
||||
This attribute prevents the sandboxed process from deleting the directories,
|
||||
even when they are empty and owned by the current user. Standard remedies
|
||||
like `chmod`, `xattr -d`, and `xattr -cr` all fail silently — the attribute
|
||||
is enforced at the kernel level for sandboxed processes.
|
||||
|
||||
## Context / Trigger Conditions
|
||||
- `rm -rf <directory>` fails with "Permission denied" on an empty directory
|
||||
- `ls -la` shows the directory is owned by you with normal permissions
|
||||
- `ls -la` shows an `@` flag on the directory (extended attributes present)
|
||||
- `xattr -l <directory>` shows `com.apple.provenance:`
|
||||
- `git worktree remove` fails with "is not a .git file, error code 2"
|
||||
- The directory was created by a sandboxed subprocess (Claude Code agent,
|
||||
Xcode build, App Sandbox process)
|
||||
|
||||
## Solution
|
||||
|
||||
**You cannot delete these directories from within the sandboxed process.**
|
||||
|
||||
Run the cleanup manually in an unsandboxed terminal:
|
||||
|
||||
```bash
|
||||
# Remove the stuck directory
|
||||
rm -rf <path-to-directory>
|
||||
|
||||
# If it was a git worktree, also prune and delete the branch
|
||||
git worktree prune
|
||||
git branch -D <branch-name>
|
||||
```
|
||||
|
||||
If running from a script that may be sandboxed, detect and warn:
|
||||
|
||||
```bash
|
||||
if xattr -p com.apple.provenance "$DIR" &>/dev/null; then
|
||||
echo "Directory $DIR has provenance lock. Delete manually from an unsandboxed terminal."
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## Verification
|
||||
```bash
|
||||
# Confirm directory is gone
|
||||
ls -la <path> # Should show "No such file or directory"
|
||||
|
||||
# Confirm worktree is pruned
|
||||
git worktree list # Should not show the removed worktree
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
**Scenario**: Claude Code spawns two agents in git worktrees. After completing
|
||||
work, the team lead tries to clean up:
|
||||
|
||||
```
|
||||
$ rm -rf .worktrees/mobile
|
||||
rm: .worktrees/mobile/frontend/node_modules: Permission denied
|
||||
rm: .worktrees/mobile/.venv: Permission denied
|
||||
|
||||
$ xattr -l .worktrees/mobile/frontend/node_modules
|
||||
com.apple.provenance:
|
||||
|
||||
$ xattr -d com.apple.provenance .worktrees/mobile/frontend/node_modules
|
||||
# Silently fails — still can't delete
|
||||
|
||||
$ chmod -R u+w .worktrees/mobile
|
||||
# Also doesn't help
|
||||
```
|
||||
|
||||
**Fix**: Open a regular Terminal.app (unsandboxed) and run:
|
||||
```bash
|
||||
rm -rf .worktrees/mobile
|
||||
git worktree prune
|
||||
```
|
||||
|
||||
## Notes
|
||||
- `com.apple.provenance` is a macOS security feature for App Sandbox tracking
|
||||
- It tracks which sandboxed app created a file/directory
|
||||
- The restriction only applies to the sandboxed process; unsandboxed terminals
|
||||
can delete freely
|
||||
- This commonly affects: node_modules, .venv, build output directories
|
||||
- The directories are often empty (contents were deleted successfully, but
|
||||
the directory itself can't be removed)
|
||||
- `git worktree remove --force` also fails for the same reason
|
||||
Loading…
Add table
Add a link
Reference in a new issue