{
  "id": "com.lattice.workouts",
  "name": "Workouts",
  "icon": "🏃",
  "color": "#087f5b",
  "description": "Log workouts, distances and times in Strava's activity format.",
  "provenance": "Strava API v3, verified 2026-10-14: https://developers.strava.com/docs/reference/#api-Activities-createActivity and https://developers.strava.com/docs/reference/#api-models-SummaryActivity . Adopted id, name, sport_type, start_date, start_date_local, timezone, distance, elapsed_time, moving_time, total_elevation_gain, commute, plus DetailedActivity.description. Uses API units (meters and seconds), not bulk CSV display units. API boolean commute is projected to SQLite 0/1. Events/listeners model local actions; they are not Strava webhook payloads.",
  "requested_permissions": {
    "storage": [
      "sql"
    ],
    "network": {
      "allowlist": []
    },
    "events": {
      "activity-recorded": {
        "description": "An activity was recorded.",
        "schema": {
          "type": "object",
          "properties": {
            "id": {
              "type": "integer",
              "description": "Activity ID."
            },
            "name": {
              "type": "string",
              "description": "Activity name."
            },
            "sport_type": {
              "type": "string",
              "description": "Strava sport type, e.g. Run, Ride, MountainBikeRide, Walk or Swim."
            },
            "start_date": {
              "type": [
                "string",
                "null"
              ],
              "description": "Activity start, UTC ISO 8601 timestamp; null means only local start known."
            },
            "start_date_local": {
              "type": "string",
              "description": "Local wall-clock ISO 8601 timestamp; any trailing Z still represents local time."
            },
            "timezone": {
              "type": [
                "string",
                "null"
              ],
              "description": "Strava timezone text, e.g. (GMT-08:00) America/Los_Angeles; null means unspecified."
            },
            "distance": {
              "type": "number",
              "description": "Distance in meters.",
              "minimum": 0
            },
            "elapsed_time": {
              "type": "integer",
              "description": "Elapsed time in seconds, including stops.",
              "minimum": 0
            },
            "moving_time": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Moving time in seconds; null means unspecified.",
              "minimum": 0
            },
            "total_elevation_gain": {
              "type": [
                "number",
                "null"
              ],
              "description": "Elevation gain in meters; null means unspecified.",
              "minimum": 0
            },
            "description": {
              "type": [
                "string",
                "null"
              ],
              "description": "Activity description; null means unspecified."
            },
            "commute": {
              "type": "integer",
              "description": "Commute flag: 0=false, 1=true.",
              "enum": [
                0,
                1
              ]
            }
          },
          "required": [
            "id",
            "name",
            "sport_type",
            "start_date_local",
            "elapsed_time",
            "distance"
          ],
          "additionalProperties": false
        }
      },
      "activity-updated": {
        "description": "An activity was updated.",
        "schema": {
          "type": "object",
          "properties": {
            "id": {
              "type": "integer",
              "description": "Activity ID."
            },
            "name": {
              "type": "string",
              "description": "Activity name."
            },
            "sport_type": {
              "type": "string",
              "description": "Strava sport type, e.g. Run, Ride, MountainBikeRide, Walk or Swim."
            },
            "start_date": {
              "type": [
                "string",
                "null"
              ],
              "description": "Activity start, UTC ISO 8601 timestamp; null means only local start known."
            },
            "start_date_local": {
              "type": "string",
              "description": "Local wall-clock ISO 8601 timestamp; any trailing Z still represents local time."
            },
            "timezone": {
              "type": [
                "string",
                "null"
              ],
              "description": "Strava timezone text, e.g. (GMT-08:00) America/Los_Angeles; null means unspecified."
            },
            "distance": {
              "type": "number",
              "description": "Distance in meters.",
              "minimum": 0
            },
            "elapsed_time": {
              "type": "integer",
              "description": "Elapsed time in seconds, including stops.",
              "minimum": 0
            },
            "moving_time": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Moving time in seconds; null means unspecified.",
              "minimum": 0
            },
            "total_elevation_gain": {
              "type": [
                "number",
                "null"
              ],
              "description": "Elevation gain in meters; null means unspecified.",
              "minimum": 0
            },
            "description": {
              "type": [
                "string",
                "null"
              ],
              "description": "Activity description; null means unspecified."
            },
            "commute": {
              "type": "integer",
              "description": "Commute flag: 0=false, 1=true.",
              "enum": [
                0,
                1
              ]
            }
          },
          "required": [
            "id",
            "name",
            "sport_type",
            "start_date_local",
            "elapsed_time",
            "distance"
          ],
          "additionalProperties": false
        }
      },
      "activity-deleted": {
        "description": "An activity was deleted.",
        "schema": {
          "type": "object",
          "properties": {
            "id": {
              "type": "integer",
              "description": "Activity ID."
            },
            "name": {
              "type": "string",
              "description": "Activity name."
            },
            "sport_type": {
              "type": "string",
              "description": "Strava sport type, e.g. Run, Ride, MountainBikeRide, Walk or Swim."
            }
          },
          "required": [
            "id",
            "name"
          ],
          "additionalProperties": false
        }
      }
    },
    "listeners": {
      "record-activity": {
        "description": "Record an activity.",
        "schema": {
          "type": "object",
          "properties": {
            "id": {
              "type": "integer",
              "description": "Activity ID; generated when omitted."
            },
            "name": {
              "type": "string",
              "description": "Activity name."
            },
            "sport_type": {
              "type": "string",
              "description": "Strava sport type, e.g. Run, Ride, MountainBikeRide, Walk or Swim."
            },
            "start_date": {
              "type": [
                "string",
                "null"
              ],
              "description": "Activity start, UTC ISO 8601 timestamp; omitted or null means only local start known."
            },
            "start_date_local": {
              "type": "string",
              "description": "Local wall-clock ISO 8601 timestamp; any trailing Z still represents local time."
            },
            "timezone": {
              "type": [
                "string",
                "null"
              ],
              "description": "Strava timezone text, e.g. (GMT-08:00) America/Los_Angeles; omitted or null means unspecified."
            },
            "distance": {
              "type": "number",
              "description": "Distance in meters; omitted defaults to 0.",
              "minimum": 0
            },
            "elapsed_time": {
              "type": "integer",
              "description": "Elapsed time in seconds, including stops.",
              "minimum": 0
            },
            "moving_time": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Moving time in seconds; omitted or null means unspecified.",
              "minimum": 0
            },
            "total_elevation_gain": {
              "type": [
                "number",
                "null"
              ],
              "description": "Elevation gain in meters; omitted or null means unspecified.",
              "minimum": 0
            },
            "description": {
              "type": [
                "string",
                "null"
              ],
              "description": "Activity description; omitted or null means unspecified."
            },
            "commute": {
              "type": "integer",
              "description": "Commute flag: 0=false, 1=true; omitted defaults to 0.",
              "enum": [
                0,
                1
              ]
            }
          },
          "required": [
            "name",
            "sport_type",
            "start_date_local",
            "elapsed_time"
          ],
          "additionalProperties": false
        }
      }
    }
  },
  "x-effects": {
    "record-activity": {
      "table": "activities",
      "emits": "activity-recorded"
    }
  },
  "source": {
    "assets": [
      "index.html",
      "app.js",
      "app.css",
      "ui.css",
      "emits.js",
      "listens.js"
    ]
  }
}