#Usage and options
maleta watch [--interval seconds] [--once]maleta prune [--dry-run] [--yes]| Option | Command | Effect |
|---|---|---|
--interval seconds | watch | Sets 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. |
--once | watch | Runs 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-run | prune | Only 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. |
--yes | prune | Authorizes 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
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.
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.Apply without removing
The plan adds or updates safe files and preserves local conflicts.
watchalways 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'.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 validRetry-Afterreplaces 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.lockper CLI home directory. A second process exits3with[error] 'maleta watch' is already running on this computer (pid <pid>), naming the holder:'maleta prune'when a removal holds it. maleta statusshows the lock aswatch: running (pid <n>)orwatch: blocked by 'maleta prune' (pid <n>). Locks left by processes that have exited are reclaimed on the next run.--onceexits 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] interruptedand exit1; 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 detachormaleta logout, resources from the previous Maleta move toorphaned. - If the binding is replaced by another document, previously recorded resources also become orphaned for a later
prunerun.
#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 offile 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, oroutside 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 onlyandprunestill handlespendingRemovalandorphanedfrom 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.jsonnorlocal-state.json, it prints[ok] nothing recorded; nothing to removeand exits0without creating.maleta. - A corrupt record (either file) exits
1with[error] corrupt state record; quarantined to <path>— orwould 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-runonly warns[warn] device identity does not match the bound record; evaluating the local record only.
#Exit codes
| Code | Condition |
|---|---|
0 | A normal watch pass or shutdown; a completed prune report or removal; a home with no record at all. |
1 | Single-pass failure, revoked credential, corrupt record, an interrupted command, or another operational error. |
2 | Invalid command, option, or value, including an --interval that is not a plain positive integer. |
3 | A conflict that needs a decision: another watch or prune holds watch.lock, or the environment credential belongs to a different device. |