# Dewitt Offline Windows companion The **0.3.2** companion prompts people to choose their name before chatting, uses names on existing messages and conversations, and generates invitations at https://dewittoffline.com/join. It retains the signed app-update copying and private chat PWA from 0.3.1. It includes a Windows tray application, bundled Node.js runtime and local management dashboard. This build targets **Windows 10/11 x64** with .NET Framework 4.8. Node does not need to be installed separately. Windows ARM64/native support, a Windows service and macOS/Linux installers are not supplied by this package. Version 0.2.2 corrects invitations that advertised a WSL/Hyper-V adapter instead of the home-network address. Windows adapters with an IPv4 gateway are preferred; short invitation replies choose an address on the requesting PC's subnet, and pairing returns the address actually reached by the joining PC. Update both PCs and create a fresh invitation on the starter. An older full `dewitt1.` invitation retains its original address. Gateway preference is read at startup, so restart the companion after changing networks. Multiple routed home networks and VPN policies still require physical testing. ## Install or run portable Download `DewittOffline-Setup.exe`, run it and approve the **per-user installation** prompt. Setup installs program files under `%LOCALAPPDATA%\Programs\DewittOffline`, adds a Start-menu shortcut and a current-user entry in Installed apps. It does not request administrator access, enable automatic sign-in startup or change firewall rules. An optional final prompt opens the companion. For LAN app updates, use the reviewed **`DewittOffline-bootstrap.zip`**: extract both its installer and `release.json` together, then run the installer. Every PC needs 0.3.1 once before later signed releases can copy automatically from another enrolled PC. Choose **Install update…** in the tray to review and install a copied update; copying never silently installs it. The standalone EXE still installs Chat but cannot seed a release without its sidecar. See included `APP-UPDATES.md` for publisher trust and transfer limits. Microsoft Windows updates are unaffected. For portable use, extract **the entire** `DewittOffline-portable.zip` into a normal folder and run `DewittOffline.exe`. The runtime and companion subfolders must remain beside it. Portable describes program deployment; family identity/data still live in the current Windows user's profile. Avoid junction/symlink folders. Installed and portable copies share one per-user instance and data location, so close one before changing to the other. The launcher starts the hidden bundled runtime and opens Chat in your default browser when enrolled, or the setup dashboard when unenrolled. Closing the small status window keeps the application in the tray. The tray menu provides **Open chat**, **Open dashboard**, **Companion status**, **Start on sign-in**, **Allow household connections…**, and **Exit**. A second normal launch opens Chat using the existing companion. Sign-in startup uses the current-user Registry Run entry and runs in the background; uncheck it to remove that entry. Moving a portable folder after enabling startup requires toggling startup again from its new location. These artifacts are **unsigned** because no code-signing certificate is available. Windows may show an unknown-publisher or reputation warning. Verify the source and supplied hashes; do not disable SmartScreen or antivirus to run them. Signing and release provenance remain distribution work. ## First steps on two PCs 1. Open the companion on the first PC and choose **Create household** with a household name. 2. If needed, use the tray's **Allow household connections…** on both PCs while connected to your private home network. 3. On the first PC, create an invitation in the dashboard. Copy the short join link or its **16-character code**, shown in four groups, and transfer it privately. Paste either into **Join household** on the second PC. Invitations last **24 hours**, are **single-use**, and authorize a PC; do not publish them. Up to **20 active invitations** can coexist, and creating another does not invalidate the previous ones. 4. Check the approved PC list shows the second PC connected. Choose **Create a storage check** and **Sync now**; the encrypted check record should appear in both PCs' record counts. This tests local storage/replication plumbing using a check record, not a family message. 5. Exit one companion, confirm it becomes offline on the other, then reopen it and confirm reconnection. Keep the family data folders private. This release adds separate private conversations among selected enrolled PCs, text messages, an encrypted browser outbox and an installable local app shell. The storage-check key still belongs to its originating PC; replica PCs retain that ciphertext rather than gaining its decryption key. The dashboard's PC coordinator state does not change membership authority. ## Open private Chat Update **every participating PC to 0.3.2** for the name setup and latest Chat improvements. Older storage companions cannot provide Chat profiles and conversation metadata. Your existing household enrollment and records are retained by an upgrade; there is no need to create another household. Download the reviewed setup ZIP from https://dewittoffline.com/downloads/. Choose **Open chat** from the tray menu or the dashboard's chat action. Choose the name your family knows you by when prompted, then choose **New chat**, select its participants and give it a title. Use **Your name** to change it later. Names are shared by everyone using the same Windows account; they are not separate sign-ins. Messages are saved locally and sync while companions can reach each other. A saved acknowledgment is not a read receipt or proof that another PC already has a copy. Queued and failed messages remain available for retry. Install Chat using your browser's install action when offered; reopen it through **Open chat** if its session expires. Conversation keys are wrapped separately for each selected enrolled device; other household PCs can relay encrypted records but cannot read that conversation's title or messages. Participant lists are immutable: create a new conversation to change its audience. Profiles name devices rather than authenticating separate people; anyone with access to the same Windows account/browser can access its local Chat. Device revocation, key recovery, attachments, human accounts and Android/iPhone connections remain subsequent gates. The browser layout accommodates phones, but a phone cannot reach a PC's loopback PWA address. Trusted phone HTTPS and enrollment must pass the actual two-PC/household-phone gate before phone access is released. See the included `CHAT-PWA.md` for privacy, build and initial limits. Update the companion on **both PCs** before using short invitations. Install the new version over the existing per-user installation; setup stops the old companion and preserves the existing household/data folder. A new household or identity reset is not required. If using the portable package, close the old copy and extract the new program tree into a new folder before opening it; retained profile data is reused. Short invitations locate the starter through **encrypted invitation discovery on the same home LAN**. Keep its updated companion running while the other PC joins, and allow household connections on a Private network. An emailed link works as an invitation handover, not an internet tunnel to a sleeping/remote PC. If lookup times out, check both versions, home-network/client-isolation/firewall state and whether the invitation is unused and unexpired. Older full invitation codes are still accepted by the join input. The starter's panel also offers **Open Gmail draft** and **Open mail app** after entering one recipient address. These actions prepare a friendly message with the join link/code and setup/expiry instructions in the chosen email app. Review it and press Send there yourself. The companion does not send email, save the recipient address or call a cloud email service. Choosing Gmail hands the draft contents to Gmail; it is an explicit user action. Copying the code/link remains available for a private handover without email. ## Networking and firewall Default ports are loopback management HTTP **43121**, peer TLS **43122**, and LAN discovery UDP **43123**. The tray launcher uses these defaults. Development code can expose configuration separately; the shipped firewall action is limited to these ports. Only **Allow household connections…** triggers elevation. It asks for confirmation and then Windows UAC approval to add two program-specific inbound rules for the bundled `runtime\node.exe`: TCP 43122 and UDP 43123, **Private** profile, **LocalSubnet** remote addresses. It does not open the dashboard port or public-network access. Declining/canceling keeps the previous state. Setup and build verification never execute this action. Ordinary Windows/network policy can still block LAN access, and guest Wi-Fi/client isolation can prevent discovery even with the rules present. If joining reports that the other PC did not respond, check the starter's **Connection address** belongs to the same home network as the joining PC, rather than a virtual adapter. Seeing a PC in Windows Explorer proves Windows discovery, not access to the companion port. Keep the starter awake with its companion running, use **Allow household connections…** on both PCs, and retry with a fresh invitation from the updated starter. Do not disable Windows Firewall. The local dashboard URL contains its management token in a fragment. Treat the full URL as private; do not paste it into chat, screenshots or public issue reports. `runtime.json` is local runtime state, not a public endpoint directory. Peers use pinned TLS certificates and the companion's own enrollment/authentication protocol. A self-signed peer certificate is **not** a browser-trusted HTTPS certificate and does not resolve phone-to-PC PWA transport feasibility; real household-phone testing remains a separate gate in `MECHANICS.md`. ## Data and shutdown The fixed per-user data location is `%LOCALAPPDATA%\DewittOffline\data`. This is separate from program installation and is not deleted by upgrade or uninstall. Private identity configuration uses Windows **DPAPI CurrentUser** through the launcher helper. That protects it for the Windows account; it is not protection from malware running as that account, nor a portable recovery backup. Copying the encrypted configuration alone to another Windows account is not a supported restore flow. Enrollment/recovery behavior is owned by the companion protocol and must be tested before relying on it. Exit writes a cooperative shutdown request, waits for the child companion to close/flush, then stops that child if it fails to exit within 15 seconds. Setup uses a separate marker that disables this forced-stop fallback: if cooperative shutdown fails, the existing tray/process stays running and setup refuses the upgrade. A Windows job object ties the hidden child to the launcher so it cannot silently outlive a crashed tray process. Interrupted work and force termination still require the companion's database recovery/idempotency guarantees. Do not infer a successful durable receipt merely from a running tray icon. Setup validates its embedded file inventory, SHA-256 hashes, bounded sizes and paths before extraction. It rejects absolute/traversing/reserved paths, ZIP symlinks, duplicates and reparse-point destinations. For upgrades it stages the new version, stops the existing companion and swaps program folders; a failed directory swap restores the prior folder. The previous program folder is retained as `DewittOffline.previous-` beside the installation, preserving unknown/user-added files. A failed stopped upgrade may leave a staged folder, without deleting data. Setup refuses replacement while the old companion cannot stop safely. After cooperative shutdown, setup retries program-directory moves for up to five seconds only for Windows sharing/lock errors 32 and 33. This covers the brief mutex-release/executable-close race without force-killing the family companion. Build verification runs an isolated native directory-lock test that checks a delayed release, bounded persistent-lock failure and immediate unrelated-error failure. Uninstall through Windows Installed apps removes manifest-listed program files, the app shortcut and its matching sign-in entry; it keeps family data, unknown files and previous-version folders. A temporary uninstall worker is used because Windows cannot remove its running installer; that temporary executable may remain in the Windows temp folder. The optional elevated firewall rules can remain after uninstall, still restricted to the old executable path. Remove the two named Dewitt Offline rules through Windows Defender Firewall if desired. Reinstalling reuses retained data; it is not an identity reset. ## Build and verify From the repository root on Windows, run: ```powershell powershell -NoProfile -File scripts/build-windows.ps1 -ReleaseSequence 2 ``` The script downloads **Node v24.21.0** from its [official release directory](https://nodejs.org/dist/v24.21.0/), checks the Windows x64 ZIP against the official `SHASUMS256.txt` and the reviewed SHA-256 pin, and bundles only `node.exe` and its `LICENSE`. Download/cache files stay under `.local/tools`; build staging stays under `.local/windows-build`. The release pin is `158f7685b44de51f6c0df1d153526cbcd3e1bc739a8dfc607721cef75de9e541` for `node-v24.21.0-win-x64.zip`. The official file/hash listing protects the build from an accidental changed download; it is not a signature on our own unsigned installer. The build first runs locked native Rust tests and builds the actual browser WASM module using Rust 1.96.0, the wasm32 target and wasm-pack 0.15.0. `npm run build:chat-wasm` runs that step independently. Browser JavaScript owns encrypted IndexedDB storage and transport; Rust validates commands and message ordering without claiming authentication or authorization. Program payload is limited to the exact reviewed file inventory in `scripts/windows-payload.json`: the compiled launcher, runtime, selected companion modules and UI assets, this guide, `CHAT-PWA.md` and `APP-UPDATES.md`. New source files are not included automatically; unfinished phone/member modules remain excluded. No `public/`, `.env`, `.local` data, test fixtures or private publisher keys enter the package. The external signed release sidecar contains only public package metadata/signature. Setup is compiled with the program ZIP embedded as a resource. Neither app modifies Daisy's public site, and building does not deploy it. Outputs under `dist/windows` are: - `DewittOffline-Setup.exe`: per-user self-extracting installer. - `DewittOffline-portable.zip`: full portable program tree. - `SHA256SUMS.txt`: hashes of those two artifacts. - `build-result.json`: runtime pin, artifact paths, unsigned status and verification result. - `release.json`: publisher-signed complete installer metadata. - `DewittOffline-bootstrap.zip`: exactly the installer and its adjacent release sidecar for first-time LAN-updater setup. Default build verification checks the embedded payload, extracts to a fresh build folder, executes launcher self-test and checks the bundled Node version. It verifies binary DPAPI roundtrip/invalid-input rejection and creates a synthetic certificate to assert RSA2048, public DER output and PFX loading by Node TLS. A headless launcher/backend smoke test then uses a fresh test-data folder and temporary ports to verify startup, authenticated local status and cooperative clean shutdown. It opens no browser/tray, changes no sign-in/firewall settings and never uses the real profile data folder. Synthetic files stay in private build folders, outside the packaged payload. Signed updater releases refuse `-SkipVerification`; signature generation follows verification and requires the matching local DPAPI publisher key. The build can be repeated after source updates; it retains staging rather than running broad recursive cleanup. Useful **headless extraction/helper verification** commands, which do not install, set startup, change firewall or start the backend: ```powershell # Exit code 0 means the entire embedded payload is valid. Start-Process -FilePath dist/windows/DewittOffline-Setup.exe -ArgumentList '--verify-payload' -WindowStyle Hidden -Wait -PassThru # TARGET must be a new/empty ordinary folder; quote an absolute path with spaces. Start-Process -FilePath dist/windows/DewittOffline-Setup.exe -ArgumentList @('--extract-only', '"C:\Temp\Dewitt-verify"') -WindowStyle Hidden -Wait -PassThru Start-Process -FilePath C:/Temp/Dewitt-verify/DewittOffline.exe -ArgumentList '--self-test' -WindowStyle Hidden -Wait -PassThru ``` ## Launcher/backend interface For strict **current-source Windows test acceptance**, run `powershell -NoProfile -File scripts/verify-windows.ps1` from this checkout. It requires the verified extraction recorded in `dist/windows/build-result.json`, validates portable payload hashes and extraction inventory, checks setup payload verification and the packaged helper self-test, and requires bundled Node **24.21.0**. It runs every existing `tests/*.test.cjs` and `tests/*.test.mjs` through that runtime with `DEWITT_TEST_HELPER` set to the packaged launcher. Missing or invalid build evidence/runtime/helper fails; test totals are printed and any failure, skip, cancellation or todo fails acceptance. This command tests current sources with the packaged Windows crypto helper. It reports packaged companion source differences but does not certify that current sources were rebuilt: this build metadata does not record launcher C# source provenance. Rebuild with `scripts/build-windows.ps1` without `-SkipVerification` before releasing changed packaged files. These synthetic loopback tests still do not replace the two-PC/household-phone gate. `-BuildResultPath` accepts alternative local build evidence inside this workspace for bounded verification; it does not install or modify the package. The launcher starts `runtime/node.exe companion/main.mjs --data-dir --port 43121 --peer-port 43122 --discovery-port 43123` with working directory set to the program folder. The backend writes `/runtime.json` with `{pid,adminUrl}` only once ready. The launcher accepts the fixed loopback origin/port and token fragment before opening a URL. The backend watches `shutdown.request`, closes listeners/storage, removes runtime state/request and exits. These are local contracts; shutdown acknowledgments must not expose private keys or plaintext conversations. Helper branches execute before all UI/instance/startup code: | Helper | Interface | | --- | --- | | `--protect` | Binary stdin (maximum 1 MiB) → binary stdout protected with DPAPI CurrentUser plus application entropy. | | `--unprotect` | Binary stdin (maximum 1 MiB) → binary stdout; nonzero exit if the Windows account/configuration cannot decrypt it. | | `--create-certificate ` | Password from `DEWITT_CERT_PASSWORD` environment (minimum 20 characters), no secret command-line argument. Creates password-protected PFX and `.cer` public DER certificate. RSA 2048/SHA-256, server-auth usage, five-year validity. Writes no secret output. | | `--self-test` | Checks bundled files and a synthetic in-memory DPAPI roundtrip; starts no Node process and writes no family data. | | Setup `--move-self-test ` | Creates synthetic program folders only, proves the bounded sharing/lock retry, and refuses nonempty/reparse targets or the real install/data locations. | | `--lan-addresses` | Returns a JSON array of active private IPv4 adapter addresses, with gateway-bearing adapters preferred. Read-only; no data, firewall or startup changes. | | `--smoke-test ` | Starts the actual bundled backend hidden on temporary ports, validates the token-bearing runtime URL privately, checks authenticated local status and verifies cooperative shutdown. Rejects nonempty/reparse targets and the real profile data location. Creates only test data; no browser, tray, startup or firewall changes. | | `--stop` | Signals the current user's existing tray process to shut down; no new backend is started. | Node invokes helpers with hidden windows, bounded timeouts and captured pipes. No reusable key/password should be logged. Certificate files, keys, SQLite content and pairing data belong only in the private data directory and must not be packaged or deployed. Cryptographic enrollment, SQLite tamper/restart checks and three-node local network integration passed separately from package extraction. Recovery, interactive install/upgrade/uninstall, physical LAN/firewall behavior and the actual two-PC/phone checks remain pending.