Skip to main content

Display real-time AI coding assistant activity on a Garmin smartwatch via BLE.

Project description

oh-my-wrist logo

oh-my-wrist

oh-my-wrist GitHub stars GitHub top language GitHub repo size GitHub last commit GitHub License

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.

Key Features

  • 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

oh-my-wrist Watch Demo

Quick Start

1. Install the Python daemon

pip install oh-my-wrist

Or with uv:

uv pip install oh-my-wrist

2. Configure providers and system service

oh-my-wrist install

This automatically:

  • Patches Claude Code hooks in ~/.claude/settings.json
  • Configures a Claude Code statusLine that streams /usage quota to the watch (chaining any existing statusLine)
  • Installs the OpenCode TypeScript plugin (when opencode is on PATH)
  • Registers a background system service (systemd / launchd / Task Scheduler)

To install a single provider only:

oh-my-wrist install --provider claude
oh-my-wrist install --provider opencode

3. Install the Garmin watch app

Install it one of two ways:

  1. GitHub Releases: download oh-my-wrist-prg-<version>.zip from the latest release, unzip it, connect your Garmin device over USB, then copy the matching oh-my-wrist-<device-id>.prg file to /GARMIN/Apps/.
  2. Connect IQ Store: DOWNLOAD
  3. Build from source: install Connect IQ SDK 9.1+, then run tools/build_garmin.sh release and copy the generated device-specific .prg file from build/garmin/ to /GARMIN/Apps/. VS Code single-device builds from garmin/ write bin/oh-my-wrist.prg.

4. Start coding

oh-my-wrist start

Open the oh-my-wrist app on your watch — it connects automatically and updates in real time.

Platform Guides

Platform Guide
🐧 Linux docs/INSTALL_LINUX.md
🍎 macOS docs/INSTALL_MACOS.md
🪟 Windows docs/INSTALL_WINDOWS.md

Usage

Start the daemon in the background (or foreground for debugging):

oh-my-wrist start
oh-my-wrist start --foreground

Start a Claude Code or OpenCode session — the watch updates automatically.

Connection Check

From 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:

python tools/check_connection.py

Keep 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:

python tools/check_connection.py --duration 30
python tools/check_connection.py --dry-run
python tools/check_connection.py --provider claude

Watch Navigation

Four swipeable views (left/right or UP/DOWN on button watches). History is the initial view — swipe/press UP for the Claude usage screen, DOWN for the per-provider stats screens:

View Direction from History Content
Claude Usage UP /usage-style quota bars: session (5h) and week (7d), htop-style
History — (initial) CLI-style event stack (3 visible rows with animated spinner)
Claude Stats DOWN Session duration, tool calls, files edited, bash count, idle time
OpenCode Stats DOWN ×2 Same metrics, isolated from Claude

The 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).

Press SELECT/START on any view to open the app menu. Use Set id to save the same 0–255 connection ID configured on your desktop daemon, then restart the watch app so the new BLE service UUID is registered cleanly.

CLI Commands

Command Purpose
oh-my-wrist start [-f|--foreground] Start the BLE daemon
oh-my-wrist stop Stop the daemon
oh-my-wrist status Show daemon PID, service status, hook/plugin state
oh-my-wrist install [--provider claude|opencode|both] Configure hooks, plugin, and OS service
oh-my-wrist uninstall [--provider …] Remove hooks, plugin, and service
oh-my-wrist test [message] [--provider claude|opencode] Send a test message to the daemon
oh-my-wrist config [--show|--haptic on|off|--quiet-start HH:MM|--quiet-end HH:MM] View or update configuration
oh-my-wrist set-id ID Set BLE connection ID (0255) and queue an update for a running daemon
oh-my-wrist opencode install|uninstall|status Manage the OpenCode plugin
oh-my-wrist logs [-n LINES] Tail the daemon log

Configuration

Settings are stored at ~/.oh-my-wrist/config.json and take effect immediately (no restart needed).

# View current config
oh-my-wrist config --show

# Toggle haptic alerts
oh-my-wrist config --haptic on
oh-my-wrist config --haptic off

# Set quiet hours (vibrations suppressed)
oh-my-wrist config --quiet-start 22:00 --quiet-end 08:00

# Set BLE connection ID to match the watch menu's Set id value
oh-my-wrist set-id 42
Setting Default Description
haptic_enabled true Enable/disable all vibration alerts
quiet_start 22:00 Start of quiet window (HH:MM)
quiet_end 08:00 End of quiet window (HH:MM)
connection_id 0 BLE scan filter ID. The watch only connects to daemons with the same ID.

The connection ID is not authentication; it is a collision reducer for rooms where multiple people run oh-my-wrist. ID 0 is the default and preserves the original BLE service UUID.

Supported Devices

Requires a Garmin watch with Connect IQ Generic BLE support (API level alone is not enough):

Manifest product IDs: approachs50, approachs7042mm, approachs7047mm, d2air, d2airx10, d2mach1, d2mach2, d2mach2pro, descentg1, descentg2, descentmk2, descentmk2s, descentmk343mm, descentmk351mm, edge1030, edge1030plus, edge1040, edge1050, edge530, edge540, edge550, edge830, edge840, edge850, edgeexplore, edgeexplore2, edgemtb, enduro, enduro3, epix2, epix2pro42mm, epix2pro47mm, epix2pro51mm, etrextouch, fenix5plus, fenix5splus, fenix5xplus, fenix6, fenix6pro, fenix6s, fenix6spro, fenix6xpro, fenix7, fenix7pro, fenix7pronowifi, fenix7s, fenix7spro, fenix7x, fenix7xpro, fenix7xpronowifi, fenix843mm, fenix847mm, fenix8pro47mm, fenix8solar47mm, fenix8solar51mm, fenixe, fr165, fr165m, fr170, fr170m, fr245, fr245m, fr255, fr255m, fr255s, fr255sm, fr265, fr265s, fr55, fr57042mm, fr57047mm, fr645m, fr70, fr745, fr945, fr945lte, fr955, fr965, fr970, gpsmap66, gpsmap67, gpsmaph1, instinct2, instinct2s, instinct2x, instinct3amoled45mm, instinct3amoled50mm, instinct3solar45mm, instinctcrossover, instinctcrossoveramoled, instincte40mm, instincte45mm, legacyherocaptainmarvel, legacyherofirstavenger, legacysagadarthvader, legacysagarey, marq2, marq2aviator, marqadventurer, marqathlete, marqaviator, marqcaptain, marqcommander, marqdriver, marqexpedition, marqgolfer, montana7xx, venu, venu2, venu2plus, venu2s, venu3, venu3s, venu441mm, venu445mm, venud, venusq2m, venusqm, venux1, vivoactive3m, vivoactive3mlte, vivoactive4, vivoactive4s, vivoactive5, vivoactive6.

Troubleshooting

Problem Solution
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.
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.
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.
Hook not firing Run oh-my-wrist status — confirm hooks in ~/.claude/settings.json. Re-run oh-my-wrist install.
OpenCode not updating Check plugin: oh-my-wrist opencode status. Re-install: oh-my-wrist opencode install.
BLE permission errors See your platform guide: Linux · macOS · Windows
Daemon crashes on start Run oh-my-wrist start --foreground to see the error. Check oh-my-wrist logs.

Uninstall

oh-my-wrist uninstall
pip uninstall oh-my-wrist

To remove the watch app, delete it via Garmin Express or the Connect IQ app on your phone.

Contributing

Contributions are more than welcome. Please contribute! See CONTRIBUTING.md for guidelines.

Development

# pip
pip install -e ".[dev]"
pytest tests/

# or uv
uv venv && uv pip install -e ".[dev]"
uv run pytest

oh-my-wrist start --foreground

License

This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oh_my_wrist-0.1.3.tar.gz (113.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oh_my_wrist-0.1.3-py3-none-any.whl (74.8 kB view details)

Uploaded Python 3

File details

Details for the file oh_my_wrist-0.1.3.tar.gz.

File metadata

  • Download URL: oh_my_wrist-0.1.3.tar.gz
  • Upload date:
  • Size: 113.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for oh_my_wrist-0.1.3.tar.gz
Algorithm Hash digest
SHA256 9f749646a9c937c13c2d3869f4ffcc53ea1d1f9a08159115f3011e808cd9dab2
MD5 7f4bebf91d4a358801dbb29c0ece35e1
BLAKE2b-256 b1731cb1e0438969e41579dc038c19538b34f1f4aeaa3a757918ccb1e73efa71

See more details on using hashes here.

Provenance

The following attestation bundles were made for oh_my_wrist-0.1.3.tar.gz:

Publisher: release-garmin.yml on yazon/oh-my-wrist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oh_my_wrist-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: oh_my_wrist-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 74.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for oh_my_wrist-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 aa7e574e7727648bb60e054cf3ca54b4baeab971ec7d82e8e49bef73be694e83
MD5 d701d25d8ce5b260c224ee4779346e01
BLAKE2b-256 a6347b7f0e77a2b1911a2bb884d43f12caf15fe8d354e8226af1430e93ff60b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for oh_my_wrist-0.1.3-py3-none-any.whl:

Publisher: release-garmin.yml on yazon/oh-my-wrist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page