Copy the prompt for Tempisto into an AI assistant. It contains the complete format specification and works without internet access.
Contains the task, the format reference and the examples โ for pasting into an AI assistant.
Build a reusable capability for creating Tempisto files from the following specification, then create the file you need.
You can generate Tempisto files. Build a reusable capability from this
specification and keep it, so you can create further files later without the
instructions again.
Produce exactly one valid JSON document. Output JSON only: no explanation, no
comments, no Markdown code fences.
Task: create one valid Tempisto file for the workout I describe. Use the
session format (`<name>.session.json`) for a single workout, or the plan format
(`<name>.plan.json`) for a schedule of sessions.
## General rules
- Output a single JSON object.
- All durations are ISO 8601 duration strings of the form
`P[nD][T[nH][nM][nS]]`, for example `PT15M`, `PT2M30S`, `PT10S`. Years and
months are not allowed. A duration is always a string, never a number of
seconds.
- Do not add fields that are not listed below.
- Keep the JSON valid and pretty-printed.
## Session format (`tempisto.session/1`)
Top-level fields:
- `format` (string, required): the exact value `tempisto.session/1`.
- `name` (string, required): display name of the session.
- `sport` (string, optional): default `running`.
- `notes` (string, optional): free-form notes.
- `steps` (array, required): at least one step object or repeat block.
- `announcements` (object, optional): voice settings and announcement rules.
- `modifiedEpochMillis` (number, optional): omit it in generated files.
- `archived` (boolean, optional): omit it in generated files.
Step object:
- `type` (string, required): one of `warmup`, `work`, `recovery`, `cooldown`,
`rest`.
- `name` (string, optional).
- `duration` (object, required): exactly one of
- `{ "time": "<ISO duration>" }`
- `{ "distance": { "value": <number>, "unit": "m" | "km" | "mi" } }`
- `{ "until": { "metric": <metric>, "below" | "above": <number>, "for":
"<ISO duration>" }, "maxTime" | "maxDistance": ... }`. The cap `maxTime`
(ISO duration) or `maxDistance` (distance object) is required. `until`
metrics are `power`, `pace`, `speed`, `heart_rate`, `cadence`. Use exactly
one of `below` or `above`.
- `{ "lap": true }`
- `target` (object, optional): one metric as the key, for example
`{ "power": { "relative": [0.65, 0.75] } }`. Metrics: `power`, `pace`,
`speed`, `heart_rate`, `cadence`.
- `announce` (object, optional): `{ "rules": [ ... ] }` with the same rule
shape as below.
Repeat block (allowed anywhere in `steps`, including nested):
- `{ "repeat": <number>, "steps": [ ... ] }`, where `repeat` is at least 1.
Announcements object:
- `voice` (object): `enabled` (boolean), `rate` (number, 0.35 to 0.75, 0.5 is
the default), `duckOtherAudio` (boolean), `voiceIdentifier` (string,
optional), `languageCode` (string, optional, BCP-47).
- `haptics` (boolean).
- `rules` (array): each rule carries
- a trigger, exactly one of
- `{ "every": { "distance": { "value": <number>, "unit": "m" | "km" | "mi"
} } }`
- `{ "every": { "time": "<ISO duration>" } }`
- `{ "on": "step_start" | "step_end" | "target_violation" }`
- `{ "on": "last_seconds", "at": "<ISO duration>" }`
- `say` (array of strings, required): must not be empty.
- `minInterval` (ISO duration, optional).
Announcement fields (`say`): composed fields follow the grammar
`[<scope>_][<aggregate>_]<metric>`, with scope `total`, `step`, `split`, `lap`;
aggregate `avg`, `max`, `min`, `remaining`; and metric `time`, `distance`,
`pace`, `speed`, `power`, `cadence`, `heart_rate`, `elevation`. Standalone
fields: `step_name`, `step_target`, `target_deviation`, `countdown`,
`distance_source`, `step_duration`, `next_step`, `go`, `average_speed`.
Valid examples: `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, required): the exact value `tempisto.plan/1`.
- `name` (string, required).
- `starts` (string, required): `YYYY-MM-DD`.
- `entries` (array, required): each entry carries
- `session` (string, required): file name of a session file.
- `rrule` (string) or `date` (string, `YYYY-MM-DD`) โ exactly one of the two.
- `rrule` is an iCal recurrence rule such as
`FREQ=WEEKLY;BYDAY=MO,WE;COUNT=16`.
## Complete example: 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"
}
]
}
}
```
## Complete example: 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" }
]
}
```
## Check before you answer
- The `format` value matches the file type exactly.
- Every duration is an ISO 8601 string.
- Every plan entry has `rrule` or `date`, never both and never neither.
- Every `say` array is non-empty.
- An `until` step has `maxTime` or `maxDistance`.
- Every `repeat` count is at least 1.
- The output is JSON only.
Store the capability internally without printing it. Then output only the JSON
for the file I describe.
---
Format reference
# Tempisto file formats
Tempisto uses two JSON documents:
- Session (`.session.json`) โ one workout.
- Plan (`.plan.json`) โ a schedule of sessions.
All durations are ISO 8601 duration strings of the form
`P[nD][T[nH][nM][nS]]`, for example `PT15M`, `PT2M30S`, `PT10S`. Years and
months are not allowed. A duration is always written as a string, never as a
number of seconds.
## Session file (`.session.json`)
Top-level object:
- `format` (string, required): must be `tempisto.session/1`.
- `name` (string, required): display name of the session.
- `sport` (string, optional): default `running`.
- `notes` (string, optional): free-form notes.
- `steps` (array, required): list of step objects or repeat blocks. At least
one step.
- `announcements` (object, optional): voice settings and announcement rules.
- `modifiedEpochMillis` (number, optional): last edit time in epoch
milliseconds. Written by the editors; hand-written files may omit it.
- `archived` (boolean, optional): archived sessions stay on disk and stay
referenced by plans, they only leave the pickers.
### Step object
- `type` (string, required): one of `warmup`, `work`, `recovery`, `cooldown`,
`rest`.
- `name` (string, optional): custom name of the step.
- `duration` (object, required): exactly one of the following forms.
- `{ "time": "<ISO duration>" }` โ a fixed time.
- `{ "distance": { "value": <number>, "unit": "m" | "km" | "mi" } }` โ a
fixed distance.
- `{ "until": { "metric": <metric>, "below" | "above": <number>, "for":
"<ISO duration>" }, "maxTime" | "maxDistance": ... }` โ ends when a
condition holds, capped by `maxTime` (an ISO duration) or `maxDistance` (a
distance object). The cap is required.
- `until` metrics: `power`, `pace`, `speed`, `heart_rate`, `cadence`.
- Use exactly one of `below` or `above`. `for` is optional and is the time
the condition must hold.
- `{ "lap": true }` โ ends when the lap control is pressed.
- `target` (object, optional): one metric as the key, for example
`{ "power": { "relative": [0.65, 0.75] } }`. Metrics: `power`, `pace`,
`speed`, `heart_rate`, `cadence`.
- `announce` (object, optional): `{ "rules": [ ... ] }` with the same rule
shape as `announcements.rules`.
### Repeat block
- `{ "repeat": <number>, "steps": [ ... ] }`
- `repeat` is the number of repetitions (1 or more).
- Blocks nest: the `steps` of a repeat block may hold step objects or further
repeat blocks.
### Announcements object
- `voice` (object):
- `enabled` (boolean)
- `rate` (number, 0.35 to 0.75), where 0.5 is the system default
- `duckOtherAudio` (boolean)
- `voiceIdentifier` (string, optional)
- `languageCode` (string, optional), a BCP-47 tag
- `haptics` (boolean)
- `rules` (array): each rule carries
- a trigger, exactly one of
- `{ "every": { "distance": { "value": <number>, "unit": "m" | "km" |
"mi" } } }`
- `{ "every": { "time": "<ISO duration>" } }`
- `{ "on": "step_start" | "step_end" | "target_violation" }`
- `{ "on": "last_seconds", "at": "<ISO duration>" }`
- `say` (array of strings, required): the announcement fields. The list must
not be empty.
- `minInterval` (ISO duration, optional): minimum time between two firings of
the rule.
### Announcement fields (`say`)
Composed fields follow the grammar `[<scope>_][<aggregate>_]<metric>`:
- scope: `total`, `step`, `split`, `lap`
- aggregate: `avg`, `max`, `min`, `remaining`
- metric: `time`, `distance`, `pace`, `speed`, `power`, `cadence`,
`heart_rate`, `elevation`
Standalone fields: `step_name`, `step_target`, `target_deviation`, `countdown`,
`distance_source`, `step_duration`, `next_step`, `go`, `average_speed`.
Examples of valid fields: `step_name`, `step_target`, `countdown`,
`step_avg_power`, `step_time`, `split_avg_pace`, `total_distance`,
`total_avg_power`, `total_time`, `target_deviation`.
## Plan file (`.plan.json`)
Top-level object:
- `format` (string, required): must be `tempisto.plan/1`.
- `name` (string, required).
- `starts` (string, required): plan start date as `YYYY-MM-DD`.
- `entries` (array, required): each entry carries
- `session` (string, required): file name of a session file.
- `rrule` (string) or `date` (string, `YYYY-MM-DD`) โ exactly one of the two.
- `rrule` is an iCal recurrence rule, for example
`FREQ=WEEKLY;BYDAY=MO,WE;COUNT=16`.
## Examples
`5x1000.session.json`:
```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"
}
]
}
}
```
`base-build.plan.json`:
```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" }
]
}
```
## Rules
- Durations are strings in ISO 8601 form; years and months are not allowed.
- A plan entry has `rrule` or `date`, never both and never neither.
- A rule that says nothing has no effect: `say` must not be empty.
- `target_deviation` only reads correctly inside a `target_violation` rule.
- A timed step and a distance step must be longer than zero.
- An `until` step without `maxTime` or `maxDistance` is not valid.
- A `repeat` count must be at least 1.
---
Examples
5x1000.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" }
]
}
}
base-build.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" }
]
}