Skip to main content
Glama
AstralVoidZ
by AstralVoidZ

ppsspp_replay

Record PPSSPP input sequences, execute replays, and save/load .ppr recordings; align boot timing to inject inputs correctly.

Instructions

PURPOSE: Aggregate PPSSPP replay subsystem — record input sequences, execute them, and save/load .ppr recordings.

USAGE: session_id optional when exactly one session is active; actions: begin/abort/flush/execute/status/time_get/time_set/save/load/wait_complete; execute needs version + base64_input; time_set needs value; save/load take a bare file name (always under output/replays/).

BEHAVIOR: STATE-CHANGE. Recording requires the CPU RUNNING (real input timing); screenshots are rejected while recording. Replay timelines use ABSOLUTE game-clock timestamps anchored at the RECORDING session's boot — a replay only injects correctly when a fresh boot's clock is aligned to them: execute/load ONLY loads the event table and returns t0_s / estimated_end_s + the boot-aligned sequence (reset -> wait_ready -> wait boot+estimated_end_s -> abort); it does NOT play by itself. executing/saving NEVER clear on their own — only abort clears them — so wait_complete times out on any un-aborted replay; completion = the timeline estimate + explicit abort. execute/load auto-abort a live executing/saving state first. restore_rtc defaults to False: setting it rewinds the game-visible wall clock of the RUNNING session and pollutes every in-game timer; when needed, set it before the boot-aligned reset.

RETURNS: {action, executing, saving, version, size, base64, base_rtc, data} — execute/load data carries t0_s, estimated_end_s, event_count and boot_aligned_sequence; fields depend on the action.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
valueNoRequired for action='time_set'. Base RTC value in seconds (uint32). Not used by the other actions. The schema default of 0 exists for legacy callers -- do NOT rely on it when the action is 'time_set'.
actionYesReplay operation. Valid values: - 'begin': begin/resume recording. - 'abort': abort any recording or execution. - 'flush': flush recorded data (returns version + base64). - 'execute': execute a replay (requires version + base64_input). ONLY loads the event table — follow the boot-aligned sequence in the response (reset + wait + abort) or input never injects. - 'status': query {executing, saving}. - 'time_get': get base RTC. - 'time_set': set base RTC (requires value). WARNING: rewinds the game-visible wall clock on the RUNNING session — pollutes every in-game timer. - 'save': flush + time_get + write .ppr file (requires file_path: bare file name under output/replays/). - 'load': read .ppr + execute (requires file_path; same containment). Returns t0_s / estimated_end_s and the boot-aligned sequence. - 'wait_complete': poll replay.status until executing=False — NOTE: executing never clears on its own (only abort clears it), so this always times out on an un-aborted replay; kept for recording-completion checks and backwards compatibility.
versionNoRequired for action='execute'. Replay format version (from a prior replay.flush). Not used by the other actions. The schema default of 0 exists for legacy callers -- do NOT rely on it when the action is 'execute'.
file_pathNoBare .ppr file NAME (no directory parts) for action='save' / action='load'. The file is always placed under the server-managed directory .ppsspp-dfx/output/replays/ — absolute paths and path separators are rejected. Required for save / load; ignored for all other actions.
session_idNoActive session ID; omit to auto-resolve when exactly one session is active.
timeout_msNoTotal timeout in milliseconds for action='wait_complete' (default 10000 = 10s, clamped 100..25000). The ceiling is 25s because the MCP client aborts a tool call at ~30s: a larger value could never be honoured. Ignored for all other actions.
interval_msNoPolling interval in milliseconds for action='wait_complete' (default 100ms, clamped 10..5000 — below 10 the poll degenerates to a busy loop on the WS). Ignored for all other actions.
restore_rtcNoWhether to restore base_rtc via replay.time_set before execute when action='load' (default False). true sets the game-visible wall clock back to the recording moment — pollutes EVERY timer of the running session (attract timeouts, clocks, cooldowns) because game time = rtcBaseTime + elapsed. Only use for deterministic replays, and prefer setting it BEFORE the reset of the boot-aligned sequence so the game boots on the shifted base. Ignored for all other actions.
base64_inputNoBase64-encoded replay data (from a prior replay.flush). Required for action='execute'; ignored for all other actions.
session_noteNoOptional human-readable note embedded in the .ppr file when action='save'. Ignored for all other actions.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
dataYesRaw PPSSPP response dict (echoed for diagnostic / future field extraction). Empty dict when no additional fields.
sizeYesRecording size in bytes from `replay.flush`. 0 when the action does not return a size.
actionYesReplay action executed: 'begin' / 'abort' / 'flush' / 'execute' / 'status' / 'time_get' / 'time_set' / 'save' / 'load' / 'wait_complete'.
base64YesBase64-encoded recording payload from `replay.flush`, or the input payload passed to `replay.execute`. Empty string when the action does not carry a payload.
savingYesTrue if a replay recording is in progress. After `begin` → True; after `flush` or `abort` → False.
versionYesRecording format version from `replay.flush` (currently 1). 0 when the action does not return a version.
base_rtcYesBase RTC timestamp (seconds) from `replay.time.get` / `replay.time.set`. 0 when the action does not return it.
executingYesTrue if a replay is currently executing. Drives `wait_complete`'s exit condition (polls until False).
wait_iterationsYesNumber of `replay.status` polls performed by `wait_complete` before exiting. 0 for non-wait actions.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed11 schema fields changedv0.1.7
    • changedInput schema / properties / action / description
      Previous value: -"Replay operation. Valid values:\n- 'begin': begin/resume recording.\n- 'abort': abort any recording or execution.\n- 'flush': flush recorded data (returns version + base64).\n- 'execute': execute a replay (requires version + base64_input). ONLY loads the event table — follow the boot-aligned sequence in the response (reset + wait + abort) or input never injects (U7 root cause).\n- 'status': query {executing, saving}.\n- 'time_get': get base RTC.\n- 'time_set': set base RTC (requires value). WARNING: rewinds the game-visible wall clock on the RUNNING session — pollutes every in-game timer (R2).\n- 'save': flush + time_get + write .ppr file (requires file_path: bare file name under output/replays/).\n- 'load': read .ppr + execute (requires file_path; same containment). Returns t0_s / estimated_end_s and the boot-aligned sequence.\n- 'wait_complete': poll replay.status until executing=False — NOTE: executing never clears on its own (only abort clears it), so this always times out on an un-aborted replay; kept for recording-completion checks and backwards compatibility."New value: +"Replay operation. Valid values:\n- 'begin': begin/resume recording.\n- 'abort': abort any recording or execution.\n- 'flush': flush recorded data (returns version + base64).\n- 'execute': execute a replay (requires version + base64_input). ONLY loads the event table — follow the boot-aligned sequence in the response (reset + wait + abort) or input never injects.\n- 'status': query {executing, saving}.\n- 'time_get': get base RTC.\n- 'time_set': set base RTC (requires value). WARNING: rewinds the game-visible wall clock on the RUNNING session — pollutes every in-game timer.\n- 'save': flush + time_get + write .ppr file (requires file_path: bare file name under output/replays/).\n- 'load': read .ppr + execute (requires file_path; same containment). Returns t0_s / estimated_end_s and the boot-aligned sequence.\n- 'wait_complete': poll replay.status until executing=False — NOTE: executing never clears on its own (only abort clears it), so this always times out on an un-aborted replay; kept for recording-completion checks and backwards compatibility."
    • changedInput schema / properties / restore_rtc / description
      Previous value: -"Whether to restore base_rtc via replay.time_set before execute when action='load' (default False; R2). true sets the game-visible wall clock back to the recording moment — pollutes EVERY timer of the running session (attract timeouts, clocks, cooldowns) because game time = rtcBaseTime + elapsed. Only use for deterministic replays, and prefer setting it BEFORE the reset of the boot-aligned sequence so the game boots on the shifted base. Ignored for all other actions."New value: +"Whether to restore base_rtc via replay.time_set before execute when action='load' (default False). true sets the game-visible wall clock back to the recording moment — pollutes EVERY timer of the running session (attract timeouts, clocks, cooldowns) because game time = rtcBaseTime + elapsed. Only use for deterministic replays, and prefer setting it BEFORE the reset of the boot-aligned sequence so the game boots on the shifted base. Ignored for all other actions."
    • addedInput schema / properties / session_id / anyOf
      Added value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / session_id / default
      Added value: +null
    • changedInput schema / properties / session_id / description
      Previous value: -"Active session ID."New value: +"Active session ID; omit to auto-resolve when exactly one session is active."
    • removedInput schema / properties / session_id / type
      Removed value: -"string"
    • changedInput schema / properties / timeout_ms / description
      Previous value: -"Total timeout in milliseconds for action='wait_complete' (default 10000 = 10s, clamped 100..60000). Ignored for all other actions."New value: +"Total timeout in milliseconds for action='wait_complete' (default 10000 = 10s, clamped 100..25000). The ceiling is 25s because the MCP client aborts a tool call at ~30s: a larger value could never be honoured. Ignored for all other actions."
    • changedInput schema / properties / timeout_ms / maximum
      Previous value: -60000New value: +25000
    • changedInput schema / properties / value / description
      Previous value: -"Base RTC value in seconds (uint32). Required for action='time_set'; ignored for all other actions."New value: +"Required for action='time_set'. Base RTC value in seconds (uint32). Not used by the other actions. The schema default of 0 exists for legacy callers -- do NOT rely on it when the action is 'time_set'."
    • changedInput schema / properties / version / description
      Previous value: -"Replay format version (from a prior replay.flush). Required for action='execute'; ignored for all other actions."New value: +"Required for action='execute'. Replay format version (from a prior replay.flush). Not used by the other actions. The schema default of 0 exists for legacy callers -- do NOT rely on it when the action is 'execute'."
    • changedInput schema / required
      Previous value: -[
      -  "session_id",
      -  "action"
      -]New value: +[
      +  "action"
      +]
  2. Changed6 schema fields changedv0.1.6
    • changedInput schema / properties / interval_ms / description
      Previous value: -"Polling interval in milliseconds for action='wait_complete' (default 100ms). Ignored for all other actions."New value: +"Polling interval in milliseconds for action='wait_complete' (default 100ms, clamped 10..5000 — below 10 the poll degenerates to a busy loop on the WS). Ignored for all other actions."
    • addedInput schema / properties / interval_ms / maximum
      Added value: +5000
    • addedInput schema / properties / interval_ms / minimum
      Added value: +10
    • changedInput schema / properties / timeout_ms / description
      Previous value: -"Total timeout in milliseconds for action='wait_complete' (default 10000 = 10s). Ignored for all other actions."New value: +"Total timeout in milliseconds for action='wait_complete' (default 10000 = 10s, clamped 100..60000). Ignored for all other actions."
    • addedInput schema / properties / timeout_ms / maximum
      Added value: +60000
    • addedInput schema / properties / timeout_ms / minimum
      Added value: +100
  3. First observedv0.1.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes far beyond the annotations (readOnly=false, destructive=false, idempotent=false) by disclosing that recording requires the CPU RUNNING, that screenshots are rejected while recording, that timelines are absolute game-clock anchored at the recording boot, that execute/load only load the event table and must be followed by the boot-aligned reset/wait/abort sequence, and that executing/saving never self-clear so wait_complete always times out on un-aborted replays.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded PURPOSE/USAGE/BEHAVIOR/RETURNS structure makes a dense description scannable, and nearly every clause carries actionable detail (timing anchor, auto-abort, restore_rtc pollution). It is long and occasionally repetitive with the schema, but not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stateful 10-parameter replay tool with an output schema present, the description covers the full lifecycle semantics an agent needs: action prerequisites, cross-action state interactions, timing anchoring, and which return fields appear per action. Nothing material is left unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 100%, so the baseline is 3, but the description adds cross-parameter context the schema treats piecewise: which fields pair with which action, that the schema defaults for value/version exist for legacy callers and must not be relied on, and the ordering constraint on restore_rtc relative to the reset.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb set and resource: record input sequences, execute them, save/load .ppr recordings in the PPSSPP replay subsystem. This is clearly distinct from siblings like ppsspp_press_button or ppsspp_wait_frames, which provide inputs/frames rather than aggregate replay lifecycle control.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly enumerates the ten actions and their per-action prerequisites (execute needs version + base64_input, time_set needs value, save/load take a bare file name under output/replays/, session_id optional when exactly one session is active). It also states when not to rely on defaults and warns when restore_rtc is needed and when it must be set relative to the boot-aligned reset.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.