# KI-Prompt fuer Tempisto-Dateien

Kopiere alles unterhalb der Linie in deine KI. Der Text ist
selbsterklaerend und benoetigt keinen Internetzugang.

---

Du kannst Tempisto-Dateien erzeugen. Baue aus dieser Spezifikation
eine wiederverwendbare Faehigkeit, die du behaeltst, damit du spaeter weitere
Dateien ohne erneute Anleitung erzeugen kannst.

Erzeuge genau ein gueltiges JSON-Dokument. Gib nur JSON aus:
keine Erklaerung, keine Kommentare, keine Markdown-Codebloecke.

Aufgabe: Erzeuge eine gueltige Tempisto-Datei fuer das von mir
beschriebene Training. Verwende das Session-Format
(`<name>.session.json`) fuer ein einzelnes Training oder das Plan-Format
(`<name>.plan.json`) fuer einen Zeitplan aus Sessions.

## Allgemeine Regeln

- Gib ein einzelnes JSON-Objekt aus.
- Alle Dauern sind ISO-8601-Dauerstrings der Form `P[nD][T[nH][nM][nS]]`, zum
  Beispiel `PT15M`, `PT2M30S`, `PT10S`. Jahre und Monate sind nicht erlaubt.
  Eine Dauer ist immer ein String, nie eine Sekundenzahl.
- Fuege keine Felder hinzu, die unten nicht aufgefuehrt sind.
- Halte das JSON gueltig und lesbar formatiert.

## Session-Format (`tempisto.session/1`)

Felder auf oberster Ebene:

- `format` (String, Pflicht): exakt der Wert `tempisto.session/1`.
- `name` (String, Pflicht): Anzeigename der Session.
- `sport` (String, optional): Standard `running`.
- `notes` (String, optional): freie Notizen.
- `steps` (Array, Pflicht): mindestens ein Step-Objekt oder Repeat-Block.
- `announcements` (Objekt, optional): Sprach-Einstellungen und Ansageregeln.
- `modifiedEpochMillis` (Zahl, optional): in erzeugten Dateien weglassen.
- `archived` (Bool, optional): in erzeugten Dateien weglassen.

Step-Objekt:

- `type` (String, Pflicht): eines von `warmup`, `work`, `recovery`, `cooldown`,
  `rest`.
- `name` (String, optional).
- `duration` (Objekt, Pflicht): genau eine der Formen
  - `{ "time": "<ISO-Dauer>" }`
  - `{ "distance": { "value": <Zahl>, "unit": "m" | "km" | "mi" } }`
  - `{ "until": { "metric": <Metrik>, "below" | "above": <Zahl>, "for":
"<ISO-Dauer>" }, "maxTime" | "maxDistance": ... }`. Die Begrenzung
    `maxTime` (ISO-Dauer) oder `maxDistance` (Distanz-Objekt) ist Pflicht.
    Metriken fuer `until` sind `power`, `pace`, `speed`, `heart_rate`,
    `cadence`. Verwende genau eines von `below` oder `above`.
  - `{ "lap": true }`
- `target` (Objekt, optional): eine Metrik als Schluessel, zum Beispiel
  `{ "power": { "relative": [0.65, 0.75] } }`. Metriken: `power`, `pace`,
  `speed`, `heart_rate`, `cadence`.
- `announce` (Objekt, optional): `{ "rules": [ ... ] }` mit derselben
  Regelform wie unten.

Repeat-Block (ueberall in `steps` erlaubt, auch verschachtelt):

- `{ "repeat": <Zahl>, "steps": [ ... ] }`, wobei `repeat` mindestens 1 ist.

Announcements-Objekt:

- `voice` (Objekt): `enabled` (Bool), `rate` (Zahl, 0.35 bis 0.75, Standard
  0.5), `duckOtherAudio` (Bool), `voiceIdentifier` (String, optional),
  `languageCode` (String, optional, BCP-47).
- `haptics` (Bool).
- `rules` (Array): jede Regel traegt
  - einen Trigger, genau einen von
    - `{ "every": { "distance": { "value": <Zahl>, "unit": "m" | "km" | "mi"
} } }`
    - `{ "every": { "time": "<ISO-Dauer>" } }`
    - `{ "on": "step_start" | "step_end" | "target_violation" }`
    - `{ "on": "last_seconds", "at": "<ISO-Dauer>" }`
  - `say` (Array aus Strings, Pflicht): darf nicht leer sein.
  - `minInterval` (ISO-Dauer, optional).

Ansage-Felder (`say`): Zusammengesetzte Felder folgen der Grammatik
`[<scope>_][<aggregate>_]<metric>`, mit scope `total`, `step`, `split`, `lap`;
aggregate `avg`, `max`, `min`, `remaining`; und metric `time`, `distance`,
`pace`, `speed`, `power`, `cadence`, `heart_rate`, `elevation`.
Standalone-Felder: `step_name`, `step_target`, `target_deviation`, `countdown`,
`distance_source`, `step_duration`, `next_step`, `go`, `average_speed`.
Gueltige Beispiele: `step_name`, `step_target`, `countdown`, `step_avg_power`,
`step_time`, `split_avg_pace`, `total_distance`, `total_avg_power`,
`total_time`, `target_deviation`.

## Plan-Format (`tempisto.plan/1`)

- `format` (String, Pflicht): exakt der Wert `tempisto.plan/1`.
- `name` (String, Pflicht).
- `starts` (String, Pflicht): `YYYY-MM-DD`.
- `entries` (Array, Pflicht): jeder Eintrag traegt
  - `session` (String, Pflicht): Dateiname einer Session-Datei.
  - `rrule` (String) oder `date` (String, `YYYY-MM-DD`) — genau eines von
    beiden.
  - `rrule` ist eine iCal-Wiederholungsregel wie
    `FREQ=WEEKLY;BYDAY=MO,WE;COUNT=16`.

## Vollstaendiges Beispiel: Session

```json
{
  "format": "tempisto.session/1",
  "name": "5 × 1000 m @ CP",
  "sport": "running",
  "notes": "Keep the recoveries honest.",
  "steps": [
    {
      "type": "warmup",
      "duration": { "time": "PT15M" },
      "target": { "power": { "relative": [0.65, 0.75] } }
    },
    {
      "repeat": 5,
      "steps": [
        {
          "type": "work",
          "name": "1000 m",
          "duration": { "distance": { "value": 1000, "unit": "m" } },
          "target": { "power": { "relative": [0.98, 1.02] } },
          "announce": {
            "rules": [
              { "on": "step_start", "say": ["step_name", "step_target"] },
              { "on": "last_seconds", "at": "PT10S", "say": ["countdown"] },
              { "on": "step_end", "say": ["step_avg_power", "step_time"] }
            ]
          }
        },
        {
          "type": "recovery",
          "duration": {
            "until": { "metric": "heart_rate", "below": 130, "for": "PT10S" },
            "maxTime": "PT3M"
          }
        }
      ]
    },
    { "type": "cooldown", "duration": { "time": "PT10M" } }
  ],
  "announcements": {
    "voice": { "enabled": true, "rate": 0.5, "duckOtherAudio": true },
    "haptics": true,
    "rules": [
      {
        "every": { "distance": { "value": 500, "unit": "m" } },
        "say": ["split_avg_pace", "total_distance"]
      },
      { "every": { "time": "PT5M" }, "say": ["total_avg_power", "total_time"] },
      {
        "on": "target_violation",
        "say": ["target_deviation"],
        "minInterval": "PT20S"
      }
    ]
  }
}
```

## Vollstaendiges Beispiel: Plan

```json
{
  "format": "tempisto.plan/1",
  "name": "Base build, 8 weeks",
  "starts": "2026-08-10",
  "entries": [
    {
      "session": "easy-45.session.json",
      "rrule": "FREQ=WEEKLY;BYDAY=MO,WE;COUNT=16"
    },
    {
      "session": "5x1000.session.json",
      "rrule": "FREQ=WEEKLY;BYDAY=TU;COUNT=8"
    },
    {
      "session": "long-run.session.json",
      "rrule": "FREQ=WEEKLY;BYDAY=SU;COUNT=8"
    },
    { "session": "benchmark.session.json", "date": "2026-10-04" }
  ]
}
```

## Pruefung vor der Antwort

- Der `format`-Wert entspricht exakt dem Dateityp.
- Jede Dauer ist ein ISO-8601-String.
- Jeder Plan-Eintrag hat `rrule` oder `date`, nie beides und nie keines von
  beiden.
- Jedes `say`-Array ist nicht leer.
- Ein `until`-Step hat `maxTime` oder `maxDistance`.
- Jeder `repeat`-Wert ist mindestens 1.
- Die Ausgabe ist nur JSON.

Lege die Faehigkeit intern ab, ohne sie auszugeben. Gib danach
nur das JSON fuer die von mir beschriebene Datei aus.
