CI now shellchecks the update skill's scripts: SC1091 is disabled at their
`source` lines as in the other skills, and the two findings this branch added
(lib.sh's loop_lock.sh source, install.sh's one-item legacy loop) are
disabled at their lines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Both installers wrote `/.venv/`, which only matches a directory: a .venv
symlink (the worktree recipe links the control root's) or file showed up as
untracked in installed repositories. The managed block now has `/.venv`.
Existing installations get it on the next install/update, which rewrites the
block between its markers as a whole; the integrity values are unaffected
(.gitignore is in neither asset_hashes.txt nor the install manifest).
Tests W10 (both installers; .venv as link, file and directory all ignored) and
W11 (a pre-#27 block is replaced, user lines outside it are kept, .gitignore
stays out of the ledgers).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017R3Eg7MEpSWnm1oB9ZPP6G
Records the measured numbers and syncs every document that names the
delegation script paths, then bumps the framework to 4.3.0 in the three-way
lockstep (lib.sh, VERSIONS.md current + matrix, eight SKILL.md frontmatters).
phase1-benchmark.md carries both arms. The deterministic fake transport is what
CI asserts on: 50 publishes cost 50 connections one-shot and 1 persistent, p50
54.813ms -> 0.002ms. The real broker run is informational, since the PoC
default is a public broker: p50 1892.728ms -> 275.992ms, about 85% off.
It also corrects the plan's own estimate rather than repeating it. D8 predicted
the new shell path would drop from 3 forks to 2; the implementation is still 3,
because keeping the `_delegate_script publish_event.py` lookup is the only
thing that produces the "missing script tree does nothing" non-fatal contract
that C-02 pins. Saving that fork would change the contract, so it is deferred
to phase 4 rather than taken quietly.
SKILL.md gains the context table saying which tree wins where, so an operator
reading it knows a frozen loop runs frozen delegation code. The script paths in
every document remain correct and every quoted command still works verbatim.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
deploy/install.sh extracted the repo archive in-place with
`tar --strip-components=1`, which inside an existing project could silently
overwrite the target's own README.md/FUTURE_WORKS.md/etc and litter it with
this repo's dev docs.
Rebuild the fetch path:
- stage the clone/extract into a `mktemp -d` dir, never in-place
- verify `.agents/skills/lib.sh` is present before copying anything
- copy only runtime assets (.agents/, AGENT.md, .env.example) into the target
with per-file no-clobber guards (`[ ! -e ]`), so existing files always win
- post-fetch sanity check now tests a file, not just the directory
- fail fast when neither git nor curl is available
Use explicit `[ ! -e ]` guards + a POSIX find merge rather than `cp -n`
(non-portable; emits a deprecation warning on GNU coreutils 9.x). The earlier
`tar --exclude` denylist idea was rejected in review: non-portable and the
unanchored `--exclude="scripts"` pattern stripped the skills' own nested
scripts/ dirs, yielding a silently broken install.
Mark FW-D1 resolved and FW-D2 partially addressed in FUTURE_WORKS.md/.ko.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>