Skip to main content
Glama
737,267 tools. Updated 2026-11-02 19:45

"TUI" matching MCP tools:

  • Legt geplante Einheiten im Kalender an — die Grundlage fuer jeden Soll-Ist-Vergleich. Mehrere Einheiten in einem Aufruf (bis 28, also vier Wochen). Der Aufruf ist idempotent: existiert am selben Tag bereits eine Einheit derselben Sportart mit demselben Titel, wird sie uebersprungen statt verdoppelt — ein Wiederholungsversuch nach einem Timeout ist also gefahrlos. Die angelegten Einheiten werden vom Import automatisch mit passenden Aktivitaeten verknuepft; danach zeigt training_stats mit include_planned den Abgleich. **Die Intervallstruktur gehoert in steps, nicht in notes.** Nur Schritte landen auf der Uhr: der Garmin-Versand baut daraus Aufwaermen, Intervalle, Erholung und Auslaufen mit eigenen Zielwerten. Ohne Schritte wird daraus ein einziger Block ueber die Gesamtdauer, und der Athlet sieht unterwegs nur eine Zahl. notes ist fuer Hinweise an den Athleten -- Absicht der Einheit, Gefuehl, Technik. Je Schritt **entweder** Dauer **oder** Distanz -- beides zusammen ist auf der Uhr mehrdeutig, sie beendet den Schritt beim ersten erreichten Kriterium. **Ohne Dauer und ohne Distanz laeuft der Schritt bis zur Rundentaste.** Das ist kein fehlender Wert, sondern die saubere Form fuer Pausen und Technikbloecke: der Athlet druckt, wenn er soweit ist. Fuer kurze Pausen mit fester Laenge gibt es duration_sec (Sekunden), weil duration_min ganze Minuten sind und 10-30 s im Schwimmen der Normalfall. **Beim Schwimmen distance_m statt distance_km** -- distance_km: 0.05 fuer ein 50er ist einen Nulldreher vom 500er entfernt. Und **stroke/equipment gehoeren als Felder mit, nicht in notes**: nur so steht auf der Uhr "Drill" oder "Paddles" und nicht bloss "100 m". Beides wirkt nur bei sport: SWIM. **Ziele sind Spannen, keine Punkte** (target.low / target.high). Garmin verlangt ohnehin ein Fenster und hat es sich bisher aus dem Einzelwert erfunden. Bei pace ist low der *schnellere* Wert; numerisch gilt immer low <= high. **Relativ planen ist der bessere Weg**: ftp_pct, lthr_pct und threshold_pace_pct werden **beim Anlegen** gegen die Schwellenwerte aus training_profile aufgeloest und **absolut** gespeichert. Ein spaeterer FTP-Test verschiebt damit keine alte Planung rueckwirkend; was gewuenscht war und wogegen aufgeloest wurde, bleibt in target_source nachlesbar. Fehlt der Schwellenwert, bleibt das Ziel leer und die Antwort sagt es — geraten wird nichts. **threshold_pace_pct ist Prozent der Schwellengeschwindigkeit, nicht der Pace** — mehr Prozent ist **schneller**. Langsamer als die Schwelle sind damit Werte **unter** 100, nicht darueber. Wer die Skala als Zeit pro Kilometer liest, schreibt 130-148 fuer eine lockere Einheit und bekommt bei einer Schwelle von 3:46/km 2:32-2:54/km — das ist der haeufigste Fehler an diesem Feld. Richtwerte Laufen: Trabpause / Regeneration 62-72 Tempodauerlauf 88-94 Ein- und Auslaufen 70-80 Schwelle 98-102 GA1 / lockerer Dauerlauf 72-80 kurze Reize (30-60 s) 105-112 Angenommen werden nur 60-120; alles darueber weist der Server ab. **Nach dem Anlegen gegenlesen:** der erzeugte Titel nennt die aufgeloeste Pace ("40 min @ 4:42-5:13/km"). Steht dort etwas um 2:30-3:00 fuer eine lockere Einheit, ist die Skala verdreht. Beim Schwimmen loest es gegen die CSS auf, **wenn** eine im Profil steht (training_profile, swim_css_pace_sec_per_100m) — sie wird nicht berechnet, sondern vom Athleten gesetzt. Fehlt sie, faellt das Ziel aus und die Antwort sagt es. **Wiederholungen als Block**: { repeat: 8, label: "400er", steps: [...] } statt achtmal derselbe Schritt — "3 x (1 km zuegig + 1 min Pause)" ist ein Eintrag, kein sechsfacher. training_plan_list gibt sie in derselben Form zurueck ("3 x:" mit den Schritten darunter), obwohl sie flach gespeichert werden. Der Server rollt sie aus und nummeriert "(1/8)"; auf der Uhr entsteht daraus wieder eine echte Wiederholungsgruppe, also "Intervall 2 von 8" statt "Schritt 5 von 20". Ein Block darf einen Block enthalten -- **zwei Ebenen**, also 2 x (4 x 50 + 100 locker), wie Schwimmsaetze geschrieben werden. Tiefer geht es nicht; auf der Uhr steht ohnehin eine flache Liste. Args: - sessions (array, 1-28): - date (string): YYYY-MM-DD - sport (string): SWIM | BIKE | RUN | LONGRUN | STRENGTH | MOBILITY | YOGA | HIIT | CARDIO | WALK | HIKE | ALPINE_SKI | NORDIC_SKI | SOCCER | RACKET | OTHER - title (string): 1-120 Zeichen - start_time (string, optional): "HH:MM" in der **Ortszeit des Athleten** (die Zone steht in training_profile, time_zone). Schliesst time_of_day aus. - time_of_day (string, optional): MORNING | AFTERNOON | EVENING — der Tag steht, die Uhrzeit noch nicht. Schliesst start_time aus. - duration_min (number, optional) - distance_km (number, optional) - intensity (string, default EASY): EASY | MODERATE | HARD | VERY_HARD - notes (string, optional): Markdown, Hinweise an den Athleten (NICHT die Struktur) - pool_length_m (number, 10-100, optional, nur SWIM): Beckenlänge in Metern. Geht mit training_plan_push_garmin auf die Uhr, damit sie die Bahnen richtig zählt; fehlt sie, nimmt die Uhr ihre eigene Einstellung. Das übliche Becken des Athleten steht in training_get einer früheren Schwimmeinheit (Abschnitt "Becken"). - brick (boolean, optional): Koppeleinheit, verknuepft mit der Radeinheit desselben Tages (der zuletzt beginnenden mit duration_min, auch aus diesem Aufruf; dort zuerst das Rad auffuehren). Hat das Rad eine feste Uhrzeit, beginnt der Lauf an dessen Ende; steht es in einem Tagesfach, steht der Lauf im selben Fach direkt dahinter. Verschiebt training_plan_update das Rad, wandert der Lauf mit. Schliesst start_time und time_of_day aus. Ohne brick meldet die Ueberschneidungspruefung Rad und Lauf als Konflikt. Gibt es kein Rad, wird die Einheit uebersprungen. - steps (array, optional): die Intervallstruktur. Ein Eintrag ist entweder ein Schritt oder ein Wiederholungsblock; nach dem Ausrollen hoechstens 120 Schritte. Schritt: - type (string, default WORK): WARM_UP | WORK | RECOVERY | COOL_DOWN | REST | CUSTOM - title (string, optional): 1-120 Zeichen. Fehlt er, wird er aus Groesse und Ziel gebaut. - label (string, optional): "Sweet Spot", "locker" — Ersatztitel, wenn title fehlt - duration_min (integer, optional): **ganze Minuten** - duration_sec (integer, 5-3600, optional): Sekunden. Schliesst duration_min aus. - distance_km (number, optional) / distance_m (integer, optional): schliessen einander aus - stroke (string, optional, nur SWIM): free | backstroke | breaststroke | butterfly | drill | im | mixed | any | im_by_round - equipment (string, optional, nur SWIM): fins | kickboard | paddles | pull_buoy | snorkel - exercise (string, optional, nur STRENGTH): Uebung aus Garmins Katalog, **englisch** wie in Garmin Connect ("Barbell Back Squat", "Push-up", "Plank") oder als KATEGORIE/UEBUNG. Ein unbekannter Name wird abgelehnt, die Fehlermeldung nennt passende Katalognamen. - reps (integer, 1-500, optional, nur STRENGTH): Wiederholungen — der Schritt endet auf der Uhr danach. Schliesst duration_* und distance_* aus; eine Halteuebung (Plank) nimmt stattdessen duration_sec. - weight_kg (number, optional, nur STRENGTH): Zielgewicht Ein Satzblock ist ein Wiederholungsblock: { repeat: 3, steps: [{ exercise, reps: 10, weight_kg: 40 }, { type: REST, duration_sec: 90 }] }. - target (object, optional): { type, low, high } absolut: power (W) | pace (s/km, Schwimmen s/100m; auch "4:30") | hr (bpm) | zone (1-6) | rpe (1-10) relativ: ftp_pct (30-200) | lthr_pct (50-130) | threshold_pace_pct (60-120) Prozent, wird beim Anlegen aufgeloest. ftp_pct und lthr_pct sind intuitiv (mehr = haerter); threshold_pace_pct ist Prozent der Geschwindigkeit, dort ist mehr = schneller und "locker" liegt bei 72-80, nicht bei 130. - target_pace / target_heart_rate / target_power (optional): Kurzform fuer ein Punktziel - notes (string, optional) Fehlen Dauer *und* Distanz, endet der Schritt auf Tastendruck (Lap-Taste). Wiederholungsblock: - repeat (integer, 2-40): wie oft - label (string, optional): Name des Blocks, z.B. "400er" - steps (array, 1-20): Schritte **oder** ein weiterer Wiederholungsblock (zweite Ebene) Steht am selben Tag schon eine Einheit derselben Sportart mit **anderem** Titel, wird die neue trotzdem angelegt — zwei Einheiten je Tag sind zulaessig — und die Antwort nennt die bestehende id unter warnings. War eine Korrektur gemeint, ist training_plan_update der richtige Weg. **Renntage:** liegt eine HARD/VERY_HARD-Einheit, ein Test ("Test" im Titel) oder eine Einheit über 90 min am Tag eines geplanten Rennens oder am Tag davor, wird sie trotzdem angelegt — warnings nennt das Rennen. Die Renntage im Fenster zeigt training_plan_list. Auf die Uhr kommt der Plan erst mit training_plan_push_garmin. Returns: { created: [{ id, date, sport, title }], skipped: [{ date, sport, title, reason }], warnings: [...] }
    ConnectorOAuth
  • Listet die Rennen des Athleten mit Prioritaet (A/B/C), Format, Distanzen, Hoehenmetern, Zielzeit und Status. **Standard: die kommenden Rennen**, naechstes zuerst. include_past: true zeigt auch vergangene — dort heisst status PLANNED "kein Ergebnis erfasst", nicht "verpasst". A-Rennen sind die Saisonziele, auf die ein Plan zielt; B-Rennen ernsthafte Formtests, C-Rennen Trainingswettkaempfe. Dieselbe Tabelle wie der Rennplaner der App. training_profile nennt das naechste A-Rennen, training_plan_list markiert Renntage. Args: - id (string, optional): genau ein Rennen; schlaegt alle Filter - from / to (string, optional): Fenster YYYY-MM-DD, Kalendertage des Athleten - include_past (boolean, default false): auch vergangene Rennen - priority (string, optional): A | B | C - limit (number): 1-100, default 20 Returns: { count, has_more, items: [{ id, name, date, start_time, days_until, location, sport, format, draft_legal, swim_km, bike_km, run_km, total_km, bike_elevation_m, run_elevation_m, course_elevation_m, priority, goal_time, goal_time_sec, personal_goal, notes, status, activity_id, result_time, goal_splits: { swim, t1, bike, t2, run }, swim_water_temp_c, checkpoints: [{ name, date_from, date_to, targets: { css, ftp, run_threshold_pace } }] }] } checkpoints tragen css und run_threshold_pace in Sekunden (je 100 m bzw. km), ftp in Watt. Soll-Ist und Rennprognose liefert training_race_prognosis.
    ConnectorOAuth
  • Triage one build, resolved by commitSha, prNumber, or buildId (exactly one). Returns the gate verdict and counts (total/changed/failed/unchanged), then the FIRST page (25) of the changed stories (story id, viewport, % pixels changed, review decision, the AI verdict aiVerdict=intended|regression + aiConfidence, and for a regression the judge's one-line aiFlagReason=what-looks-unintended, when AI review is on, and the story's own review-comment tally comments {total, unresolved}) and the first page of failed stories (failedStories[].kind is `render` when the story produced no frame, or `interaction` when it rendered and its play() assertion threw; failedStories[].error is the message's first line, errorTruncated marks the ones that carried more). When AI review ran, aiReview tallies how many changes look like regressions vs intended, and the changed list is ordered likely-regressions-first. changedNextCursor / failedNextCursor are non-null when there are more than 25: page the rest with list_build_stories. counts.unchanged is how many stories did NOT change and have a baseline - this triage call does NOT list them (keeps the response lean); call list_build_stories status=unchanged to browse them (e.g. to confirm a passed build's stories are 'identical to baseline'). comments is the build-wide review-comment tally {total, unresolved}: unresolved>0 means a designer/QA (or another agent) left an open note on a story - read it with list_comments BEFORE you accept. No image URLs here - call get_diff or render_diff_image for pixels.
    ConnectorNo auth
  • Page through one build's stories filtered by status (resolved by commitSha/prNumber/buildId). Use it to read past get_build's first page, or to browse the unchanged/passed stories get_build only counts. status='changed' returns changed stories (same shape + order as get_build, regression-first, each with its comments {total, unresolved}; unresolved>0 means an open review note - read it with list_comments first); status='failed' returns failed stories; status='unchanged' returns the stories that did NOT change this build but have a baseline on this branch (storyId, viewport, browser) - fetch any of their images by storyId with get_diff or render_diff_image to confirm 'identical to baseline'. Returns { stories, nextCursor }: pass nextCursor back as `cursor` for the next page; null means no more. limit defaults to 25 (max 100). Unchanged is only available once the build has settled (an in-progress build has rendered nothing, so it returns an empty page).
    ConnectorNo auth
  • The cumulative 'this PR vs base' visual changeset (resolved by commitSha/prNumber/buildId) - what the whole PR does to the UI versus the branch it merges into, INDEPENDENT of what is left to review on the latest build. Unlike get_build (this commit vs the branch's own accepted baseline), this survives in-PR accepts: a story accepted mid-PR still shows under `changed` with status=accepted, so it answers 'what did this PR change' even after the gate reads clean. Returns base (the branch it merges into), counts {new,changed,removed,unchanged}, and the first page of `new` + `changed` + `removed` stories (storyId, title, name, kind, review status, aiVerdict). `removed` lists stories that HAD a baseline on the base branch but are gone from this PR's head (a deletion - otherwise invisible; each carries lastBuildId, the build that rendered its now-orphaned baseline). newNextCursor / changedNextCursor / removedNextCursor page the rest with list_pr_stories. No image URLs - fetch pixels by storyId with get_diff / render_diff_image.
    ConnectorNo auth
  • Page through the PR-vs-base changeset stories of one kind (resolved by commitSha/prNumber/buildId) - use it to read past get_pr_changeset's first page. kind='new' returns stories the PR adds that the base branch has no baseline for; kind='changed' returns stories whose image differs from the base branch's accepted image (even if accepted mid-PR, with status=accepted); kind='removed' returns stories that HAD a baseline on the base branch but are gone from head (a deletion; each carries lastBuildId, not a review status or verdict). Returns { stories, nextCursor }: pass nextCursor back as `cursor` for the next page; null means no more. limit defaults to 25 (max 100).
    ConnectorNo auth

Matching MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    What Chrome DevTools MCP is for the browser, tui-mcp is for the terminal. Launch any TUI app, take screenshots, send keystrokes, read text - works with any framework.
    13
    43 npm
    15
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for creating interactive terminal canvases (calendar, document, flight) in AI coding assistants. Supports multiple TUI frameworks and integrates with tmux.
    MIT

Matching MCP Connectors

  • Per-story diff detail for a build (resolved by commitSha/prNumber/buildId). Returns diff metrics and presigned, time-limited URLs (download them to a file, or link them in a PR comment) for the baseline, candidate, and diff PNGs. Defaults to the changed stories; pass storyId for one specific story. When that storyId is an UNCHANGED story it returns its baseline (diffResultId null, changed false, the baseline URL as both baselineUrl and candidateUrl) - the story rendered identical to baseline. Use render_diff_image instead when you want the actual pixels inline for a vision model, not a URL. When AI review is on, each diff carries the judge's call: aiVerdict (intended|regression), aiConfidence, aiSummary (what changed), aiReasoning, and aiFlagReason; all null when AI review didn't run for it. Each diff also carries comments {total, unresolved} for THAT story - unresolved>0 means an open review note; read the thread with list_comments before accepting.
    ConnectorNo auth
  • Record a review on a single diff result (get diffResultId from get_build/get_diff). 'accept' makes the candidate the new baseline for that story on its branch, so the next build is clean; 'deny' records the rejection without changing the baseline; 'ignore' excludes the story from the gate persistently (the snapshot keeps differing on future builds but no longer flags the check) — use it for an intentional, ongoing diff like an animation or a live timestamp. This is the same accept/deny/ignore as the dashboard, attributed to the agent (and to you, when you logged in). Use after you've inspected the diff (e.g. with render_diff_image) and decided intended vs. regression. accept and ignore are refused while the story has an unresolved review comment (read it with list_comments, address it, resolve_comment the thread, then retry); deny is always allowed.
    Connector
    Destructive
    No auth
  • A natural-language instruction to the project's Director — the same chat turn the human director types: the planner reads the instruction, picks the ops (rewrite_scene / set_scene_fields / set_visual / swap_voice / replan_scenes / tighten_hook) and applies them to the staged draft. Suited to an editorial change that spans several fields or scenes («make scene 3 quote the source verbatim and shorten the closing»); a single exact op has its own tools. The call waits up to 60 s for the turn (50 of the 58 turns measured finished within that) and answers with the reply, the staged ops and the coherence report (`outcome: completed_inline`); a longer turn keeps running and the answer is its job (`outcome: still_running`, `runId`), which the project status reports by `run_id`. An identical call while the turn runs, or within 15 minutes after it succeeded, returns the same job, so a retry does not pay a second turn; `request_id` names a deliberately repeated request. One authoring turn at a time per project (`authoring-in-progress`). The staged draft becomes a version when it is committed. Requires `write`. Spends LLM budget (charged like a chat turn); a turn whose planned edits all fail stages nothing and is not charged (`editOutcome: none_applied`).
    Connector
    Destructive
    API key
  • Rewrites the WHOLE piece under the brief with the format's writer (the same revision pass the writing pipeline runs), then re-dresses only the scenes whose narration changed (visuals are kept). It covers a brief that spans the piece («more rhythm in the second act, and let the ending return to the thesis»); a single scene has its own re-authoring op. Asynchronous: returns a run id, and the project status reports the job by `run_id` — once `completed`, with the new version id (`job.result.editorialVersionId`, also in `latestRunByKind.editorial_rewrite`). `as_branch=false` (default) makes the result THE CUT the line renders, as committing a draft does. Writers that require spend confirmation need `confirm_spend=true`. Requires `write`. Spends LLM budget: a full script pass, priced like the writing profile of the piece (`writingProfiles[].measure` in the catalogue of formats).
    Connector
    Destructive
    API key
  • Aggregiert Dauer, Distanz und TSS pro Kalenderwoche (Montag-basiert) und pro Sportart. Das Tool für Trend-Fragen ("läuft mein Aufbau?", "wie entwickelt sich mein Umfang?") — es ersetzt dutzende Einzelabfragen. Einheiten mit excluded_from_stats werden ignoriert. Args: - from (string, optional): Startdatum YYYY-MM-DD - to (string, optional): Enddatum YYYY-MM-DD - sport (string, optional): auf eine Sportart einschraenken - include_planned (boolean, default false): stellt die geplanten Einheiten aus dem Kalender daneben Bei include_planned kommen je Woche planned_sessions / done_sessions / missed_sessions / unplanned_sessions dazu — und **planned_tss neben der Ist-TSS (tss)**, je Woche und je Woche x Sportart (weeks[].by_sport). planned_tss wird aus den Schritten gegen die heutige Schwelle gerechnet (wie in training_plan_list); planned_tss_estimated ist der davon nur geschaetzte Anteil (Dauer x Label, Schwimmen ohne CSS), planned_without_tss die Einheiten ohne jede Grundlage. Verpasste Einheiten zaehlen im Plan mit. In weeks[].by_sport zaehlt LONGRUN als RUN (geplant LONGRUN, gelaufen RUN). Fuer die Wirkung auf CTL/ATL/TSB bis zum Rennen: training_load_projection. Returns: { total: { activities, duration_min, distance_km, tss, planned? }, by_sport: [{ sport, ..., planned_tss? }], weeks: [{ week_start, ..., planned_tss?, planned_tss_estimated?, by_sport?: [{ sport, tss, planned_tss }] }] } `week_start` ist immer ein Montag (YYYY-MM-DD). Tage und Wochen gelten in der Zeitzone aus dem Athletenprofil (training_profile → time_zone), nicht in UTC.
    ConnectorOAuth
  • Liefert die Referenzwerte, gegen die alle anderen Tools rechnen: Schwellenwerte, HF- und Pace-Zonen, Körpermasse, Trainingsvorgaben — **jeweils mit Herkunft** (AUTO = aus den eigenen Einheiten geschätzt, MANUAL = vom Athleten gesetzt). Lies dieses Tool, bevor du Zahlen aus training_get einordnest: die HF-Zonen dort stammen aus genau diesen Werten. Args: keine Returns: { thresholds (inkl. time_zone), auto, manual, trend, hr_zones, run_pace_zones, body, training, next_a_race, predictions } next_a_race ist das naechste geplante A-Rennen ab heute samt days_until (Kalendertage in der Zone des Athleten), Format, Distanzen und Zielzeit — oder null. Alle Rennen und Ziele liefert training_race_list. thresholds.bike_ftp / run_threshold_pace / swim_css sind { watts | sec_per_km | sec_per_100m, source, set_at }: der geltende Wert, seine Herkunft und sein Stand (AUTO: Montag der Wochenreihe, MANUAL: letzte Änderung, null = unbekannt). Es gilt die vom Athleten gewählte Quelle; ist sie leer, die andere. training_get (Stream-Analyse, thresholds_used) und relative Ziele rechnen mit genau diesen Werten. time_zone ist die Zone, in der training_plan_create eine start_time liest. Fehlende Werte sind null und werden nicht geschätzt. Nur lesend. Nach einem Test (FTP, CSS 400/200, Laufschwelle) setzt training_profile_update den neuen Wert — vor dem Anlegen der nächsten Wochen, sonst lösen relative Ziele gegen den alten auf.
    ConnectorOAuth
  • Korrigiert die Markierungen einer bereits importierten Einheit. **Sport und Distanz werden gegen den Strava-Sync gesperrt.** Wer sie hier korrigiert, dessen Wert ueberlebt jeden kuenftigen Strava-Edit — der Import laesst gesperrte Spalten und alles daraus Abgeleitete (Pace, TSS) in Ruhe. Die TSS wird nicht neu gerechnet. Dauer, Datum und Titel bleiben ungeschuetzt und werden weiterhin von Strava ueberschrieben. Zum Loeschen einer Einheit: es gibt keins. Der naechste Strava-Sync legt sie wieder an. Wer eine Einheit aus allen Statistiken haben will, setzt excluded_from_stats auf true — die Zeile bleibt, zaehlt aber nirgends mit. Fuer Text zu einer Einheit ist dieses Tool nicht zustaendig. Der Weg, eine AI note an eine Aktivität zu hängen, ist training_write_note mit related: [id] — sie erscheint dann in der Aktivitätsansicht unter ‹AI notes›. Activity.notes ist eine Kopie des Strava-Titels, kein Notizfeld. Args: - id (string): Aktivitäts-id aus training_list - is_race (boolean, optional): Renn-Markierung. true verknuepft mit einem geplanten Rennen desselben Tages oder legt ein leichtgewichtiges an; false loest die Verknuepfung wieder. - excluded_from_stats (boolean, optional): aus Statistik, Trainingslast und Auswertungen nehmen - sport (string, optional): SWIM | BIKE | RUN | LONGRUN | STRENGTH | MOBILITY | YOGA | HIIT | CARDIO | WALK | HIKE | ALPINE_SKI | NORDIC_SKI | SOCCER | RACKET | OTHER — korrigiert die Sportart dauerhaft - distance_km (number, optional): korrigiert die Distanz dauerhaft Returns: { id, is_race, excluded_from_stats, race_action }
    Connector
    Destructive
    OAuth
  • Listet die geplanten Einheiten eines Zeitraums — **mit ids und Schritten**, aelteste zuerst. Das ist das Gegenstueck zu training_plan_create: erst hier siehst du, was tatsaechlich im Kalender steht, und nur ueber die ids kann training_plan_update etwas davon aendern. training_stats mit include_planned zaehlt bloss (5 geplant, 3 erledigt) und nennt keine einzelne Einheit. **Das Standardfenster liegt in der Zukunft** — heute bis heute + days, weil ein Plan bevorsteht. Fuer die Rueckschau auf verpasste Einheiten from/to setzen. **Fuer eine einzelne Einheit id setzen** — das ist zugleich der Ersatz fuer ein training_get auf eine Planung. training_get kennt nur absolvierte Einheiten: geplante liegen in einer eigenen Tabelle mit eigenem id-Raum, und Streams, Runden und Zonen gibt es fuer sie nicht. Wer es doch versucht, bekommt von training_get einen Verweis hierher statt einer Fehlermeldung. Eine Einheit gilt als erledigt, wenn sie als erledigt markiert ist **oder** der Import eine Aktivitaet mit ihr verknuepft hat; only_open zeigt genau die uebrigen. Dieselbe Regel benutzt training_stats — waeren es zwei Regeln, wuerden die Tools einander widersprechen. **Sortiert nach Zeitpunkt, nicht nur nach Tag.** start_time ist die Ortszeit des Athleten; steht time_of_day daneben, ist die Uhrzeit noch offen und start_time nur der Platzhalter des Tagesfachs (morgens 08:00, nachmittags 15:00, abends 20:00). Einheiten ohne jede Zeitangabe liegen mittags. garmin_workout_id sagt, ob die Einheit schon auf der Uhr liegt. Steht dort eine id, traegt die Uhr nach einer Aenderung weiter den alten Stand, bis die Einheit erneut an Garmin geschickt wird. **Koppelläufe (Brick)** tragen brick_of (id des Rads); brick beschreibt das Paar von beiden Seiten: group = id des Rads, position 1 = Rad, 2 = Koppellauf, size = Teile des Bricks, partner_ids = die anderen Teile — auch wenn sie wegen Filter oder limit nicht in items stehen. Im Text: "Brick 1/2", "Brick 2/2". Rad und Lauf stehen im selben Tagesfach (gleiche start_time mit ~), der Lauf beginnt am Radende. Args: - id (string, optional): genau eine Einheit. Schlaegt from/to/days/sport/only_open. - from (string, optional): Startdatum YYYY-MM-DD, inklusive. Default heute. - to (string, optional): Enddatum YYYY-MM-DD, inklusive. Default from + days - 1. - days (number): 1-365, default 28 (vier Wochen). Wirkt nur, solange to fehlt. - sport (string, optional): SWIM | BIKE | RUN | LONGRUN | STRENGTH | MOBILITY | YOGA | HIIT | CARDIO | WALK | HIKE | ALPINE_SKI | NORDIC_SKI | SOCCER | RACKET | OTHER - include_steps (boolean, default true): Intervallschritte mit ausgeben - only_open (boolean, default false): nur Einheiten, die weder erledigt noch verknuepft sind - limit (number): 1-200, default 50 **Renntage im Fenster werden markiert** (race_days, und je Einheit race_day), aus derselben Tabelle wie training_race_list — ein Rennen ist keine geplante Einheit und steht deshalb nicht in items. Einheiten am **Tag davor** tragen race_eve ({ id, name, priority, risk }); risk ist true bei HARD/VERY_HARD, einem Test im Titel oder mehr als 90 min — dieselbe Regel, nach der training_plan_create/_update warnen. **planned_tss je Einheit** — aus den Schritten gegen die **heutige** Schwelle gerechnet (Rad ftp, Lauf Schwellenpace, Schwimmen CSS mit IF^3; ohne Ziel IF nach Schritttyp), nicht gespeichert: nach einem FTP-Test sinkt die TSS derselben 230 W von selbst. planned_tss_method: steps | intensity (Dauer x Intensitaetslabel) | engine_target (Kraft: "Ziel N TSS" der Plan-Engine) | per_minute (Kraft/Mobility). planned_tss_estimated: true, wenn nichts davon an einer gesetzten Schwelle haengt (z.B. Schwimmen ohne CSS) — im Text mit ≈ markiert. null = weder Schritte noch Dauer. **Harte Einheiten an schlechten Tagen tragen readiness_warning** ({ status YELLOW|RED, date, reasons }): HARD/VERY_HARD und die Readiness-Ampel des Tages ist gelb oder rot — fuer eine Einheit morgen gilt der heutige Stand, weiter voraus gibt es keine Warnung. Dieselbe Bewertung wie training_readiness. Returns: { from, to, count, has_more, race_days: [{ id, date, name, priority, format, status }], items: [{ id, date, start_time, time_of_day, sport, title, duration_min, distance_km, intensity, planned_tss, planned_tss_estimated, planned_tss_method, completed, done, matched_activity_ids, notes, pool_length_m, garmin_workout_id, brick_of, brick: { group, position, size, partner_ids } | null, race_day, race_eve, readiness_warning, steps: [{ order, type, title, duration_min, duration_sec, distance_km, stroke, equipment, exercise?, reps?, weight_kg?, target_kind, target_low, target_high, target_pace, target_heart_rate, target_power, notes }] }] } — exercise/reps/weight_kg stehen nur bei Kraftschritten
    ConnectorOAuth
  • Nimmt einen Schreibvorgang dieses Connectors zurueck — ohne Argument den neuesten, sonst den mit change_id aus training_changes. Deckt alle Schreibtools ab: training_update setzt die Felder auf ihren Vorzustand zurueck (**inklusive der manualOverrides-Sperre**, es gibt also keinen anderen Weg, eine Sport- oder Distanzsperre zu loesen), training_plan_create loescht die angelegten Einheiten, training_write_note loescht die Notiz, und training_plan_update nimmt eine Planaenderung zurueck — bei einer Absage legt es die Einheit samt Schritten und **derselben id** wieder an und haengt die verknuepften Aktivitaeten zurueck, soweit sie seither nicht an einer anderen Einheit haengen. Das Garmin-Workout kommt dabei **nicht** zurueck: es ist in Garmin Connect geloescht, die Einheit muss dort neu hochgeladen werden. **Ein Feld wird nur zurueckgesetzt, wenn es seither niemand anders geaendert hat.** Steht dort inzwischen ein anderer Wert — durch einen Strava-Sync, die App oder einen spaeteren Aufruf — bleibt er stehen und erscheint unter skipped. Bei geplanten Einheiten wird verglichen, was der Aufruf **geschrieben** hat, nicht wann die Zeile zuletzt angefasst wurde: ein Garmin-Versand oder die automatische Verknuepfung mit einer importierten Aktivitaet sind keine Bearbeitung. Zwei Gruende fuehren trotzdem zum Ueberspringen, und sie sagen welcher: "vom Nutzer bearbeitet (<Feld>)" und "inzwischen mit einer Aktivitaet verknuepft" — letzteres, weil eine absolvierte Einheit keine blosse Planung mehr ist und das Loeschen der Aktivitaet ihren Planbezug naehme. Mehrfach aufgerufen arbeitet sich das Tool rueckwaerts durch das Journal, eine Aenderung je Aufruf. Args: - change_id (string, optional): id aus training_changes; ohne sie der neueste offene Eintrag Returns: { ok, change: { id, tool, summary, created_at }, undone: [...], skipped: [{ what, reason }] }
    Connector
    Destructive
    OAuth
  • Readiness-Ampel je Kalendertag: GREEN | YELLOW | RED | UNKNOWN aus HRV, Ruhepuls und Schlaf. Wofuer: vor einer harten Einheit klaeren, ob der Koerper bereit ist. training_plan_list haengt dieselbe Bewertung als readiness_warning an HARD/VERY_HARD-Einheiten (am Tag selbst; fuer morgen gilt der heutige Stand, weil die Nacht davor noch nicht gemessen ist). Regeln (stehen mit ihren Zahlen unter rules im Ergebnis): Baseline = Schnitt der 7 Vortage **ohne** den Tag selbst, mindestens 4 Messwerte. HRV < 85 % der Baseline gelb, < 75 % rot. Ruhepuls > Baseline +3 bpm gelb, > +6 rot. Schlaf < 6 h oder Score < 60 gelb, < 4.5 h oder Score < 40 rot. Gesamtstatus = der schlechteste Einzelstatus. **Messlücke:** Schlaf unter rules.sleepGapBelowHoursWithoutHrv (2 h) **und** keine HRV heisst "Uhr nachts nicht getragen" — Dauer und Score zählen dann als nicht gemessen statt rot, der Grund steht in reasons. Die Rohwerte bleiben in inputs. Fehlende Werte sind kein Fehler — HRV und Schlafscore gibt es nur bei nachts getragener Uhr; was fehlt, steht in reasons. UNKNOWN heisst: kein einziges Signal bewertbar. Der heutige Tag kann unvollstaendig sein, Garmin traegt den Schlaf oft Stunden spaeter nach — ein sehr kurzer Schlaf am Morgen kann ein noch nicht synchronisierter sein. Die Rohwerte liefert training_wellness. Args: - date (string, optional): YYYY-MM-DD, letzter Tag. Default heute (Zone des Athleten). - days (number): 1-60, default 1 — so viele Tage bis einschliesslich date Returns: { rules, days: [{ date, status, reasons[], inputs: { hrv_ms, resting_hr_bpm, sleep_h, sleep_score }, baselines: { hrv_ms, resting_hr_bpm, hrv_values, resting_hr_values } }] }, neueste zuerst
    ConnectorOAuth
  • Mark a comment thread resolved or reopen it (get the id from list_comments). Resolving stamps the thread ROOT, so pass a root comment's id - a reply id is a no-op. Any team writer may toggle this.
    ConnectorNo auth
  • Commits the project's staged conversation draft as a new version and makes it THE CUT the production line renders (`isHead: true` in the answer). Re-validates coherence (the same blocking/non-blocking report the human sees); `force=true` overrides a blocking report; `as_branch=true` keeps the new version as a branch instead, in the version timeline, where it can become the cut later. Requires `write`. $0.
    ConnectorAPI key
  • Stages ONE free edit op on a project — deterministic, no provider is called — into the project's conversation draft: the SAME op the human director runs from a panel or the chat (agent and human edits converge on ONE op-log). The draft becomes a new version when it is committed. Only the free ops run here: the paid re-authoring ops and the creation fields have their own tools (`invocableVia` in the op catalogue names the tool of each op). Ops: - `assign_material_to_shot`: Puts a piece of the person's own library material (its asset_id: a photo or a video they uploaded) on one shot of a scene, by default the base shot that is the scene's visual; the edit mounts it as is, with nothing bought or searched. Deterministic, $0. Args: scene_index, asset_id (the `assetId` of the person's own material in the piece), shot_index? (0-based; default the base shot, which is the scene's visual), shows? (what the material shows, in English; the shot's brief only when the scene has no shot list yet), source_start_sec? (second of the video the shot enters from); only on an ai_image, ai_video or archive scene. - `assign_narration_to_scene`: Sets a segment (from_sec-to_sec) of the person's own recording (its asset_id: an audio file, or the sound of a video they uploaded) as the VOICE of one scene; with with_picture that video is also the scene's picture, tied to its voice. The voice is cut from the recording at the next build, not synthesized, and a voice regeneration keeps it. Deterministic, $0. Args: scene_index, asset_id (the `assetId` of the person's own recording in the piece: an audio file, or a video whose sound is the voice), from_sec, to_sec (the segment, in seconds from the start of the recording), with_picture? (video only: the same segment is also the scene's picture, tied to its voice; only on an ai_image, ai_video or archive scene). The voice is cut from the recording at the next build, not synthesized. - `remove_narration_from_scene`: Returns one scene to the cast voice: the person's own recording it spoke with is taken away. Deterministic, $0. Args: scene_index (the scene goes back to the cast voice). - `replan_scenes`: Reorder the scenes (a permutation of indexes). Deterministic, $0. Args: order=[int...]. - `set_piece_fields`: Set PIECE-level fields (production_score: silence_plan, music_intent, narrative_arc…), validated by the schema. Deterministic, $0. Args: fields (partial production_score: silence_plan, music_intent, narrative_arc, expected_total_duration_sec…; lists replace). - `set_scene_fields`: Set concrete fields of one scene (narration, duration, silences, infographic data…), validated by the schema. Deterministic, $0. Args: scene_index, fields (partial scene object: narrator_text, direction_notes, pre_silence_sec, pause_after_sec, visual.duration_target_sec, visual.prompt, infographic.data, kinetic_caption…; nested dicts merge by key, null deletes; validated by the VBP schema). - `set_visual`: Set a scene's visual type and/or visual prompt. Deterministic, $0. Args: scene_index, visual_type?, visual_prompt?. - `swap_voice`: Change the voice (semantic attributes) of one scene or all of them. Deterministic, $0. Args: voice_spec={...} (semantic attributes only: timbre, cadence, accent, language, apparent_gender, voice_style — NOT a voice id: the concrete voice is a piece-level decision made when the piece is created; a scene has no voice pin of its own, for the human either), scene_index?. The result carries the coherence report: a `hasBlocking` draft can still be committed with `force=true`. While an authoring turn of the same project is in flight the draft is not touched (`authoring-in-progress`). Requires the `write` scope. $0.
    ConnectorAPI key
  • Mint serial-over-SSH credentials so the USER can open their own interactive console session on a virtual machine, and return the exact ssh command to run. Use this when a person wants to drive the console themselves — poke around, watch a boot, run an interactive installer or a TUI. To run a specific command and get its output back, use run_vm_command instead; do NOT take these credentials and try to drive an interactive shell yourself. What comes back: the ssh command, the connection address, the connection secret (used at ssh's own password prompt), and the token's expiry. The credentials reach the VM's serial console through the Cycle gateway — no VM networking required, so this works even with public networking disabled or the guest's network broken. Logging IN to the guest is separate: past ssh, the console lands at the guest's own login prompt. The response includes the generated root password when it is still retrievable (~10 minutes after creation); after that the user needs their own guest credentials or an attached SSH key. Relay the credentials to the user plainly so they can paste the command. They are short-lived and they grant root-capable console access — treat them as a secret, do not write them into files, commits, or issues. action:"revoke" expires ALL serial-over-SSH tokens for the VM, immediately disconnecting every active console session on it (including a session the user is in the middle of, and anyone else's). It is a mutation: confirm with the user before calling it.
    Connector
    Destructive
    API key
  • Audits EVE Frontier Tribe diplomatic standings, friendly/hostile reputation scores, and pilot override entries across solar systems. Use when checking diplomatic relations or detecting conflicting friendly-fire rules across tribe registries; for compiling those standings into executable Sui Move Smart Gate ACL bytecode, use compile_eve_gate_acl instead. Stateless read-only edge call (max 32 KB, 60 RPM): accepts 'tribe_id' ('standing_filter' defaults to 'all'), supports '?demo=true' or L402 (20 sats), and returns HTTP 400 if invalid.
    ConnectorNo auth