# Windows Setup and Run Guide This guide covers running the Clawdmeter Windows daemon on native Windows hardware. It includes the turnkey `install-windows.ps1` bootstrap (tray icon + login autostart), the manual-run fallback, and how to manage or remove autostart. --- ## Prerequisites | Requirement | Details | |-------------|---------| | **Native Windows** | Must run on real Windows — not WSL. The script prints a warning and BLE will not work under WSL. | | **Python 3.11+** | Download from [python.org](https://www.python.org/downloads/) if not already installed. Ensure "Add python.exe to PATH" is checked during install. | | **Claude Code installed** | Install Claude Code and complete `claude login` so credentials exist on disk. | | **Clawdmeter powered on** | The device must be powered on and in range before the daemon starts. | | **Paired with Windows Bluetooth** | Pair the device once via **Settings → Bluetooth & devices → Add device** (see [Pair the device](#pair-the-device-one-time)). This is required — the device is a bonded BLE HID keyboard, so pairing enables its physical buttons and keeps a persistent connection that shows your last usage even when the daemon is stopped. | ### Where are my credentials? `claude login` writes the OAuth token to (first match wins): 1. `%USERPROFILE%\.claude\.credentials.json` — primary path (confirmed by Claude Code docs) 2. `%LOCALAPPDATA%\Claude\.credentials.json` — fallback 3. `%APPDATA%\Claude\.credentials.json` — fallback The daemon probes these paths in order. You can also set `CLAUDE_CREDENTIALS_PATH` to an absolute path or `CLAUDE_CONFIG_DIR` to a directory to override the search entirely. > **Security note:** The credentials file contains your OAuth token. Never share its contents > or embed it in scripts. The daemon reads it from disk and uses it only as the API > `Authorization` header — the token is never written to any log, tooltip, or notification. --- ## Pair the device (one time) The Clawdmeter is a **bonded BLE HID keyboard** as well as a usage display — its firmware enables bonding (`NimBLEDevice::setSecurityAuth`) and advertises the HID service so its physical buttons act as a keyboard (Space / Shift+Tab). Pair it with Windows **once**, before running the daemon: 1. Put the device on its Bluetooth waiting screen (powered on, not yet connected). 2. Open **Settings → Bluetooth & devices → Add device → Bluetooth**. 3. Select **Claude Controller** and complete pairing. **Why this is required:** - **Keyboard buttons** — HID over BLE requires bonding on Windows. Without pairing, the device's buttons won't reach the PC. - **Persistent point-in-time view** — once paired, Windows maintains the BLE link and auto-reconnects the device whenever it is in range. This is intentional: the device keeps showing your **last-synced** usage even after you Quit the daemon, as a glanceable point-in-time view. Quitting the daemon releases only its data connection — it does **not** drop the Windows pairing, so the device stays connected to Windows. To undo, use **Settings → Bluetooth & devices → (device) → Remove device**. Removing the pairing disables the keyboard buttons. --- ## Standalone executable — no Python required (recommended) To run Clawdmeter on a machine **without Python**, use the single-file `Clawdmeter.exe`. It bundles its own Python, the WinRT BLE stack and the media-session reader, so nothing needs to be installed. > **Download:** the repo is private, so **sign in to Gitea first**, then download > **`Clawdmeter.exe`** with this direct link: > > — or browse [all releases](https://gitea.bvrdo.online/wenil/clawdmeter/releases) for the newest build. 1. Pair the device with Windows once (see [Pair the device](#pair-the-device-one-time)). 2. Get `Clawdmeter.exe` — download it from the [latest Gitea release](https://gitea.bvrdo.online/wenil/clawdmeter/releases/latest), or build it yourself (below). 3. Double-click `Clawdmeter.exe`. The tray icon appears and the watch starts updating within ~10 seconds. 4. To launch it automatically at every logon, right-click the tray icon → **Start at login**. That registers the exe itself under `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` — no Python, no console window. There is no console window; the exe logs to `%LOCALAPPDATA%\Clawdmeter\daemon.log`. ### Building the exe On a machine that *does* have Python (e.g. your dev box), from the repo root: ```powershell powershell -ExecutionPolicy Bypass -File build-exe.ps1 ``` This creates `dist\Clawdmeter.exe` (~30–60 MB). The PyInstaller config lives in `clawdmeter.spec`. The exe is intentionally **not** committed to git — distribute it through a Gitea release. > **SmartScreen / antivirus:** unsigned PyInstaller executables are sometimes > flagged by a generic heuristic (not a real detection). Until the exe is > code-signed, you may need to allow it through SmartScreen ("More info → Run > anyway"). Building from source sidesteps this entirely. --- ## Setup from source (one time) > Use this if you prefer running from a Python checkout instead of the standalone > exe above (e.g. on your dev box). Open a PowerShell terminal and `cd` to the repository root. **1. Create a virtual environment** ```powershell python -m venv .venv ``` **2. Activate it** ```powershell .venv\Scripts\Activate.ps1 ``` If you see a scripts-execution-policy error, run: ```powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned ``` Then repeat the `Activate.ps1` step. **3. Install dependencies** ```powershell pip install -r daemon\requirements-windows.txt ``` This installs `bleak` (WinRT BLE) and `httpx` (async HTTP for the Anthropic API). --- ## Running the daemon With the venv active and the Clawdmeter powered on: ```powershell python daemon\claude_usage_daemon_windows.py ``` ### Expected console output ``` [HH:MM:SS] === Claude Usage Tracker Daemon (BLE, Windows) === [HH:MM:SS] Poll interval: 60s [HH:MM:SS] Scanning for 'Claude Controller' (8.0s)... [HH:MM:SS] Found: XX:XX:XX:XX:XX:XX [HH:MM:SS] Connecting to XX:XX:XX:XX:XX:XX... [HH:MM:SS] Connected [HH:MM:SS] Sending: {"s":42,"sr":180,"w":17,"wr":8820,"st":"active","ok":true} ``` - **The device must be paired with Windows first** (see [Pair the device](#pair-the-device-one-time)). The daemon then connects over that existing link via `BleakScanner` + `BleakClient`; it does not pop its own pairing dialog. - After `Connected`, the daemon polls the Anthropic API immediately and sends the first payload within a few seconds of connect (warm token path). With a valid, non-expired token the device should leave its waiting screen and show session + weekly percentages within about 10 seconds of launch. - The daemon then re-polls the Anthropic API every 60 seconds while connected. If the device fires a refresh request (e.g., after a button press), an immediate re-poll occurs without waiting for the 60-second interval. - The **Now Playing** screen updates on a separate, faster cadence: the daemon reads the Windows media session every 3 seconds and pushes an update the moment the track or play/pause state changes — so the watch reflects a song change within a few seconds, not at the next 60-second API poll. The cached usage data is re-sent with each of these updates, so the rate-limit / token screens never blank between polls. - If the device disconnects or goes out of range, the daemon logs `Device disconnected` and re-scans automatically with exponential backoff (starting at 1 second, capped at 60 seconds). ### Stopping Press **Ctrl+C** in the terminal. The daemon logs `Daemon stopping` and exits cleanly. --- ## Troubleshooting | Symptom | Likely cause | Fix | |---------|-------------|-----| | `Warning: running under Linux/WSL` | Running in WSL, not native Windows | Run from a native PowerShell or Command Prompt on Windows | | `Scanning for 'Claude Controller'… Device not found` | Clawdmeter is off, out of range, or showing a non-Bluetooth screen | Power on the device and ensure it is on the Bluetooth waiting screen | | `No token; skipping poll` | No credentials file found at any candidate path | Confirm `claude login` ran on this machine; check `%USERPROFILE%\.claude\.credentials.json` exists | | `API HTTP 401` | Token expired | Re-run `claude login` in a terminal to refresh the token, then restart the daemon | | `Connection failed` | WinRT BLE initialisation issue | Ensure Windows Bluetooth is on; try toggling Bluetooth off/on in Windows Settings | --- ## Tray icon, login autostart, and turnkey install ### One-command install (recommended) > **Copy the repo to a native Windows path first.** Clone or copy this repository > to a Windows location such as `%USERPROFILE%\Clawdmeter` — **not** a WSL share > (`\\wsl$\...` or `\\wsl.localhost\...`). Installing from the WSL share would point > the virtual environment and the login-autostart entry at a path that disappears when > WSL shuts down, defeating the whole point of the Windows daemon. The installer > detects a WSL path and refuses to run, telling you how to relocate. > > ```powershell > Copy-Item -Recurse '\\wsl.localhost\Ubuntu\home\\repos\Clawdmeter' "$env:USERPROFILE\Clawdmeter" > cd "$env:USERPROFILE\Clawdmeter" > ``` Run this once from the repository root in PowerShell (a native Windows path): ```powershell powershell -ExecutionPolicy Bypass -File install-windows.ps1 ``` The script does four things in order and logs progress at each step: 1. Creates a Python virtual environment at `.venv`. 2. Installs dependencies from `daemon\requirements-windows.txt` (bleak, httpx, pystray, Pillow). 3. Registers the tray app to launch automatically at login via `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` — per-user, no admin required. 4. Launches the tray app immediately (headless — no console window). The script downloads nothing from the internet. It only installs the packages listed in the in-repo `daemon\requirements-windows.txt`. ### Tray icon and status After install, the Clawdmeter icon appears in the Windows notification area: | State | Icon bubble | Tooltip | |-------|-------------|---------| | Connected | green | `Connected · last update HH:MM` | | Scanning | amber | `Scanning…` | | Error | red | `Error: token expired — run claude login` | Hover over the icon to see the current status tooltip. A notification fires once when the daemon first enters the Error state (e.g. after a token expiry). ### Tray menu Right-click the tray icon for the menu: - **Status header** (non-clickable) — live status + last data sync time. - **Start at login** (checkable toggle) — enables or disables autostart at runtime. Reflects the current registry state each time the menu opens. - **Quit** — stops the daemon cleanly and exits with no lingering process. It releases the daemon's own data connection but does **not** drop the Windows Bluetooth pairing — the device stays connected to Windows and keeps showing your last-synced usage (point-in-time view). ### Disabling or removing autostart Use the tray menu toggle, or remove the registry value manually: ```powershell reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v Clawdmeter /f ``` ### WSL independence The daemon operates fully independently of WSL. The token is read from native Windows credential paths (`%USERPROFILE%\.claude\.credentials.json` and fallbacks); BLE uses the WinRT stack directly. Running `wsl --shutdown` does not affect the BLE link, and the daemon starts correctly even in a fresh Windows session where WSL has never been launched. --- ## What is NOT covered here - Code-signing the standalone `.exe` (to avoid SmartScreen/AV prompts) — future - MAC-address cache / sleep-wake reconnect hardening — Phase 3