Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ jobs:
- name: Assert the tag matches all five version files
run: bash scripts/check-version-lockstep.sh "${GITHUB_REF_NAME#v}"

# X6 — an unsigned update artifact is worse than no release: it uploads
# fine, publishes fine, and then every installed client silently refuses
# it. Catch the missing secret here rather than an hour of build minutes
# later. Only presence is checked; the value never reaches the log.
- name: Assert the updater signing key is configured
env:
KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
run: |
set -euo pipefail
if [[ -z "${KEY}" ]]; then
echo "::error::TAURI_SIGNING_PRIVATE_KEY is not set. Update artifacts would ship unsigned and every client would reject them. Add the secret (see PLAN §8) and re-run."
exit 1
fi

- name: Extract this version's CHANGELOG section for the release body
id: notes
run: |
Expand All @@ -62,7 +76,10 @@ jobs:
macOS users right-click the app and choose Open the first time;
Windows users click "More info" → "Run anyway" on the SmartScreen warning.

StudyVis does not auto-update. Download a new version here when one drops.'
If you are already on StudyVis 1.5.0 or newer, you do not need to download
anything — the app picks this up on its own and offers to restart into it.
Auto-update reads `latest.json` from the LATEST published release, so this
draft has to be published before anyone receives it.'
{
echo "body<<CHANGELOG_SECTION_EOF"
printf '%s\n\n---\n\n%s\n' "$section" "$boiler"
Expand All @@ -76,6 +93,13 @@ jobs:
contents: write
strategy:
fail-fast: false
# X6 — serialized deliberately. Both jobs append their platform's entry
# to the SAME `latest.json` on the release, and tauri-action does that
# as a read-merge-write with no locking: run in parallel and the slower
# job can overwrite the faster one's entry, silently stranding a whole
# platform on the old version with no error anywhere. Serializing costs
# one build's wall-clock on a workflow that runs a few times a year.
max-parallel: 1
matrix:
include:
# Per-arch, not universal: the llama-server sidecar (externalBin)
Expand All @@ -88,10 +112,16 @@ jobs:
rust-targets: aarch64-apple-darwin
args: --target aarch64-apple-darwin --bundles app,dmg
llama-triples: aarch64-apple-darwin
# X6 — NSIS, not MSI. The updater re-runs the installer to apply an
# update, and an MSI needs msiexec elevation every single time,
# which turns "auto-update" into a UAC prompt per release. NSIS
# installs per-user (bundle.windows.nsis.installMode) and supports
# the passive install mode the updater config asks for, so the
# update applies with a progress bar and no interaction.
- label: Windows
platform: windows-latest
rust-targets: ''
args: --bundles msi
args: --bundles nsis
llama-triples: x86_64-pc-windows-msvc
runs-on: ${{ matrix.platform }}
timeout-minutes: 60
Expand Down Expand Up @@ -129,6 +159,13 @@ jobs:
uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0.6.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# X6 — the minisign keypair that signs update artifacts. This is
# NOT Apple/Windows code signing: it's the updater's own integrity
# chain, verified in-app against `plugins.updater.pubkey`. Without
# these two the bundler emits unsigned artifacts and every client
# rejects the update, so the build fails loudly instead (below).
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
tagName: ${{ github.ref_name }}
releaseName: 'StudyVis ${{ github.ref_name }}'
Expand All @@ -139,5 +176,9 @@ jobs:
# Tags with a prerelease suffix (e.g. v1.1.0-rc.1) publish as GitHub
# prereleases; clean vX.Y.Z tags are full releases.
prerelease: ${{ contains(github.ref_name, '-') }}
includeUpdaterJson: false
# X6 — both matrix jobs write `latest.json` on the same release;
# tauri-action merges each platform's entry into the existing file
# rather than overwriting it, so the published release ends up with
# both darwin-aarch64 and windows-x86_64.
includeUpdaterJson: true
args: ${{ matrix.args }}
16 changes: 14 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,19 @@ Pinned versions are the floor; bump as needed but never silently downgrade.
- **tauri-plugin-dialog** — native message dialogs for the unrecoverable startup paths (corrupt-DB set-aside, newer-version refusal) and the file save pickers (report / audit / CSV export).
- **tauri-plugin-store** — small key/value config (separate from SQLite for hot config).

The **`tauri-plugin-updater`** dependency that earlier sat dormant in `Cargo.toml` was **removed** (X6) — it had zero runtime effect, and re-enabling it is gated on signing credentials anyway. The full re-add checklist lives in PLAN §8 ("Signing / notarization / auto-update"); it returns as a single coordinated change when a Developer ID / EV cert is acquired.
- **tauri-plugin-updater** (X6, v1.5.0) — in-app auto-update. Desktop-only registration in `lib.rs`; `updater:default` is granted to the **main** window only, so the floating AI dialog cannot reach check/download/install.

### Auto-update (X6)

**Integrity.** Release artifacts are signed with a minisign keypair generated by `npx tauri signer generate`. The public half is baked into `plugins.updater.pubkey` (`tauri.conf.json`); the private half lives outside the repo and reaches CI as the `TAURI_SIGNING_PRIVATE_KEY` secret. The plugin verifies the signature *before* unpacking, so a compromised release page still cannot hand the app a payload it will install. **This is independent of Apple / Windows code signing** — which is why auto-update ships on ad-hoc-signed builds. An earlier revision of this document and PLAN §8 conflated the two; see PLAN §8 for the correction and the macOS TCC caveat that comes with staying unsigned.

**Discovery.** `plugins.updater.endpoints` points at `releases/latest/download/latest.json` on the public repo. GitHub resolves `/latest/` to the newest **published, non-prerelease** release, so a draft release (what `release.yml` produces) reaches nobody until it is published, and `-rc.N` tags never auto-ship.

**Scheduling** lives in `src/features/updater/UpdaterBoot.tsx`, not in the store. Two rules: nothing outbound while the `auto_update_enabled` setting is off, and nothing at all during a session — a WebRTC mesh has no bandwidth to spare for an installer download. The first check is delayed 20 s after boot so it doesn't race P2P discovery; thereafter every 6 h.

**Apply.** Downloads run unattended; only the restart waits for a person, via `UpdateReadyBanner` on the dashboard (and a mirrored row in Settings → About). The store stops the llama-server sidecar before `install()` — on Windows the NSIS installer cannot overwrite a running `llama-server.exe`, and on macOS an orphan would survive the relaunch holding its port and model file.

**Windows packaging.** NSIS (`-setup.exe`), per-user install, `installMode: "passive"`. MSI was dropped at X6: applying an MSI update requires msiexec elevation every time, which is a UAC prompt per release.

### AI inference (V2+)
- **llama-server** (binary from llama.cpp build) — Tauri sidecar. The release matrix bundles `mac-arm64` + `win-x64` (matching the Apple-Silicon/Windows-only install story in INSTALL.md / README.md); `mac-x64` and `linux-x64` remain fetchable for local dev (`scripts/fetch-llama-server.sh` supports all four triples — see the Linux unblock trigger in PLAN §8).
Expand Down Expand Up @@ -615,7 +627,7 @@ When code-signing credentials become available (V3 or later), an `Entitlements.p

### Windows
- WebView2 handles camera/mic/screen prompts natively.
- V1 ships an unsigned `.msi`. Windows SmartScreen will warn on first launch ("Windows protected your PC") — friends click "More info" → "Run anyway". A code-signing certificate (and ideally an EV cert for instant SmartScreen reputation) would remove the warning; deferred until creds are available.
- Ships an unsigned NSIS `-setup.exe` (per-user; the MSI target was dropped at X6 — see the updater section's "Windows packaging" note for why). Windows SmartScreen will warn on first launch ("Windows protected your PC") — friends click "More info" → "Run anyway". A code-signing certificate (and ideally an EV cert for instant SmartScreen reputation) would remove the warning; deferred until creds are available. Note this governs only the *first* install — X6 auto-update carries its own minisign signature, independent of Authenticode.

### Linux (deferred)
Linux is not part of the V1 release matrix — V0 deferred WebKitGTK `getDisplayMedia` validation, and the friends-only V1 audience is macOS + Windows only (`keyring` is gated to those two platforms; the V1-P12 release workflow excludes Linux). When V0 is re-run on Linux and passes, V3 lights up Linux:
Expand Down
45 changes: 43 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,50 @@ V3 work was drafted as v1.0.4 but shipped under the **v1.0.5** tag —
there is no v1.0.4 tag; the section below is labelled by the tag that
shipped it.)

## Unreleased
## 1.5.0 — 2026-07-21 — auto-update + a window-size settings pass

### Settings GUI pass: window sizes first-class everywhere
> **This is the last version you install by hand.** From here on StudyVis
> updates itself. **Windows:** this release switched installer format —
> uninstall your existing StudyVis from Settings → Apps _before_ running the
> new `-setup.exe`, or Windows will list two copies. Your identity, friends,
> and history are untouched. **macOS:** after a self-update, macOS may ask
> for camera / microphone / screen-recording permission again (the app isn't
> notarized yet); granting it is safe.

### Added

- **StudyVis updates itself.** It checks for new releases in the
background, downloads them, and shows a "StudyVis X.Y.Z is ready"
banner with a Restart now button — the restart is a couple of seconds
because the download already happened. Nothing checks, downloads, or
interrupts during a session. Dismissing with "Later" leaves the update
waiting in Settings → About.

Each update is signature-verified before it is installed, so a tampered
download is rejected. This does not require the code-signing
certificates StudyVis still lacks — the updater carries its own key.

- **Remember window size and position** (Settings → Appearance → Window,
on by default): the window reopens where you left it — size, position,
and maximized state — restored by Rust before the window is shown, so
there's no resize flash. Geometry saved on an unplugged monitor falls
back to centering instead of opening off-screen. A **Reset** row returns
the window to the default 1280 × 800, centered.

### Changed

- **Automatic updates are ON by default** (Settings → About). This widens
the privacy stance: previously the only outbound request beyond P2P was
an opt-in, OFF-by-default version check. The requests are still
anonymous fetches of a public file with no identifiers and no payload,
and turning the toggle off restores zero outbound. If you had
deliberately turned the old version check off, that choice carries over
and auto-update stays off.
- **The Windows installer is now `-setup.exe` (NSIS), not `.msi`.**
Applying an MSI update needs an administrator prompt every single time,
which defeats the point. **Upgrading from 1.4.0 or earlier: uninstall
the old StudyVis from Settings → Apps first**, then run the new
installer — otherwise Windows lists two copies. Your data is untouched.
- Settings nav rework: the eleven categories are grouped (You / Study /
App / System) with lucide icons and an accent edge on the active item;
the rail is now fluid (`clamp(224px, 22vw, 280px)`) so narrow windows
Expand All @@ -49,6 +83,13 @@ shipped it.)
About pane's copyright line sits beside the version it belongs to; the
two stats charts share one left plot edge.

### Known issue

- **macOS may re-ask for camera / microphone / screen-recording
permission after an update.** macOS ties those grants to a signed app
identity, and StudyVis is not yet notarized. Granting again is safe.
A Developer ID certificate would remove this.

## 1.4.0 — 2026-07-19 — multi-friend sessions, faster AI, and the verified backlog

Everything merged since v1.3.1: a production-readiness audit, a settings
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Auto-loaded by Claude Code at the start of every session in this repo. It summarizes how to work here and points to the canonical docs. Read the relevant ones in full at the start of any non-trivial session — they are the source of truth, not training data.

StudyVis is **shipped and feature-complete**: a peer-to-peer desktop study app for friends (body-doubling video + optional on-device AI focus detection), released friends-only and unsigned for macOS + Windows. The current line is **v1.x** (see `CHANGELOG.md`). Work is now **maintenance and new features**, not a from-scratch build. There are real installed builds but no auto-update and no public users — friends pull releases manually.
StudyVis is **shipped and feature-complete**: a peer-to-peer desktop study app for friends (body-doubling video + optional on-device AI focus detection), released friends-only and unsigned for macOS + Windows. The current line is **v1.x** (see `CHANGELOG.md`). Work is now **maintenance and new features**, not a from-scratch build. There are real installed builds and no public users. As of **v1.5.0** the app self-updates in-app (tauri-plugin-updater, tag X6): background download + signature-verified restart, defaults ON — only the *first* install is manual. Builds remain unsigned for OS code-signing purposes, so friends still clear the Gatekeeper/SmartScreen warning on that first install.

## Canonical documents

Expand Down
37 changes: 27 additions & 10 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

StudyVis ships unsigned installers for a friends-only audience. Each OS will warn the first time you run the app — the steps below explain how to clear those warnings. After the first launch, the OS remembers your decision and stops asking.

> StudyVis does **not** auto-update. When a new version is available, download the latest installer from the [GitHub Releases page](https://github.com/scotej/studyvis/releases) and re-run the install steps for your OS.
> **You only have to do this once.** From v1.5.0 on, StudyVis updates itself — see [Updating](#updating) below.

## macOS (Apple Silicon)

Expand All @@ -16,27 +16,44 @@ StudyVis ships unsigned installers for a friends-only audience. Each OS will war

## Windows 10 / 11

1. From the [Releases page](https://github.com/scotej/studyvis/releases), download `StudyVis_<version>_x64_en-US.msi`.
2. Double-click the `.msi`. **SmartScreen** intercepts: _"Windows protected your PC"_. Click **More info**, then **Run anyway**.
1. From the [Releases page](https://github.com/scotej/studyvis/releases), download `StudyVis_<version>_x64-setup.exe`.
2. Double-click the installer. **SmartScreen** intercepts: _"Windows protected your PC"_. Click **More info**, then **Run anyway**.
3. Step through the installer (defaults are fine). StudyVis lands in your Start menu and Programs list.
4. The first time you join a session, Windows asks for camera and microphone permission via WebView2. Allow both.

> **Coming from StudyVis 1.4.0 or earlier?** Those shipped as an `.msi`. Uninstall the old StudyVis from Settings → Apps first, then run this installer — otherwise Windows lists two copies. Your identity, friends, and history are untouched by the uninstall; they live in your user data directory, not the program folder.

## Linux

Linux installers are not available yet. WebKitGTK's `getDisplayMedia` support was not validated during the V0 sanity check; Linux returns once that path is verified. If you want to try the development build today, clone the repo and run `npm run tauri dev`.

## Updating

StudyVis never updates itself, but it can tell you when an update
exists: Settings → About has an optional, off-by-default new-version
check that compares against the GitHub Releases page (an anonymous
lookup — no identifiers sent). Downloading and installing stays
manual. To upgrade:
StudyVis updates itself. It checks GitHub for new releases shortly after
launch and every few hours after that, downloads one in the background when
it finds it, and then shows a **"StudyVis X.Y.Z is ready"** banner with a
**Restart now** button. Clicking it takes a couple of seconds — the download
already happened.

It will not interrupt you: no check, no download, and no banner while you are
in a session. Dismissing the banner with **Later** keeps the update waiting;
it stays available in Settings → About until you restart.

Nothing about you is sent in any of this — the requests are anonymous
fetches of a public file. Each update is signature-checked before it is
installed, so a tampered download is rejected. To opt out entirely, turn
**Automatic updates** off in Settings → About; StudyVis then makes no
outbound requests at all beyond connecting you to friends.

**If you ever need to install by hand** — you're on a build older than
v1.5.0, or an update failed:

- **macOS:** download the new `.dmg` and drag StudyVis to Applications, replacing the existing app.
- **Windows:** download the new `.msi` and run it; it upgrades the existing install in place.
- **Windows:** download the new `-setup.exe` and run it; it upgrades the existing install in place.

Your identity, friends list, and local session history live in your OS data directory — they are preserved across updates and reinstalls.

Your identity, friends list, and local session history live in your OS data directory — they are preserved across reinstalls.
> **macOS permission re-prompts.** Because the app is not yet signed with an Apple Developer ID, macOS may treat an updated StudyVis as a new app and ask for camera / microphone / screen-recording permission again after an update. Granting it again is safe; this goes away if the app is ever properly signed.

## Troubleshooting

Expand Down
Loading