Install
openclaw skills install @pinguy/symlink-space-saverReduce duplicate storage by replacing safe redundant copies with symlinks. Identify the canonical copy first, verify consumers tolerate symlinks, preserve rollback, detect already-shared storage, guard against state drift, prefer atomic replacement, and prove the referenced path still works before reclaiming redundant data.
openclaw skills install @pinguy/symlink-space-saverUse this skill when multiple copies of the same large file or directory are consuming unnecessary disk space and a symlink could safely let several consumers share one canonical copy.
The goal is deduplication without creating hidden coupling.
A symlink saves space by turning a duplicate into a dependency. Treat that dependency as real system state.
Choose one canonical copy, prove every proposed consumer can safely follow a symlink to it, create and verify the link, then remove the redundant copy only after rollback is clear.
Do not use symlinks merely because two paths currently contain the same bytes.
The safe loop is:
discover → prove duplicate → inspect physical storage → choose canonical → check consumers → assess failure modes → preserve rollback → link atomically where practical → verify → reclaim → record
Configured is not working.
A symlink existing is not proof that the application using it still works.
A successful hash match is not proof that the files remained unchanged until replacement.
A visible duplicate is not proof that it occupies duplicate physical storage.
Consider this skill when:
Do not trigger just to tidy small files. The added coupling is rarely worth saving a few kilobytes.
Before changing the filesystem, produce a compact decision receipt.
Recommended form:
Candidate:
Canonical proposal:
Identity proof:
Physical-storage status:
Proposed mechanism:
Expected physical saving:
Consumer(s):
Consumer symlink support:
Risk class:
Rollback plan:
State-drift sensitivity:
Platform/tool assumptions:
Do not mutate paths until the proposed state transition is understood.
This separates analysis from execution and makes accidental destructive changes less likely.
Before linking anything, establish that the candidates are actually equivalent.
For files, prefer strong receipts.
stat --printf='%s %n\n' -- "$a" "$b"
sha256sum -- "$a" "$b"
For large files where hashing is materially expensive, size + metadata may be used as a preliminary filter, but do not call two files identical from names alone.
Useful progressive checks:
stat --printf='%s\n' -- "$file"
cmp -s -- "$a" "$b"
sha256sum -- "$a" "$b"
For directories, compare content deliberately. A matching directory name is not evidence of identical state.
Do not deduplicate:
Directory deduplication is not merely "file deduplication, but recursive."
Directory symlinks can interact differently with:
For directory replacement, require explicit consumer verification rather than relying on generic filesystem compatibility.
Before creating a new dependency, determine whether the apparent duplicates already share storage or whether the expected saving is real.
Two paths may already be:
Check inode/device identity where available:
ls -li -- "$a" "$b"
stat -- "$a" "$b"
Check allocated size rather than only apparent size:
du -h -- "$a" "$b"
du --apparent-size -h -- "$a" "$b"
Where the filesystem exposes reflink or extent-sharing information, use filesystem-aware tooling when the saving matters.
Do not introduce a symlink dependency to save effectively zero physical space.
Record the difference between:
Logical duplicate size:
Physical allocated size:
Expected reclaimable size:
Already-shared storage detected: yes/no/unknown
A duplicate proved identical at one moment may change before replacement.
For mutable-looking candidates, record state before or during identity verification:
device
inode
size
mtime
optional ctime
hash
Immediately before replacing the consumer path, re-check the relevant state.
If device, inode, size, modification time, or other material identity changed unexpectedly:
abort and re-prove identity.
Do not continue from a stale hash receipt.
For actively written files or directories, prefer quiescing the writer, taking an application-supported snapshot, or declining deduplication.
This is especially important for:
The canonical copy should be the path most likely to remain stable.
Prefer a location that is:
Avoid making these canonical without strong justification:
/tmp/
/var/tmp/
browser/application caches
package build directories
download scratch directories
temporary mount points
If one copy is managed by a package manager, model manager, application updater, or cleanup job, understand that lifecycle before pointing unrelated consumers at it.
A canonical path is not just "the copy we kept."
Record who owns its lifecycle:
Canonical path:
Lifecycle owner:
Expected mutability:
Expected cleanup/update mechanism:
Consumers:
Rollback source:
If nobody clearly owns the canonical copy, the proposed deduplication creates future ambiguity.
A symlink is appropriate only when the consumer behaves correctly with one.
Check whether the target software:
Do not assume "the operating system supports symlinks" means every application supports them safely.
Avoid or escalate for review when:
Never use symlinks to weaken a permission boundary.
The safest symlink targets are files whose meaning does not change underneath consumers.
Good candidates often include:
Higher-risk candidates include:
If consumers expect independent mutation, use separate copies or a purpose-built shared-storage mechanism instead.
Inspect the existing paths before changing them:
ls -ld -- "$source" "$duplicate"
readlink -f -- "$source"
readlink -f -- "$duplicate"
findmnt -T "$source"
findmnt -T "$duplicate"
Confirm:
Remember that directory execute permission controls traversal.
A readable file behind an untraversable parent directory is still unusable.
The shell examples in this skill primarily assume a GNU/Linux userland.
Commands such as:
stat --printf
readlink -f
findmnt
are not uniformly portable across macOS, BSD, BusyBox, containers, or minimal recovery environments.
Before relying on a diagnostic command:
A safety check that silently behaves differently on another platform is not a safety check.
Prefer a relative link when the two paths move together as one tree and portability matters.
Example:
ln -s -- "../shared/model.gguf" "models/model.gguf"
Relative links survive moving the containing tree together.
Prefer an absolute link when the canonical location is an intentional machine-level anchor.
Example:
ln -s -- "/srv/models/model.gguf" "$HOME/.models/model.gguf"
Absolute links are clearer for stable system locations but break if the canonical root moves.
Do not choose based on habit. Choose based on expected lifecycle.
Do not delete the duplicate first.
Safe pattern for a file:
duplicate exists
→ verify equality
→ capture state receipt
→ move duplicate aside
→ create replacement symlink
→ verify resolution
→ test consumer
→ keep rollback copy until acceptance
→ remove rollback copy
Example:
mv -- "$duplicate" "$duplicate.rollback"
ln -s -- "$canonical" "$duplicate"
If the consumer test fails:
rm -- "$duplicate"
mv -- "$duplicate.rollback" "$duplicate"
For high-value or difficult-to-reproduce data, do not make the sole remaining copy depend on an unverified storage location.
If there is not enough free space to preserve a full rollback copy, say so before proceeding.
Possible alternatives:
Do not silently trade recoverability for disk space.
Avoid leaving the consumer path absent longer than necessary.
Where the platform and consumer semantics allow it:
Example pattern:
mv -- "$consumer_path" "$consumer_path.rollback"
ln -s -- "$canonical" "$consumer_path.new"
test -L "$consumer_path.new"
test -e "$consumer_path.new"
mv -- "$consumer_path.new" "$consumer_path"
A same-filesystem rename is typically the cleanest visible state transition, but do not assume every consumer tolerates replacement while running.
For live services, package managers, or watchers:
Atomic replacement narrows the interruption/race window; it does not eliminate application-level semantics.
For a file:
ln -s -- "$canonical" "$consumer_path"
For a directory:
ln -s -- "$canonical_dir" "$consumer_dir"
Do not casually use ln -sf against an unknown destination.
Before replacing anything, inspect exactly what occupies the consumer path:
ls -ld -- "$consumer_path"
file -- "$consumer_path"
A force flag can overwrite a link pointing somewhere important or behave unexpectedly around directories.
Prefer explicit remove/rename + create steps where the state transition is visible.
First verify the link mechanically:
test -L "$consumer_path"
test -e "$consumer_path"
readlink -- "$consumer_path"
readlink -f -- "$consumer_path"
Then verify the real consumer.
Examples:
Weak:
readlink shows the expected target.
Better:
The application opened the symlinked 18.5 GB model and completed the expected inference/import operation.
If the consumer has a restart boundary, test through it where practical.
Record what actually proved the replacement worked.
Recommended form:
Consumer:
Consumer path:
Resolved canonical target:
Mechanical link checks:
Application test:
Command / action:
Exit status / observed result:
Restart boundary tested: yes/no/not applicable
Test timestamp:
Verifier:
Outstanding caveats:
A configured verifier is not evidence that verification happened.
An application opening the path once may still be insufficient if the real failure mode occurs during restart, upgrade, cleanup, or watcher refresh.
Test the boundary that matters.
Once the symlink and application behaviour have passed:
Example:
rm -- "$duplicate.rollback"
du -sh -- "$canonical"
df -h -- "$(dirname "$canonical")"
Do not report space reclaimed merely from apparent file sizes.
Sparse files, compression, reflinks, hard links, and filesystem deduplication can make logical and physical usage differ.
Where it matters, use filesystem-aware tools to confirm actual storage impact.
A symlink is not always the best deduplication mechanism.
Use when:
Trade-off: target removal breaks consumers.
Use when:
Trade-off: changes through either path affect the same inode, and directory hard links are normally unavailable.
Before creating one, check whether the paths are already hard-linked.
Use when:
Example where supported:
cp --reflink=always -- "$source" "$dest"
Trade-off: not universally supported, and later writes consume additional space.
Choose the mechanism that matches the consumer contract, not merely the one with the smallest immediate disk usage.
Large model ecosystems are particularly good candidates for safe deduplication because weights are often immutable and expensive to duplicate.
Before linking GGUFs, projectors, adapters, or checkpoints:
If an importer monitors a directory, test whether creating a symlink triggers the expected import.
Some watchers react differently to links than to new regular files.
If a model manager may update or replace the target, record that manager as the lifecycle owner and re-check the dependency after upgrades.
If either the canonical path or consumer path requires root-level mutation, apply the privileged-operations rules.
The privilege boundary must remain visible to the user.
Do not use elevated symlink creation to bridge a security boundary such as:
root-owned service → user-writable target
without explicitly analysing the security consequences.
A privileged process following a mutable user-controlled symlink can turn a space-saving optimisation into an escalation path.
test -e "$consumer_path"
A symlink itself may exist while its target does not.
Use:
readlink -f -- "$consumer_path"
Failure to resolve can indicate a loop or missing component.
Re-check the recorded device/inode/size/mtime receipt before replacement.
If it changed unexpectedly, re-prove identity.
Do not assume logical duplicates consume independent extents.
Check inode identity, allocated blocks, reflink behaviour, or filesystem deduplication before promising meaningful savings.
Identify cleanup policies before linking caches or manager-owned content.
An updater may unlink the symlink and write a new regular file at the consumer path.
Re-check after upgrades when this behaviour is plausible.
All consumers must retain traverse/read/write permissions appropriate to their use.
Links crossing mounts fail when the target filesystem is absent.
Know whether backup tooling stores the symlink itself or dereferences the target.
Backup, packaging, indexing, and recursive-copy tools may treat a symlinked directory differently from a real directory.
Treat directory replacements as a higher-risk class.
A diagnostic command that is unavailable or behaves differently can invalidate the safety procedure.
Verify the platform assumptions before acting.
A useful durable record is compact:
Consumer:
Symlink:
Canonical target:
Reason:
Identity receipt:
Physical-storage receipt:
Lifecycle owner:
Verified by:
Application acceptance receipt:
Rollback/rebuild:
Platform:
State-drift sensitive: yes/no
Drift-sensitive as of:
Do not record every obvious project-local symlink.
Record links that:
The next agent should not "fix" a deliberate symlink by copying another 20 GB file back into place.
Before deduplicating, the answer to each of these should be explicit:
Are these objects actually identical?
Are they still identical now?
Are they already sharing physical storage?
Which copy owns the lifecycle?
Will every consumer follow the proposed mechanism safely?
Does the link cross a trust, sandbox, mount, or privilege boundary?
Can the original state be restored?
Can the switch be made without a dangerous race window?
Did the real consumer pass?
Was acceptance recorded?
Was physical space actually reclaimed?
If one of the load-bearing answers is unknown, do not paper over it with confidence.
Investigate it, reduce scope, or leave the duplicate alone.