Codex Pet is a local-first Garmin Connect IQ app that shows your latest Codex activity on a Garmin watch with an animated pet, task overview, task details, and a browser-based build pipeline.
The goal of this repo is that a Mac user can clone it, run one setup script, start one local server, and build a watch app without manually wiring bridge ports or editing config files.
git clone https://github.com/Mooreel/garmin-pet.git
cd garmin-pet
scripts/setup_mac.sh
scripts/start.shOpen the local pipeline:
http://127.0.0.1:8790
Then use the browser flow:
- Connect your Garmin watch over USB.
- Import a pet from Petdex or drop a local pet ZIP/folder.
- Pick your watch target and theme.
- Run security check.
- Click Save & build app.
- Click Deploy latest PRG.
- Unplug the watch so Garmin can ingest the sideloaded app.
| Requirement | Why it is needed | Setup script |
|---|---|---|
| macOS | Current build/deploy scripts target Mac paths and launch services. | Checks only |
| Python 3 | Runs the local pipeline server and setup tooling. | Checks only |
| Pillow Python package | Exports Petdex/local pet spritesheets into Garmin PNG frames. | Installs into .venv |
| Garmin Connect IQ SDK Manager | Provides monkeyc and device SDKs for building the PRG. |
Checks only |
| JDK | Required by Garmin monkeyc. |
Can install OpenJDK with --install-deps if Homebrew exists |
| Garmin watch | Needed for deploy and real-device testing. | Auto-detects in the web UI |
| Garmin Connect on iPhone | Carries watch web requests to the local bridge. | Manual |
| Same WiFi/LAN for Mac and iPhone | The watch bridge runs on your Mac. | Auto-generates the LAN URL |
Optional libmtp |
Helps deploy to watches that do not mount as USB storage. | Can install with --install-deps if Homebrew exists |
Garmin SDK Manager itself is not installed automatically because it is a licensed Garmin desktop tool. Install it from Garmin, add an SDK, and make sure monkeyc is on PATH or set GARMIN_SDK_HOME.
Run:
scripts/setup_mac.shIt safely creates local, git-ignored files:
.venv/bridge_token.txtpipeline/local.jsonpipeline/work/build/developer_key.derwhenopensslis available
It also checks:
- Python 3
- Python packages from
requirements.txt - Garmin
monkeyc - Java / OpenJDK
libmtpdeploy tools- generated watch bridge URL
To let the script install the Homebrew packages it can safely automate:
scripts/setup_mac.sh --install-depsThat may install:
openjdklibmtp
It will not install Garmin SDK Manager automatically.
Start the pipeline:
scripts/start.shThe browser UI is:
http://127.0.0.1:8790
The watch bridge is served by the same process and port:
http://<mac-lan-ip>:8790/garmin/latest?token=<local-token>
You do not need to configure a second bridge server. The pipeline detects the Mac LAN address, creates a token, and injects the correct bridge URL when you save/build.
If you do not want the Mac pipeline server running all day, host only the watch bridge on a Synology NAS:
scripts/synology/deploy_bridge.shThat starts a small Python bridge on the Synology and updates local builds to use:
http://synology.local:8790/garmin/latest?token=<local-token>
The Mac is still needed for pet import, preview, Garmin SDK builds, and USB deploy. The NAS only keeps the watch endpoint available. After using Codex on the Mac, publish the latest payload to the NAS:
scripts/synology/publish_payload.shFor a custom pet.local URL, make sure pet.local resolves on your LAN through router DNS or an mDNS/Bonjour alias, then deploy with:
GARMIN_PUBLIC_BRIDGE_HOST=pet.local scripts/synology/deploy_bridge.shSee docs/SYNOLOGY_BRIDGE.md for the full setup and reboot notes.
On Nico's Synology setup, pet.local is published through a small mDNS alias
process and the browser dashboard is available at:
http://pet.local:8790/
If the Mac pipeline is running, that URL proxies the full browser pipeline from the Mac. If the Mac is offline, it falls back to the Synology bridge dashboard.
Use the web UI at http://127.0.0.1:8790.
Recommended flow:
- Confirm the watch banner says the Garmin watch is accessible.
- Import a pet from Petdex or drop a ZIP/folder with
pet.jsonandspritesheet.webp. - Preview the pet home, task list, and task detail screens in the watch frame.
- Run security check.
- Click Save & build app.
- Deploy latest PRG.
The security check is required before build because this project creates local tokens and keys that must never be committed.
python3 scripts/configured_build.py --config pipeline/local.json --device fr265sDeploy the last build:
scripts/install_to_watch.shThe generated app lives at:
build/CodexPet.prg
For a persistent local server:
scripts/install_pipeline_launch_agent.shThis installs a user LaunchAgent that runs the unified pipeline server on port 8790.
pipeline/ Local web app, API, Petdex import, bridge endpoint
pipeline/app/bridge.py Garmin payload, token, LAN URL, /garmin/latest route
pipeline/web/preview.js Browser watch-screen simulator
source/ Monkey C Garmin app
config/devices.json Extendable watch device registry
resources/images/ Generated pet frames
scripts/ Setup, start, build, deploy, validation helpers
docs/ Extra quickstart and troubleshooting notes
- Add the watch profile to
config/devices.json. - Add the real frame image under
pipeline/web/assets/devices/. - Set the screen size, shape, and frame screen rectangle.
- Keep
buildEnabled: falseuntil the Garmin target is inmanifest.xml. - Run:
python3 scripts/configured_build.py --config pipeline/local.json --device <device-id>Only set buildEnabled: true after the build works for that device.
Use the browser importer, or prepare a folder/ZIP with:
pet.json
spritesheet.webp
The pipeline exports the frames into resources/images/ for the Garmin app.
Run:
python3 scripts/security_check.py
python3 scripts/validate_project.pysecurity_check.py fails if tracked files contain local tokens, private keys, developer keys, local certificates, or build artifacts.
If the watch shows Bridge -300, the phone/watch path timed out reaching your Mac.
Check:
scripts/start.shis running.- The app was rebuilt after setup or network changes.
- The bridge URL shown in the UI uses port
8790. - The iPhone and Mac are on the same LAN.
- Garmin Connect has Local Network permission in iOS Settings.
- macOS firewall allows Python/local network access.
More detail is in docs/TROUBLESHOOTING.md.