Spec: Stamp (Intent Tracker)

Objective

Build a lightweight yet powerful wrapper for native package managers. Stamp lets developers install, search, get info, and remove packages and repositories across multiple package managers through a single CLI — tracking every intentional choice into a portable, version-controllable TOML manifest. The primary workflow is using stamp install as a unified wrapper to guarantee total traceability from day one. It also acts as a passive safety net, allowing developers to track changes retroactively via local snapshot diffing (stamp reconcile) if they bypass the tool. It fully supports tracking custom repositories (taps, remotes) across all supported package managers.

Tech Stack

Command Blueprint

The complete surface area of the CLI, including aliases and flags.

Global Flags:

Flag Standardization Rules

  1. Every flag SHOULD have a single-character short form (e.g. --manager, -m).
  2. Actions MUST be subcommands, not flags. (e.g. stamp man install, not stamp man --install).
  3. Boolean flags for enabling/disabling behavior are acceptable (e.g. --dry-run, --json).

Destructive commands (install, remove, reinstall, restore, update, autoremove, clean, hold, unhold, repo add/remove) share one fail-closed gate:

  1. -y/--yes skips refresh, preview, and prompt entirely.
  2. Otherwise the command renders the adapter-owned transaction preview (manager.Previewer returns a typed Preview{Output, Noop}; combined stdout+stderr, never parsed by the CLI — see ADR-016), then prompts with a default of no ([y/N]).
  3. A Noop preview (e.g. package already up to date, or remove of an absent package) fails fast with nothing to do — no prompt.
  4. A preview that cannot be rendered warns (⚠ could not render preview) and still prompts; managers without a Previewer do the same.
  5. Non-interactive input without -y refuses with a non-zero exit — a forgotten -y in a script or CI pipeline fails loud instead of silently doing nothing. An interactive decline (and a Noop preview) stops cleanly with exit 0.
  6. After confirmation, the CLI marks the context with manager.WithYes; destructive adapter methods refuse to run without that marker (ErrConfirmationRequired). This is defense-in-depth at the privileged boundary.

autoremove/clean --dry-run are read-only and never require consent.

See ADR-015 and ADR-016 for the full design.

Core Commands:

Command Aliases Flags Description
stamp     Prints welcome message suggesting stamp hello or stamp --help.
stamp setup hello   Runs first-time setup wizard: completions, man pages, init, doctor.
stamp init     Initializes manifest.toml and takes baseline snapshot.
stamp install <pkg>... add --manager, -m <name>, --note, -n <text> Installs natively and records intent. Multiple packages require -m (native batch support).
stamp remove <pkg>... uninstall, rm, delete, del --manager, -m <name> Removes natively and untracks. Multiple packages require -m (native batch support).
stamp reinstall <pkg>...     Reinstalls natively and records intent. Works for both manifest-tracked and pre-existing packages. Multiple packages require -m (native batch support).
stamp search <query>   --manager, -m <name> Searches across managers.
stamp info <pkg>   --manager, -m <name> Shows package information across managers, including raw outputs.
stamp reconcile   --dry-run, -d, --manager, -m <name> Detects drift since last snapshot and auto-tracks discovered packages and repositories. Warns when tracked packages are no longer installed.
stamp restore   --dry-run, -d, --manager, -m <name> Reinstalls repos and packages on a new machine.
stamp update upgrade --manager, -m <name>, --package, -p <pkg>, --serial, -s Runs system upgrades across all managers. Parallel by default. Use -s for serial, -p for single-package.
stamp list ls --json, -j, --manager, -m <name>, --type, -t <type> Lists tracked packages and repos. Filter by entity type and origin (stamped/reconciled); --type missing lists manifest packages not installed.
stamp manifest   --json, -j Manifest management. Subcommands: history (list backups), diff [ts\|hash] (compare current with a backup).
stamp doctor   --json, -j, --manager, -m <name> Checks manager availability, manifest integrity, manifest-vs-system drift, and UNIX compliance.
stamp self-update self-upgrade --check, -c Checks for and installs the latest version of stamp.
stamp completion [shell]   --stdout, -s Generates and installs shell completion scripts. Auto-detects shell if not specified.
stamp man     Command group for system reference page management.
stamp auto-reconcile on\|off   --period, -p hourly\|daily(default)\|weekly Installs or removes automated reconcile timer (systemd/launchd).

Man Subcommands:

Command Flags Description
stamp man   Shows help for stamp man command group. Same as stamp man help.
stamp man install --prefix <path> Installs man page to system or user path. Default: ~/.local/share/man/man1/.
stamp man check   Verifies installed man page version matches stamp version.

Repository Commands:

Command Aliases Flags Description
stamp repo add <name> [url] install --manager, -m <name> (Required) Adds custom repository and records it. DNF: URL ending in .repo is fetched and installed verbatim, preserving gpg settings. A single URL argument derives the name from the URL (basename with .repo stripped, or host).
stamp repo remove <name> uninstall, rm, delete, del --manager, -m <name> Removes a repository and untracks it. -m is optional when the repo is tracked in the manifest.
stamp repo list ls --json, -j, --manager, -m <name> Lists all tracked repositories.

Supported Package Managers

System Managers

Manager OS Notes
DNF / YUM Fedora/RHEL/CentOS DNF preferred, YUM fallback when DNF unavailable
APT / apt-get Debian/Ubuntu  
Paru Arch Linux Preferred when both Paru and Pacman are installed
Pacman Arch Linux Fallback when Paru not installed
Zypper openSUSE/SLES  
Snap Linux (universal)  
Flatpak Linux (sandboxed)  
Brew macOS, Linux User-space, no sudo for most operations
MacPorts macOS  

Language Toolchain Managers

Manager Scope Notes
go install Go binaries Full module paths required
pipx Python CLI tools  
uv Python CLI tools Faster alternative to pipx

Package Manager Resolution Engine

When a user runs a package or repository command (e.g., stamp install htop) without specifying --manager, the tool resolves ambiguity using a three-tier engine:

  1. Tier 1: Explicit Override: If --manager <name> or -m <name> is provided, stamp directly executes that manager’s command.

  2. Tier 2: User Preference (Declarative): If the package exists in multiple managers, stamp checks the user’s config.toml precedence list:
    precedence = ["dnf", "flatpak", "brew"]
    

    If a match is found, stamp automatically selects the manager with the highest configured precedence.

  3. Tier 3: Interactive Choice (Fallback): If no precedence is defined (or there’s a tie) and the process runs in an interactive terminal (TTY), stamp prompts the user to select the manager. In non-interactive environments (scripts/pipelines), the command fails with a clean error prompting the user to specify --manager.

Configuration

The stamp configuration is stored securely at ~/.config/stamp/config.toml. It allows users to define global precedence and regex-based routing rules.

TOML Schema:

# ~/.config/stamp/config.toml

# The global order of preference when a package exists in multiple managers.
# Checked from left to right.
precedence = ["dnf", "flatpak", "brew"]

# Pattern-based rules override the global precedence list.
# Useful for routing specific patterns (like reverse-DNS or development libs).
[[rules]]
pattern = "^com\\..*|^org\\..*" # Matches reverse-DNS App IDs
prefer = "flatpak"

[[rules]]
pattern = "^lib.*|-devel$"     # Matches libraries and dev headers
prefer = "dnf"

Precedence Matching Logic:

  1. Rule Match: The resolution engine iterates through the [[rules]] slice. If the package name matches a defined regular expression pattern, the engine immediately selects the associated prefer manager.
  2. Global Precedence: If no pattern rules match, the engine scans the global precedence array from left to right. The first manager in the list that reports the package as “available” is selected.
  3. Tie-Breaker: If the package is not found in the precedence list (or the list is empty), the engine falls back to prompting the user (in an interactive TTY) or failing cleanly (in scripts).

Commands Specs

Detailed specifications, execution behaviors, and business rules for every subcommand.

stamp (root)

stamp setup (alias hello) — Setup Wizard (C1)

stamp init

stamp install <pkg> (alias add)

stamp remove <pkg> (aliases uninstall, rm, delete, del)

stamp reinstall <pkg> (C4)

stamp search <query>

stamp info <pkg> (C2)

stamp reconcile

stamp restore

stamp doctor

stamp update (alias upgrade)

stamp self-update (alias self-upgrade)

stamp completion [shell]

stamp man

stamp repo


Data Model

The TOML manifest supports notes for user context, an origin field for provenance, and a repositories block.

[[repositories]]
name = "flathub"
manager = "flatpak"
url = "https://dl.flathub.org/repo/flathub.flatpakrepo"
origin = "stamped"

[[packages]]
name = "lazygit"
manager = "brew"
notes = "better git TUI than default"
origin = "stamped"

Origin Provenance

Every [[packages]] and [[repositories]] entry may carry an origin field recording how it entered the manifest. It is optional (omitempty) — an absent field is treated as stamped, so pre-existing manifests load without migration.

Value Meaning
stamped Recorded by a direct user action (stamp install, stamp repo add, stamp reinstall)
reconciled Auto-tracked by stamp reconcile after drift detection

The origin field powers stamp list --type (issue #178) and stamp manifest history / stamp manifest diff (issue #179).

List Command (stamp list)

stamp list (alias ls) lists tracked packages by default. The --type, -t flag filters by entity type and origin. All flags compose with AND logic (--type × --manager × --json).

Valid --type values:

Value Description
packages All packages (default, backward compatible)
repos All repositories
stamped All entries installed via stamp (packages + repos)
reconciled All entries discovered by reconcile (packages + repos)
stamped-packages Packages with origin = "stamped"
stamped-repos Repos with origin = "stamped"
reconciled-packages Packages with origin = "reconciled"
reconciled-repos Repos with origin = "reconciled"
missing Manifest packages not installed on this system

--type packages and --type repos ignore origin and show all entries of that entity type. An unknown value returns unknown type "<value>"; valid types: packages, repos, stamped, reconciled, stamped-packages, stamped-repos, reconciled-packages, reconciled-repos, missing. On a pre-origin manifest (entries without an origin field) the origin defaults to stamped, so --type stamped-packages shows everything and --type reconciled-packages shows nothing.

--type missing (issue #182) is the only system-aware view: it queries each active manager’s installed packages and lists manifest entries absent from the system, i.e. packages removed via the native manager. It composes with --manager, -m and --json, but not with an origin filter. Group and cask entries are excluded (they never appear in the installed list). A manager whose installed list cannot be queried is skipped. No matches prints no missing packages. It never mutates the manifest — stamp restore is the convergence tool.

Manifest Management (stamp manifest)

stamp manifest history lists the current manifest and every timestamped backup (manifest.toml.<TS>.bak), newest first, with package/repo counts and a short SHA-256 content-hash prefix. * marks the current entry; backups whose content equals the current manifest are marked unchanged. Corrupted backups are skipped with a warning. No backups yet prints a hint pointing at re-init and reconcile.

stamp manifest diff [ts|hash] compares the current manifest against a backup (default: most recent), for both packages and repositories using name+manager as the identity key. The argument is either a timestamp (2026-08-02T09:15:00Z or 20260802T091500Z) or a content-hash prefix (pure hex, ≥ 6 chars) from history. Added entries render with +, removed with -. --manager, -m and --origin (stamped/reconciled) filter both sets after diffing. An unknown or ambiguous reference errors with no backup found for <arg> / ambiguous hash. Diffing against a corrupted backup errors with `failed to parse backup at

`. If no backup exists, `diff` errors with `no backup to compare against`. ### Exit Codes `stamp` follows BSD `sysexits.h` conventions (shipped by glibc on Linux) for error categories. Success is always `0`. Unclassified failures exit `1`, the POSIX catchall. Scripts can distinguish failure modes by code: | Code | Constant | Category | Examples | |------|----------|----------|----------| | `64` | EX_USAGE | Bad command line / flag / argument | invalid `--type`, `--origin`, diff timestamp, repo name/URL; flag-parse errors | | `65` | EX_DATAERR | Input data incorrect | corrupt manifest, corrupt backup, ambiguous hash | | `66` | EX_NOINPUT | Referenced input absent | `diff` with no backup, no matching timestamp/hash | | `69` | EX_UNAVAILABLE | Required resource absent | no package manager available, `-m` manager not installed | | `73` | EX_CANTCREAT | Cannot create output | manifest/snapshot save or backup failure | | `78` | EX_CONFIG | Unconfigured/misconfigured | invalid `config.toml`, `manifest not found; run stamp init first` | Backup/rotation failures on reconcile and init are non-fatal (warning to stderr, exit `0`). The mapping and its rationale are recorded in [ADR-018](../decisions/ADR-018-sysexits-exit-codes.md) (supersedes the exit-code note in ADR-002). ### Backup Retention Policy Stamp keeps timestamped backups before rewriting the manifest or snapshots. Backup naming is lexicographically sortable: `manifest.toml..bak` (files) and `snapshots..bak/` (directories). Retention is controlled by the `[backup]` section of `config.toml` and mirrors logrotate's `rotate`, `minage`, and `maxage` directives: | Config key | Default | Logrotate equivalent | Meaning | |------------|---------|----------------------|---------| | `max_manifest_backups` | `10` | `rotate` | Max manifest backups to keep (count cap) | | `min_manifest_backups` | `3` | — | Always keep at least this many manifest backups (count floor) | | `min_manifest_backup_age_days` | `7` | `minage` | Backups younger than this are never deleted (floor) | | `max_manifest_backup_age_days` | `30` | `maxage` | Backups older than this are always deleted (ceiling) | | `max_snapshot_backups` | `10` | `rotate` | Max snapshot backup dirs to keep | | `min_snapshot_backups` | `3` | — | Always keep at least this many snapshot backups (count floor) | | `min_snapshot_backup_age_days` | `7` | `minage` | Snapshot backups younger than this are never deleted | | `max_snapshot_backup_age_days` | `30` | `maxage` | Snapshot backups older than this are always deleted | A value of `0` on any axis means **unlimited** on that axis. The manifest and snapshot policies are independent; `stamp reconcile` only rotates manifest backups, while `stamp init` re-init rotates both manifest and snapshot backups. **Precedence (highest to lowest):** 1. **Min-age floor** — backups younger than `min_*_backup_age_days` are **protected**: never deleted, even when the count cap is exceeded. 2. **Min-count floor** — at least `min_*_backups` backups are always kept. The newest backups survive, so the max-age ceiling can never wipe the backup set to zero. 3. **Max-age ceiling** — among eligible backups (age ≥ min-age), any backup older than `max_*_backup_age_days` is deleted, except those needed to meet the min-count floor (count does not protect ancient backups beyond the floor). 4. **Count cap** — if the eligible set still exceeds `max_*_backups`, the oldest surplus backups are deleted, except those needed to meet the min-count floor. **Worked example (ceiling vs min-count):** `min_manifest_backups=3`, `max_manifest_backup_age_days=30`, 5 backups all older than 30 days → the ceiling wants to delete all 5, but the min-count floor keeps the newest 3, so only 2 are deleted. **Misconfiguration:** if `min_*_backup_age_days > max_*_backup_age_days`, the floor wins on the overlapping window (protective), but the configuration is reported as invalid in `stamp doctor` and the docs warn against it. If `min_*_backups > max_*_backups`, the min-count floor wins (protective). ## Project Structure ```text stamp/ ├── cmd/stamp/ → Main application entrypoint ├── internal/ │ ├── cli/ → Cobra commands (init, reconcile, restore, install, etc.) │ ├── manager/ → Package manager adapters (dnf/yum, brew, flatpak) │ ├── state/ → Local JSON snapshotting and delta calculation │ ├── manifest/ → TOML parsing and writing │ └── config/ → XDG path resolution and user config ├── tools/docgen/ → Build-time doc generation tool ├── docs/ → ADRs, specifications, generated docs └── README.md ``` ## Code Style Idiomatic Go with strict error wrapping and interface-driven design for testability. ## Testing Strategy - **Framework:** standard `testing` package + `stretchr/testify` for assertions. - **Test Locations:** Co-located with source (`state_test.go` next to `state.go`). - **Core Coverage:** 100% on `internal/state/` and `internal/manifest/`. - **Mocks:** Mock the `PackageManager` interface. - **Minimum:** 90% overall project coverage. ## Go Adapter The Go adapter supports `go install @latest` for installing end-user CLI tools. It follows the `pipx` model — installing user-facing tools, not project dependencies. ### Package Names - Requires full module paths (e.g., `github.com/golangci/golangci-lint`). - Short names (e.g., `golangci-lint`) are rejected. - Module paths are validated via `ValidateModulePath` — blocked: empty, missing `/`, or containing shell metacharacters. ### ListInstalled (Name-space Contract) - Returns module paths when recoverable from binary metadata via `go version -m `. - Falls back to the binary name for stripped or old binaries. - Module paths are stored in the manifest and snapshot — enabling round-trip remove/info. ### Search / Doctor / Repos - Search and Doctor return errors (`not supported`). Search errors are printed as warnings to stderr; valid results from other managers remain on stdout. - `ListRepos` returns an empty list (no error) — adapters without repo support signal "no repos available" rather than failing the snapshot pipeline. - `AddRepo`/`RemoveRepo` return errors (`not supported`) — these are user-facing write ops. ### Update - Single package (`-p -m go`): runs `go install @latest`. - Batch (`stamp update`): lists installed binaries, recovers module paths, reinstalls each one with `@latest`. Binaries without recoverable module paths are skipped. ### GOBIN / GOPATH Resolution - Checks `go env GOBIN` first (returns the bin directory directly). - Falls back to `go env GOPATH` (uses the first entry of the colon-separated list joined with `/bin`). - Falls back to `$HOME/go/bin`. ## Pipx Adapter The Pipx adapter supports `pipx install` for CLI tools from the Python ecosystem. ### Package Names - Uses standard `ValidatePackageName` (simple names like `black`, `httpie`). - Names starting with `-` are rejected. Shell metacharacters rejected. ### ListInstalled - Tries `pipx list --json` first (parses the `venvs` JSON object for package names). - Falls back to `pipx list` text parsing for older pipx installations. ### Search / Doctor / Repos - Search and Doctor return errors. Repo operations: `AddRepo`/`RemoveRepo` error; `ListRepos` returns empty list. ### Update - Single: `pipx upgrade `. Batch: `pipx upgrade-all`. ## Uv Adapter The Uv adapter supports `uv tool install` for CLI tools from the Python ecosystem. ### Package Names - Uses standard `ValidatePackageName`. Simple names like `black`, `ruff`. ### ListInstalled - Parses `uv tool list` output line-by-line. Package names are the first token on each non-indented line. ### Search / Doctor / Repos - All return errors or empty (same pattern as pipx). ### Update - Single: `uv tool upgrade `. Batch: `uv tool upgrade --all`. ## Boundaries - **Always:** Use `context.Context` for all shell executions (`os/exec`). - **Always:** Return meaningful delta states (added, removed, unchanged). - **Always:** Every flag MUST have a single-character short form. - **Always:** Actions MUST be subcommands, not flags. - **Always:** Snapshot diffing is the default mechanism for drift detection. - **Always:** Packages and repositories installed before `stamp init` are never tracked or detected by `stamp reconcile`. They are captured in the baseline snapshot. - **Always:** To track a pre-existing package, use `stamp reinstall `. - **Ask first:** Before adding any third-party dependencies beyond `cobra` and `go-toml`. - **Ask first:** Before changing the structure of the `manifest.toml`. - **Never:** Mutate the actual system state (run native installs) during a `reconcile` or `list` command. - **Never:** Use flags to represent actions (e.g. `--install`). Use subcommands instead. - **Never:** Present interactive prompts during `stamp reconcile`. The command is fully deterministic. - **Never:** Execute destructive adapter operations without explicit consent (`manager.WithYes`). The CLI gate is the only source of consent. ## Edge Cases ### Reinstall Gap **Scenario:** A package is removed and reinstalled between two `stamp reconcile` runs. Snapshot diffing sees no net change and reports no drift. This edge case only applies when the user **bypasses stamp and uses native package manager commands (dnf, brew, flatpak) directly**, then relies on reconcile as a safety net. **Root Cause:** Snapshot diffing is a point-in-time comparison between two snapshots. If the removed package is reinstalled before the next reconcile, the baseline and current snapshots are identical. Stamp has no event monitoring — it cannot observe intermediate states. **Mitigation:** - **Always use stamp (recommended):** The edge case never occurs if packages are managed through stamp (`stamp install`/`stamp remove`). Stamp records every install and removal in the manifest instantly — no snapshot diffing involved. - **Regular reconciliation:** If using native commands directly, remember to run `stamp reconcile` after each uninstall operation to keep snapshots in sync. - **Automated timer:** `stamp auto-reconcile on` installs a daily systemd/launchd timer. - **Manual timer files:** Pre-configured service/timer files available in `contrib/`. ## UNIX Compliance & Documentation Strategy To be a "good UNIX citizen", `stamp` must adhere to: - **POSIX Syntax:** Handled natively by `spf13/cobra`. - **XDG Base Directory:** Config in `~/.config/stamp`, state in `~/.local/share/stamp`. - **Exit Codes:** `0` for success, `>0` for failures (e.g., standard `sysexits`). - **I/O Separation:** Informational output/UI to `stdout`, errors to `stderr`. - **NO_COLOR:** Respect the `NO_COLOR=1` environment variable. - **Auto-Generated Docs:** Usage documentation for GitHub Pages must be auto-generated from the codebase using `github.com/spf13/cobra/doc` to ensure docs and code never drift. - **UNIX Man Pages:** System reference pages (Section 1) must be self-contained via `stamp man` so users can run `man stamp` locally. - **Project Landing Page:** A custom landing page at `docs/index.html` served via GitHub Pages (`/docs` folder on main branch, `https://rossijonas.github.io/stamp/`). ## Success Criteria 1. **Init:** Running `stamp init` creates the correct XDG directories and an empty `manifest.toml`, and takes baseline snapshots for each available manager. 2. **Reconcile (No Drift):** If system state matches the last snapshot, `reconcile` exits cleanly with `"No drift detected"`. 3. **Reconcile (Drift):** If `flatpak install com.spotify.Client` is run externally, `stamp reconcile` detects this one new package and auto-tracks it to `manifest.toml` without prompting. 4. **Reconcile (Dry Run):** `stamp reconcile --dry-run` shows all discovered drift but does NOT save manifest or snapshots. 5. **Reconcile (Pre-existing):** Packages installed before `stamp init` are never detected by `stamp reconcile`. To track them, use `stamp reinstall `. 6. **Reinstall (Manifest-tracked):** `stamp reinstall htop` reinstalls a manifest-tracked package using its recorded manager. 7. **Reinstall (Pre-existing):** `stamp reinstall htop` installs a pre-existing package not in the manifest, resolves its manager, runs native reinstall, and records it in the manifest. 8. **Restore:** Running `stamp restore` successfully adds repositories *before* executing the respective package manager install commands concurrently. 9. **Notes:** A user can pass `--note "reason"` to `stamp install` or `stamp edit`, which will be correctly saved in the TOML manifest. 10. **Doctor:** `stamp doctor` reports manager status, manifest health, and UNIX compliance in both TTY and JSON. 11. **Man Pages:** `stamp man` displays help; `stamp man install` installs man pages; `stamp man check` verifies version matches binary. 12. **Completions:** `stamp completion bash|zsh|fish|powershell` generates valid shell completion scripts. 13. **Info:** `stamp info htop -m dnf` prints raw dnf info metadata directly. 14. **Install:** `stamp install htop` installs the package natively via the resolved manager and records it in `manifest.toml`. 15. **Remove:** `stamp remove htop` removes the package natively and removes it from the manifest. 16. **Search:** `stamp search ripgrep` returns matching packages from all available managers. 17. **Repo Add:** `stamp repo add myrepo -m brew` adds the repository via the specified manager and records it. 18. **Repo Remove:** `stamp repo remove myrepo` removes the repository and untracks it. When tracked, the manager is looked up from the manifest; `-m` overrides it. For DNF, URL-added repos are removed by deleting their `.repo` file and COPR repos via `dnf copr disable`. 19. **Repo List:** `stamp repo list` prints all tracked repositories; `--json` outputs machine-readable. 20. **Setup:** `stamp setup` runs the setup wizard with completion, man pages, init, and doctor. `stamp hello` works as an alias. 21. **Completion:** `stamp completion bash|zsh|fish|powershell` generates valid shell completion scripts for each shell. 22. **Reconcile (Repo Drift):** If a new flatpak remote or brew tap is added externally, `stamp reconcile` detects and auto-tracks the repository alongside packages. 23. **Reconcile (Manager Scope):** `stamp reconcile -m dnf` scopes drift detection to a single manager only. 24. **Reinstall (Manager Flag):** `stamp reinstall htop -m brew` overrides manager resolution via the `--manager` flag for pre-existing packages. 25. **Reinstall (Adapters):** `adapter.Reinstall()` executes the native reinstall command for each manager (brew reinstall, dnf reinstall, flatpak install). 26. **Reconcile (Snapshot Save on No Drift):** If reconcile detects no drift, the current snapshot is saved to disk so future package removals are tracked correctly. 27. **Update:** `stamp update` runs native upgrade commands for all available managers concurrently. Errors from one manager don't block others. `--manager` flag scopes to a single manager. Non-zero exit if any manager fails. 27. **Auto-Reconcile:** `stamp auto-reconcile on --period daily` installs a systemd or launchd timer to run `stamp reconcile` automatically at the configured interval.