diff --git a/docs/superpowers/specs/2026-07-25-garmin-direct-wrapper-design.md b/docs/superpowers/specs/2026-07-25-garmin-direct-wrapper-design.md index 1fbf5da..deae802 100644 --- a/docs/superpowers/specs/2026-07-25-garmin-direct-wrapper-design.md +++ b/docs/superpowers/specs/2026-07-25-garmin-direct-wrapper-design.md @@ -57,6 +57,7 @@ Go's line reader uses a raised buffer size (well above the default 64KB `bufio.S ### Python wrapper — `backend/garmin-wrapper/wrapper.py` - Single file. Same shape as today's `server.py` minus all MCP scaffolding (`FastMCP`, `@mcp.tool()` decorators, `mcp.run()`). +- Embedded into the Go binary at compile time via `//go:embed wrapper.py` (a `[]byte`/`string` constant in `internal/garmin`), rather than referenced by a configurable filesystem path. At process start, `ensureStarted` writes the embedded source to a temp file (`os.CreateTemp`) once per process lifetime and execs the configured Python interpreter against that path. This removes any notion of a "server script location" from configuration entirely — whatever `wrapper.py` shipped inside the running binary is exactly what gets executed, so there's no drift between binary version and script version, and the container image needs no separate `COPY` step for it. - Reads `GARMIN_EMAIL` / `GARMIN_PASSWORD` / `GARMIN_TOKENSTORE` from the environment at process start — unchanged from today. - Holds one module-level `Garmin` client instance and an auth-state variable (`unauthenticated` / `mfa_pending` / `authenticated`). - Main loop: `for line in sys.stdin`, parse `{"id", "cmd", "params"}`, dispatch to the `authenticate` / `complete_mfa` / `call` handler, write exactly one JSON line to stdout per response, flush immediately. Debug/diagnostic output continues to go to stderr only (stdout is reserved for the response protocol) — Go already drains stderr today and keeps doing so unchanged. @@ -91,8 +92,8 @@ Go's line reader uses a raised buffer size (well above the default 64KB `bufio.S ## Migration & container - Full replacement, no compatibility shim, consistent with this project's "no migration history" stance elsewhere: `mcp-go` import and all MCP-specific code in `client.go` are deleted in the same change, not kept behind a flag. -- `backend/start.sh`'s `MCP_GARMIN_PYTHON` / `MCP_GARMIN_SERVER` env vars are renamed (e.g. `GARMIN_WRAPPER_PYTHON` / `GARMIN_WRAPPER_SCRIPT`) and default to paths inside the geniusrun repo (`backend/garmin-wrapper/`) instead of a sibling `mcp-garmin` checkout. -- Container image only needs: a Python runtime, `pip install garminconnect`, and `backend/garmin-wrapper/wrapper.py` copied in — no second repo to clone/vendor, no `mcp` SDK on either side. +- `backend/start.sh`'s `MCP_GARMIN_PYTHON` / `MCP_GARMIN_SERVER` env vars are retired, not just renamed. Only one config knob remains: `GARMIN_WRAPPER_PYTHON`, and it becomes **optional** (default `"python3"`, resolved via `PATH`) rather than required — matching how `config.Load()` already treats genuinely-optional plumbing (e.g. `GENIUSRUN_OIDC_REQUIRED_ROLE`). There is no longer a script-location env var at all, since `wrapper.py` is embedded in the binary (see Components above). Local dev can still point `GARMIN_WRAPPER_PYTHON` at a venv interpreter if desired; it's just no longer required to. +- Container image only needs: a Python runtime with `garminconnect` installed (`pip install garminconnect` in the image, no venv necessary since the container itself is the isolation boundary) — no second repo to clone/vendor, no `mcp` SDK on either side, and no separate wrapper script file to `COPY` in. - The standalone `mcp-garmin` repo is retired (archived) once this ships; its test suite (`tests/test_server.py`) either gets ported to test `wrapper.py` directly inside geniusrun, or is dropped in favor of the new `internal/garmin` tests above, whichever ends up covering the same ground with less duplication — a call to make during implementation, not part of this spec. ## Rollout notes