Audit and safely clean Xcode-related developer storage on macOS. Use whenever a developer mentions low disk space, Xcode storage, DerivedData, simulator devices or runtimes, stale beta platforms in Xcode Settings, DeviceSupport, archives, dSYMs, CocoaPods caches, simulator dyld caches, project .build folders, downloaded Xcode DMGs/XIPs, duplicate Xcode installers, or old Xcode applications. Also use this skill proactively when you hit low storage during other work, such as a build, download, ...
Scanned 9/2/2026
Install to Claude Code
npx -y skills add patrickserrano/lacquer --skill xcode-disk-cleanup --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Xcode Disk Cleanup?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/patrickserrano-xcode-disk-cleanup)More formats (shields.io, HTML) on the badges page.
---
name: xcode-disk-cleanup
description: >-
Audit and safely clean Xcode-related developer storage on macOS. Use whenever a
developer mentions low disk space, Xcode storage, DerivedData, simulator devices
or runtimes, stale beta platforms in Xcode Settings, DeviceSupport, archives,
dSYMs, CocoaPods caches, simulator dyld caches, project .build
folders, downloaded Xcode DMGs/XIPs, duplicate Xcode installers, or old Xcode
applications. Also use this skill proactively when you hit low storage during
other work, such as a build, download, or install failing with an
out-of-disk-space error. Always measure first, report recoverable GiB with
evidence, and obtain explicit itemized approval before any mutation.
---
# Xcode Disk Cleanup
## Safety contract
- Treat every cleanup request as permission to audit, not permission to delete.
- Never mutate storage before presenting exact candidate IDs, paths or simulator
identifiers, measured sizes, risks, and regeneration costs.
- Treat a category-level request made after an audit (for example, “remove all
outdated documentation caches”) as approval of the matching, current frozen
selection set when it was already fully enumerated to the user. Execute in
that turn after revalidation; do not restate the set and ask again. No special
command or repeated confirmation is required. Broad requests made before an
audit, such as “clean Xcode” or “delete everything,” remain audit-only.
- Default ordinary files and directories to Trash. Explain that space is not
reclaimed until Trash is emptied, and request separate approval before doing so.
- Revalidate identity and running-process usage immediately before mutation.
- Never use wildcards, unbounded `rm -rf`, `sudo`, SIP changes, or manual deletion
inside system-managed CoreSimulator and MobileAsset directories.
- Preserve archives and dSYMs unless the user proves the exact distributed build
is backed up elsewhere and separately approves deletion.
- Never delete `Package.resolved`, signing assets, credentials, custom DocSets, the
active Xcode, a running simulator, or an Xcode that uniquely provides a required
SDK/toolchain.
- Report summed candidate sizes separately from actual APFS space recovered.
Read `references/safety-model.md` before applying cleanup.
## Workflow
### 1. Preflight
1. Confirm the host is macOS and the bundled script is available.
2. Check for active Xcode, Simulator, `xcodebuild`, Swift build, test, archive, and
package-resolution processes.
3. Treat an open Xcode or Simulator application as context, not an automatic
cleanup blocker. Defer an affected cleanup when a build, test, archive, or
package-resolution process is active, an exact candidate is actively needed
by that operation, or a supported deletion API requires the app/device to be
stopped.
4. Do not ask the user to quit apps merely because they appear in `ps`. For
regenerable documentation caches, moving an old cache while Xcode is open may
temporarily remove local documentation until it reloads, but does not require
quitting Xcode or Simulator. State that cost instead.
5. Determine optional source roots for project-local `.build` and `.derived-data`
scanning. Do not crawl the whole home directory.
### 2. Run the read-only audit
```bash
python3 "${SKILL_DIR}/scripts/xcode_disk_cleanup.py" audit \
--output-dir .xcode-disk-cleanup-audit \
[--scan-root /path/to/projects]
```
Read both generated files:
- `.xcode-disk-cleanup-audit/report.md`
- `.xcode-disk-cleanup-audit/audit.json`
The script audits DerivedData, documentation caches, CocoaPods caches, simulator
devices and runtimes (including stale superseded beta runtimes), orphan runtime
volumes, simulator dyld caches, Xcode-managed components, Xcode installers,
installed Xcodes, archives (including never-distributed orphans), DeviceSupport
for every platform, diagnostic logs, XCTest device clones, legacy DocSets, and
explicitly requested project roots.
Shared compiler caches (`ModuleCache.noindex`, precompiled SDK modules) and the
global SwiftPM download cache are deliberately out of scope: they are always in
use on an active development machine, and clearing them trades real build-time
pain for little lasting space. Do not propose them.
### 3. Validate and enrich findings
Use the category router:
| Finding | Reference |
|---|---|
| DerivedData, module caches, project `.build`, CocoaPods | `references/generated-data.md` |
| Simulator devices, runtimes, dyld caches, XCTest clones | `references/simulators.md` |
| Archives, dSYMs, DeviceSupport, logs, DocSets | `references/release-artifacts.md` |
| Xcode DMGs/XIPs and installed Xcodes | `references/xcode-installations.md` |
| Confirmation and deletion behavior | `references/safety-model.md` |
Do not mechanically accept a scanner classification. Verify uncertain ownership,
custom paths, backups, and toolchain requirements.
### 4. Present the proposal
Sort by recoverable GiB and show:
1. Candidate ID
2. Category and exact path/identifier
3. Recoverable GiB
4. Risk: regenerable, destructive, or preserve
5. Evidence — a short "why this is stale" phrase (age in days, superseded-by,
missing workspace), not just a classification label
6. What must be rebuilt, redownloaded, or permanently lost
7. Proposed action
Keep the proposal scannable:
- Render folder candidates as clickable `file://` links so the user can inspect
them before approving. Show the candidate ID only where the user needs it to
approve, not as the item's display name.
- Carry the audit's `evidence` and `reason` fields into your notes. The script
already explains *why* each item is stale ("Unchanged for 4 days", "Superseded
by 16.4.1 (325) archived 2026-07-21", "the same documentation stays available");
dropping that context turns an explainable proposal into a bare file list.
- Hide individual items below roughly 0.5 GiB; the full itemized list stays in
`report.md` for reference. Do not pad the proposal with a "small items" bucket —
it adds questions, not signal.
- Group unavailable simulators into a table per runtime.
- Give every category its own subheading with its total size, even small ones
like documentation caches or orphan archives. A category summarized in a
trailing paragraph under another category's table gets overlooked, and
overlooked items cannot be meaningfully approved.
- Trust the scanner's classification unless you have live contrary evidence.
In particular, `Orphan archive` candidates already encode proof (no Organizer
distribution record plus a newer archive of the same app); do not demote them
back to preserve just because archives are preserve-by-default elsewhere.
Format each category like this example, adapting labels to the machine:
```markdown
### Orphaned DerivedData — 15.5 GiB · regenerable
All four belong to workspaces that no longer exist.
| Folder | Size | Why stale |
|---|---:|---|
| [RocketSim-beqqrx…](file:///Users/me/Library/Developer/Xcode/DerivedData/RocketSim-beqqrximmvoaakbpvjshhqhuacyv) | 5.6 GiB | Workspace deleted; unchanged for 1 day |
| [RocketSim-fjapct…](file:///Users/me/Library/Developer/Xcode/DerivedData/RocketSim-fjapctdhvtzcaaabmtsyumkmcarf) | 4.0 GiB | Only package downloads, no build products; unchanged for 4 days |
```
Include:
- Total candidate GiB by risk
- Current free disk space
- A warning that APFS cloning and snapshots make candidate sizes non-additive
- A direct request for approval of exact IDs. When the user selects a category,
restate every selected ID, the summed size, risk, and proposed action in a
single frozen selection set. State once that a later plain-language removal
request approves the matching set. Do not ask the user to repeat IDs, use a
prescribed phrase, or reconfirm after an unchanged revalidation.
### 5. Expand category selections and apply only approved IDs
After a completed audit, a request such as “delete all stale DerivedData” or
“clean up all outdated documentation caches” may approve every currently audited
candidate in that category only when all of the following hold:
1. Every selected item has already passed the category-specific validation and
has an exact stable ID, path or simulator identifier, size, risk, and action.
2. The assistant prints the complete expanded ID list, summed size, and action
as a frozen selection set and explains that a plain-language category request
will approve it.
3. The user then makes an unambiguous, affirmative request to remove that
category. This is the single approval and authorizes only the IDs in the
displayed set, not the category in general. Apply it immediately after
revalidation; never require a magic phrase or another user turn.
4. Revalidation succeeds. A refreshed audit does not invalidate approval when
every approved candidate retains the same ID, identity, risk, and action.
Silently use the refreshed audit and proceed. Never add a new candidate.
5. If an approved item changes, becomes active, or is reclassified, exclude and
report that item. Continue with unchanged approved items when safe; ask again
only if proceeding would materially change the approved scope or action.
Never infer category membership from a broad request before the audit, and never
include preserve items, archives/dSYMs, active assets, or simulator operations
unless their separate safeguards and approvals are met.
Invoke apply only after direct per-ID approval or a plain-language approval of a
frozen expanded ID set from the current audit:
```bash
python3 "${SKILL_DIR}/scripts/xcode_disk_cleanup.py" apply \
--audit-file .xcode-disk-cleanup-audit/audit.json \
--ids "<approved-id-1>" "<approved-id-2>" \
--confirm I_APPROVED_THE_SELECTED_ITEMS \
--output .xcode-disk-cleanup-audit/cleanup-result.json
```
Simulator device and runtime deletions are irreversible and require a second
approval plus:
```text
--confirm-irreversible I_APPROVED_IRREVERSIBLE_SIMULATOR_DELETION
```
A stale runtime is only proposed when `simctl` reports it deletable, no installed
Xcode SDK resolves to its build, and a newer runtime supersedes it on the same
platform. This is the pattern behind leftover beta platforms in Xcode Settings →
Components after installing a newer Xcode beta.
Do not pass either confirmation phrase unless the corresponding user approval is
present in the conversation.
“Separate approval” means distinct, explicit intent for the irreversible
Simulator category, not necessarily a separate message. After exact Simulator
IDs and permanent data loss have been shown, a single request such as “remove
the DerivedData and unavailable simulators” contains both ordinary approval and
separate category-specific irreversible approval. Revalidate and execute both in
that turn. A generic “clean everything” does not provide irreversible approval.
### 6. Verify
1. Re-run the audit.
2. Compare `df` free space before and after.
3. Distinguish “moved to Trash” from immediately reclaimed space.
4. Confirm protected and unapproved candidates remain.
5. Report successes, failures, and deferred items.
## Xcode installer and application rules
- Search `.xip`, `.dmg`, and `.zip` installers through Spotlight and common
download folders.
- Suggest an installer only when its parsed version matches an installed Xcode;
otherwise report it as uncertain.
- An older Xcode may only be suggested, never automatically selected, when it is
not active/running and a newer same-channel installation exists.
- Spotlight `kMDItemLastUsedDate` reflects LaunchServices opens, not command-line
use. Combine it with `xcode-select`, `DEVELOPER_DIR`, running processes,
`.xcode-version`, CI scripts, and unique SDK/toolchain evidence.
- Never infer that a stable Xcode supersedes a beta, or vice versa.
## Output quality checklist
- [ ] Audit completed without mutation
- [ ] Every item has an exact size and stable ID
- [ ] Candidate and actual recovered space are separate
- [ ] Archives/dSYMs are preserve-by-default
- [ ] Active processes and selected Xcode are protected
- [ ] User directly approved exact IDs or made an unambiguous category request
after its fully enumerated frozen selection set was shown
- [ ] Irreversible operations received separate approval
- [ ] Post-cleanup audit confirms only approved items changed
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!