Skip to content

feat(updater): opt-in SessionStart update notice for Claude Code (off by default) (PR-3)#180

Merged
Yoojin-nam merged 1 commit into
mainfrom
feat/v46-update-notify-hook
Jun 22, 2026
Merged

feat(updater): opt-in SessionStart update notice for Claude Code (off by default) (PR-3)#180
Yoojin-nam merged 1 commit into
mainfrom
feat/v46-update-notify-hook

Conversation

@Yoojin-nam

Copy link
Copy Markdown
Contributor

PR-3 — opt-in update notice for Claude Code (off by default)

"Increment 2" of the self-update feature (after #177 installer, #178 updater, #179 release
hardening). A physician who installed once gets a one-line "update available" nudge at session
start — only if they opt in, with no telemetry and no session reads. No release is cut.

Why

The updater (#178) exists, but a non-GitHub user has to remember to run it. This adds an opt-in,
privacy-preserving reminder so they actually learn a new version exists — without nagging, tracking,
or auto-installing.

What this adds

  • installers/session_update_check.py (new) — a Claude Code SessionStart hook that prints
    {"systemMessage": …} only when latest > installed. By construction it:
    • does not read the SessionStart stdin (cwd / transcript / session id are never read or sent);
    • has no telemetry, analytics, or unique id — one GitHub version GET, only on a stale 24h cache,
      with a 4s timeout, and silent on any error (never delays/blocks a session);
    • honors MEDSCI_NO_UPDATE_CHECK=1; installs nothing — it only notifies.
  • update.pyresolve_latest_tag() (tag-only check; needs no OS asset/digest, so it works on
    Linux too); register_session_hook / unregister_session_hook MERGE/unmerge the hook into
    ~/.claude/settings.json (idempotent, preserves foreign hooks/settings, removes only ours, refuses
    to clobber an unparseable file, preserves file mode); install_updater_home now also ships the hook.
  • install.py--enable-update-notify / --disable-update-notify. A normal install never
    enables it.
  • CI/packaging/docsinstallers/tests/test_session_hook.py (38 offline cases) on Ubuntu +
    macOS + Windows; package.json + distribution_files.json (727) include the hook; README
    "Updating", docs/update_privacy.md, and CHANGELOG document it.

Review

Adversarial review (4 lenses → per-finding refutation, 13 agents): 4 confirmed, 5 refuted. The
MAJOR fix: the hook matcher now keys on the home-anchored script path, not the bare filename,
so --disable can't delete an unrelated foreign SessionStart hook and --enable can't be silently
no-op'd by a coincidental substring (both regression-tested). Also fixed: settings.json mode
preserved across the atomic rewrite; resolve_latest_tag draft/prerelease guard tested.

CI

  • validate (Ubuntu) + foundation-os (macOS + Windows) both run test_session_hook.py.

Draft until CI is green.

… by default) (PR-3)

Increment 2 of the self-update feature: a physician who installed once gets a one-line
"update available" nudge — only if they opt in, with no telemetry and no session reads.

- installers/session_update_check.py (new): SessionStart hook. Never reads stdin (no
  cwd/transcript/session id), honors MEDSCI_NO_UPDATE_CHECK=1, uses the shared clock-sane
  24h cache + a 4s network timeout, stays silent on any error (never blocks a session), and
  prints {"systemMessage": ...} only when latest > installed. Installs nothing.
- update.py: resolve_latest_tag() (tag-only check, no OS asset/digest needed -> works on Linux
  too); register/unregister_session_hook() MERGE/unmerge a hook into ~/.claude/settings.json
  (idempotent, preserves foreign hooks/settings, removes only ours, refuses to clobber an
  unparseable file, preserves the file's mode); install_updater_home now also ships the hook.
- install.py: --enable-update-notify / --disable-update-notify (a normal install never enables it).
- CI: test_session_hook.py (38 cases, offline) on Ubuntu + macOS + Windows; package.json +
  distribution_files.json (727) include the hook; README/privacy/CHANGELOG document it.

Folds an adversarial review (4 lenses -> per-finding refutation): 4 confirmed, 5 refuted.
The MAJOR fix: the hook matcher now keys on the home-anchored script path, not the bare
filename, so --disable can't delete an unrelated foreign hook and --enable can't be no-op'd
by a coincidental substring (regression-tested). Also: settings.json mode preserved across
the rewrite; resolve_latest_tag draft/prerelease guard tested.

No release cut.
@Yoojin-nam Yoojin-nam marked this pull request as ready for review June 22, 2026 08:57
@Yoojin-nam Yoojin-nam merged commit 4ea3f94 into main Jun 22, 2026
3 checks passed
@Yoojin-nam Yoojin-nam deleted the feat/v46-update-notify-hook branch June 22, 2026 09:06
Centaurioun pushed a commit to Centaurioun/medsci-skills that referenced this pull request Jun 26, 2026
Cuts v4.7.0 bundling the self-update foundation (PRs Aperivue#177Aperivue#180): transactional
crash-recoverable installer + per-target state, the one-click verified self-updater,
release-pipeline supply-chain hardening (provenance + attestation + updater round-trip
gate), and the opt-in SessionStart update notice (off by default).

Additive and backward-compatible — no skill/CLI/output-path change; 45 skills / 36
reporting guidelines / 30 detectors unchanged. Version synced across CITATION.cff ==
package.json == metadata/distribution_manifest.json (4.7.0); CHANGELOG [Unreleased]
consolidated to [4.7.0] - 2026-06-22; README "What's New" updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant