Replay and Overrides
Replay executions from checkpoints with flow and checkpoint overrides
Replay creates a new execution from a previous one.
Use replay when you want to keep earlier durable work and rerun only parts of your workflow.
SDK replay
import kitaru
client = kitaru.KitaruClient()
replayed = client.executions.replay(
"kr-a8f3c2",
from_="write_draft",
topic="New topic",
overrides={
"checkpoint.research": "Edited notes",
},
)
print(replayed.exec_id)
print(replayed.original_exec_id) # points to source executionFlow-object replay
handle = content_pipeline.replay(
exec_id="kr-a8f3c2",
from_="write_draft",
topic="New topic",
overrides={"checkpoint.research": "Edited notes"},
)
result = handle.wait()CLI replay
kitaru executions replay kr-a8f3c2 \
--from write_draft \
--args '{"topic":"New topic"}' \
--overrides '{"checkpoint.research":"Edited notes"}'Selector rules
from_ can target:
- checkpoint name (for example
write_draft) - checkpoint invocation ID
- checkpoint call ID
If a selector is ambiguous, replay raises KitaruStateError.
What gets replayed
Replay computes a set of replay roots, then re-executes those roots and their downstream descendants.
from_always contributes one replay root.- Each
checkpoint.<selector>override adds replay roots at the direct consumers of that checkpoint output. - Any checkpoint that is neither a replay root nor a downstream dependency is skipped.
Override keys
Replay override keys must start with checkpoint..
Examples:
checkpoint.researchcheckpoint.fetch_data
Any other prefix raises KitaruUsageError.
Override behavior:
- Overrides target checkpoint outputs (
checkpoint.<selector>). - The overridden checkpoint must expose a single output.
checkpoint.<selector>replaces that checkpoint output at each direct consumer input; the source checkpoint itself is not forced to re-execute.- Replay roots include direct consumers of the overridden checkpoint output, so replay re-executes from those consumers forward.
- If an overridden checkpoint fans out to multiple direct consumers, replay re-executes all those consumer branches.
Waits during replay
Replay does not support overriding or pre-populating wait results. If a replayed
execution reaches a wait() during normal execution, that wait behaves like any
new wait and must be resolved through the normal wait input flow:
- SDK:
client.executions.input(exec_id, wait="name", value=...) - CLI:
kitaru executions input <exec_id> --value ...(auto-detects single pending wait) - CLI interactive:
kitaru executions input <exec_id> --interactive
Divergence
Replay can raise KitaruDivergenceError when the backend detects that durable
call sequence compatibility is broken.
Also check replayed execution failure metadata:
latest = client.executions.get(replayed.exec_id)
if latest.failure:
print(latest.failure.origin, latest.failure.message)Example in this repository
uv sync --extra local
uv run examples/features/replay/replay_with_overrides.py
uv run pytest tests/test_phase16_replay_example.pyFor the broader catalog, see Examples.