# Hardi agents V2 — actions

Contract: 2. Revision: 2026-11-03. Status: available to active verified Hardi accounts; Free, Plus and Pro retain their native limits.

The batch syntax in this guide is for the CLI. ChatGPT uses the separately named operations in the MCP guide, with the same native checks and real IDs from earlier calls.

Errors carry a stable code, a localized message, retryable, optional requiredScopes/retryAfterSeconds and recovery=same_request_id for uncertain outcomes. A native plan refusal is quota_exceeded, not a server outage. Never recover an uncertain commit with a different request ID.

Each write is an atomic batch of actions with schemaVersion 2 and a requestId shaped v2.<13 digit Unix milliseconds>.<16–64 random URL-safe characters>.

Example (replace the reference-free title/content as desired):

```json
{
  "schemaVersion": 2,
  "requestId": "v2.1793232000000.example_random_key_123",
  "actions": [
    {
      "type": "workout.create",
      "ref": "warmup",
      "content": {
        "title": "Warm-up",
        "blocks": [
          {
            "blockType": "warmup",
            "contentText": "Easy mobility"
          }
        ]
      }
    }
  ]
}
```

Generate a fresh current timestamp and random key before first send. This documentation key is illustrative and expires. Same user + same key + same normalized body returns the same receipt across CLI and MCP. A different body under the same key is a conflict. New keys expire after twenty-four hours (five-minute future skew). Retained receipts last thirty days.

Existing objects require expectedVersion from the corresponding read. Library folder restrictions cover reads, writes and retained history. Future-only dated access covers both sides of moves, shifts and inverses; copying from past dates to authorized future dates is allowed. Relative days have no past-date concept. Whole-tree folder reordering needs whole-library access. Models have a separate explicit permission. New preference/cycle/template scopes are never added to an existing grant. Notes require explicit isPublic. Template day positions start at one; dates remain civil ISO dates.

Existing objects require expectedVersion from the corresponding read. Workout/occurrence body edits also require expectedRevision. Omitted fields, media and metadata are preserved. Block insert/update/remove/move uses native block IDs. Local refs can connect a new folder, workout and planning addition within one batch.

Folder trash requires an explicit contentPolicy: error_if_not_empty, move_contents with a destinationFolderId (null means root), or trash_contents with the appropriate workout permission. Root plus one subfolder level, fifty folders.

Planning moves preserve occurrence IDs/results. Removal of result-bearing or dependent sessions is refused. Copy/shift require an explicit contentKinds array (workouts, notes, rest) and an error or append collision policy; no silent overwrite. Cross-calendar changes require both calendars authorized and current targetVersion.

Action permissions:
- calendar.create: actions:read, planning:read, calendars:create
- training.performance.create: actions:read, training:read, training:write
- training.performance.update: actions:read, training:read, training:write
- training.result.upsert: actions:read, training:read, training:write, workouts:read
- preferences.update: actions:read, preferences:read, preferences:write
- settings.update: actions:read, settings:read, settings:write
- workout.create: actions:read, catalog:read, workouts:read, workouts:create
- workout.update: actions:read, workouts:read, workouts:update
- workout.duplicate: actions:read, workouts:read, workouts:create
- workout.move: actions:read, workouts:read, workouts:update, folders:read
- workout.trash: actions:read, workouts:read, workouts:delete
- workout.restore: actions:read, workouts:read, workouts:restore
- folder.create: actions:read, folders:read, folders:write
- folder.update: actions:read, folders:read, folders:write
- folder.reorder: actions:read, folders:read, folders:write
- folder.trash: actions:read, folders:read, folders:delete
- folder.restore: actions:read, folders:read, folders:write
- planning.add: actions:read, planning:read, planning:create, workouts:read
- planning.update: actions:read, planning:read, planning:update, workouts:read
- planning.move: actions:read, planning:read, planning:update
- planning.reorder: actions:read, planning:read, planning:update
- planning.swap: actions:read, planning:read, planning:update
- planning.copy: actions:read, planning:read, planning:create, workouts:read
- planning.shift: actions:read, planning:read, planning:update
- planning.remove: actions:read, planning:read, planning:delete
- planning.note: actions:read, planning:read, planning:create
- planning.edit_note: actions:read, planning:read, planning:update
- planning.remove_note: actions:read, planning:read, planning:delete
- planning.rest: actions:read, planning:read, planning:create
- planning.remove_rest: actions:read, planning:read, planning:delete
- cycle.create: actions:read, planning:read, cycles:read, cycles:write
- cycle.update: actions:read, planning:read, cycles:read, cycles:write
- cycle.delete: actions:read, planning:read, cycles:read, cycles:delete
- template.create: actions:read, templates:read, templates:write
- template.update: actions:read, templates:read, templates:write
- template.add_workout: actions:read, templates:read, templates:write, workouts:read
- template.move_workout: actions:read, templates:read, templates:write
- template.remove_workout: actions:read, templates:read, templates:delete
- template.delete: actions:read, templates:read, templates:delete
- planning.apply_template: actions:read, planning:read, planning:create, templates:read, workouts:read

[JSON schema](https://hardi.app/agents/schema.json).

Template reads: hardi_get_templates pages workouts followed by annotations with one nextCursor; collect items and template.dayEntries until complete. metadataOnly with templateId returns metadata and its version without content. hardi_get_template_workout reads and paginates the saved snapshot by templateId and itemId; templates:read is required. The library source may have changed independently. CLI: templates get <template-id> --metadata-only; templates get-workout <item-id> --template <template-id>. Private coach notes and media are excluded.

calendars:create creates private personal calendars through native quotas, and authorizes this connection to use its own created calendars. calendar.create accepts ref, name, timelineType (dated/fixed), durationWeeks for fixed and optional description. Later actions in the same atomic batch can use calendarRef; earlier-step receipts can supply calendarId. Creation never enables sharing. Conditional actions:undo can retract only this connection's verified calendar creation, after dependent actions are reversed and only when no later protected use exists. CLI: hardi calendars create --name 'Twelve weeks' --timeline-type fixed --weeks 12 --json. hardi calendars list is paginated; follow nextCursor with the same page size. Explicit all_personal calendar access is dynamic and excludes Teams, followed, archived and foreign calendars.

workout-results:read is separate, unchecked by default, and permits read-only native coach-visible participant results on an authorized library workout or scheduled occurrence. hardi_get_workout_results takes source, exactly its workoutId/scheduledWorkoutId, blockId, optional category/division, limit (maximum 20) and cursor. Follow the same filters and page size; changes invalidate the cursor. Native anonymization and hidden-result rules apply. No athlete auth IDs, emails, avatars or unrelated history. CLI: hardi workouts results <workout-id> --block <block-id>; hardi planning results <occurrence-id> --block <block-id>.

The action schema and examples are available in /agents/schema.json. Advertised permissions are minimums: folder contents, destinations, exercise references and selected calendar sources can require additional scopes. The server validates all of them against current grants in the execution transaction. CLI program checks share the same conditional rules.
