{"slug": "show-hn-oh-my-wrist-garmin-alerts-for-claude-code-and-opencode", "title": "Show HN: Oh my wrist – Garmin alerts for Claude Code and OpenCode", "summary": "A new open-source tool called oh-my-wrist streams real-time Claude Code and OpenCode AI coding assistant activity directly to Garmin smartwatches over Bluetooth Low Energy. The tool provides haptic alerts for tool calls, file edits, session state changes, and destructive commands, displaying a CLI-styled interface with an animated amber spinner and per-provider statistics on the watch. Available via pip install or as a Garmin Connect IQ app, oh-my-wrist runs on Linux, macOS, and Windows, and includes quiet hours and connection ID filtering to prevent interference between nearby users.", "body_md": "**oh-my-wrist displays real-time Claude Code and OpenCode activity on your Garmin smartwatch over Bluetooth Low Energy. See what your AI coding assistant is doing — right on your wrist.**\n\n**Real-time BLE updates**— tool calls, file edits, and session state streamed to your watch** Haptic alerts**— vibration patterns for idle, session done, destructive commands, and agent completion** CLI-styled watch UI**— terminal aesthetic with animated amber spinner, event stack, and per-provider stats** Multi-provider**— supports Claude Code and OpenCode simultaneously** Cross-platform**— runs on Linux, macOS, and Windows** Quiet hours**— suppress vibrations during configurable time windows** Connection ID filter**— optional 0–255 ID keeps nearby users' watches from pairing with each other\n\n```\npip install oh-my-wrist\n```\n\nOr with [uv](https://docs.astral.sh/uv/):\n\n```\nuv pip install oh-my-wrist\noh-my-wrist install\n```\n\nThis automatically:\n\n- Patches\n**Claude Code** hooks in`~/.claude/settings.json`\n\n- Configures a\n**Claude Code statusLine** that streams`/usage`\n\nquota to the watch (chaining any existing statusLine) - Installs the\n**OpenCode** TypeScript plugin (when`opencode`\n\nis on PATH) - Registers a background\n**system service**(systemd / launchd / Task Scheduler)\n\nTo install a single provider only:\n\n```\noh-my-wrist install --provider claude\noh-my-wrist install --provider opencode\n```\n\nInstall it one of two ways:\n\n- GitHub Releases: download\n`oh-my-wrist-prg-<version>.zip`\n\nfrom the latest release, unzip it, connect your Garmin device over USB, then copy the matching`oh-my-wrist-<device-id>.prg`\n\nfile to`/GARMIN/Apps/`\n\n. - Connect IQ Store:\n[DOWNLOAD](https://apps.garmin.com/en-US/apps/1fff0ec7-4813-4f94-8d24-3dc9fef0b9df) - Build from source: install Connect IQ SDK 9.1+, then run\n`tools/build_garmin.sh release`\n\nand copy the generated device-specific`.prg`\n\nfile from`build/garmin/`\n\nto`/GARMIN/Apps/`\n\n. VS Code single-device builds from`garmin/`\n\nwrite`bin/oh-my-wrist.prg`\n\n.\n\n```\noh-my-wrist start\n```\n\nOpen the **oh-my-wrist** app on your watch — it connects automatically and updates in real time.\n\n| Platform | Guide |\n|---|---|\n| 🐧 Linux |\n|\n\n[docs/INSTALL_MACOS.md](/yazon/oh-my-wrist/blob/main/docs/INSTALL_MACOS.md)[docs/INSTALL_WINDOWS.md](/yazon/oh-my-wrist/blob/main/docs/INSTALL_WINDOWS.md)Start the daemon in the background (or foreground for debugging):\n\n```\noh-my-wrist start\noh-my-wrist start --foreground\n```\n\nStart a Claude Code or OpenCode session — the watch updates automatically.\n\nFrom a source checkout, run the one-minute diagnostic stream to verify the daemon-to-watch link without starting a real Claude Code or OpenCode session:\n\n```\npython tools/check_connection.py\n```\n\nKeep the daemon running and the watch app open. You should see history rows change, Claude/OpenCode stats increment, and Claude usage bars move. Useful options:\n\n```\npython tools/check_connection.py --duration 30\npython tools/check_connection.py --dry-run\npython tools/check_connection.py --provider claude\n```\n\nFour swipeable views (left/right or UP/DOWN on button watches). History is the\ninitial view — swipe/press **UP** for the Claude usage screen, **DOWN** for the\nper-provider stats screens:\n\n| View | Direction from History | Content |\n|---|---|---|\n| Claude Usage | UP | `/usage` -style quota bars: session (5h) and week (7d), htop-style |\n| History | — (initial) | CLI-style event stack (3 visible rows with animated spinner) |\n| Claude Stats | DOWN | Session duration, tool calls, files edited, bash count, idle time |\n| OpenCode Stats | DOWN ×2 | Same metrics, isolated from Claude |\n\nThe usage screen is Claude-only and shows an empty bar with no percentage when quota data is unavailable (API-key users, or before the first API response in a session).\n\nPress **SELECT/START** on any view to open the app menu. Use **Set id** to\nsave the same 0–255 connection ID configured on your desktop daemon, then\nrestart the watch app so the new BLE service UUID is registered cleanly.\n\n| Command | Purpose |\n|---|---|\n`oh-my-wrist start [-f|--foreground]` |\nStart the BLE daemon |\n`oh-my-wrist stop` |\nStop the daemon |\n`oh-my-wrist status` |\nShow daemon PID, service status, hook/plugin state |\n`oh-my-wrist install [--provider claude|opencode|both]` |\nConfigure hooks, plugin, and OS service |\n`oh-my-wrist uninstall [--provider …]` |\nRemove hooks, plugin, and service |\n`oh-my-wrist test [message] [--provider claude|opencode]` |\nSend a test message to the daemon |\n`oh-my-wrist config [--show|--haptic on|off|--quiet-start HH:MM|--quiet-end HH:MM]` |\nView or update configuration |\n`oh-my-wrist set-id ID` |\nSet BLE connection ID (`0` –`255` ) and queue an update for a running daemon |\n`oh-my-wrist opencode install|uninstall|status` |\nManage the OpenCode plugin |\n`oh-my-wrist logs [-n LINES]` |\nTail the daemon log |\n\nSettings are stored at `~/.oh-my-wrist/config.json`\n\nand take effect immediately (no restart needed).\n\n```\n# View current config\noh-my-wrist config --show\n\n# Toggle haptic alerts\noh-my-wrist config --haptic on\noh-my-wrist config --haptic off\n\n# Set quiet hours (vibrations suppressed)\noh-my-wrist config --quiet-start 22:00 --quiet-end 08:00\n\n# Set BLE connection ID to match the watch menu's Set id value\noh-my-wrist set-id 42\n```\n\n| Setting | Default | Description |\n|---|---|---|\n`haptic_enabled` |\n`true` |\nEnable/disable all vibration alerts |\n`quiet_start` |\n`22:00` |\nStart of quiet window (HH:MM) |\n`quiet_end` |\n`08:00` |\nEnd of quiet window (HH:MM) |\n`connection_id` |\n`0` |\nBLE scan filter ID. The watch only connects to daemons with the same ID. |\n\nThe connection ID is not authentication; it is a collision reducer for rooms\nwhere multiple people run oh-my-wrist. ID `0`\n\nis the default and preserves the\noriginal BLE service UUID.\n\nRequires a Garmin watch with Connect IQ Generic BLE support (API level alone is not enough):\n\nManifest product IDs: `approachs50`\n\n, `approachs7042mm`\n\n, `approachs7047mm`\n\n, `d2air`\n\n, `d2airx10`\n\n, `d2mach1`\n\n, `d2mach2`\n\n, `d2mach2pro`\n\n, `descentg1`\n\n, `descentg2`\n\n, `descentmk2`\n\n, `descentmk2s`\n\n, `descentmk343mm`\n\n, `descentmk351mm`\n\n, `edge1030`\n\n, `edge1030plus`\n\n, `edge1040`\n\n, `edge1050`\n\n, `edge530`\n\n, `edge540`\n\n, `edge550`\n\n, `edge830`\n\n, `edge840`\n\n, `edge850`\n\n, `edgeexplore`\n\n, `edgeexplore2`\n\n, `edgemtb`\n\n, `enduro`\n\n, `enduro3`\n\n, `epix2`\n\n, `epix2pro42mm`\n\n, `epix2pro47mm`\n\n, `epix2pro51mm`\n\n, `etrextouch`\n\n, `fenix5plus`\n\n, `fenix5splus`\n\n, `fenix5xplus`\n\n, `fenix6`\n\n, `fenix6pro`\n\n, `fenix6s`\n\n, `fenix6spro`\n\n, `fenix6xpro`\n\n, `fenix7`\n\n, `fenix7pro`\n\n, `fenix7pronowifi`\n\n, `fenix7s`\n\n, `fenix7spro`\n\n, `fenix7x`\n\n, `fenix7xpro`\n\n, `fenix7xpronowifi`\n\n, `fenix843mm`\n\n, `fenix847mm`\n\n, `fenix8pro47mm`\n\n, `fenix8solar47mm`\n\n, `fenix8solar51mm`\n\n, `fenixe`\n\n, `fr165`\n\n, `fr165m`\n\n, `fr170`\n\n, `fr170m`\n\n, `fr245`\n\n, `fr245m`\n\n, `fr255`\n\n, `fr255m`\n\n, `fr255s`\n\n, `fr255sm`\n\n, `fr265`\n\n, `fr265s`\n\n, `fr55`\n\n, `fr57042mm`\n\n, `fr57047mm`\n\n, `fr645m`\n\n, `fr70`\n\n, `fr745`\n\n, `fr945`\n\n, `fr945lte`\n\n, `fr955`\n\n, `fr965`\n\n, `fr970`\n\n, `gpsmap66`\n\n, `gpsmap67`\n\n, `gpsmaph1`\n\n, `instinct2`\n\n, `instinct2s`\n\n, `instinct2x`\n\n, `instinct3amoled45mm`\n\n, `instinct3amoled50mm`\n\n, `instinct3solar45mm`\n\n, `instinctcrossover`\n\n, `instinctcrossoveramoled`\n\n, `instincte40mm`\n\n, `instincte45mm`\n\n, `legacyherocaptainmarvel`\n\n, `legacyherofirstavenger`\n\n, `legacysagadarthvader`\n\n, `legacysagarey`\n\n, `marq2`\n\n, `marq2aviator`\n\n, `marqadventurer`\n\n, `marqathlete`\n\n, `marqaviator`\n\n, `marqcaptain`\n\n, `marqcommander`\n\n, `marqdriver`\n\n, `marqexpedition`\n\n, `marqgolfer`\n\n, `montana7xx`\n\n, `venu`\n\n, `venu2`\n\n, `venu2plus`\n\n, `venu2s`\n\n, `venu3`\n\n, `venu3s`\n\n, `venu441mm`\n\n, `venu445mm`\n\n, `venud`\n\n, `venusq2m`\n\n, `venusqm`\n\n, `venux1`\n\n, `vivoactive3m`\n\n, `vivoactive3mlte`\n\n, `vivoactive4`\n\n, `vivoactive4s`\n\n, `vivoactive5`\n\n, `vivoactive6`\n\n.\n\n| Problem | Solution |\n|---|---|\n| Watch can't find daemon | Run `oh-my-wrist status` — verify daemon is advertising and that desktop/watch connection IDs match. Restart with `oh-my-wrist stop && oh-my-wrist start` . From a source checkout, run `python tools/check_connection.py` with the watch app open to exercise live HISTORY, stats, and usage updates. |\n| Garmin app does not connect to daemon on PC | Make sure your Bluetooth adapter is supported. Some adapters or OS settings, such as Windows random MAC behavior, can prevent stable BLE connections. If problems persist, macOS or Linux is preferred. |\n| Garmin app does not start on watch | Create an empty `/GARMIN/Apps/Logs/oh-my-wrist-YOUR_WATCH_ID.log (e.g oh-my-wrist-fenix7x.log)` file on the device, run the app, wait for the issue to occur, reconnect the device to your PC, download log file, then create a GitHub issue with the log for debugging. |\n| Hook not firing | Run `oh-my-wrist status` — confirm hooks in `~/.claude/settings.json` . Re-run `oh-my-wrist install` . |\n| OpenCode not updating | Check plugin: `oh-my-wrist opencode status` . Re-install: `oh-my-wrist opencode install` . |\n| BLE permission errors | See your platform guide:\n|\n\n`oh-my-wrist start --foreground`\n\nto see the error. Check `oh-my-wrist logs`\n\n.\n\n```\noh-my-wrist uninstall\npip uninstall oh-my-wrist\n```\n\nTo remove the watch app, delete it via Garmin Express or the Connect IQ app on your phone.\n\nContributions are more than welcome. Please contribute! See [CONTRIBUTING.md](/yazon/oh-my-wrist/blob/main/docs/CONTRIBUTING.md) for guidelines.\n\n```\n# pip\npip install -e \".[dev]\"\npytest tests/\n\n# or uv\nuv venv && uv pip install -e \".[dev]\"\nuv run pytest\n\noh-my-wrist start --foreground\n```\n\nThis project is licensed under the BSD 3-Clause License. See the [LICENSE](/yazon/oh-my-wrist/blob/main/LICENSE) file for details.", "url": "https://wpnews.pro/news/show-hn-oh-my-wrist-garmin-alerts-for-claude-code-and-opencode", "canonical_source": "https://github.com/yazon/oh-my-wrist", "published_at": "2026-06-06 15:51:50+00:00", "updated_at": "2026-06-06 16:19:21.515300+00:00", "lang": "en", "topics": ["ai-tools", "ai-products", "ai-infrastructure", "ai-agents", "generative-ai"], "entities": ["Garmin", "Claude Code", "OpenCode", "Bluetooth Low Energy", "Linux", "macOS", "Windows", "Astral"], "alternates": {"html": "https://wpnews.pro/news/show-hn-oh-my-wrist-garmin-alerts-for-claude-code-and-opencode", "markdown": "https://wpnews.pro/news/show-hn-oh-my-wrist-garmin-alerts-for-claude-code-and-opencode.md", "text": "https://wpnews.pro/news/show-hn-oh-my-wrist-garmin-alerts-for-claude-code-and-opencode.txt", "jsonld": "https://wpnews.pro/news/show-hn-oh-my-wrist-garmin-alerts-for-claude-code-and-opencode.jsonld"}}