Trash

The one stash for everything smine removes or replaces.

Every writer deleting or overwriting a file it does not own outright calls its *trash.Store (internal/trash) before the destructive step.

Layout

Under the state dir ~/.claude/smine:

PathHolds
trash/<stamp>/<rel>The stashed file or dir; <rel> is the original absolute path minus volume and leading separator (C:\Users\k → C/Users/k).
owned/<rel>.sha256Hex sha256 of the bytes smine last wrote there, plus a newline.
journal.jsonlOne line per event: {time, action, kind, path, reason?, stash?}

Stamp: UTC time, RFC 3339 shape with nanoseconds, - for the time's colons (NTFS refuses a colon in a file name). Two stashes in one nanosecond share a stamp dir.

2026-10-17T13-07-01.000000000Z

Rules

CallDoes
MoveRenames a file or dir into the stash; across devices, copies then removes.
KeepCopies the current bytes before the caller overwrites them.
NoteJournals a fileless event: a forgotten row, a deleted branch.
RestoreTarget derived from the stash path alone. A present target is refused unless replacing, which stashes it first. An emptied stamp dir is removed.
IsUnchanged"Did smine write these bytes", from the owned digest; no record means no.
HasMarker, MarkerLine, StripMarkerRead and write the # smine-deployed <sha256> line, the ownership proof of hook scripts and agent files.
nil storeKeeps and journals nothing; passed by a caller writing its own scratch file.
Retention

The retention sweep is the trash's only deletion: with config-server.trash_retention_days above 0, every stash and server boot remove stamp dirs older than that many days. The journal is never truncated.