- Brand
- Unknown
- Category
- Pending
- Primary Subcategory
- Strength & Gym Workout Trackers
Integration details
Description
Evertrain connects ChatGPT to the user's own Evertrain training account. Once connected, ChatGPT can read their programs, scheduled workouts, training history, coaching notes and their profile and equipment context, and — when asked — create or update programs and workouts, schedule a program, reschedule workouts or substitute exercises, and record what it changed. Every action is scoped to the signed-in account: no other user's data is reachable, and no billing or payment operation is exposed. Load and effort are logged by the athlete, never prescribed by the tools. Destructive actions are marked so ChatGPT confirms first, completed sessions cannot be modified, and coaching preferences are staged for the user to confirm in the app. Requires an Evertrain account.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Category
- Pending
- Primary Subcategory
- Strength & Gym Workout Trackers
- Secondary Subcategories
- None listed
- Brand
- Unknown
- Access
- Account required
- First tracked
- 2026-10-13
- Tool count
- 32
- Geography
- US
The broad Category that contains the Primary Subcategory.
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Your score is coming
ChatGPT now suggests Plugins on its own when they match a user's request.Your Plugin Discovery Score measures how often yours appears, and it will show here as soon as it’s ready.
What discovery looks like

Get alerts for evertrain
Get updates when evertrain’s Discoverability Score or category rank changes.
Competing in ChatGPT Strength & Gym Workout Trackers
View Category32 tools agents can invoke
Adds one exercise to a single future calendar workout, in one of TWO placements chosen by the optional targetGroup param. Omit targetGroup (default) to append the exercise as its own NEW standalone group (super_set:false) at the end of the workout. Supply targetGroup (a group key from a prior get_scheduled_calendar read, e.g. '0', '1') to instead add the exercise INTO that existing group as a superset partner — the group's super_set is set to true and no new group is created. The workout to act on is identified by its REQUIRED instanceId (the per-instance id from a get_scheduled_calendar read — the read-then-write flow); two workouts scheduled from one template share a workoutId but have distinct instanceIds, so instanceId (never workoutId) selects the instance. workoutId is validation context — a mismatch with the located instance is rejected with code:'invalid_argument'. Provide programId, dayMs (UTC-midnight epoch-ms from get_scheduled_calendar), instanceId, workoutId, exercise_id (resolved server-side from the exercise catalog — name/muscles/video are looked up, not supplied by you), optionally targetGroup, and a non-empty 'sets' array (1-15 entries) of planned prescriptions: { reps?: string (a range like '8' or '8-10', bounds 1-100), duration?: number (seconds, 0-86400), rest?: number (seconds, 0-600), tempo?: string }. Every set must carry 'reps' or 'duration' (or both) — an entry with neither is rejected with code:'invalid_argument'. The supplied sets are validated against the exercise's modality — a repetitions exercise requires 'reps' on every set, a time/cardio exercise requires 'duration' on every set; a mismatch is rejected with code:'invalid_argument' and nothing is written. When targetGroup is omitted, the new group's key is minted as the next available numeric index (max existing key + 1) — it never collides with a surviving group after a prior delete_exercise call. Rejects with code:'not_found' if exercise_id is not in the catalog or not visible to you, OR if targetGroup names a group that is not present in the workout. Rejects with code:'duplicate_exercise' if targetGroup names a group that already contains exercise_id — pick a different exercise or remove the existing one first. Rejects with code:'immutable' if the slot or workout is completed. Single-day scope only — does NOT propagate to other calendar days or the program template. Returns { success: true, exercise_id, name, group, superset } — the resolved exercise identity, the group key it landed in (the target group when superset:true, or the newly minted group when superset:false), and whether it was added as a superset partner into an existing group.
add_exercise
CALENDAR-layer origination: places an existing, owned workout TEMPLATE onto a dayMs within a program that has ALREADY been scheduled onto the calendar at least once — for a brand-new session the template never described (e.g. an extra conditioning day, a make-up session). This does NOT edit an already-scheduled instance (use update_future_workout / substitute_exercise / add_exercise / delete_exercise for that, or reschedule_workout to move one) and does NOT accept inline exercises — workoutId must already exist (create_workout first). workoutId does NOT need to appear anywhere in programId's training_blocks — a pure library workout (create_workout with no addToProgramId) can be placed directly. Rejects with code:'program_never_scheduled' if programId has never been scheduled (schedule_program first) — this tool originates new sessions WITHIN an existing run, it never performs a program's first schedule. Rejects with code:'before_program_start' if dayMs precedes the program's scheduled start date; there is no upper date bound. Rejects with code:'corrupt_root_pointer' in the rare case the program's calendar start-date pointer itself is corrupt (not a finite, in-range timestamp) and this call would have had to mint a brand-new slot — re-run schedule_program to repair the pointer, then retry (an append onto an already-existing slot is unaffected and still succeeds). Because the minted ad-hoc slot key is deterministic (one per program+date), repeated calls onto the SAME date for the SAME program always resolve to that SAME slot rather than minting a new one each time — but each call still appends its OWN new workout entry (this tool is NOT a no-op-on-repeat: calling it N times adds N workouts to that slot), UNLESS the slot has since become completed — a completed slot permanently blocks any further add_workout_to_day call for that exact program+date (code:'immutable'; two sessions on one date for one program isn't supported yet — use a different date, a different program, or edit the completed session directly). Placements minted by this tool use an ad-hoc key that does NOT follow the day{N}_week{W} grid schedule_program produces, but remains fully visible to every other program-scoped read/scan (get_scheduled_calendar, shift_from, insert_week, archive_program) — they all match on the program_id field, not the key shape. Rejects with code:'not_found' if programId or workoutId does not resolve to a document owned by you (identical response whether it doesn't exist or belongs to someone else). Returns { success: true, data: { programId, dayMs, workoutId, instanceId, slotKey, minted } } — instanceId is the freshly minted per-instance id for the placed workout (address it with that, never workoutId, in any later calendar-instance tool call), slotKey is the day-doc field the workout landed under, and minted is true only when a brand-new ad-hoc slot was created rather than appended to an existing one.
add_workout_to_day
CALENDAR-layer marker on the live plan: returns { success: true, appendedAfterDayMs } — the program's last scheduled day — and records the block extension in the mutation log. Writes NO day docs, NO workout content, and moves NO days, so logged days are never touched. READ THIS BEFORE CALLING: no tool can author a NEW session onto the empty days after the anchor. create_workout only edits the reusable template (it does not schedule); update_future_workout needs a day doc that already holds the workout; reschedule_workout can place a session on those dates but only by MOVING one that is already scheduled elsewhere. So append_week marks the boundary and makes room to reschedule existing days into — it does NOT add a week of new training. To give the user genuinely new sessions, author a block with create_program + schedule_program. Refuses with program_fully_logged when every scheduled day is already logged.
append_week
Hides an owned program from the app's active lists and forward-unschedules it, without deleting logged training history. Sets is_archived on the program and removes its FUTURE calendar days that have nothing logged (day, workout, exercise, or single-set completion) — a future session with any logged data is preserved. Past days, any partially-logged future day, and the program's training history are all kept. Any unlogged future PLAN EDITS made via update_future_workout or reschedule_workout are lost along with the removed days — re-scheduling later regenerates the program's default plan, not the curated one. The program document itself is never deleted. Call with { unarchive: true } to reverse this: it clears the hidden flag ONLY — it does NOT restore the removed future schedule. Because the app's Available list excludes any program that has ever been scheduled, the program reappears in app lists only after calling schedule_program again (or if its history already carries a completion date). Both directions are idempotent — safe to call twice. For a program the user wants gone for good, use delete_program instead. Returns { success: true, isArchived, futureSlotsRemoved }.
archive_program
Creates a reusable training program TEMPLATE (blueprint layer) with its workout documents. This does NOT put anything on the user's calendar — a created program is an un-started template until schedule_program materializes it onto actual dates. Provide the program structure as EITHER trainingBlocks (a block repeats one day-pattern for N weeks) OR trainingWeeks (an ordered list of explicit weeks, natural for progression/deload — the server run-length-encodes identical consecutive weeks into blocks, producing the identical calendar). Supply exactly one of the two. All exerciseIds must exist in the catalog. Maximum 20 workouts per program. Each set-spec's `sets` field is a COUNT: '{ reps: "8-10", sets: 3 }' means 3 physical sets and is persisted as 3 set elements (max 15 physical sets per exercise). A set-spec is rep-based (`reps` a range string like "8-10", no `duration`), timed (`duration` in seconds, no `reps` — for planks, holds, cardio), or both (a set can carry both fields, e.g. "8 reps of 3s holds"). At least one of reps/duration is required. Check get_exercise_library's exerciseType/measurementType for an exercise before authoring — a time/cardio exercise requires duration; a repetitions exercise requires reps; a mismatch is rejected. Each workout object accepts an optional `description` field — a brief pre-flight briefing rendered before the user starts that session (e.g. "Heavy lower day anchoring this block"). This is template-level context; it differs from `notes` in update_future_workout, which is instance-level and travels into the live session. Use description for structural intent, notes for session-specific instructions. Returns { programId, workoutIds } on success.
create_program
Creates a workout TEMPLATE (blueprint layer). If addToProgramId and programDay are provided, the new workout is also linked into the program template at the given day, in the training block(s) selected by `programBlocks` — NOT broadcast to every block. Linking does NOT schedule it onto the user's calendar — schedule_program materializes a program's workouts onto actual dates. `programBlocks` selects the target block(s) by 0-based index (from get_program's ordered trainingBlocks[] array): an index array like [1, 2] targets exactly those blocks (e.g. a session shared by the Strength and Peak blocks but not Hypertrophy); the literal "all" targets every block (e.g. a fixed conditioning day recurring every block). If omitted and the program has exactly one training block, that sole block is targeted automatically. If omitted and the program has MORE THAN ONE block, the call is refused with 'invalid_argument' — the target is ambiguous, so pass programBlocks explicitly (this is deliberate: it replaces an earlier silent broadcast-to-all-blocks behavior). An out-of-range index is also refused with 'invalid_argument'. `programBlocks` supplied without addToProgramId/programDay is refused with 'invalid_argument' (it is meaningless without a link target). The addToProgramId link is refused with 'invalid_argument' if the target program has zero (or a malformed) training_blocks — author a block first with create_program or update_program. It is refused with 'scheduled_program' if the program has EVER been scheduled onto the calendar — once scheduled, the calendar is the source of truth and template edits (including this link) move to update_future_workout / shift_from / insert_week / append_week. On success the response reports linkedBlocks (how many training blocks received the new workout — the count of blocks actually targeted, not the program's total block count) and programDay. All exerciseIds must exist in the catalog. Each set-spec's `sets` field is a COUNT: '{ reps: "8-10", sets: 3 }' means 3 physical sets and is persisted as 3 set elements (max 15 physical sets per exercise). A set-spec is rep-based (`reps` a range string like "8-10", no `duration`), timed (`duration` in seconds, no `reps` — for planks, holds, cardio), or both (a set can carry both fields, e.g. "8 reps of 3s holds"). At least one of reps/duration is required. Check get_exercise_library's exerciseType/measurementType for an exercise before authoring — a time/cardio exercise requires duration; a repetitions exercise requires reps; a mismatch is rejected. Optional `description` field accepts a brief pre-flight briefing for the workout (e.g. "Heavy lower day anchoring this block") — template-level context rendered before the user starts the session. This is distinct from `notes` in update_future_workout, which is instance-level and travels into the live session; use description for structural intent, notes for session-specific instructions. Returns { workoutId }, plus { linkedBlocks, programDay } when linked into a program.
create_workout
Removes an exercise from a single future calendar workout. The workout is identified by its REQUIRED instanceId (the per-instance id from a get_scheduled_calendar read — the read-then-write flow); two workouts scheduled from one template share a workoutId but have distinct instanceIds, so instanceId (never workoutId) selects the instance. workoutId is validation context — a mismatch with the located instance is rejected with code:'invalid_argument'. Provide programId, dayMs (UTC-midnight epoch-ms from get_scheduled_calendar), instanceId, workoutId, group (the group's key as returned by get_scheduled_calendar — a minted numeric-string index such as '0', '1', '2'), and exercise_id (the exercise to remove). If removing it empties the group, the group itself is dropped. If the group survives with exactly one exercise, its superset flag is normalized off. Rejects with code:'would_empty_workout' if this would leave the workout with zero exercises — nothing is written; delete the whole workout/day via a different tool if that's the intent. Rejects with code:'immutable' if the slot or workout is completed, OR if the target exercise carries any logged set data (a completed set, a logged weight, actual reps, actual duration, or RIR) — logged training is never deleted. Rejects with code:'not_found' if group/exercise_id is not present — including a re-issued call after a successful delete (calling twice is safe: the second call no-ops with not_found rather than erroring on something else). Single-day scope only — does NOT propagate to other calendar days or the program template. Returns { success: true, exercise_id, name, groupDropped, superSetNormalized, remainingExerciseCount }.
delete_exercise
PERMANENTLY and IRREVERSIBLY erases an owned program: every one of its calendar day slots across ALL scheduled runs, its root calendar map entry, its available_programs journal entry, every workout document it owns, and the program document itself. Nothing is recoverable after this call succeeds. If the program has ANY logged training history (a completed day, workout, exercise, or even a single logged set, at any point across its scheduled runs) the call is refused with { code: 'program_has_history', sessionCount: N } and NOTHING is written — use archive_program instead if the goal is to hide the program while keeping its history intact. Only call this again with { force: true, confirmSessions: N } — where N is EXACTLY the sessionCount just reported — AFTER the user has explicitly confirmed, in response to that refusal, that they want those N logged sessions permanently destroyed along with the program. Never send force pre-emptively or guess a count; a mismatched confirmSessions is refused the same way. With a matching confirmation the full cascade runs regardless of history, including completed calendar days and the journal entry. A program published to the store with at least one subscriber is refused with { code: 'program_in_store' } instead — even with force — because deletion covers only the caller's own data, not a shared store asset other users depend on. A program with no history and not in active store use deletes immediately, no confirmation required. Returns { success: true, calendarSlotsRemoved, workoutsDeleted, workoutsSkipped } on success.
delete_program
Removes a workout REFERENCE from one or more blocks of an UNSCHEDULED program template — the delete counterpart to create_workout's addToProgramId link. It removes only the entry from training_blocks[].workouts[programDay]; it NEVER deletes the workouts/{workoutId} document itself, since a workout template can legitimately be referenced from multiple placements (other blocks, other programs, or already-scheduled calendar snapshots). `programBlocks` selects which block(s) to remove from, using the identical selector and resolution rules as create_workout: an index array like [1, 2] targets exactly those blocks; the literal "all" targets every block. If omitted and the program has exactly one training block, that sole block is targeted automatically. If omitted and the program has MORE THAN ONE block, the call is refused with 'invalid_argument' — pass programBlocks explicitly. An out-of-range index is also refused with 'invalid_argument'. Presence semantics differ by selector shape: an EXPLICIT programBlocks array (or the implicit sole-block target) is ALL-OR-NOTHING — if workoutId is absent from ANY named block's workouts[programDay], the whole call is rejected with 'not_found' (naming the failing block(s)) and nothing is written. "all" is different: it removes workoutId from every block where it is actually present, succeeds as long as at least one occurrence was removed, and rejects with 'not_found' only if workoutId is absent from every block in the program. If workoutId occurs more than once in a single targeted block's day-array, every occurrence is removed, and the response's per-block count reflects the true number removed. Rejects with 'scheduled_program' if the program has EVER been scheduled onto the calendar — once scheduled, template edits are disabled; use the calendar ops instead (update_future_workout / shift_from / insert_week / append_week). Rejects with 'invalid_argument' if the target program has zero (or a malformed) training_blocks. Never rejects a removal that leaves a block's day-array empty — that's a normal rest day. If the removed reference was the workout's LAST placement anywhere in the program, the success response includes a non-fatal `warnings` entry noting it is now unreferenced — the workouts document itself is left intact, not cascade-deleted. Returns { programId, programDay, workoutId, touchedBlocks, removedCounts, totalRemoved } on success — touchedBlocks names exactly which block indices were modified, removedCounts gives the per-block removed count, and totalRemoved is their sum.
delete_workout_from_block
CALENDAR-layer removal: deletes a single scheduled workout entry from a live calendar day. The workout is identified by its REQUIRED instanceId (the per-instance id from a get_scheduled_calendar read — the read-then-write flow); two workouts scheduled from one template share a workoutId but have distinct instanceIds, so instanceId (never workoutId) selects the instance. workoutId is validation context — a mismatch with the located instance is rejected with code:'invalid_argument'. Provide programId, dayMs (UTC-midnight epoch-ms from get_scheduled_calendar), instanceId, and workoutId. This does NOT delete the workouts/{workoutId} TEMPLATE document — only the calendar-day reference to it — and NEVER touches any other program's slot on a shared dayMs document, nor any other slot-field belonging to this SAME program under a different key. Rejects with code:'immutable' if the slot or workout is already completed, OR if ANY set anywhere in the workout carries logged data (a completed set, a logged weight, a non-empty actual reps/duration value, or a logged RIR) — regardless of the completed flag. This is an UNCONDITIONAL refusal: there is NO force or override parameter of any kind, so logged training history can never be destroyed directly by this tool. If the user has explicitly confirmed they want a partially-logged session discarded, the accepted path is: (1) reschedule_workout with force:true and confirmLoggedSets echoing the exact logged-set count, moving the workout to a DIFFERENT day (this resets its actuals — it cannot be an in-place reset, fromDayMs and toDayMs must differ), then (2) delete_workout_from_day against the workout's NEW location, which now carries no logged data and deletes cleanly. Rejects with code:'not_found' if instanceId is not present at the named address — including a re-issued call after a successful delete (calling twice is safe: the second call no-ops with not_found rather than erroring on something else), or if programId does not match the slot actually located there. On success, removal cascades depending on what else remains on the day document: if the deleted workout was the only one in its slot AND that slot was the only slot on the whole day document, the ENTIRE day document is deleted; if it was the only workout in its slot but other slot-fields remain (another program's, or this same program's under a different key), only that one slot-field is deleted; otherwise only the targeted workout is removed from its slot's array and every sibling workout/slot is untouched. Single-day scope only — does NOT propagate to other calendar days or the program template. Returns { success: true, data: { programId, dayMs, instanceId, workoutId, dayDocDeleted, slotFieldDeleted, remainingWorkoutsInSlot } }.
delete_workout_from_day
Returns the authenticated user's durable coaching facts: movement_restriction, preference, and current_phase entries, grouped by type. By default returns only CURRENT facts (still true today). Pass as_of (an ISO date, YYYY-MM-DD) to see the historical view as of that date, including since-superseded records that were valid then. Pass type to filter to a single fact type. Also returns pendingProposals — the count of the user's open pending proposals awaiting in-app confirmation, so you can remind them to review if it's non-zero. This is read-only awareness; this tool cannot write or propose anything.
get_coaching_facts
Returns daily notes (body metrics, cardio, sleep, mood) for a date range. body_weight is parsed from '75|kg|08:30 AM' → { value, unit }; body_fat from '18.5|08:30 AM' → { value }. Trailing time segments are stripped.
get_daily_notes
Returns exercises from the catalog visible to the user (default exercises + user's own). All enum filters take camelCase enum KEYS, matched exactly (in-memory): bodyRegion (one of: chest, back, shoulders, arms, legs, core), movementType (one of: bilateral, unilateral), equipment (a single value, one of: dumbbells, smithMachine, ankleWeights, medicineBall, machines, barbell, kettlebells, step, powerbands, resistanceBands, fitball, landmineAttachment, trapBar, trx, abWheel, plyoBox, battleRopes, stepper, crossTrainer, treadmill, bike, bosuBall, boxingGloves, chains, rower, skippingRope, sled, thickGrips), muscles (a list of camelCase muscle keys, each one of: calves, gastrocnemius, anteriorDeltoids, deltoids, elbowExtensors, pecMajor, pecs, elbowFlexors, medialDeltoids, brachialis, gluteMaximus, glutes, traps, upperTraps, hamstrings, abdominals, core, obliques, bicepLongHead, bicepShortHead, quads, rectusFemoris, vastusLateralis, vastusMedialis, gluteMedius, lats, rotatorCuff, shoulderExternalRotators, transverseAbdominis, adductors, brachioradialis, forearms, posteriorDeltoids, pecMajorClavicle, tricepLateralHead, tricepLongHead, tricepMedialHead, lowerTraps, midTraps, hipExternalRotators, hipRotators, pecMajorSternal, lowerBack, gluteMinor, soleus, shoulderInternalRotators, pecMinor, latThoracic, latLumbar, latIlliac, erectorSpinae), exerciseType (one of: resistance, cardio), and measurementType (one of: repetitions, time). The modality filters (exerciseType/measurementType) match only exercises that declare that field — an unclassified exercise is not returned by a modality filter. Default limit: 50. Each entry MAY carry exerciseType ("resistance"|"cardio") and measurementType ("repetitions"|"time") when the exercise has been classified — these two fields tell you which set-spec shape to author: a "time" or "cardio" exercise wants a `duration` set-spec (no reps needed); a "repetitions" exercise wants a `reps` set-spec. When absent, the exercise is unclassified and either shape is accepted by create_program/create_workout.
get_exercise_library
Reads a program TEMPLATE (blueprint layer) — the reusable plan, NOT the user's scheduled calendar (use get_scheduled_calendar / get_training_history for calendar days). Returns the program document with all associated workout documents resolved: trainingBlocks, goal, focus, equipment, and the full workout exercise groups with plain-string reps (no pipe format). Each workout includes `description` when one was set (the coach-authored context note visible to the athlete before they start the session). Sets are presented in the compact count form: runs of identical physical sets read as one spec with `sets: N` — the same shape create_program accepts. A set is rep-based (a `reps` key, e.g. '6-8'), timed (a `duration` key in seconds, no `reps` key), or both. Caveat: legacy documents may report counts above 15 (create_program's cap).
get_program
Returns the user's UPCOMING scheduled calendar days for a date range — the live forward plan with completion status, NOT the completed-log history (use get_training_history for past logs). startDate defaults to today, endDate to a 4-week forward window. Each day carries clean programId/workoutId/date join keys and a completed flag so the AI can target not-done sessions. Completed days in the window are included with completed:true — the AI decides which ones to act on. Applies the same visibility rule the app itself applies: a day is only omitted if its programId is not present at all in the user's calendar root (fully deleted / never-scheduled). A previous run's day after a program restart, and days belonging to an archived program, are still returned — the human user sees them too. The response's `hidden` field reports how many entries were dropped as orphans ({orphans}) — this is never silent.
get_scheduled_calendar
Returns the user's training history (live calendar layer) for a date range, as a list of days. Each day has a clean array of scheduled program-days carrying programId and the day's date (dayMs), with workoutId on each workout inside — the raw composite storage key is never exposed. Set fields (reps, rest) are parsed from pipe format into { planned, actual } objects; rir is a separate integer; rpe = 10 - rir is computed. No raw pipe strings in the response. Applies the same visibility rule the app itself applies: a day is only omitted if its programId is not present at all in the user's calendar root (fully deleted / never-scheduled). A previous run's day after a program restart, and days belonging to an archived program, are still returned — the human user sees them too. The response's `hidden` field reports how many entries were dropped as orphans ({orphans}) — this is never silent.
get_training_history
Returns the authenticated user's training profile: first name, age, role, isOnboarded (computed from 4 onboarding sub-objects), personal stats, training experience, and facility/schedule preferences. Does not include contact details or account identifiers. accessToFacilities.facilities is one of: 'fullGym' (a fully-equipped gym — barbells, racks, machines, and cables), 'limitedEquipment' (free weights and a bench, but no machines or cables — e.g. a home or garage setup), or 'noEquipment' (bodyweight only, typically training at home or outdoors). Program the user's available movements accordingly.
get_user_profile
Lists the user's program TEMPLATES (blueprint layer) available to the authenticated user (from users/{uid}/available_programs) — the plans they can view or schedule, not their calendar days. Each entry includes programId, name, and imagePath.
get_user_programs
Reads a single workout TEMPLATE (blueprint layer) — the reusable plan, not a scheduled calendar day. Returns the workout document with exercise groups and sets. Includes `description` when one was set (the coach-authored context note visible to the athlete before they start the session). Set reps are plain strings (e.g. '6-8') — no pipe format on the blueprint side. Sets are presented in the compact count form: runs of identical physical sets read as one spec with `sets: N` — the same shape create_workout accepts. A set is rep-based (a `reps` key, e.g. '6-8'), timed (a `duration` key in seconds, no `reps` key), or both. Caveat: legacy documents may report counts above 15 (the write-side cap).
get_workout
CALENDAR-layer mutation of the live plan: inserts an empty REST week after afterDate by shifting every scheduled day strictly after that date forward exactly 7 days. Days with any logged training are NEVER moved — a logged day after afterDate refuses the insert. The gap is created EMPTY and STAYS empty: no tool can place a new session on a new calendar date (create_workout only edits the template; update_future_workout needs a day doc that already holds the workout). You may move an existing scheduled day into the gap with reschedule_workout. If the user wants a lighter week rather than none, author a block with create_program + schedule_program instead. Not idempotent — calling twice inserts two weeks. Returns { success: true, movedDays } on success.
insert_week
Health-check tool. Returns {pong:true}. readOnly, idempotent.
ping
Publishes a daily AI activity card summarising this session. Provide a headline (≤80 chars) and rationale (≤2000 chars) describing what you accomplished and why. The changes[] list is derived automatically from the server's record of this token's write operations today — do NOT supply a changes field. An empty changes list is valid (reasoning-only sessions). Same-day calls revise the card; prior versions are preserved in history. Returns { success: true, dayMs } on success, or a structured error object on failure.
post_activity
STAGES a current-training-phase proposal for the user to confirm in-app (e.g. 'hypertrophy block 2/4', 'deload week', 'peaking for a meet'). This does NOT commit anything — it only queues a pending item; the fact only becomes real coaching context after the user explicitly confirms it in the app. Propose SPARINGLY: only when the training phase has genuinely changed — not every session. Bias strongly toward NOT proposing; an empty pending queue is the win condition, not a failure. phase is a short label (max 64 chars); rationale is an optional short explanation (max 280 chars). There is only ever ONE current phase — confirming this proposal will retire the previous current phase fact, if any (would_supersede reflects that when applicable). Returns { success: true, proposal_id, would_supersede, expires_at } — would_supersede is null or { fact_id, summary } describing the current phase this would retire on confirmation.
propose_current_phase
STAGES a training-preference proposal for the user to confirm in-app. This does NOT commit anything — it only queues a pending item; the fact only becomes real coaching context after the user explicitly confirms it in the app. Propose SPARINGLY: only durable, programming-relevant preferences the user has clearly stated (e.g. 'I always want to superset arms' or 'I dislike running') — not a one-off mood comment. Bias strongly toward NOT proposing; an empty pending queue is the win condition, not a failure. text is freeform (max 280 chars) since preferences are consumed by the brain, not executed by the app. Optional tags reference equipment the preference relates to. Preferences are ADDITIVE — this never supersedes an existing preference (would_supersede is always null). Returns { success: true, proposal_id, would_supersede: null, expires_at }.
propose_preference
STAGES a movement-restriction proposal for the user to confirm in-app. This does NOT commit anything — it only queues a pending item; the fact only becomes real coaching context after the user explicitly confirms it in the app. Propose SPARINGLY: only durable, programming-relevant restrictions the user has clearly stated (e.g. a real injury or a hard no-go movement) — not passing comments, not every mention of soreness. Bias strongly toward NOT proposing; an empty pending queue is the win condition, not a failure. Provide at least one of exclude_exercise_ids (catalog exercise ids) or exclude_body_regions (chest|back|shoulders|arms|legs|core). An unknown exercise id is rejected and nothing is staged. Do not include diagnosis, cause, or medical detail — only the training consequence (what to avoid) and an optional short note. Returns { success: true, proposal_id, would_supersede, expires_at } — would_supersede is null or { fact_id, summary } describing the current restriction this would retire on confirmation.
propose_restriction
CALENDAR-layer mutation of the live plan: moves a single not-yet-completed workout from one calendar day to another. The workout to move is identified by its REQUIRED instanceId (the per-instance id from a get_scheduled_calendar read — the read-then-write flow); two workouts scheduled from one template share a workoutId but have distinct instanceIds, so instanceId (never workoutId) selects the instance. workoutId is validation context — a mismatch with the located instance is rejected with code:'invalid_argument'. toDayMs is the date you are naming, so it must be a UTC-midnight epoch-ms day-doc id (as returned by get_scheduled_calendar); non-midnight values are rejected, never rounded. toDayMs must also be on/after the program's scheduled start date — a date before it is refused with code:'before_program_start', because the app never renders pre-start days (pick a later date, or re-schedule the program at the earlier start). fromDayMs is a handle on a day doc that already exists and stays permissive — that is what lets you move a legacy non-midnight day onto a clean date, the recovery calendar_day_misaligned asks for. The move is transaction-atomic — the logged-set check and both writes are serialized, so a set logged while the move is in flight can't be lost. Rejects if the slot or workout is completed (immutable), and rejects a workout with ANY logged set (workout_has_logged_sets, naming loggedSets) — logged training is NEVER relocated to a date it wasn't performed. To move such a day anyway the user must explicitly agree to DISCARD the partial log: retry with force: true and confirmLoggedSets echoing the refusal's exact count; the actuals are then reset and the clean planned workout moves. If the partial is worth keeping, leave the day in place and author the session fresh on the target day instead. Returns { success: true, instanceId } on success — instanceId is the moved workout's resulting id (re-minted if it collided on the target day), so you can keep addressing it without a re-read.
reschedule_workout
Materializes a program TEMPLATE onto the user's actual CALENDAR (calendar layer), starting from the given date. This is what STARTS a program: it writes calendar day documents for all workout slots in the program's training blocks — until you call this, a created program is just an un-started template that puts nothing on the user's calendar. The program must be accessible to the user (owned, purchased, or in store). Day keys are weekdays, not offsets: day1=Monday…day7=Sunday, and each dayN lands on the NEXT occurrence of that weekday on or after startDate — a start date that doesn't match the program's first day key rolls forward (a Wednesday start on a day1-led program trains nothing until Monday), so tell the user when their first session actually is. Re-scheduling the same program replaces its PRISTINE planned days only: any slot that already holds logged training — even a single logged set — is kept, and its date is returned in preservedDates. A date can be in preservedDates and still have other, pristine slots on it rescheduled, so relay it as 'kept your logged sessions on these dates', not 'these whole days were untouched'. If the program is CURRENTLY ACTIVE (already scheduled with at least one future, not-completed day of that run remaining), this call is refused with code:'program_already_scheduled' and no write — re-scheduling an active run would strand its remaining days. Tell the user to quit or archive the active run first, or let it finish, then re-schedule. startDate must be this week's Monday (UTC) or later — a fully-past start is refused with code:'start_date_in_past' and no write, since it would schedule days born already-missed. An ARCHIVED program is refused with code:'program_archived' and no write — tell the user to unarchive it first with archive_program {unarchive:true}, then schedule. A program whose training blocks reference no workout under any day key has nothing to schedule and is refused with code:'nothing_to_schedule' and no write — add workouts to the training blocks first. Returns { scheduledDays, preservedDays, preservedDates } on success, plus a non-fatal `warnings` array (rule + message) when the schedule wrote successfully but degraded in a way worth relaying: a dangling workout reference scheduled as an empty session, an exercise ID with no catalog name (shown as a raw ID), or the app-library journal entry failing to write (program may not appear in the user's list until refreshed). If this program was previously scheduled at a DIFFERENT start date (a finished or quit run — an ACTIVE run is refused above, not silently moved), the response also includes `previousRun: {startDate, loggedDates}`: the earlier run's start date and the dates it holds logged training on. Those logged days still render on the calendar and in get_training_history, but no longer count toward this new run once this call moves the start pointer — tell the user their old logged sessions are still there, just detached from the new run.
schedule_program
CALENDAR-layer mutation of the live plan: pushes a contiguous block of the program's upcoming scheduled days forward or back by ±N days (travel, illness). Anchors at the first not-yet-completed day on or after fromDate and moves that contiguous run; days with any logged training are NEVER moved. Refuses (with a structured code) if a logged day sits inside the range, a moved day would land on an occupied date for the same program, or a backward shift would overlap logged history or land before the program's scheduled start date. NOTE the shift is not bounded by today: a backward shift can land days in the past, and a program left with no day after today disappears from the app's Current Programs while its days still show on the calendar. This is surfaced structurally: a successful shift that leaves the program with no unlogged day strictly after today returns programStillCurrent: false — tell the user rather than assuming the tool prevents it. Call get_scheduled_calendar first to confirm the live schedule. Not idempotent — calling twice shifts twice. Shifts spanning more than ~249 days commit in multiple batches (typical programs are atomic). On any failure read the flags before acting: retryable: true means the write provably never started (safe to retry); partial: true with committedDays means that many days ARE moved; outcomeUnknown: true means the write was in flight and may or may not have landed. For the last two, re-read get_scheduled_calendar and re-plan from what you see — never retry blindly. Returns { success: true, movedDays } on success, plus programStillCurrent: false when applicable.
shift_from
Submits a problem-first feature request to the Evertrain product owner when you (the agent) hit a capability gap — a tool that doesn't exist, a field that isn't exposed, a workflow you cannot complete. Use this INSTEAD of simply telling the user you can't do something. Describe the GAP, not just a solution: provide userGoal (what the user was trying to accomplish), situation (relevant context about the user — training phase, program, goal), currentLimitation (what specifically cannot be done today), and desiredOutcome (what success would look like). proposedSolution is optional and secondary — only include it if you have a concrete, well-formed suggestion. contactConsent must reflect whether the user has EXPLICITLY agreed to be contacted about this request; do not assume consent. Submissions are rate-limited to one per user per topic per 24 hours — resubmitting the same underlying problem within that window is rejected. Returns { success: true, requestId } on success, or a structured error object. The request is still persisted even if the owner's Slack notification fails to send — that failure surfaces as warnings: [{rule: 'slack_notification_failed', message}] alongside success:true (the same {rule, message} shape create_program and schedule_program use), since Slack is the triage surface and the request may otherwise go unseen.
submit_feature_request
Replaces one exercise slot on a single future calendar day. The workout to act on is identified by its REQUIRED instanceId (the per-instance id from a get_scheduled_calendar read — the read-then-write flow); two workouts scheduled from one template share a workoutId but have distinct instanceIds, so instanceId (never workoutId) selects the instance. workoutId is validation context — a mismatch with the located instance is rejected with code:'invalid_argument'. Provide programId, dayMs (UTC-midnight epoch-ms from get_scheduled_calendar), instanceId, workoutId, group (the group's key as returned by get_scheduled_calendar — a minted numeric-string index such as '0', '1', '2', NOT a letter), oldExerciseId (the exercise to replace), and newExerciseId (the replacement, resolved server-side from the exercise catalog). For same-type swaps (reps→reps or time→time): planned reps/duration and rest are preserved; logged set data (weight, actual reps, RIR, completed) is cleared since the movement has changed. Do NOT supply 'sets' on a same-type swap — it is rejected with code:'invalid_argument' since a same-type swap always preserves the existing planned values. For cross-type swaps (repetitions↔time): you MUST supply a 'sets' array (one entry per set) specifying reps (string, e.g. '10') or duration (seconds, integer) for the new exercise type. Omitting 'sets' on a cross-type swap returns code:'invalid_argument'. Single-day scope only — does NOT propagate to other calendar days or the program template. Rejects with code:'immutable' if the slot or workout is completed, or if any set in the target exercise has logged data. Rejects with code:'duplicate_exercise' if newExerciseId is already present elsewhere in the same group — substituting would create two entries with the same exercise; pick a different exercise or remove the existing one first. Rejects with code:'not_found' if oldExerciseId is not in the named group (calling twice is safe — the second call returns not_found without writing). Returns { success: true }.
substitute_exercise
CALENDAR-layer merge-patch of one not-yet-completed workout on the live plan. The workout is identified by its REQUIRED instanceId (the per-instance id from a get_scheduled_calendar read — the read-then-write flow); two workouts scheduled from one template share a workoutId but have distinct instanceIds, so instanceId (never workoutId) selects the instance. workoutId is validation context — a mismatch with the located instance is rejected with code:'invalid_argument'. dayMs is the UTC-midnight epoch-ms day-doc id (from get_scheduled_calendar). Rejects if the workout is completed, and rejects STRUCTURAL patches (setPatches/groupPatches) once the workout has any logged set — logged training is never restructured or truncated; name/notes edits remain allowed on a started session. Changes are additive — only provided fields are updated. Returns { success: true }, or { success: true, unchanged: true } when a name/notes-only request (no setPatches/groupPatches) already matched the stored workout — no write occurred and no activity-feed entry was created for it.
update_future_workout
Edits a program TEMPLATE (blueprint layer) owned by the user — for NEVER-SCHEDULED programs only (rename/retune before go-live). Uses merge semantics — only provided fields are changed; unmentioned fields are preserved. Once a program has been scheduled onto the calendar this tool is rejected with code 'scheduled_program': the calendar is then the single source of truth, and structural changes to the live plan happen on the calendar layer via update_future_workout, shift_from, insert_week, or append_week. Returns { success: true } on success, or { success: true, unchanged: true } when every requested field already matched the stored value — no write occurred and no activity-feed entry was created for it.
update_program
evertrain ChatGPT Plugin FAQ
How the directory, categories and Discoverability Score work.
Read the methodologyHow do I improve evertrain's ChatGPT Plugin discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are evertrain alternatives on ChatGPT?
As of 2026-10-13, evertrain competes with Alkemy, Autelica, Caliber, CoachPilot, Compass Gym, Do Workout, Face Yoga, FitAI Pro and 33 more in ChatGPT Strength & Gym Workout Trackers, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.