The update is a skill (decision 4); deploy/update.sh and the installed
.mam_deploy/update.sh are gone.
- Phase 1 (installed code, update.sh): publish the update marker under the
exclusive admission lock; refuse before any change while a running row, a
live herdr agent in the workspace on any running server, an open job
(unreadable JSON included, dry_run not), a live loop marker or a
monitor.lock held by a monitor the skills did not start (U3) is there - the
calling agent (server + pane, its row and one running job) excepted
(lib_py/update.py precheck, decisions 1 and 7). Stop the monitor (TERM, then
KILL and restart it if it does not end; decision 2), handle a leftover
backup by its state (U4), back up .agents, .mam_deploy, root files, .venv,
the installer's .mam files and the registry (SQLite backup API under the
registry lock) into .mam/update-backup/, then exec a copy of
install_phase.sh outside the tree (decision 5).
- The copy (no lib.sh/lib_py, bash 3.2) runs the installer in place; on
failure it restores the backup and restarts the monitor from the restored
tree; on success it runs phase 2, post_update.sh of the new tree, which
converts the registry with lib_py.registry_format and restarts the monitor
if it ran. The backup and the marker are removed at the end.
- install.sh updates in place (decisions 3, 4, 9): install_state keys are set,
one line each; no updater is installed and an old one (.mam_deploy/update.sh,
or a root update.sh the manifest lists) is removed; framework files the new
version no longer ships are deleted when unmodified, kept and listed when
modified, and dropped from base/, the manifest and asset_hashes.txt; a local
source's .mam is not staged. remove.sh knows the new skill; CI shellchecks
its scripts; docs point at the skill.
- test_issue8_update_state and test_deploy_layout td6/td27 run the skill.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>