Cookwala / SDK and scenarios / 044
Retrying a start with the same Idempotency-Key never starts a second pot
Networks drop answers. An agent that retries POST /v1/executions with the same Idempotency-Key gets the execution already started, in its current state, instead of a second run of the same recipe.
Read first: /docs/CORE/ /docs/HUB/
Steps
Start a shakshuka run with the key ex-044-idem-key.
startExecutionThe run advances to the first step that needs a person.
Send the identical request with the identical key, as a client would after a lost answer. The hub returns the same execution at its current state, not a new one.
startExecutionReading the status confirms there is one execution and it is the one both answers described.
getExecutionThe retry carried the plan of the original start.
Outcome
You can retry a start safely. Next: scenario 050 shows what happens when the key differs but the execution id repeats.
Command line
cookwala hub --recipes examples --speed 200
jq '. + {"x-hub-human-present": true}' examples/core/execute-request.json | curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: ex-2026-10-04-001-a' -d @-
jq '. + {"x-hub-human-present": true}' examples/core/execute-request.json | curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: ex-2026-10-04-001-a' -d @-Recorded output
Status: ok
[1] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-044-idem", "seq": 0, "state": "accepted", "request": "ex-044-idem", "updatedAt": "2026-10-07T00:54:27Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": "hu…
[3] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-044-idem", "seq": 6, "state": "needs_human", "request": "ex-044-idem", "updatedAt": "2026-10-07T00:54:29Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": …
[4] getExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-044-idem", "seq": 6, "state": "needs_human", "request": "ex-044-idem", "updatedAt": "2026-10-07T00:54:29Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": …Code
Run: python scenarios/out/044-idempotent-retry-returns-the-same-execution/python.py
# Scenario 044: Retrying a start with the same Idempotency-Key never starts a second pot
# Networks drop answers. An agent that retries POST /v1/executions with the same Idempotency-Key gets the execution already started, in its current state, instead of a second run of the same recipe.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem
def load(path):
with open(path, encoding="utf-8") as f:
return json.load(f)
def pick(obj, path):
for part in path.replace("]", "").replace("[", ".").split("."):
obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
return obj
c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))
# Step 1: Start a shakshuka run with the key ex-044-idem-key.
try:
first = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-044-idem", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-044-idem-a"}, "ex-044-idem-key", True)
except CookwalaProblem as p:
first = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(first, "state") == "accepted", pick(first, "state")
print("ok", "state", "=", "accepted")
assert pick(first, "seq") == 0, pick(first, "seq")
print("ok", "seq", "=", 0)
assert pick(first, "id") == "ex-044-idem", pick(first, "id")
print("ok", "id", "=", "ex-044-idem")
# Step 2: The run advances to the first step that needs a person.
import time; time.sleep(4)
# Step 3: Send the identical request with the identical key, as a client would after a lost answer. The hub returns the same execution at its current state, not a new one.
try:
retry = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-044-idem", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-044-idem-a"}, "ex-044-idem-key", True)
except CookwalaProblem as p:
retry = p.body # a refusal is a result, not a crash
print("refused:", p.refusal)
assert pick(retry, "id") == "ex-044-idem", pick(retry, "id")
print("ok", "id", "=", "ex-044-idem")
assert pick(retry, "state") == "needs_human", pick(retry, "state")
print("ok", "state", "=", "needs_human")
assert pick(retry, "seq") == 6, pick(retry, "seq")
print("ok", "seq", "=", 6)
# Step 4: Reading the status confirms there is one execution and it is the one both answers described.
status = c.get_execution("ex-044-idem")
assert pick(status, "seq") == 6, pick(status, "seq")
print("ok", "seq", "=", 6)
assert pick(status, "state") == "needs_human", pick(status, "state")
print("ok", "state", "=", "needs_human")
# Step 5: The retry carried the plan of the original start.
assert pick(retry, "x-hub-plan.length") == 13, pick(retry, "x-hub-plan.length")
print("ok", "x-hub-plan.length", "=", 13)
print("scenario complete")
scenarios/044-idempotent-retry-returns-the-same-execution.json