On this page
saferm is an AI-first safe rm replacement that archives files instead of permanently deleting them, with rich metadata capture and full undo support.
#saferm
AI-first safe rm replacement. Archives files instead of deleting them.
#CLI Reference
#Packages
#internal/archive
Package archive handles file and directory archival to the saferm archive. It supports atomic same-filesystem renames, cross-device copy-and-verify, and tar+zstd compression for directories.
#ErrFileNotFound
var ErrFileNotFound = errors.New("file not found")Sentinel errors.
#ErrRecursiveRequired
var ErrRecursiveRequired = errors.New("target is a directory; recursive flag required")#ErrConflict
var ErrConflict = errors.New("destination already exists")#ErrHashMismatch
var ErrHashMismatch = errors.New("hash mismatch after copy")#ArchiveResult
type ArchiveResult structArchiveResult holds the outcome of archiving a file or directory.
#Archive
func Archive(path string, archiveDir string, isRecursive bool) (*ArchiveResult, error)Archive moves a file or directory into archiveDir, returning the result. For files: moved directly (or copied cross-device) with SHA-256 hash. For directories: compressed into a .tar.zst archive.
#Restore
func Restore(uuid string, archiveDir string, destPath string, isDirectory bool, force bool) errorRestore extracts an archived file or directory to destPath.
#internal/db
Package db manages the SQLite database tracking all saferm deletions. It uses WAL mode and busy_timeout for concurrency safety across multiple simultaneous sessions.
#SchemaSQL
const SchemaSQL = `#ErrNotFound
var ErrNotFound = errors.New("record not found")ErrNotFound is returned when a queried record does not exist.
#DB
type DB structDB wraps a *sql.DB connection to the saferm SQLite database.
#DeletionRecord
type DeletionRecord structDeletionRecord represents a single archived deletion in the database.
#Open
func Open(dbPath string) (*DB, error)Open opens (or creates) the SQLite database at dbPath with WAL mode and busy_timeout=5000ms, then runs the schema DDL.
#DB.Close
func (d *DB) Close() errorClose closes the underlying database connection.
#DB.Insert
func (d *DB) Insert(rec *DeletionRecord) (int64, error)Insert inserts a DeletionRecord and returns the auto-increment ID.
#DB.QueryByID
func (d *DB) QueryByID(id int64) (*DeletionRecord, error)QueryByID retrieves a single record by ID. Returns ErrNotFound if it does not exist.
#DB.QueryByPath
func (d *DB) QueryByPath(path string) ([]*DeletionRecord, error)QueryByPath returns all non-restored records matching the given original_path, ordered by deleted_at DESC (newest first).
#DB.QueryAll
func (d *DB) QueryAll(includeRestored bool) ([]*DeletionRecord, error)QueryAll returns all records ordered by deleted_at DESC. If includeRestored is false, restored records are excluded.
#DB.MarkRestored
func (d *DB) MarkRestored(id int64, restoredTo string) errorMarkRestored sets restored_at to now and restored_to to the given path. Returns ErrNotFound if the record does not exist.
#DB.Delete
func (d *DB) Delete(id int64) errorDelete permanently removes a record by ID (used for purge). Returns ErrNotFound if the record does not exist.
#DB.QueryOlderThan
func (d *DB) QueryOlderThan(before time.Time) ([]*DeletionRecord, error)QueryOlderThan returns all non-restored records deleted before the given time.
#internal/git
Package git provides helpers for managing the git index alongside saferm's archive/restore operations.
#IsInGitRepo
func IsInGitRepo(dir string) boolIsInGitRepo returns true if dir is inside a git working tree.
#IsGitTracked
func IsGitTracked(path string) boolIsGitTracked returns true if the file at path is tracked by git (i.e., known to the index). The path must be absolute or relative to the current working directory; the command runs from the file's parent directory.
#GitRmCached
func GitRmCached(path string, recursive bool) errorGitRmCached stages the removal of path in the git index without touching the working tree (the file is already archived). When recursive is true, -r is added for directory removal.
#GitAdd
func GitAdd(path string) errorGitAdd stages a file in the git index. The command runs from the file's parent directory.
#internal/meta
Package meta collects rich metadata about each deletion: environment variables, git repository context, parent process information, and arbitrary user-supplied key-value pairs.
#Metadata
type Metadata structMetadata holds contextual information captured at deletion time.
#Collect
func Collect(cfg *config.Config, customMeta map[string]string) (*Metadata, error)Collect gathers metadata from the current environment. Never fails fatally -- if a collector errors, it populates what it can.
#internal/config
Package config manages saferm's TOML configuration and directory initialization. Configuration is loaded from ~/.saferm/config.toml with sensible defaults when the file is absent.
#Config
type Config structConfig holds saferm configuration, loaded from TOML.
#BaseDir
func BaseDir() stringBaseDir returns the saferm base directory. If SAFERM_HOME is set, its value is used as-is (expected to be an absolute path). Otherwise falls back to ~/.saferm/.
#DefaultConfig
func DefaultConfig() *ConfigDefaultConfig returns a Config with all defaults filled in.
#Load
func Load() (*Config, error)Load reads the config file from the default location (~/.saferm/config.toml) and returns a Config with defaults applied. If the file doesn't exist, returns the default config without error.
#LoadFrom
func LoadFrom(path string) (*Config, error)LoadFrom reads config from the specified path. If the file doesn't exist, returns the default config without error. If it exists but is malformed, returns an error.
#EnsureDirectories
func EnsureDirectories(cfg *Config) errorEnsureDirectories creates the archive dir, db dir (parent of DBPath), and base dir if they don't exist. Uses 0700 permissions.