Document the proposed Windows installation and persistent-model policy

* docs: add the Windows installation policy; models are persistent asse…

…ts, not caches

A companion policy to settings-storage.md: dual-scope per-user-default MSIs,
the ArtCraft suite folder, what an update must preserve (folder, context, no
duplicates), standalone installability, and the platform-native boundary on
macOS, Linux and FreeBSD. Splits models out of the disposable-caches row:
downloaded models are persistent user assets that cache cleanup and app
uninstallers must never delete.

* docs: describe suite Windows installation policy

* docs: record the wizard scope and folder rules and the real-install c…

…hecks

The scope page leaves ALLUSERS unset for Only for me, and the wizard sets the new-install folder itself after the choice, because Windows Installer resolves Program Files once for the context it started in. Notes the 32-bit Program Files (x86) folder and updates the adoption table to say real per-user and all-users msiexec runs were done. Clean-machine and second-account checks are still pending.

* docs: new installs default to per-machine; only the old default folde…

…r moves

* docs: say plainly that released packages still default to per-user

The policy says new installs are per-machine, but every released package is
dual-scope with a per-user authored default, and the inventory still listed
"Per-user default". The policy now separates the two: what the policy is, what
the packages do today, who picks per-machine (the launcher, or "Everyone" in the
wizard), and the follow-up that closes the gap.

Also: Update all's one-prompt route was reverted after the antivirus incident,
so the policy no longer says it asks once; the Linux model folder names its
ArtCraft/models subfolder; repair is listed where the 26/10 payload runs
covered it; the inventory no longer says nothing was released.

* docs: the launcher and a direct MSI run match only for the same scope…

… and folder

CodeRabbit pointed out that 'produce the same result' contradicted the
documented new-install difference: the launcher sets ALLUSERS=1, while a
direct run keeps the package's per-user default.

* docs: make the legacy-folder migration exception explicit

State that exact former-default paths can migrate even when manually
chosen, subject to maintainer acceptance of the proposed policy. Preserve
other chosen folders and document the effect on custom shortcuts.

---------

Co-authored-by: Jeremy <jeremy8776@googlemail.com>
This commit is contained in:
Jeremy authored and GitHub committed 2026-11-12 10:43:51 -05:00
1 parent 65cf3f9b0d
commit e85bd30bb2
3 files changed
+171 -1

No files matched your search

+121
View File
@@ -0,0 +1,121 @@
# Installing the Craft apps on Windows
This is a proposed policy, not a claim about a published release. Preparation covers every
current Craft app with a Windows MSI, plus the launcher's new-install folder. The
[adoption inventory](windows-installation-adoption.md) records the scope and remaining gates.
Folders are preserved except for the proposed automatic migration of an exact former default
path (see below). That exception also covers a manually chosen path with the same spelling;
all other chosen folders stay. Maintainer acceptance of this exception is part of accepting
the policy. Storage of settings, caches and models is separate: [settings-storage.md](settings-storage.md).
## Installation contexts
**The policy (amended 29/10/2026): new installs are per-machine**, so every app sits in one
`Program Files\ArtCraft` folder. Per-user copies that already exist keep their context.
**What the released packages do today differs, and this is a known gap.** Each app ships one
dual-scope MSI (Microsoft's "Single Package Authoring": `ALLUSERS=2` with `MSIINSTALLPERUSER=1`
in the Property table, written by WiX's `Package/Scope="perUserOrMachine"`). That authored
default is **per-user**: run with no scope property, the package installs for one account. So
today only the launcher, which passes `ALLUSERS=1` for a new install, follows the policy by
itself. A person running the MSI directly gets per-machine only by choosing "Everyone" in its
wizard. Closing the gap is follow-up work: one small PR per app making its package per-machine
only (`Scope="perMachine"`, no scope page), which also removes the per-user default here and
in the [adoption inventory](windows-installation-adoption.md).
| Context | Default destination | Who chooses it today |
|---|---|---|
| Per-machine (the policy for new installs) | `%ProgramFiles%\ArtCraft\<App>` (`Program Files (x86)` for a 32-bit package) | The launcher, with `ALLUSERS=1`; the setup wizard's "Everyone" choice |
| Per-user (the package's authored default; kept for existing copies) | `%LOCALAPPDATA%\Programs\ArtCraft\<App>` | An MSI run with no scope property; the wizard's "Only for me" choice; copies installed per-user keep their context on update |
**Permission prompts.** Each all-users install or update asks Windows for permission. One
prompt per **Update all** run was built (craft-launcher#974) with a hidden PowerShell, which
antivirus flagged; it was reverted (craft-launcher#1077). The launcher's signed installer
helper (craft-launcher#1080, in review) does all-users downgrades under one prompt, with no script.
Update all keeps one prompt per all-users package until it uses that helper too. No resident
service is planned.
The launcher itself remains per-user only, with new copies under
`%LOCALAPPDATA%\Programs\ArtCraft\Launcher`. Existing launcher folders and its current
self-update mechanism are preserved.
In a per-user install Windows Installer itself redirects the `ProgramFiles` folder to the
user's own Programs folder and the `HKMU` registry root to `HKCU`, so one package serves both
contexts. Everything a package writes follows its context automatically:
- `InstallDir` record: `HKLM\Software\<App>` per-machine, `HKCU\Software\<App>` per-user.
- File associations and "Open with" registrations: `HKLM\Software\Classes` per-machine,
`HKCU\Software\Classes` per-user.
- Registry writes use context-sensitive roots. Existing component key paths and app-owned
associations are retained where valid. Each package must pass the compiled install-policy
checks; unresolved ICE57 shortcut diagnostics are tracked separately from the path policy.
Scope is chosen before launch conditions and directory costing. The scope page must not be
added as a late checkbox after the default directory has already been resolved.
The page also has to leave `ALLUSERS` unset for "Only for me". Setting `ALLUSERS=2` there makes
Windows Installer search for related products as if the run were per-machine, so an interactive
upgrade skips the existing per-user copy and installs a second registration beside it.
Windows Installer also resolves Program Files once, for the context it started in, so the wizard
sets the new-install folder itself after the choice. Without that, "Everyone" installed into the
user profile with a machine-wide registration.
For the same scope and folder, the ArtCraft Launcher and a direct install of the same MSI
produce the same result: the launcher dispatches the same package and only adds properties.
For an update, those are `INSTALLFOLDER` (the remembered folder) and the context properties of
the copy being updated. For a new install, the launcher also sets `ALLUSERS=1`, so the copy is
per-machine; a direct run of the MSI keeps the package's per-user default unless the person
picks "Everyone" in the wizard.
## What an update must preserve
- **The exact folder, subject to the following exception.** An ordinary update installs into
the remembered folder of the copy being replaced. Every chosen folder outside the exact
former default is preserved.
- **Explicit automatic-migration exception: the former default.** This proposal moves a copy
whose remembered folder is exactly `%ProgramFiles%\<App>\` to
`%ProgramFiles%\ArtCraft\<App>` on its next update, without a separate migration confirmation.
It also moves that exact path when someone typed it by hand: Windows Installer kept no
record that distinguishes a chosen path from an accepted default. Matching the path is not
evidence that the person accepted a default. An unreadable or different folder stays.
Maintainers must accept this exact-path exception as part of the policy before it is
adopted; it must not be described as preserving every manually chosen folder. Package-owned
shortcuts are recreated, but a shortcut someone made by hand to the old path may break.
Requiring migration consent instead is a change to this proposed rule; an in-app choice
would not itself require another Windows elevation prompt.
- **The context.** A per-machine copy updates per-machine (`ALLUSERS=1`), a per-user copy
per-user. MSI major upgrades cannot cross installation contexts, so a context change is a
deliberate uninstall-and-reinstall, never an ordinary upgrade. The launcher queries
authoritative MSI registration, not the hive containing a display entry. An unknown or
conflicting context stops the update rather than selecting the new-install default.
- **No duplicates.** Installing in the other context while a copy already exists is a visible
stop with a message naming the fix, never a silent second copy. The wizard pre-ticks the
matching scope when a copy in the other context is registered.
- **The chosen folder survives elevation.** `INSTALLFOLDER` is a secure MSI property, so
the elevated installer receives the same exact destination selected in the setup wizard.
- **Custom folders stay first-class.** A chosen exact app folder is used as-is; a chosen
suite root gets the app subfolder appended once (`D:\Craft` becomes `D:\Craft\PhotoCraft`,
never `D:\Craft\PhotoCraft\PhotoCraft`). A missing drive or an unavailable folder is a
visible error, not permission to fall back to the default.
## What an app must still do without the launcher
Install, launch, update and uninstall work standalone: the MSI's own wizard, its App Paths
registration (`Win+R`), its Start Menu shortcut and its entry in "Apps & features" never
require the launcher. The launcher reuses a standalone installation it finds rather than
installing a duplicate, and detection reads both contexts' registrations.
## Other platforms
macOS `.app` bundles, Linux packages/AppImages and FreeBSD tarballs keep their platform-native
conventions; nothing imitates the Windows directory tree. Linux settings live under
`XDG_CONFIG_HOME` and persistent models under `XDG_DATA_HOME` (`~/.local/share/ArtCraft/models`)
per [settings-storage.md](settings-storage.md).
## Models are not caches
Downloaded model files are persistent user assets. An app's cache cleanup and an app's
uninstaller must never delete them, another app's data, or user documents; existing model
folders are discovered read-only. See [settings-storage.md](settings-storage.md) for where
models live and what is disposable. Model resources shipped inside an application package,
such as bundled OCR resources, remain part of that package; this does not give an installer
ownership of separately downloaded shared models or discovered model folders.
+4 -1
View File
@@ -2,6 +2,8 @@
How every Craft app stores its settings, and what goes where. The shared code is
[`craft-settings`](../crates/settings/README.md); this page is the policy it implements.
Where the apps install on Windows, and what an update may move, is the companion policy
[installation-policy.md](installation-policy.md).
Discussion: [storytold/craft-libs#12](https://github.com/storytold/craft-libs/issues/12).
## What goes where
@@ -10,7 +12,8 @@ Discussion: [storytold/craft-libs#12](https://github.com/storytold/craft-libs/is
|---|---|---|
| Settings people might edit | `config.toml` in the config folder | One readable file with comments, atomic saves, backup, recovery, migrations |
| Window and UI state | `ui.ron` / `app.ron` beside `config.toml` | Changes every session; not worth comments or hand edits |
| Caches and models | Platform cache folder (`paths::cache_dir`); `%LOCALAPPDATA%` on Windows so it does not roam | Disposable, large |
| Caches | Platform cache folder (`paths::cache_dir`); `%LOCALAPPDATA%` on Windows so it does not roam | Disposable, large |
| Downloaded models | The user's chosen persistent model root (suggested `%LOCALAPPDATA%\ArtCraft\models` on Windows; `$XDG_DATA_HOME/ArtCraft/models` on Linux, or `~/.local/share/ArtCraft/models` when it is unset) | Persistent user assets: never deleted by cache cleanup or an app's uninstaller, never disposable ([installation-policy.md](installation-policy.md)) |
| Recovery and autosave files | Platform data folder (`paths::data_dir`) | Not settings; must survive a settings reset |
| Settings that belong to a library or project (LightCraft) | Inside that folder, via `SettingsStore::open_at` | Travels with the library |
| API keys and tokens | The OS keychain | Never in a plain-text file |
+46
View File
@@ -0,0 +1,46 @@
# Windows installation policy adoption
This is the inventory for the policy across the live app repositories and the launcher, not
merely the repositories on one developer's machine. The app packages below were merged on
27/10/2026 and released on 28/10/2026 as dual-scope MSIs whose authored default is per-user.
The policy since 29/10/2026 is per-machine for new installs: today the launcher applies it
(`ALLUSERS=1`), and per-machine-only packages are follow-up work, one PR per app (see
[installation-policy.md](installation-policy.md)).
| Repository | Prepared Windows scope | Verification boundary |
|---|---|---|
| `effectcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `pdfcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `lightcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `photocraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `figcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `vectorcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `wordcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `gridcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `deckcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `filmcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `craft-launcher` | Per-user launcher; context-safe app updates | x64, x86 and arm64 metadata checks pass; real installation gates pending |
| `artcraft` | Not applicable | No Windows MSI definition on the inventoried default branch |
| `soundcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `cadcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `designcraft` | Released dual-scope, per-user authored default; the launcher installs per-machine | x64, x86 and arm64 metadata checks pass; real msiexec runs pass in both scopes (fresh install, upgrade, repair, uninstall; wizard and silent); clean-machine and second-account gates pending |
| `artcraftx` | Not applicable | No Windows MSI definition on the inventoried default branch |
| `AniCraft` | Not applicable | No Windows MSI definition on the inventoried default branch |
## Before publication and release
- Maintainer acceptance of the shared path/scope/model-ownership policy is still required.
- Keep app changes independent. Reconcile open installer UI and file-association PRs rather
than assuming their work is absent or overwriting it.
- Test real release payloads and previous release MSIs in an authorised clean Windows test
environment. Verify both standalone and launcher routes, old/custom folders, both scopes,
second-account visibility, optional shortcuts and menus, active apps, cancellation, rollback,
repair, uninstall and launcher self-update. Validate actual MSI assignment context, not only the
registry hive containing a display/uninstall entry.
- Metadata-only fixtures never substitute for those tests. x86/arm64 package validation on an
x64 host does not prove application execution on those architectures.
- No macOS/Linux layout change, settings migration, user-model relocation or new cleanup is
included. These platforms retain their native conventions.
- ArtCraft and ArtCraftX have no Windows MSI definition in the inventoried source; AniCraft
has no default branch/source to package. Do not invent installers for those repositories as
part of this rollout.