feat: in-app auto-update (X6) + v1.5.0 - #78
Conversation
StudyVis now updates itself: it checks GitHub for new releases on launch and every 6h, downloads them in the background, and offers a "Restart now" banner once the new version is staged and signature-verified. The blocker recorded in PLAN §8 / ARCHITECTURE §2 — "auto-update can't be verified without signed artifacts" — was a conflation. Tauri's updater carries its own integrity chain: artifacts are signed with a minisign keypair and verified in-app against `plugins.updater.pubkey` before unpacking. That is independent of Apple/Windows code signing, so this ships on the existing ad-hoc-signed builds. The docs are corrected rather than quietly worked around, and the macOS TCC caveat that comes with staying unsigned is written down where someone will find it. Behavior: - No check, no download, no banner during a session — a WebRTC mesh has no bandwidth to spare for an installer, and nothing should offer to restart out of a live study session. - The sidecar is stopped before the bundle swap: Windows NSIS cannot overwrite a running llama-server.exe, and a macOS orphan would survive the relaunch holding its port and model file. - Background failures are silent; only user-initiated checks surface copy. Notable changes: - Windows ships NSIS `-setup.exe` instead of `.msi`. Applying an MSI update needs msiexec elevation every time, i.e. a UAC prompt per release. NSIS installs per-user and supports passive install mode. - Auto-update defaults ON, widening PLAN §3's outbound carve-out from X4's opt-in tag check. Requests stay anonymous with no payload, and the toggle still buys literal zero outbound. An explicit OFF on the old `version_check_enabled` key migrates to OFF. - X4's hand-rolled `system_fetch_latest_version` command is retired — the updater subsumes it, and two overlapping mechanisms would be worse than one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both matrix jobs append their platform's entry to the same latest.json on the release, and tauri-action does it as a read-merge-write with no locking. Run in parallel and the slower job can overwrite the faster one's entry — which fails silently: the release looks fine, and an entire platform never sees the update. max-parallel: 1 costs one build's wall-clock on a workflow that runs a few times a year. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An adversarial multi-agent review of the auto-update change surfaced six minor issues before the v1.5.0 cut; all applied: - updaterStore: close the check→download race. UpdaterBoot only gates *scheduling*, so a session starting during the network-bound check could still let the installer download onto a live WebRTC mesh. The check→download boundary now re-reads session state (new isSessionActive dep) and defers to the next post-session check. The residual — a download already in flight — is documented as unfixable in this plugin version (no AbortSignal). - AboutCategory: a downloaded, verified "ready" update now always shows its restart row, even with auto-update toggled off, so Settings agrees with the Home banner instead of going silent while the banner prompts. - README / ARCHITECTURE §12 / CLAUDE.md: corrected stale "download the .msi" / "no auto-update" / "V1 ships an unsigned .msi" claims the feature commit missed. README versioning section advanced to v1.5.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the five tracked version files in lockstep and retitles the CHANGELOG's Unreleased section to 1.5.0 (auto-update). Tagging v1.5.0 dispatches release.yml to build the per-OS installers as a draft. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 52 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughStudyVis 1.5.0 adds signed Tauri auto-updates with scheduled background checks, staged installation, restart controls, migrated settings, NSIS packaging, serialized publishing, updater tests, and updated release and installation documentation. ChangesAutomatic update release
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant App
participant UpdaterBoot
participant UpdaterStore
participant TauriUpdater
participant UpdateReadyBanner
App->>UpdaterBoot: mount updater scheduler
UpdaterBoot->>UpdaterStore: checkNow after delay or interval
UpdaterStore->>TauriUpdater: check and download
TauriUpdater-->>UpdaterStore: staged update
UpdaterStore-->>UpdateReadyBanner: ready status
UpdateReadyBanner->>UpdaterStore: installAndRestart
UpdaterStore->>TauriUpdater: install and relaunch
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
# Conflicts: # CHANGELOG.md # src-tauri/capabilities/default.json # src/App.tsx
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/features/updater/updaterStore.ts (1)
145-148: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the unused release-notes state and copy.
notesis stored in updater state, but neitherUpdateReadyBannernorAboutCategoryreads it, andstrings.updater.banner.notesCtais unused too. If release notes aren’t going to be surfaced, drop both; otherwise wire them into the update UI.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/updater/updaterStore.ts` around lines 145 - 148, Remove the unused release-notes state by deleting the notes assignment from the updater store’s downloading update state, and remove the unused strings.updater.banner.notesCta copy. Do not add UI wiring; keep the existing update flow and other state fields unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@PLAN.md`:
- Around line 27-28: Revise the updater privacy wording to distinguish
application data from unavoidable HTTP transport metadata such as source IP,
User-Agent, and request timing. Update PLAN.md lines 27-28 as the canonical
statement, and apply the same narrower claim in INSTALL.md lines 42-46,
README.md lines 46-51, and CHANGELOG.md lines 46-50; avoid claiming that nothing
about the user is sent.
In `@README.md`:
- Around line 78-81: Update the Linux platform note in the README to remove the
stale “not in 1.0” reference and use a current version-neutral statement, such
as indicating that Linux is not currently in the release matrix. Preserve the
existing explanation about WebKitGTK validation and the development build
command.
In `@src/features/settings/categories/AboutCategory.tsx`:
- Around line 113-120: Update the help-text selection around the updater status
logic so updaterCopy.upToDateHelp(__APP_VERSION__) is returned only after a
confirmed up-to-date state, not for idle or error states with a null errorKind.
Add a neutral fallback for unchecked and silently failed states while preserving
the existing checking and attributed check/download error messages.
---
Nitpick comments:
In `@src/features/updater/updaterStore.ts`:
- Around line 145-148: Remove the unused release-notes state by deleting the
notes assignment from the updater store’s downloading update state, and remove
the unused strings.updater.banner.notesCta copy. Do not add UI wiring; keep the
existing update flow and other state fields unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6e63158f-d8d8-4782-afd5-701d94314094
⛔ Files ignored due to path filters (2)
package-lock.jsonis excluded by!**/package-lock.jsonsrc-tauri/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (24)
.github/workflows/release.ymlARCHITECTURE.mdCHANGELOG.mdCLAUDE.mdINSTALL.mdPLAN.mdREADME.mdpackage.jsonsrc-tauri/Cargo.tomlsrc-tauri/capabilities/default.jsonsrc-tauri/src/commands/system.rssrc-tauri/src/lib.rssrc-tauri/tauri.conf.jsonsrc/App.tsxsrc/components/UpdateReadyBanner.tsxsrc/features/settings/categories/AboutCategory.tsxsrc/features/updater/UpdaterBoot.tsxsrc/features/updater/index.tssrc/features/updater/updaterStore.tssrc/routes/Home.tsxsrc/stores/settingsStore.tssrc/stories/UpdateReadyBanner.stories.tsxsrc/strings.tstests/unit/updater-store.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
src/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.{ts,tsx,css}: All design tokens—including colors, spacing, fonts, radii, shadows, motion, and z-index values—must come fromsrc/design/tokens.ts; do not use raw hex values, arbitrary pixel values, or inline cubic-bezier values outside that file.
Meet WCAG AA contrast requirements for text/background pairings in both themes, never convey information by color alone, and implement reduced motion as a global kill switch with new motion gated by default.
Files:
src/App.tsxsrc/stories/UpdateReadyBanner.stories.tsxsrc/routes/Home.tsxsrc/features/updater/UpdaterBoot.tsxsrc/features/updater/index.tssrc/components/UpdateReadyBanner.tsxsrc/features/settings/categories/AboutCategory.tsxsrc/strings.tssrc/features/updater/updaterStore.tssrc/stores/settingsStore.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.{ts,tsx}: Keep toast and notification copy insrc/strings.ts; prefer centralized strings for other user-facing text, including JSX text and aria labels, and follow the voice in DESIGN-SYSTEM.md §14.
Treat peer wire formats and identity derivation as cross-version contracts; coordinate changes so older peers continue to work and existing identity/data are not stranded.
The application is local-only: never add telemetry, and never instruct users to paste model files or BIP39 mnemonics into an AI service.
Use Context7 to verify current external library, API, framework, version, CLI, and platform behavior before relying on it; do not assume facts from memory when they are load-bearing.
Files:
src/App.tsxsrc/stories/UpdateReadyBanner.stories.tsxsrc/routes/Home.tsxsrc/features/updater/UpdaterBoot.tsxsrc/features/updater/index.tssrc/components/UpdateReadyBanner.tsxsrc/features/settings/categories/AboutCategory.tsxsrc/strings.tssrc/features/updater/updaterStore.tssrc/stores/settingsStore.ts
src/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Only import Radix or shadcn primitives from
src/components/ui/; application components undersrc/components/must compose fromui/,src/design/, and shared utilities, with no reverse imports.
Files:
src/App.tsxsrc/stories/UpdateReadyBanner.stories.tsxsrc/routes/Home.tsxsrc/features/updater/UpdaterBoot.tsxsrc/components/UpdateReadyBanner.tsxsrc/features/settings/categories/AboutCategory.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: TypeScript must remain strict and pass the repository TypeScript/build checks.
Run the frontend quality gates before committing or opening a PR: build, lint, tests, token checking, string checking, contrast checking, and Storybook accessibility checking (building Storybook first when required).
Files:
src/App.tsxsrc/stories/UpdateReadyBanner.stories.tsxsrc/routes/Home.tsxsrc/features/updater/UpdaterBoot.tsxsrc/features/updater/index.tssrc/components/UpdateReadyBanner.tsxtests/unit/updater-store.test.tssrc/features/settings/categories/AboutCategory.tsxsrc/strings.tssrc/features/updater/updaterStore.tssrc/stores/settingsStore.ts
**/*.{ts,tsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
When fixing behavior traceable to an existing issue or improvement, preserve the repository's compact comment tags such as
I9,F6, orPR-27and retain the surrounding rationale needed for safe editing.
Files:
src/App.tsxsrc/stories/UpdateReadyBanner.stories.tsxsrc/routes/Home.tsxsrc/features/updater/UpdaterBoot.tsxsrc/features/updater/index.tssrc/components/UpdateReadyBanner.tsxtests/unit/updater-store.test.tssrc/features/settings/categories/AboutCategory.tsxsrc/strings.tssrc-tauri/src/commands/system.rssrc/features/updater/updaterStore.tssrc-tauri/src/lib.rssrc/stores/settingsStore.ts
{package.json,package-lock.json,src-tauri/Cargo.toml,src-tauri/Cargo.lock,src-tauri/tauri.conf.json}
📄 CodeRabbit inference engine (CLAUDE.md)
Release version bumps must update all five tracked version locations in lockstep, and CHANGELOG.md must be updated as part of the release.
Files:
src-tauri/Cargo.tomlpackage.jsonsrc-tauri/tauri.conf.json
src/**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Every primitive and feature component must have a Storybook story, and every Storybook story must pass the axe-core accessibility gate.
Files:
src/stories/UpdateReadyBanner.stories.tsx
**/*.test.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Vitest tests run in a Node environment without RTL/jsdom; do not add component tests in
*.test.tsxwithout a deliberate, flagged scope expansion. Component behavior is covered by Storybook and axe-core.
Files:
tests/unit/updater-store.test.ts
src-tauri/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
src-tauri/**/*.rs: Treat Tauri/Rust changes affecting peer wire formats, identity derivation, or persisted data as cross-version compatibility changes; do not break older peers or stored data.
For Rust changes, runcargo test,cargo fmt --check, andcargo clippybefore committing or opening a PR.
Files:
src-tauri/src/commands/system.rssrc-tauri/src/lib.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Read the canonical documents relevant to a task—PLAN.md, ARCHITECTURE.md, and DESIGN-SYSTEM.md are the sources of truth; surface conflicts rather than silently deviating.
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Do not create new documentation files unless explicitly requested; update canonical documentation, CHANGELOG.md, or ISSUES.md only when justified.
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Add comments only when the reason is non-obvious; identifiers should carry meaning and code should read top-to-bottom.
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Maintain scope discipline: do not refactor adjacent code while implementing a feature, add abstractions for hypothetical future needs, or expand a bug fix beyond the bug.
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Use one focused change per commit, with a Conventional Commit subject such as `feat:`, `fix:`, `chore:`, `docs:`, or `ci:`; pull requests are squash-merged.
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Before committing multi-file or subagent work, run repository-wide formatting; keep the pre-commit gates functioning and run `npm run prepare` if Husky hooks are not firing.
Learnt from: CR
Repo: scotej/studyvis
Timestamp: 2026-07-20T21:42:37.356Z
Learning: Use desktop-control tooling when live-app observation benefits a task; confirm before destructive on-screen actions and state which manual checks were machine-walked versus user-walked.
🔇 Additional comments (25)
.github/workflows/release.yml (1)
51-64: LGTM!Also applies to: 79-82, 96-102, 115-124, 162-168, 179-183
src-tauri/Cargo.toml (1)
3-3: LGTM!Also applies to: 41-41
src-tauri/capabilities/default.json (1)
4-12: LGTM!src-tauri/src/commands/system.rs (1)
7-10: LGTM!Also applies to: 363-364, 516-524
src-tauri/src/lib.rs (1)
57-61: LGTM!Also applies to: 85-97, 150-150
src-tauri/tauri.conf.json (1)
4-4: LGTM!Also applies to: 35-49, 63-67
package.json (1)
4-38: 📐 Maintainability & Code QualityNo change needed.
ARCHITECTURE.md (1)
78-90: LGTM!Also applies to: 630-630
CHANGELOG.md (2)
31-42: LGTM!Also applies to: 53-65
21-29: 📐 Maintainability & Code QualityNo release-state mismatch here.
v1.5.0is already treated as the current release across the changelog, README, and version files.> Likely an incorrect or invalid review comment.CLAUDE.md (1)
5-5: LGTM!INSTALL.md (1)
5-5: LGTM!Also applies to: 19-24, 30-40, 48-56
PLAN.md (1)
66-66: LGTM!Also applies to: 164-166
README.md (1)
69-76: LGTM!Also applies to: 83-86, 220-228
src/stores/settingsStore.ts (1)
75-80: LGTM!Also applies to: 151-155, 182-186, 227-227, 586-586, 654-663, 873-876
tests/unit/updater-store.test.ts (1)
1-289: LGTM!src/App.tsx (1)
14-14: LGTM!Also applies to: 54-54
src/features/updater/UpdaterBoot.tsx (1)
30-62: LGTM!src/features/updater/index.ts (1)
1-9: LGTM!src/features/settings/categories/AboutCategory.tsx (1)
27-44: LGTM!Also applies to: 79-111, 153-170
src/components/UpdateReadyBanner.tsx (1)
1-109: LGTM!src/routes/Home.tsx (1)
22-22: LGTM!Also applies to: 455-458
src/strings.ts (1)
1248-1258: LGTM!Also applies to: 1577-1617
src/stories/UpdateReadyBanner.stories.tsx (1)
1-30: LGTM!src/features/updater/updaterStore.ts (1)
55-60: 🩺 Stability & AvailabilityNo missing updater wiring —
sidecar_stopandsystem_relaunch_appare registered insrc-tauri/src/lib.rs, andsrc-tauri/capabilities/default.jsongrantsupdater:defaultto the main window, so the restart flow has the needed IPC access.> Likely an incorrect or invalid review comment.
| - **Outbound data beyond P2P + Nostr signaling**: zero, with one explicit carve-out — **auto-update** (X6, ON by default, Settings → About). While it is on, the app fetches `latest.json` from the public GitHub Releases page on launch and every 6 hours, and downloads the installer when a newer version exists. Every request is unauthenticated and carries no identifiers, no query parameters, and no payload; nothing about the user, their friends, or their sessions is transmitted, and background failures are silent. Turning the toggle off restores literal zero outbound — no check is scheduled and none is made. No telemetry, no crash auto-uploads. Crash logs stay local with a manual "Share Log" button. | ||
| - *This widened in v1.5.0.* Before it, the carve-out was an opt-in, OFF-by-default tag comparison the user had to visit Settings to trigger. The exchange is deliberate: friends installing by hand meant security fixes landed only when someone remembered to check. The privacy properties that mattered — no identifiers, no payload, user-disableable — are unchanged. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use precise privacy wording for updater requests.
The app can avoid sending application identifiers, friend/session data, and payloads, but GitHub still receives ordinary HTTP metadata such as source IP, User-Agent, and timing.
PLAN.md#L27-L28: make the canonical outbound-data statement distinguish app data from transport metadata.INSTALL.md#L42-L46: replace “Nothing about you is sent” with the narrower claim.README.md#L46-L51: apply the same precise wording.CHANGELOG.md#L46-L50: keep the release note consistent with the canonical privacy statement.
📍 Affects 4 files
PLAN.md#L27-L28(this comment)INSTALL.md#L42-L46README.md#L46-L51CHANGELOG.md#L46-L50
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@PLAN.md` around lines 27 - 28, Revise the updater privacy wording to
distinguish application data from unavoidable HTTP transport metadata such as
source IP, User-Agent, and request timing. Update PLAN.md lines 27-28 as the
canonical statement, and apply the same narrower claim in INSTALL.md lines
42-46, README.md lines 46-51, and CHANGELOG.md lines 46-50; avoid claiming that
nothing about the user is sent.
Source: Learnings
| **Linux** — not in 1.0. WebKitGTK's `getDisplayMedia` support was not | ||
| validated; Linux returns when the V0 sanity pass is re-run on it. If | ||
| you want to try the dev build today, clone the repo and run | ||
| `npm run tauri dev`. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the stale Linux version reference.
This says Linux is “not in 1.0,” but the document now describes v1.5.0 as the current release. Say Linux is not currently in the release matrix or otherwise use a current version-neutral statement.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` around lines 78 - 81, Update the Linux platform note in the README
to remove the stale “not in 1.0” reference and use a current version-neutral
statement, such as indicating that Linux is not currently in the release matrix.
Preserve the existing explanation about WebKitGTK validation and the development
build command.
| const help = | ||
| status === 'checking' | ||
| ? updaterCopy.checkingHelp | ||
| : errorKind === 'check' | ||
| ? strings.updater.errors.checkFailed | ||
| : errorKind === 'download' | ||
| ? strings.updater.errors.downloadFailed | ||
| : updaterCopy.upToDateHelp(__APP_VERSION__) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
"Up to date" copy is shown for un-checked and silently-failed states.
The final else returns upToDateHelp(__APP_VERSION__) whenever status isn't checking/downloading/ready and there's no attributed errorKind. That also covers status === 'idle' (before the first scheduled check runs) and status === 'error' with errorKind === null (a silent background check/download failure), so the row asserts the user is on the latest version without ever confirming it.
Gate the up-to-date message on the actual state:
🐛 Proposed fix
const help =
status === 'checking'
? updaterCopy.checkingHelp
: errorKind === 'check'
? strings.updater.errors.checkFailed
: errorKind === 'download'
? strings.updater.errors.downloadFailed
- : updaterCopy.upToDateHelp(__APP_VERSION__)
+ : status === 'upToDate'
+ ? updaterCopy.upToDateHelp(__APP_VERSION__)
+ : copy.version.helpidle/silent-error then falls back to neutral copy while the "Check now" button still invites an explicit check. Adjust the neutral string as fits the voice.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/features/settings/categories/AboutCategory.tsx` around lines 113 - 120,
Update the help-text selection around the updater status logic so
updaterCopy.upToDateHelp(__APP_VERSION__) is returned only after a confirmed
up-to-date state, not for idle or error states with a null errorKind. Add a
neutral fallback for unchecked and silently failed states while preserving the
existing checking and attributed check/download error messages.
What
StudyVis now updates itself, via
tauri-plugin-updater. It checks GitHub on launch and every 6h, downloads new releases in the background, and offers a Restart now banner once the new version is staged and signature-verified. Only the first install stays manual. This is the v1.5.0 release.The premise correction
The repo's docs claimed auto-update was blocked on an Apple Developer ID / Windows cert. That was a conflation. Tauri's updater has its own integrity chain — artifacts are signed with a minisign keypair and verified in-app against
plugins.updater.pubkeybefore unpacking, independent of OS code signing. So this ships on the existing ad-hoc-signed builds. PLAN §8, ARCHITECTURE, README, INSTALL, and CLAUDE.md are corrected rather than worked around.Behavior
llama-server.exe; a macOS orphan would survive the relaunch.Notable changes
-setup.exe, not.msi. MSI updates need msiexec elevation every time (a UAC prompt per release). NSIS installs per-user + passive. Friends on ≤1.4.0 uninstall the old MSI once first — documented in CHANGELOG / INSTALL / README.version_check_enabledkey migrates to OFF.system_fetch_latest_versioncommand.release.yml: signing secrets + preflight gate,includeUpdaterJson: true, NSIS bundles,max-parallel: 1so the two jobs can't clobber each other'slatest.jsonentry.Verification
StudyVis.app.tar.gz+.sig, signature key ID cross-checked against the configured pubkey.cargo fmt.Manual-test note
Not machine-walked (no updater end-to-end without a published release). The runtime relaunch + signature-verify semantics were confirmed against the plugin's own source rather than a live run.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
x64-setup.exeinstaller.Documentation
Bug Fixes