Rename smartrun to geniusrun throughout the codebase
Updates the Go module path, cmd/smartrund -> cmd/geniusrund, the smartrun-dev skill, .gitignore, and every reference in docs/CLAUDE.md to match.
This commit is contained in:
12
CLAUDE.md
12
CLAUDE.md
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project overview
|
||||
|
||||
geniusrun (Go module `smartrun/backend`) is a personal web app that pulls running activities from Garmin Connect (via the `mcp-garmin` MCP server), classifies each run into one of a fixed set of running-specific "workout kinds" (Easy, Long, 60' Threshold, 30' Threshold, Tempo, Intervals, MAS Test, Race), and charts progression over time per kind. Ambiguous runs (matching zero, multiple, or only weakly one kind) go to a manual review queue instead of being silently misclassified.
|
||||
geniusrun (Go module `geniusrun/backend`) is a personal web app that pulls running activities from Garmin Connect (via the `mcp-garmin` MCP server), classifies each run into one of a fixed set of running-specific "workout kinds" (Easy, Long, 60' Threshold, 30' Threshold, Tempo, Intervals, MAS Test, Race), and charts progression over time per kind. Ambiguous runs (matching zero, multiple, or only weakly one kind) go to a manual review queue instead of being silently misclassified.
|
||||
|
||||
All Garmin credentials and every tunable analysis-engine parameter (HR zones, phase-detection minutes, pace-artifact filtering, chart colors, etc.) live in a single-row `profile` table, edited from the frontend's Profile screen — there is no multi-profile support, and `internal/config`'s env vars are limited to process-level plumbing (listen addr, DB path, mcp-garmin subprocess paths).
|
||||
|
||||
@@ -13,13 +13,13 @@ The "Training plan" tab (`frontend/src/pages/Plan.tsx`) is an intentional empty
|
||||
## Commands
|
||||
|
||||
Backend (from `backend/`):
|
||||
- Run the server: `./start.sh` (wraps `go run ./cmd/smartrund` with the local mcp-garmin subprocess paths and DB path already set) or `go run ./cmd/smartrund` directly if you export `MCP_GARMIN_PYTHON`/`MCP_GARMIN_SERVER` yourself.
|
||||
- Run the server: `./start.sh` (wraps `go run ./cmd/geniusrund` with the local mcp-garmin subprocess paths and DB path already set) or `go run ./cmd/geniusrund` directly if you export `MCP_GARMIN_PYTHON`/`MCP_GARMIN_SERVER` yourself.
|
||||
- Build/vet: `go build ./...` && `go vet ./...`
|
||||
- Format: `gofmt -l .` must report nothing before committing.
|
||||
- All tests: `go test ./...`
|
||||
- Single package: `go test ./internal/store/...`
|
||||
- Single test: `go test ./internal/store/... -run TestProfile -v`
|
||||
- Seed sample data (no live Garmin account needed): `go run ./cmd/seedsample -db /tmp/sample.db`, then point `smartrund` at that DB via `SMARTRUN_DB_PATH`.
|
||||
- Seed sample data (no live Garmin account needed): `go run ./cmd/seedsample -db /tmp/sample.db`, then point `geniusrund` at that DB via `GENIUSRUN_DB_PATH`.
|
||||
- Migrations live in `internal/store/migrations/`; add a new numbered file, never edit an already-applied one (the runner tracks applied filenames in a `schema_migrations` table).
|
||||
|
||||
Frontend (from `frontend/`):
|
||||
@@ -32,7 +32,7 @@ Frontend (from `frontend/`):
|
||||
|
||||
```
|
||||
backend/
|
||||
cmd/smartrund/ main server entrypoint
|
||||
cmd/geniusrund/ main server entrypoint
|
||||
cmd/seedsample/ inserts synthetic data for frontend dev/demoing without live Garmin creds
|
||||
cmd/mcpspike/ throwaway MCP-client spike, safe to delete
|
||||
internal/garmin/ MCP client wrapper (auth, get_activities, get_activity_splits, get_activity_details, get_workout_by_id)
|
||||
@@ -68,7 +68,7 @@ Each `workout_kinds.rule_json` is a recursive AND/OR condition tree (`internal/c
|
||||
- Leaf conditions: `{metric, op, value}`. `op` is `==`, `!=`, `>`, `>=`, `<`, `<=`, or `between` (value is a 2-element array).
|
||||
- Supported metrics (see `internal/sync/mapping.go`'s `buildMetricContext`): `avg_pace_sec_per_km`, `avg_hr`, `avg_hr_pct_max`, `max_hr`, `duration_seconds`, `distance_meters`, `elevation_gain_m`, `aerobic_training_effect`, `anaerobic_training_effect`, `vo2max_value`, `is_race`, `lap_interval_pattern` (0/1), `lap_pace_stddev`, `lap_hr_drift_bpm_per_min`, `lap_hr_recovery_bpm_per_min`.
|
||||
- **Scoring**: each leaf gets a margin-based confidence in ~[0,1] (`between` = distance from center; comparisons = logistic squash of margin past the threshold). Branches aggregate via `min` (AND) / `max` (OR) — no ML, fully explainable.
|
||||
- **`needs_review` triggers** (in `classify.Classify`): zero kinds matched, 2+ kinds matched, or exactly one matched below `min_confidence` (default from `SMARTRUN_MIN_CONFIDENCE`, 0.6). All three populate `Candidates` for the review UI.
|
||||
- **`needs_review` triggers** (in `classify.Classify`): zero kinds matched, 2+ kinds matched, or exactly one matched below `min_confidence` (default from `GENIUSRUN_MIN_CONFIDENCE`, 0.6). All three populate `Candidates` for the review UI.
|
||||
- **Interval detection** (`classify.DetectIntervalPattern`) trusts Garmin's own per-lap `IntensityType` tagging (ACTIVE vs REST/RECOVERY/WARMUP/COOLDOWN) rather than inferring it from pace variance.
|
||||
- **HR drift/recovery** (`classify.HRDrift`/`HRRecovery`): linear regression of heart rate vs elapsed time within a lap's sample window. Drift = rising HR during an active lap. Recovery = HR decay rate during a rest lap, sign-flipped so positive = good recovery.
|
||||
- Max HR for `avg_hr_pct_max` comes from `profile.max_heart_rate`, not a static config value — nil/unset omits that metric from the context rather than erroring.
|
||||
@@ -109,4 +109,4 @@ Each `workout_kinds.rule_json` is a recursive AND/OR condition tree (`internal/c
|
||||
- `internal/classify` tests are pure (no DB/network): construct a `MetricContext` + `RuleKind`s directly.
|
||||
- `internal/store` and `internal/sync` tests open a real temp-file SQLite DB (`store.Open` against `t.TempDir()`) — deliberate, not mocked, since migration/SQL correctness is exactly what needs catching.
|
||||
- `internal/api` tests use `httptest` against a `Server` wired to a temp DB + `mock.Client`.
|
||||
- The MCP/Garmin integration itself can't be safely automated (real account, MFA, rate limits) — it's a manual smoke test via `cmd/mcpspike` or the real `smartrund` auth endpoints.
|
||||
- The MCP/Garmin integration itself can't be safely automated (real account, MFA, rate limits) — it's a manual smoke test via `cmd/mcpspike` or the real `geniusrund` auth endpoints.
|
||||
|
||||
Reference in New Issue
Block a user