Halopen Windows
Two copy-pastes. That's the whole job.
Step 1 — Open PowerShell, paste this
Open Windows PowerShell (Windows key → type "PowerShell" → Enter), click Copy setup above, paste into PowerShell, hit Enter. Sets up Claude CLI's permissions so the next step runs without asking you to approve each command.
# Halopen Windows port — Dallas's Claude CLI setup.
# Self-contained: writes %USERPROFILE%\.claude\settings.json + CLAUDE.md
# so Claude CLI runs autonomously without per-command permission prompts.
#
# Paste this whole block into PowerShell and hit Enter.
$claudeDir = Join-Path $env:USERPROFILE ".claude"
New-Item -ItemType Directory -Force -Path $claudeDir | Out-Null
# ─── settings.json — wide Bash(*) allow, binary + credential read denies ───
$settings = @'
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(*)",
"Read",
"Write",
"Edit",
"Glob",
"Grep",
"Agent",
"WebFetch",
"WebSearch"
],
"deny": [
"Read(*.mp4)",
"Read(*.mov)",
"Read(*.avi)",
"Read(*.mkv)",
"Read(*.mp3)",
"Read(*.flac)",
"Read(*.aac)",
"Read(*.zip)",
"Read(*.tar.gz)",
"Read(*.rar)",
"Read(*.7z)",
"Read(*.dmg)",
"Read(*.iso)",
"Read(*.exe)",
"Read(*.msi)",
"Read(*.psd)",
"Read(*.ai)",
"Read(*.sketch)",
"Read(*.fig)",
"Read(~/.ssh/**)",
"Read(~/.gnupg/**)",
"Read(~/.aws/**)",
"Read(~/.azure/**)",
"Read(~/.kube/**)",
"Read(~/.docker/config.json)",
"Read(~/.npmrc)",
"Read(~/.git-credentials)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/*.gpg)",
"Read(**/*.cert)",
"Read(**/*.crt)",
"Read(**/*.pfx)",
"Read(**/*.p12)"
]
},
"effortLevel": "high",
"skipDangerousModePermissionPrompt": true
}
'@
Set-Content -Path (Join-Path $claudeDir "settings.json") -Value $settings -Encoding UTF8
# ─── CLAUDE.md — universal Meria engineering standard ───
$claudeMd = @'
# Universal instructions — Halopen Windows port
You are Claude CLI on a Windows 11 machine, running on behalf of Dallas Meria. Ship the Halopen Windows port autonomously. Dallas is not a developer — you do the work, he watches the screen and clicks Yes on UAC prompts when Windows asks.
## Operating posture
- **Wide `Bash(*)` allow + Write + Edit permission is already configured.** Do not stop to ask before shell commands or file writes.
- **Default shell is PowerShell.** Use it natively. Git Bash is fine when needed.
- **Project CLAUDE.md is the spec.** Read every line of `windows\CLAUDE.md` after cloning the repo.
## Discipline (Meria engineering standard)
1. **No human time estimates.** Don't write "this will take ~30 min" or "in a few weeks." Describe what is happening or what is done. Time is for calendar dates and cron schedules, never effort estimates.
2. **No `// TODO` stubs.** Production-ready on first write or do not write it.
3. **No `git add -A` / `git add .`.** Stage files by name.
4. **Never amend.** Always create a new commit.
5. **Never `git push --force`** unless explicitly approved.
6. **No emojis** in code, commits, or user-facing text unless asked.
7. **Adversarial verification.** Ask "find 5 ways this will break" — not "verify it works." Real-user smoke tests, not happy-path-only.
8. **Banned phrases** without real-user-testing evidence: "100% operational", "fully verified", "best in class", "production-ready", "no issues", "complete." Use "happy path verified; known edges: X, Y" instead.
9. **Read files before editing.** Never edit blind.
10. **Trust the codebase, validate at boundaries.** No defensive code for impossible scenarios.
## Brand discipline (Halopen)
- Apple-level polish is the bar — calm, premium, intentional, frictionless.
- No competitor names in user-facing text (internal research notes are fine).
- Cream paper background (#FBF6EC), Inter font, halo-gradient accents. Tokens baked into `App.axaml`.
- No location language ("Northern Michigan", etc.) anywhere user-facing.
## When in doubt
- Read `windows\CLAUDE.md` for project rules.
- Read `windows\research\mac_to_windows_api_mapping.md` for Swift → Win32 translations.
- Read `Sources\Halopen\<File>.swift` for the canonical Mac behavior. The Windows port targets feature parity.
- Cloud backend matches the Mac client byte-for-byte. Do not reinvent the wire format.
## Hard nopes
- Do not commit credentials, .env files, or .pfx code-signing material.
- Do not push to non-Meria remotes.
- Do not skip pre-commit hooks.
- Do not propose UI/UX that diverges from the Mac client.
When the work is done: push a branch, open a PR, write `windows\test-artifacts\STATUS_<date>.md` with what works / what is broken / what is deferred, and tell Dallas the PR URL.
'@
Set-Content -Path (Join-Path $claudeDir "CLAUDE.md") -Value $claudeMd -Encoding UTF8
Write-Host ""
Write-Host "Halopen Claude CLI setup complete." -ForegroundColor Green
Write-Host " - $claudeDir\settings.json (permissions)"
Write-Host " - $claudeDir\CLAUDE.md (engineering standard)"
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host " 1. Open a fresh Windows Terminal (so Claude picks up the new settings)"
Write-Host " 2. Run: claude"
Write-Host " 3. Open https://halopen.com/dallas/ and click 'Copy prompt'"
Write-Host " 4. Paste into Claude CLI (Ctrl+Shift+V) and hit Enter"
Write-Host ""
Step 2 — Run claude, paste this
Open a fresh Windows Terminal (close + reopen so it picks up Step 1's settings), run
claude, then click
Copy prompt above, paste into Claude (Ctrl+Shift+V), hit Enter.
Claude does the rest. It will ask you to click Yes on Windows pop-ups during the dev-tool
installs and to authorize GitHub in your browser at one point. Otherwise leave it alone.
You are Claude CLI on a Windows 11 machine. The user is **Dallas Meria** (Jesse's son, not a developer). You will install everything needed, clone the project, build a Halopen.exe, test it, iterate, and ship. Dallas's role is to click "Yes" on UAC prompts and complete the browser-based GitHub auth when the gh CLI asks. Otherwise leave him alone. **Project context:** Halopen is a Mac hold-to-talk dictation app being ported to Windows. Mac source: `MeriaApp/halopen` repo on GitHub. The Windows port lives in the `windows/` subdirectory of that repo. Feature parity with the Mac client is the contract; do not invent UI/UX that diverges. The build target is a single self-contained `Halopen.exe` produced by `dotnet publish -r win-x64 --self-contained`, wrapped in an Inno Setup installer. ## Phase 0 — Bootstrap Run these in order using PowerShell (which is Bash's default shell on Windows for you). ### 0.1 Verify winget exists ```powershell winget --version ``` If that errors, tell Dallas to install App Installer from the Microsoft Store and re-run the prompt. Otherwise continue. ### 0.2 Install dev tools These can be slow (Visual Studio is 5-10GB). Run them sequentially. If a Bash timeout fires mid-install, that's fine — winget continues in the background. Re-run the same `winget install` command after a pause; it'll detect the in-progress install and skip cleanly. ```powershell winget install --id Microsoft.VisualStudio.2022.Community -e --silent --accept-package-agreements --accept-source-agreements --override "--passive --add Microsoft.VisualStudio.Workload.NativeDesktop;Microsoft.VisualStudio.Workload.ManagedDesktop;Microsoft.VisualStudio.Component.Windows11SDK.22621" winget install Microsoft.DotNet.SDK.9 -e --silent --accept-package-agreements --accept-source-agreements winget install Git.Git -e --silent --accept-package-agreements --accept-source-agreements winget install GitHub.cli -e --silent --accept-package-agreements --accept-source-agreements winget install Microsoft.WindowsTerminal -e --silent --accept-package-agreements --accept-source-agreements ``` When Windows UAC pops, tell Dallas to click **Yes**. If a winget command hangs more than 5 minutes without progress, kill it and continue with the next. ### 0.3 Confirm tools landed After the installs finish, open a fresh shell (PowerShell or Windows Terminal — you may need to ask Dallas to close + reopen this terminal so the new PATH entries are picked up). Then: ```powershell dotnet --version # expect 9.x git --version gh --version ``` If any of those fail, the path didn't refresh. Tell Dallas to close and reopen Windows Terminal (or restart his computer) and re-run the prompt — pick up from this point. ### 0.4 Authenticate with GitHub ```powershell gh auth login ``` Answer the prompts: - "Where to log in?" → **GitHub.com** - "Preferred protocol?" → **HTTPS** - "Authenticate Git with your GitHub credentials?" → **Yes** - "How would you like to authenticate?" → **Login with a web browser** The CLI will display a one-time code (e.g., `XXXX-XXXX`) and a URL (`https://github.com/login/device`). Tell Dallas to: 1. Copy the code, 2. Open https://github.com/login/device in his browser, 3. Paste the code, 4. Click "Authorize", 5. Come back to the terminal. ### 0.5 Accept the repo invite + clone The MeriaApp/halopen repo is private. Jesse has already invited `dmeria02` as a write collaborator. Dallas needs to accept the invite first. Open https://github.com/MeriaApp/halopen/invitations in his browser and click Accept (the URL is also in the GitHub email he received). Once accepted: ```powershell New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\Developer" | Out-Null cd $env:USERPROFILE\Developer gh repo clone MeriaApp/halopen cd halopen\windows ``` ### 0.6 Read the project context ```powershell type CLAUDE.md ``` That's the canonical Halopen Windows spec. Read every line — it tells you the brand rules, the cloud config (already wired in `Config.cs`), the file layout, and the hard rules. Do not skip. Also worth reading next: - `DALLAS_PROMPT.md` (you're already reading this — skip) - `research/mac_to_windows_api_mapping.md` (Swift API → Win32 reference) - The Mac source at `..\Sources\Halopen\*.swift` whenever you need to know "what should this behavior do" — feature parity wins. ## Phase 1 — First build ```powershell dotnet restore dotnet build src\Halopen.Windows\Halopen.Windows.csproj ``` Expected: it'll either build clean or surface 1-10 compile errors. Most likely failure modes (in order): 1. **Missing asset file** (`Assets\halopen-icon.ico`, `Assets\start.wav`, `Assets\end.wav`). Generate them: - **Icon:** convert from `..\Resources\Brand\halopen-icon-master.png` if it exists. Use ImageMagick on Windows: `winget install ImageMagick.ImageMagick -e`, then `magick "..\Resources\Brand\halopen-icon-master.png" -define icon:auto-resize=256,128,64,48,32,16 src\Halopen.Windows\Assets\halopen-icon.ico`. If the master PNG isn't there, generate any 1024×1024 placeholder (cream background + a solid black circle) and ico-convert it; this is a placeholder only. - **Sounds:** short click .wav files. You can grab `Sources/Halopen/Resources/start.aiff` from the Mac side and convert with ffmpeg, OR generate synthetic clicks using NAudio in a one-off C# script, OR use Windows defaults from `C:\Windows\Media\`. Whatever lands as 0.1-0.3s 16-bit PCM .wav at 44.1 kHz is fine for v1. 2. **Avalonia or NAudio version conflict** — adjust the `<PackageReference Version="...">` in the csproj as needed for net9.0-windows. 3. **NetSparkleUpdater preview package not on the feed** — pin to the latest stable, OR comment out both NetSparkle PackageReferences AND the body of `TrayIconManager.CheckForUpdates()` (leave the stub log line). Auto-update can land in a follow-up. 4. **Missing `using` directive somewhere** — add it. 5. **`PaywallWindow.axaml` referenced but missing** — it's not actually wired into TrayIconManager, but if a stale reference exists, stub it out with a minimal Window class. Fix every error. **No `// TODO` stubs to make the build pass** — fix it for real. When the build is green: ```powershell dotnet run --project src\Halopen.Windows\Halopen.Windows.csproj ``` Expected: a tray icon appears in the Windows 11 system tray (you may need to expand the overflow with the up-arrow next to the clock). The Welcome wizard window should open on first run. ## Phase 2 — Smoke test the dictation pipeline Walk Dallas through the Welcome wizard (5 steps). On the last step, click "Get started" — the wizard closes and Halopen lives in the tray. Now smoke test: 1. Open Notepad. 2. Click into the empty document so the cursor is there. 3. Tell Dallas to **hold the right-Alt key** for 2 seconds while saying "Halopen on Windows is working". 4. Release right-Alt. 5. Within 2-3 seconds, the text should appear in Notepad. If the text doesn't land, debug in this order: | Symptom | Likely cause | Fix | |---|---|---| | No tray icon | Avalonia TrayIcon missing icon asset | check Assets/halopen-icon.ico exists | | Tray icon present, but no recording pill while held | Hotkey not firing | Check the `HotkeyService.HookCallback` — print the `info.vkCode` for every event to logs and confirm right-Alt sends `0xA5` | | Pill shown but nothing happens after release | Audio capture failing | Check `AudioService` + Windows Settings → Privacy → Microphone (allow desktop apps) | | Audio captures but no text | Transcribe HTTP failing | Check Config.cs URLs + network; tail logs for `Halopen.Network` errors | | Text returned but doesn't paste | TextInjector / clipboard / SendInput | Check the `TextInjector.SendCtrlV()` and the strategy table; try increasing the post-paste delay from 150ms to 250-300ms | Capture screenshots of each Phase 2 step into `test-artifacts/phase2-smoketest/`. ## Phase 3 — App-coverage matrix Run dictation in each of these and confirm the text lands. Capture a screenshot of each into `test-artifacts/phase3-app-matrix/`: - [ ] Notepad - [ ] WordPad or Microsoft Word - [ ] VS Code (any text file) - [ ] Cursor (any text file) — install if not present: `winget install Anysphere.Cursor -e` - [ ] Chrome (Gmail compose, address bar, search box) - [ ] Microsoft Edge - [ ] Slack (DM compose) — install if needed: `winget install SlackTechnologies.Slack -e` - [ ] Discord (DM compose) — `winget install Discord.Discord -e` - [ ] Windows Terminal (PowerShell prompt) - [ ] Outlook (compose pane) - [ ] OneNote - [ ] Notion (web client) For each failure: note the exe name (Task Manager → Details → Image Name column) and add it to `TextInjector.StrategyByExe` if missing. Some Electron apps need 250-300ms post-paste delay. ## Phase 4 — Production polish These are the gaps the scaffold left for you. Resolve in any order: - [ ] Replace stub `TrayIconManager.CheckForUpdates()` with real NetSparkle integration. Appcast at `https://halopen.com/appcast-windows.xml` (Jesse will host the appcast file separately). Use the same EdDSA public key from the Mac client. - [ ] Replace tray-tooltip error notifications with real Windows toast notifications. Use `Microsoft.Toolkit.Uwp.Notifications` (NuGet) or `Windows.UI.Notifications`. - [ ] WelcomeWindow steps 2 (Mic) and 3 (Hotkey) should show live status pills that flip green when the gate clears. - [ ] PaywallWindow — mirror Mac's `PaywallWindowController.swift`. Opens via `LicenseClient.CreateCheckoutSessionAsync` in default browser. - [ ] AuditLogWindow — small list of recent events from `IAuditLog`; opens via Settings menu. ## Phase 5 — Build the installer ```powershell dotnet publish src\Halopen.Windows\Halopen.Windows.csproj -c Release -r win-x64 --self-contained ``` Output: `src\Halopen.Windows\bin\Release\net9.0-windows10.0.19041.0\win-x64\publish\Halopen.exe` (~50-80MB self-contained). ```powershell winget install JRSoftware.InnoSetup -e ``` Then compile the installer: ```powershell & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer\halopen-windows.iss ``` Output: `installer\Output\Halopen-1.0.0-Setup.exe`. Run it on this same machine to verify it installs cleanly to Program Files, creates a Start Menu shortcut, registers at-login auto-start, and uninstalls cleanly. ## Phase 6 — Code signing (deferred to Jesse) Authenticode EV cert procurement is a Jesse-side task and is not happening in this prompt. The unsigned installer will trigger Windows SmartScreen on first run — that's expected. Note in your final report. ## Phase 7 — Capture screenshots for /press/ Polished captures of: - Tray icon in the Windows 11 system tray (zoom in) - Welcome wizard step 1 (the brand-mark intro) - Settings window - The recording pill mid-dictation - Halopen pasting into Cursor or VS Code Save to `test-artifacts/press-screenshots/`. These will be added to halopen.com/press/ and the Windows download page. ## Phase 8 — Push branch + GitHub Release + open PR This is the verification handoff. Without it, the build artifacts live only on Dallas's machine. With it, Jesse can download + test from any browser. ### 8.1 — Compute build-artifact hashes for the status report ```powershell $exe = "src\Halopen.Windows\bin\Release\net9.0-windows10.0.19041.0\win-x64\publish\Halopen.exe" $msi = "installer\Output\Halopen-1.0.0-Setup.exe" "Halopen.exe : $((Get-Item $exe).Length) bytes / SHA256 $((Get-FileHash $exe -Algorithm SHA256).Hash)" "Halopen-Setup.exe : $((Get-Item $msi).Length) bytes / SHA256 $((Get-FileHash $msi -Algorithm SHA256).Hash)" ``` Save those numbers — they go in the STATUS report. ### 8.2 — Write the status report Create `windows\test-artifacts\STATUS_<YYYY-MM-DD>.md`: ```markdown # Halopen Windows — Status <YYYY-MM-DD> ## What works - (every Phase 2 + Phase 3 item that passed) ## What's broken - (every issue you couldn't resolve) ## What's deferred - Code signing (waiting on EV cert from Jesse) - (anything else) ## Build artifacts - Halopen.exe — <bytes> / SHA-256 <hash> - Halopen-1.0.0-Setup.exe — <bytes> / SHA-256 <hash> ## How Jesse downloads + tests the build - Both binaries are attached to the GitHub Release at: https://github.com/MeriaApp/halopen/releases/tag/windows-dallas-build-1 - Jesse downloads Halopen-1.0.0-Setup.exe on a Windows machine, runs the installer, smoke-tests dictation in his own apps. ## Screenshots - (list of files in test-artifacts/, organized by phase) ``` ### 8.3 — Push the branch ```powershell cd $env:USERPROFILE\Developer\halopen git checkout -b windows/dallas-build-1 git add windows/ git commit -m "Windows: phase 1-5 complete — first working build, app-matrix verified" git push -u origin windows/dallas-build-1 ``` ### 8.4 — Create the GitHub Release with both binaries attached This is the load-bearing step for Jesse-side verification. Without it, there's no downloadable artifact. ```powershell gh release create windows-dallas-build-1 ` --target windows/dallas-build-1 ` --title "Halopen Windows — Dallas build 1" ` --notes "First working Windows build from Dallas's machine. Phase 1-5 verified. Code-signing deferred (Authenticode EV cert pending). See windows/test-artifacts/STATUS_<YYYY-MM-DD>.md for details." ` --prerelease ` installer\Output\Halopen-1.0.0-Setup.exe ` src\Halopen.Windows\bin\Release\net9.0-windows10.0.19041.0\win-x64\publish\Halopen.exe ``` That uploads BOTH the standalone `Halopen.exe` and the wrapped `Halopen-1.0.0-Setup.exe` as release assets. Jesse can grab either from `https://github.com/MeriaApp/halopen/releases/tag/windows-dallas-build-1`. ### 8.5 — Open the PR ```powershell gh pr create ` --title "Windows build — phase 1-5 verified" ` --body "First working Windows build from Dallas's machine. Build artifacts: see Release windows-dallas-build-1 Smoke tests: windows/test-artifacts/phase2-smoketest/ + phase3-app-matrix/ Status report: windows/test-artifacts/STATUS_$(Get-Date -Format yyyy-MM-dd).md Code-signing: deferred (Authenticode EV cert pending Jesse procurement) Reviewer (Jesse): download installer from Release page, smoke-test on a Windows machine before merging." ``` Print the PR URL — that's the handoff back to Jesse. ## Discipline rules - **Never `git add -A`** — stage by name. - **Never amend** — new commit per change. - **Never push --force.** - **No TODO stubs** — production-ready on first write. - **No emojis in code or commits** unless asked. - **No human time estimates in status reports.** Describe what's done, not how long anything took. - **Adversarial verification** — "find 5 ways this will break" before declaring done. Banned phrases: "100% operational", "fully verified", "production-ready", "no issues." ## When in doubt - Read `windows/CLAUDE.md` for the project rules. - Read `windows/research/mac_to_windows_api_mapping.md` for Swift → Win32 translations. - Read `Sources/Halopen/<File>.swift` for the canonical Mac behavior. - The cloud backend is identical to the Mac client — same anon keys, same edge function URLs, same wire format. Don't reinvent the contract. Now run `winget --version` and start Phase 0.
Step 3 (status check & finalize) — paste in your active Claude session
Use this after Step 2 has been running for a while (or if Claude says it's done). It runs a status report, audits the Windows build for parity with the Mac version (waveform, halo gradient, recording pill animation, welcome wizard, settings, audit log, paywall, sounds, tray menu — all the polish), finishes anything that fell short, then publishes a GitHub Release with the installer + opens a PR. Copy this, paste into the same Claude window, hit Enter.
You're partway through (or finished with) the autonomous Halopen Windows port. Before you declare done, do a comprehensive parity audit against the Mac version, finish anything that fell short, and hand back a complete deliverable. The Mac version is the spec — feature-for-feature, polish-for-polish. ## Phase A — Status report (do this first, even if you're mid-build) Print a status table to the terminal answering each of these explicitly. Don't skip anything — Jesse needs the full picture. 1. **Build state:** does `dotnet build src\Halopen.Windows\Halopen.Windows.csproj` succeed cleanly? 2. **Run state:** does `dotnet run` open the tray icon + Welcome wizard? 3. **Tools installed:** which winget commands succeeded, which (if any) hung or failed? 4. **GitHub state:** is the repo cloned? Is `gh auth login` done? Are you on the `main` branch? 5. **Smoke tests:** for each of these apps, has dictation been verified end-to-end? `Notepad`, `WordPad/Word`, `VS Code`, `Cursor`, `Chrome`, `Edge`, `Slack`, `Discord`, `Windows Terminal`, `Outlook`, `OneNote`, `Notion`. Mark each: ✓ verified / ✗ failed / – not yet tried. 6. **Installer state:** has `dotnet publish` produced `Halopen.exe`? Has Inno Setup produced `Halopen-1.0.0-Setup.exe`? 7. **Open issues:** every problem you couldn't resolve. Be honest — half-fixes don't count. If any of phases 1-6 are incomplete, finish them per the instructions in `windows/DALLAS_PROMPT.md` before moving to Phase B. ## Phase B — Mac-parity audit (the load-bearing part) For EACH of these Mac UI surfaces, verify the Windows equivalent exists, looks right, behaves right. The Mac source for each is in `Sources\Halopen\<file>.swift`. The Windows equivalent is in `windows\src\Halopen.Windows\<dir>\<file>.cs`. If a Windows equivalent exists but is a STUB or doesn't match Mac polish, **fix it before declaring done.** Stubs are not acceptable. ### B.1 — Brand visual identity (these are the load-bearing pixels) Brand tokens are already wired in `windows\src\Halopen.Windows\App.axaml`. Verify they're actually applied across every surface: | Token | Hex | Where it shows up | |---|---|---| | Cream paper page bg | `#F5EFE3` | All window backgrounds (Welcome, Settings, SignIn, Paywall) | | Cream soft / hover | `#FBF6EC` | Sub-surfaces, cards within windows | | Ink 950 (text/buttons) | `#0B0A07` | Primary text, primary buttons fill | | Ink 700 (secondary text) | `#3F3A30` | Body copy in instruction-heavy panes | | Ink 500 (muted) | `#7C7569` | Captions, helper text under fields | | Ink 300 (subtle) | `#B8B0A1` | Inactive dots, subtle borders | | Halo cyan | `#7AD8E0` | Gradient stop 1 (recording pill, accent gradient strokes) | | Halo periwinkle | `#9EA8E8` | Gradient stop 2 | | Halo magenta | `#E59ACB` | Gradient stop 3 (recording pill pulse dot) | | Halo magenta deep | `#A6125B` | Focus rings, the halo-glyph dot | Typography: **Inter Variable** (UI). Already wired via `Avalonia.Fonts.Inter` package in the csproj. Verify it's the resolved font on every text element — don't fall back to Arial silently. ### B.2 — App icon The Mac master icon is at `Resources\Brand\halopen-icon-master.png` (1024×1024). It's a vertical white pen lit from within, intersected by a horizontal audio waveform in the cyan→periwinkle→magenta brand gradient, on textured cream paper. The Windows `.ico` must derive from THIS master, not a placeholder. If you generated a placeholder during Phase 1, regenerate properly: ```powershell winget install ImageMagick.ImageMagick -e --silent --accept-package-agreements --accept-source-agreements magick "..\Resources\Brand\halopen-icon-master.png" -define icon:auto-resize=256,128,96,64,48,32,16 src\Halopen.Windows\Assets\halopen-icon.ico ``` The .ico must contain all standard Windows resolutions (16/32/48/64/96/128/256). Verify with: ```powershell magick identify src\Halopen.Windows\Assets\halopen-icon.ico ``` The output should show 7 frames at the resolutions above. Tray icon (small): the same .ico, rendered at 16×16 by Windows. If 16×16 looks muddy, generate a dedicated tray-optimized version (simplified single-color silhouette of the pen) and reference it from `TrayIconManager.cs`. ### B.3 — Recording pill (the most-seen UI element) Mac source: `Sources\Halopen\RecordingPill.swift`. Windows: `windows\src\Halopen.Windows\Views\RecordingPillWindow.axaml(.cs)`. What it must do: - Black background (`#0B0A07`), 92% opacity - Pill shape, ~180×44, rounded ~22px corners - Centered at the bottom of the primary screen, ~64px above the taskbar - Top-most, transparent canvas (no system chrome, no taskbar entry) - Inside: a 10×10 dot in halo magenta (`#E59ACB`) that **pulses** — opacity oscillates 0.4 ↔ 1.0 over ~1 second, infinite loop - Right of the dot: text "Listening…" in Inter Medium, 14px, cream-soft (`#FBF6EC`) - Drop shadow: subtle, ~16px blur, 25% black The pulse animation is already declared in `RecordingPillWindow.axaml` via `<Animation>` styles — verify it's actually running. If it's static, the brand feels broken. Open the pill in dev mode and watch for 5 seconds; the dot should breathe. Show + hide animation: the pill should fade in over ~120ms when recording starts, fade out over ~180ms when injection finishes. Currently the scaffold just toggles `IsVisible`. Add Avalonia `Transitions` on `Opacity` for smooth fade. ### B.4 — Welcome wizard (first-run onboarding) Mac source: `Sources\Halopen\WelcomeWindowController.swift`. Windows: `windows\src\Halopen.Windows\Views\WelcomeWindow.axaml(.cs)`. 5 steps, identical to Mac: 1. **Welcome / brand intro** — H1 "Hold to talk. Anywhere there's a cursor." Subhead explains the product in one sentence. Brand-mark visible (the icon, large, ~64×64). 2. **Microphone permission** — explains why, deep-link button "Open Microphone Settings" (already wired via `ms-settings:privacy-microphone`). **Live status pill** that says "Microphone access not granted" in muted ink, flips to "Microphone access granted ✓" in halo-magenta when `PermissionManager` reports granted. Auto-advances when granted. 3. **Hotkey** — explains right-Alt is the default, with a screenshot or live demo of holding right-Alt. **Live status pill** that says "Press right-Alt to test" — when the user actually presses right-Alt, the pill flips to "Hotkey detected ✓". Auto-advances on first detected press. 4. **Sign in (optional)** — "You can use Halopen on the free tier without signing in. To go Pro, sign in any time from the tray menu." Skip-friendly button. 5. **Ready** — "You're set. Halopen lives in your system tray. Hold right-Alt anywhere and start talking." Primary CTA "Get started" — closes wizard, sets `WelcomeAcknowledged = true`. Step transitions: subtle fade between steps, ~200ms cross-fade. Step indicator dots at the bottom, current step in `Ink-950`, others in `Ink-300`. This is in the scaffold but verify it actually renders correctly. If steps 2 and 3 still have text-only status (no live status pills), wire them up before declaring done. The Mac version's whole point is that the gate is unmistakable — flip green or stay grey. ### B.5 — Settings window Mac: `Sources\Halopen\AppDelegate.swift` (settings menu) + various windows. Windows: `windows\src\Halopen.Windows\Views\SettingsWindow.axaml(.cs)`. Must have: - Hotkey picker (dropdown): Right-Alt (default), Right-Ctrl, Caps Lock, F13, F14, F15 - Toggles: "Play start sound", "Play end sound", "Launch at login", "Show recording pill" - Vocabulary-hints text area (multiline, ~100 chars wide, watermark explains the use case) - "Save" primary button (closes window + persists to `SettingsStore`) - "Open audit log…" button — opens a dedicated AuditLog window showing recent dictation events - "Sign in…" button if not signed in / "Manage subscription" if signed in - Footer with version number + "Check for updates…" link The scaffold has the basics but no audit-log button yet. Add the audit log window (see B.7). ### B.6 — Sign-in window Mac: `Sources\Halopen\SignInWindowController.swift`. Windows: `windows\src\Halopen.Windows\Views\SignInWindow.axaml(.cs)`. The scaffold has email magic-link only. Mac also supports Sign in with Apple + Google OAuth. For the Windows v1 release, **email magic-link is acceptable** — Sign in with Apple is Apple-only by definition, and Google OAuth on Windows is a separate integration that can ship in v1.1. Note the deferred items in your STATUS report. Polish checklist: - Email field with proper Watermark - "Email me a sign-in link" primary button (full width) - Status block below the button that flips through "Sending…" → "Check your email…" → error states - After magic-link is clicked in email, the deep-link handler resumes the session — Windows protocol handler `halopen://` registered via the installer ### B.7 — Audit log window Mac: `Sources\Halopen\AuditLogWindowController.swift`. Windows: NOT YET BUILT in the scaffold. Build it. Spec: - Window: 600×500, cream paper bg, Inter font - DataGrid (Avalonia.Controls.DataGrid) showing the last 100 entries from `IAuditLog` - Columns: Time (relative — "2 min ago"), Kind (Press / Release / Transcribe / Inject / Error), Detail - "Clear log" button at the bottom - "Export…" button that writes JSON to %USERPROFILE%\Documents Wire it from Settings window's "Open audit log" button. ### B.8 — Paywall window Mac: `Sources\Halopen\PaywallWindowController.swift`. Windows: NOT YET BUILT in the scaffold. Mac uses a custom paywall (no native subscription store) per Apple App Store rule 3.1.2(a). For Windows there is no Microsoft Store gate — but maintain visual + structural parity with the Mac paywall so the brand experience is consistent. Spec: - Window: 480×640, cream paper bg - H1 "Halopen Pro" - Three-tier display (or two-tier if Mac shows two): Free / Pro Monthly / Pro Annual with the gradient-bordered "Annual" highlighted as best value - Each tier: Title, price, billing period, feature list (bulleted), CTA button - Pro CTA: opens `LicenseClient.CreateCheckoutSessionAsync` URL in default browser via `Process.Start` - Below tiers: tiny print explaining auto-renewal, refund policy, link to Terms + Privacy - Restore button (rare on Windows but include for parity): triggers a license re-check - X button top-right to dismiss Pull the actual prices from the live `license-check` response so they're never hardcoded — the Mac client does this and the same edge function returns the price in cents. ### B.9 — System tray icon + menu Mac: `NSStatusItem` in `AppDelegate.swift`. Windows: `Avalonia.Controls.TrayIcon` in `TrayIconManager.cs`. Verify the menu has these items in this order, matching the Mac: 1. **Halopen** (header, disabled, just shows the brand) 2. (separator) 3. **Settings…** → opens SettingsWindow 4. **Sign in / Account…** → opens SignInWindow if not signed in, otherwise opens account portal in browser 5. (separator) 6. **Open audit log…** → opens AuditLogWindow 7. (separator) 8. **Check for Updates…** → triggers NetSparkle check 9. (separator) 10. **Quit Halopen** Tooltip on the tray icon: "Halopen — hold right-Alt to talk" (or the user's configured hotkey). State indicators (nice-to-have, not blocking): when recording, the tray icon could subtly tint magenta or show a small dot. Mac doesn't currently do this either, so it's parity-OK to skip. ### B.10 — Sounds Mac: `Sources\Halopen\SoundPlayer.swift` plays `start.aiff` and `end.aiff` from the bundle. Windows: `SoundPlayer.cs` reads `Assets/start.wav` and `Assets/end.wav`. If you haven't put real sound assets in `Assets/`, the start/end clicks are silent right now. Either: - Convert from Mac's `Resources/start.aiff` and `Resources/end.aiff` using ffmpeg: `winget install Gyan.FFmpeg -e`, then `ffmpeg -i ..\Resources\start.aiff -ar 44100 -ac 2 src\Halopen.Windows\Assets\start.wav` (same for end), OR - Generate gentle clicks programmatically via NAudio (a one-off C# script: 30ms decay sine at 880Hz for start, 30ms decay sine at 660Hz for end), OR - Use Windows defaults from `C:\Windows\Media\` (cheap fallback) Pick the first option if you can — exact parity with Mac sounds is the goal. ### B.11 — Auto-update (NetSparkle) Mac: Sparkle 2.x, EdDSA-signed appcast at `https://halopen.com/appcast.xml`. Windows: NetSparkleUpdater 3.x, separate appcast at `https://halopen.com/appcast-windows.xml`. Wire `TrayIconManager.CheckForUpdates()` to NetSparkle's check. The appcast file isn't hosted yet (Jesse's task) — use a placeholder URL and log a warning if 404. The check + prompt UI must work; it just won't find updates until the appcast goes live. Same EdDSA public key as the Mac client — get the key from the Mac side via `defaults read app.halopen` if needed, or from `Resources/sparkle-public-eddsa-key.txt` if it's checked in. ## Phase C — Polish gates before declaring done Run through this checklist. Every item must be ✓ before you declare the work complete. - [ ] Cream paper bg is visible behind every window's content (not white, not gray) - [ ] Inter font resolves on every text element (right-click any text in Avalonia DevTools to confirm) - [ ] Halo gradient (`#7AD8E0` → `#9EA8E8` → `#E59ACB`) appears at least on the recording pill dot OR a subtle accent stroke somewhere on the brand-mark - [ ] Recording pill pulse animation runs at 60fps on the screen — it actually breathes, not freezes - [ ] Welcome wizard cross-fades between steps in ~200ms, no jump cuts - [ ] Welcome step 2 (Mic) flips green when permission is granted - [ ] Welcome step 3 (Hotkey) flips green when the user presses right-Alt - [ ] Tray menu shows all 10 items in the correct order - [ ] Settings window persists changes after close + reopen - [ ] Sign-in flow lands the user in an active session (the magic-link click resumes via `halopen://` protocol handler — installer registers this) - [ ] Audit log window shows real entries from the most recent dictation cycles - [ ] Sounds play on dictation start + end (not silent) - [ ] Installer registers the app in Add/Remove Programs with the correct icon + version - [ ] After installer runs, Halopen launches at login on next reboot (verify by reboot) - [ ] Cold start to tray icon visible: under 2 seconds on a typical PC If any item fails, fix it before Phase D. ## Phase D — Press-quality screenshots For halopen.com/press/ and the eventual halopen.com/download/ Windows section. Capture each at native resolution (don't shrink), save as PNG to `windows\test-artifacts\press-screenshots\`: 1. Tray icon in the Windows 11 system tray (zoom-in crop, ~400×200) 2. Welcome wizard step 1 (full window, brand-mark visible) 3. Welcome wizard step 3 with hotkey detected (showing the green flip) 4. Settings window (full window) 5. Recording pill mid-dictation (capture during a 3-second hold) 6. Halopen pasting into Cursor (split-screen showing the recording pill + the text appearing in Cursor) 7. Halopen pasting into Word 8. The system tray menu open showing all 10 items These go on the website later — Jesse will route them to the right pages. ## Phase E — Final handoff ### E.1 — Hash + size the build artifacts ```powershell $exe = "src\Halopen.Windows\bin\Release\net9.0-windows10.0.19041.0\win-x64\publish\Halopen.exe" $msi = "installer\Output\Halopen-1.0.0-Setup.exe" "Halopen.exe : $((Get-Item $exe).Length) bytes / SHA-256 $((Get-FileHash $exe -Algorithm SHA256).Hash)" "Halopen-Setup.exe : $((Get-Item $msi).Length) bytes / SHA-256 $((Get-FileHash $msi -Algorithm SHA256).Hash)" ``` ### E.2 — Write the STATUS report `windows\test-artifacts\STATUS_<YYYY-MM-DD>.md`. Use this exact structure (Jesse reads these): ```markdown # Halopen Windows — Status <YYYY-MM-DD> ## What works (verbatim, no over-claiming) - (every Phase A item that passed) - (every Phase B parity item that's complete) - (every Phase C polish gate that's ✓) ## What's broken - (every issue you couldn't resolve, with file:line and what you tried) ## What's deferred - Code signing (Authenticode EV cert pending Jesse procurement) - (Sign in with Apple + Google OAuth on Windows — v1.1) - (anything else you couldn't get to) ## Build artifacts (with hashes) - Halopen.exe — <bytes> / SHA-256 <hash> - Halopen-1.0.0-Setup.exe — <bytes> / SHA-256 <hash> ## How Jesse downloads + tests - GitHub Release: https://github.com/MeriaApp/halopen/releases/tag/windows-dallas-build-1 - Both artifacts attached - Run Halopen-1.0.0-Setup.exe on a Windows 11 machine; expect a SmartScreen warning until the EV cert lands ## Press screenshots - (file list under windows/test-artifacts/press-screenshots/) ## Adversarial notes — 5 ways this might break in production 1. (specific scenario) 2. ... ``` The "5 ways this might break" section is non-optional. Adversarial verification is the discipline rule. ### E.3 — Push branch + Release + PR ```powershell cd $env:USERPROFILE\Developer\halopen git checkout -b windows/dallas-build-1 git add windows/ git commit -m "Windows: phase A-D complete — first working build, Mac-parity verified" git push -u origin windows/dallas-build-1 gh release create windows-dallas-build-1 ` --target windows/dallas-build-1 ` --title "Halopen Windows — Dallas build 1" ` --notes "First working Windows build from Dallas's machine. Phase A-D complete. Code-signing deferred." ` --prerelease ` installer\Output\Halopen-1.0.0-Setup.exe ` src\Halopen.Windows\bin\Release\net9.0-windows10.0.19041.0\win-x64\publish\Halopen.exe gh pr create ` --title "Windows build — Dallas build 1, Mac-parity verified" ` --body "First working Windows build from Dallas's machine. Build artifacts: see Release windows-dallas-build-1 Status report: windows/test-artifacts/STATUS_$(Get-Date -Format yyyy-MM-dd).md Smoke tests: windows/test-artifacts/phase2-smoketest/ + phase3-app-matrix/ Press screenshots: windows/test-artifacts/press-screenshots/ Code-signing: deferred (Authenticode EV cert pending Jesse procurement) Reviewer (Jesse): download installer from Release page, smoke-test on a Windows machine before merging." ``` ### E.4 — Print the handoff to Dallas Print to terminal (so Dallas can copy-paste into his email reply to Jesse): ``` ======================================== Halopen Windows — handoff complete ======================================== PR: <URL> Release: <URL> Status: windows/test-artifacts/STATUS_<date>.md Tell Jesse: - Done. Status report and press screenshots in the PR. - Installer is on the GitHub Release. ======================================== ``` That's the signal that the work is done. Dallas pastes that block into his email reply to Jesse. ## When in doubt - **Mac source is the spec.** Read `Sources\Halopen\<File>.swift` whenever you need to know "what should this do or look like." - **No TODO stubs.** Production-ready or don't write it. - **No human time estimates** in the STATUS report. Describe what's done, not how long anything took. - **No emojis** in code, commits, or user-facing text. - **Never `git add -A`.** Stage by name. - **Adversarial verification.** "Find 5 ways this will break" — banned phrases: "fully verified", "100% operational", "production-ready", "no issues", "complete." Begin Phase A now. Print the status table before touching any code.
If anything weird happens, screenshot it and reply to the email thread. The Claude CLI on this Mac handles everything else from there.