A 2s fixed sleep after launchctl kickstart produced a false-negative health
failure on the mini (hub still booting) and triggered an unnecessary
rollback. Poll /health up to 20s before declaring failure.
Versioned filenames fixed the per-path code-signature cache kill (exit 137)
but made macOS TCC treat every build as a new app: each deploy re-prompted for
Documents/media-library access, and while the prompt was unanswered every
process touching those folders (model probes, session startup) blocked -
visible as slow/timeout requests in the app.
Go back to the fixed path ~/.hapi/bin/hapi (a real file) so TCC asks once and
remembers it across deploys. Guard the signature-cache hazard with explicit
verification: back up the installed binary to ~/.hapi/bin/backups/, install
with a fresh mtime, prove it execs repeatedly (--version x3) plus
codesign --verify, restart the hub / kickstart the runner, and restore the
backup on any failure.
- deploy-local.sh / deploy-remote.sh: fixed-path install, verify, rollback
- prune-backups.sh replaces prune-versions.sh (keeps newest N backups, drops
legacy versioned binaries)
- AGENTS.md, docs/local-deployment.md and the hapi-deploy skill updated
Every deploy writes a new ~110MB binary; without pruning the bin dir grows
unbounded (7.4GB across 48 versions on the mini). Keep the current symlink
target plus the N most recent previous versions (default 2, override with
HAPI_KEEP_VERSIONS).
- add scripts/prune-versions.sh: filename-sorted prune; safe while sessions
are live because unlinking does not affect running processes
- deploy-local.sh and deploy-remote.sh run it after a successful deploy
- extract the pinned-identity signing into scripts/sign-build.sh so local and
remote deploys ship the same stable signature (macOS TCC grants key on the
signing identity, not the path)
- add scripts/deploy-remote.sh: signs locally, copies the binary to a new
versioned file on the remote host, swaps the ~/.hapi/bin/hapi symlink,
kicks the launchd job (default com.hapi.runner, override via
HAPI_REMOTE_LAUNCHD_LABEL), and verifies the runner executes the new file;
running sessions survive
- document the remote flow in AGENTS.md and docs/local-deployment.md
The runner keeps its old machine RPC handlers and capability flags until
the process restarts: compiled binaries never self-update because the
heartbeat compares the mtime of the runner's own resolved exec path,
which is fixed for the life of the process.
- scripts/deploy-local.sh runs 'HAPI_CLI_EXECUTABLE=<stable symlink> hapi
runner start' when a runner is running; skips when none; warns and
exits 1 when the refresh fails (the hub deployment stays)
- AGENTS.md and docs/local-deployment.md document the runner refresh and
the manual sequence step
Ad-hoc signatures carry a cdhash-based TCC requirement that changes on
every build, so macOS treats each local binary as a new app and re-asks
protected permissions (Documents, Downloads, media library, ...) after
every deploy.
- add scripts/deploy-local.sh: pins one Apple Development identity
(SHA-1 stored in ~/.hapi/signing-identity, override via
HAPI_SIGN_IDENTITY), signs with identifier run.hapi.cli, copies to a
new versioned file, repoints ~/.hapi/bin/hapi, restarts the hub, and
rolls back when /health fails
- document the identity step and TCC rationale in AGENTS.md and
docs/local-deployment.md; agent sessions must prune TCC-protected
folders (~/Music, ~/Pictures, ~/Movies, ~/Library) from recursive
$HOME sweeps
- drop the one-off scripts/deploy-local-capacity-retry.sh (ad-hoc)