/ documentation

maleta watch and prune

Continuously apply a bound Maleta and safely remove only files that the CLI can prove it managed.

#Usage and options

Follow the bound Maleta
bash
maleta watch [--interval seconds] [--once]
Review or perform pending removals
bash
maleta prune [--dry-run] [--yes]
Watch and prune options
OptionCommandEffect
--interval secondswatchSets the interval as a plain decimal integer of seconds. 0x10, 1e3, 10.0, 0 and -5 are usage errors (exit 2). A value below the 10-second floor warns [warn] the server accepts at least 10s between polls; using that instead; a value above the 300-second ceiling warns [warn] the interval is capped at 300s; using that instead.
--oncewatchRuns one pass and exits. If that pass only got throttled, it waits once for Retry-After and tries again; a second throttle in the same pass exits 1 instead of waiting forever.
--dry-runpruneOnly reports what would be removed. It never writes (no quarantine rename, no state sync, no fetch) and never takes the lock. Without --yes, prune is a dry run by default.
--yespruneAuthorizes the actual removal, which takes the watch.lock first.

Without --interval, the first interval is 30 seconds; after the first response, the cadence provided by the server takes over. The banner [ok] watch started; applying "<name>" every <seconds>s is printed only after the lock is held and the first poll has returned, and it reports the server's cadence when that poll supplied one.

#What happens on each pass

  1. Read the binding

    The CLI reads the device session and the revision of the bound Maleta. If the locally applied revision and the revision reported by the account already match, it does not download the document again.

  2. Fetch and plan

    When the revision changed or the previous pass ended in a conflict, it downloads the document, validates the Maleta, and creates the plan for the host. Plugins are deliberately excluded: a server-provided list must not become a remote-execution channel. The CLI prints [skip] <n> plugin(s) in this Maleta are not applied by watch; run 'maleta sync' to apply them.

  3. Apply without removing

    The plan adds or updates safe files and preserves local conflicts. watch always plans with removal disabled: it never deletes files. When the bound Maleta was replaced, it warns [warn] the bound Maleta was replaced; the previous files are now waiting for 'maleta prune'.

  4. Record and report

    The CLI writes the local state, including the revision and result, then reports the result to the account. A reporting failure only prints [warn] could not report progress: <message> and does not undo a completed write.

An inline skill arrives inside the downloaded Maleta. After that document fetch, watch needs no GitHub request to materialize it; the files are opaque data and are never executed. Its resource label is inline:<name>.

#Cadence, retries, and locking

A pass that applies prints [ok] applied: rev <n>; one that applies with local conflicts prints [warn] rev <n> applied with conflicts; local files were kept. A successful pass with nothing bound prints [warn] no Maleta bound; run 'maleta attach <maleta>'.

  • After an error, the delay grows as min(intervalo × 2^tentativa, 5 min) with ±20% jitter, printed as [warn] retrying in <n>s. A valid Retry-After replaces this delay; a proxy or CDN HTML response without the JSON error envelope is never read as one.
  • A revision that keeps moving between the read and the apply earns one immediate follow-up; a persistent mismatch still respects the poll floor instead of spinning.
  • There is one watch.lock per CLI home directory. A second process exits 3 with [error] 'maleta watch' is already running on this computer (pid <pid>), naming the holder: 'maleta prune' when a removal holds it.
  • maleta status shows the lock as watch: running (pid <n>) or watch: blocked by 'maleta prune' (pid <n>). Locks left by processes that have exited are reclaimed on the next run.
  • --once exits after one successful or conflicting pass; an error on that pass returns failure, except for the single throttling retry.
  • Ctrl+C is honoured during an in-flight request, not only between polls. An abort while resolving the environment identity ends the command with [error] interrupted and exit 1; a signal during the loop exits cleanly.

#What remains pending

  • Resources that the current Maleta revision no longer uses move to pendingRemoval.
  • When you run maleta detach or maleta logout, resources from the previous Maleta move to orphaned.
  • If the binding is replaced by another document, previously recorded resources also become orphaned for a later prune run.

#Prune and proof of ownership

Before deleting, prune reports each resource. Without --yes it is a simulation: each candidate prints [dry-run] would remove <label> (<n> file|files) -> <dest> and the summary is <n> resource|resources: run 'maleta prune --yes' to remove. A real run takes the watch.lock first; if another command holds it, it exits 3 with [error] a 'maleta <command>' is already running on this computer (pid <pid>); stop it before removing.

  • Removal is bounded to the managed skill roots <home>/.claude/skills/<name> and <home>/.agents/skills/<name>. A record whose destination points anywhere else is reported as [skip] <label> cannot be removed (outside managed skill roots) -> <dest> and never touched. The check is re-applied immediately before unlinking.
  • Only files with origin: "written" whose hash still matches the record can be deleted. Adopted or modified files, symlinks, unsafe paths, and unrecorded entries are preserved and reported as [skip] <label> cannot be removed (<reason>) -> <dest>, where <reason> is one of file was modified locally, an unrecorded file exists here, the path is not a plain directory, the local record could not be verified, the recorded path escapes its destination, or outside managed skill roots.
  • A directory is removed only after it becomes empty. A user-added file keeps the directory and blocks removal of the resource.
  • Removal prints [ok] removed <label> (<n> file|files) -> <dest> after the fact, with what actually left the disk.
  • Orphaned resources are evaluated whether or not the account is reachable; unreachable, offline mode prints [warn] could not reach the account; evaluating the local record only and prune still handles pendingRemoval and orphaned from the local record.

#Local installs are pruned too

A local install or sync records what it wrote in <home>/.maleta/local-state.json, keyed by the absolute document path. prune re-reads each recorded maleta.json, recomputes the plan, and removes resources—including inline:<name>—that the document no longer declares, using the same proof and managed roots as any other resource. A recorded document that is missing or unreadable protects its files with [skip] recorded Maleta file is missing; kept its resources -> <path>.

#Missing, corrupt, or mismatched records

  • With neither state.json nor local-state.json, it prints [ok] nothing recorded; nothing to remove and exits 0 without creating .maleta.
  • A corrupt record (either file) exits 1 with [error] corrupt state record; quarantined to <path> — or would quarantine to <path> under --dry-run, which renames nothing.
  • A device identity that differs from the recorded one makes a real run refuse with exit 3 (MALETA_DEVICE_TOKEN belongs to a different device than the one this computer last used. Delete .maleta/state.json if you mean to switch devices, or use the original token.); a --dry-run only warns [warn] device identity does not match the bound record; evaluating the local record only.

#Exit codes

CodeCondition
0A normal watch pass or shutdown; a completed prune report or removal; a home with no record at all.
1Single-pass failure, revoked credential, corrupt record, an interrupted command, or another operational error.
2Invalid command, option, or value, including an --interval that is not a plain positive integer.
3A conflict that needs a decision: another watch or prune holds watch.lock, or the environment credential belongs to a different device.

Privacy preferences

Choose what this origin may measure. You can change it here at any time.

Essential storage

This browser always keeps your theme, the Maletas you save here and this choice so the site works. They stay on this origin.

Optional analytics

Maleta.dev measures aggregate traffic and real-user performance only after you allow it.

Current choice: not made yet, so measurement stays off.

Privacy policy