Raise the Mac's actual available space to a specified target while protecting user data, active projects, and existing paths. First perform a read-only inventory and generate a plan, then execute rollback-capable cleanup or cold-storage migration for clearly identified candidates, and finally verify against the real byte count of the system data volume.
Triggers
Activate when
- The user says "help me free up at least 200GB", "intelligently clean up my Mac disk", or "migrate important but temporarily unused data to an external drive".
- The user provides Mole, DaisyDisk, Finder storage space, or
duscan results and wants direct analysis and execution of safe optimization. - The user says "optimize my Mac disk space", "free TARGET_GB on macOS", or "archive inactive files to an external drive".
Do not activate when
- The user wants to diagnose SMART warnings, bad sectors, file system corruption, or recover accidentally deleted files; hand off to storage health or data recovery capabilities.
- The user wants to erase a disk, repartition, format the system volume, or migrate an entire macOS installation; hand off to the disk management process.
- The user only wants to manage cloud quotas, or the target system is not macOS.
- The user only asks whether a certain file is important but has no capacity optimization goal; first answer what the file is used for, and do not start the whole-disk workflow.
User Configuration
This Skill can save the default target capacity, safety margin, archive volume, cleanup policy, and protected paths. Parse strictly according to user configuration ; explicit requests and CLI parameters always take precedence, and no personal paths are written into the Skill source code.
Required Resources
$SKILL_DIR/scripts/disk_optimizer.py$SKILL_DIR/references/safety-and-classification.md$SKILL_DIR/references/user-config.md
Workflow (MANDATORY)
Step 0: Parse target and boundaries
- Parse
TARGET_FREE_GB, interpreted as decimal GB by default; if the user only says "leave a bit more", first read the current space and give a reasonable target with a 15 GB margin. - Parse the optional
ARCHIVE_VOLUME、PROTECTED_PATHS, cleanup policy, and whether to keep original path links. - When key targets or boundaries are missing, use
AskUserQuestionto ask only one focused question that would change the execution plan. - Treat information such as people, project background, directory aliases, and "why it is temporarily unused" as internal judgment clues, and by default do not write them into the final report.
- Before any modification, read Safety and classification。
~/Library/Application Support/Screen Studio/Screen Studio Recordingsis a built-in protected workspace; it itself, its descendants, and any parent directory that can wholly contain it must not be cleaned or migrated, and cannot be overridden by policy or execution confirmation.- Directories loaded by other applications are likewise not to be cleaned or migrated: plugin hosts, unpacked browser extensions, and paths pointed to by globally linked commands are automatically identified during scanning as
in-use, and handled according to the protection boundary.
Step 1: Establish a real capacity baseline
python3 "$SKILL_DIR/scripts/disk_optimizer.py" status
- Use the real available byte count of
/System/Volumes/Dataas the completion criterion. - Calculate
TARGET_FREE_GB + BUFFER_GB - 当前可用空间。 - When the target has already been reached, still check whether there is a clear low-risk optimization request; do not expand the scope just for a "sense of cleanup".
Step 2: Read-only inventory and generate a minimal plan
Scan only the root directories relevant to the current task. Write runtime paths to the task temporary directory, and do not write them back to the Skill source code.
python3 "$SKILL_DIR/scripts/disk_optimizer.py" inventory \
--root ROOT_A --root ROOT_B \
--protected PROTECTED_PATH \
--min-gb 0.5 \
--output INVENTORY_JSON
python3 "$SKILL_DIR/scripts/disk_optimizer.py" plan \
--inventory INVENTORY_JSON \
--target-free-gb TARGET_FREE_GB \
--buffer-gb BUFFER_GB \
--output PLAN_JSON
The plan priority is fixed as:
- Caches, simulators, dependencies, and build artifacts that can be rebuilt by official cleanup commands;
- Clearly low-frequency but important data migrated to cold storage;
- Other large directories only enter manual review;
- Protected data never enters the execution plan.
Modification dates serve only as a signal and cannot by themselves prove that a directory is idle. Access dates likewise serve only as a signal: a full-disk backup or migration will refresh the access times of a large batch of files to the same day,recently-accessed so they are downgraded to manual review only and are not used as a standalone basis for retention or deletion. When different directories contain the same build artifact, the freed space is not counted twice.
Step 3: Pre-check the external archive volume
When migration is needed, first run:
python3 "$SKILL_DIR/scripts/disk_optimizer.py" preflight-volume \
--archive-root ARCHIVE_ROOT \
--required-gb REQUIRED_GB
- Confirm that the volume is mounted, writable, has sufficient free space, and that the source and destination are not on the same volume.
- Use directories organized stably by content source, such as
cold-storage/projects、cold-storage/media; dates go only into logs, not into the top-level directory hierarchy. - When the destination already exists, stop overwriting and first determine whether it is a formal archive or an incomplete copy.
Step 4: Perform rebuildable cleanup
Prefer to invoke the tool's own cleanup commands, such as npm, Homebrew, CocoaPods, Xcode, or simulator commands. When no dedicated command exists, use two-phase cleanup for explicit directories within the allowlist:
# 先预览
python3 "$SKILL_DIR/scripts/disk_optimizer.py" stage-cleanup \
--path REBUILDABLE_PATH
# 明确执行,只移入回滚区,不清空废纸篓
python3 "$SKILL_DIR/scripts/disk_optimizer.py" stage-cleanup \
--path REBUILDABLE_PATH \
--execute --confirm STAGE_REBUILDABLES
Passing the user directory, disk root directory, Git history, Photos library, Messages, Mail, Agent sessions, or additional protected paths to the script is prohibited. When executing with multiple paths, let the script complete all pre-checks; if a permission or lock error occurs on any path, the script should roll back the paths already moved in this round and return a structured error.
An active workspace managed by an application is not a cache. Even if a candidate is named Caches、build or another allowlist name, as long as it is located in a built-in/explicitly protected path, or its parent directory would as a whole contain protected content, the script must refuse to execute.
Referenced build artifacts are likewise not caches.dist、build Once it becomes the target of an Obsidian plugin, an unpacked browser extension, a VS Code extension, or npm link , deleting it is equivalent to uninstalling that integration, not deleting a rebuildable copy; the script directly refuses such candidates for stage-cleanup and migrate。
Step 5: Transactionally migrate important low-frequency materials
For each candidate, independently perform "copy → verify → move source into the local rollback area → link at the original path → log":
# 先预览
python3 "$SKILL_DIR/scripts/disk_optimizer.py" migrate \
--source SOURCE_PATH \
--archive-root ARCHIVE_ROOT \
--protected PROTECTED_PATH \
--category media
# 用户已要求直接执行时,确认字符串必须等于规范化源路径
python3 "$SKILL_DIR/scripts/disk_optimizer.py" migrate \
--source SOURCE_PATH \
--archive-root ARCHIVE_ROOT \
--category media \
--verify metadata \
--execute --confirm-source NORMALIZED_SOURCE_PATH
- Use
--verify checksumfor high-value small materials; for large media, verification by full relative path, file count, and byte count may be used. - If dynamic files, permissions, resource forks, or destination conflicts occur during copying, stop that candidate and keep the source directory; use another stable candidate to make up the capacity.
- By default, do not copy resource forks for code and ordinary data; use
--preserve-xattrs。 - only when it is confirmed that the application bundle depends on extended attributes. When the external volume is disconnected, the symbolic links are temporarily unavailable, and the final report must state this.
migratemust use the same built-in andstage-cleanupboundaries as--protected; protected workspaces cannot be bypassed through migration.
Step 6: Precisely reclaim this round's rollback items
Before cleanup, confirm that all migration writes have finished and properly unmount the archive volume. Do not invoke Finder's batch delete、empty trash or automatic retries; locked or system-protected items will trigger modal confirmation dialogs, and repeated submissions will cause a popup storm.
First list the items generated by this Skill in the local rollback area:
python3 "$SKILL_DIR/scripts/disk_optimizer.py" list-staged \
--rollback-root "$HOME/.Trash" \
--output STAGED_JSON
Pass only the explicit top-level STAGED_JSON paths in .cleanup to the preview command:
python3 "$SKILL_DIR/scripts/disk_optimizer.py" purge-staged \
--path ROLLBACK_ITEM \
--output PURGE_PLAN_JSON
After checking the paths, sizes, and number of items, execute with explicit confirmation:
python3 "$SKILL_DIR/scripts/disk_optimizer.py" purge-staged \
--path ROLLBACK_ITEM \
--execute --confirm PURGE_STAGED \
--output PURGE_RESULT_JSON
This command deletes only the explicit .cleanup items, preserves the user's original Trash contents, does not follow symbolic links, does not retry failed items, and outputs each item's purged、already-absent or error status. On error, stop and preserve the remaining rollback items. After completion, remount the archive volume, then verify the migration links and actual capacity.
Step 7: Real acceptance and minimal supplementation
python3 "$SKILL_DIR/scripts/disk_optimizer.py" verify \
--target-free-gb TARGET_FREE_GB \
--buffer-gb BUFFER_GB \
--link MIGRATED_SOURCE_PATH
passed=true, capacity reachesTARGET_FREE_GB + BUFFER_GB, and all migration links are valid after remounting; only when all three hold simultaneously is it considered complete.- If only a small amount of space is missing, append only the minimal necessary rebuildable build artifacts; do not expand to photos, sessions, browser data, or active source code.
- The final report lists: capacity before and after cleanup, actual amount freed, migration mapping, cleaned categories, retained items, rebuild cost, impact of disk disconnection, and unresolved anomalies.
Failure Recovery
- Dynamic files or copy failure: keep the source directory as is; move the incomplete target out of the official archive tree before deciding whether to retry.
- Screen Studio save report
can't be recovered: stop all cleanup/migration of its recording workspace, first check the error path, workspace directory, and rollback items; do not judge the project state as intact just because the media files still exist. - Verification mismatch: do not move the source directory and do not create links; resynchronize the differences and re-verify.
- Space does not increase after cleanup: check the local Trash, APFS snapshots, and files still held by processes, then read the actual data volume capacity.
- Finder shows a deletion confirmation dialog: immediately stop the automation process calling Finder, read
list-staged, and switch topurge-stagedexplicit path mode; do not repeatedly submit the same batch of deletions. purge-stagedreturnspartial-failure: retain the error items and structured results, review permissions or occupancy status item by item, and then have the user initiate a new explicit operation.- Links invalid after remounting: check the volume name and archive location; repair the links first before emptying the rollback copies.
- Execution script returns exit code
3: indicates insufficient targets or candidates, not a script crash; continue minimal supplementation or report the shortfall.
Validation
python3 "$SKILL_DIR/scripts/validate_skill.py" "$SKILL_DIR"
python3 "$SKILL_DIR/scripts/disk_optimizer.py" --help
python3 "$SKILL_DIR/scripts/disk_optimizer.py" status
python3 "$SKILL_DIR/scripts/test_disk_optimizer.py"
Activation regression: "Help me free up at least 200GB and put low-frequency data on an external drive."
Non-triggering regression: "What does the SMART warning on this SSD mean?"
Dependencies
- macOS
- Python 3.8+
rsyncdiskutilis used for archive volume mounting and read-back; rollback item reclamation uses direct Python filesystem operations and does not call Finder
Runtime context
Before running, read the same-directory skill.yaml, injected by the host's skill-runtime in the order of "current request, project context, personal configuration, brand Profile, security defaults", using only the fields declared in the manifest.
- When the
required: truefield is missing, ask the user one focused question according toquestions; the answer is used only for this run unless the user explicitly requests that it be saved. - Profile is used only for public brand facts; personal configuration is used only for decisions and is not automatically written into artifacts or source code.
- Debug errors provide copyable
context_id, field paths, and sources, without outputting secrets, full private paths, or raw content.
Runtime context (shared)
Before running, read this Skill package's skill.yaml, with the host providing the skill-runtime/v1 context. The field resolution order is: current request, project context, personal Preferences, brand Profile, general defaults.
- Use only the fields declared in the Manifest; Profile stores public brand facts, and Preferences stores personal work preferences.
required: trueWhen the field is missing, ask the user one focused question according to the Manifest's question configuration; save the answer only after the user explicitly agrees.- Errors provide copyable
context_idfield paths and sources, and the diagnostic content avoids secrets, full private paths, and raw configuration.