Cookwala reference hub
The Core 0.2 API (api/core.openapi.yaml) served by a simulated device, so the quickstart curl works on your laptop and device makers have something to test against before they have hardware. Standard library Python, no persistence, no accounts.
python hub/cookwala_hub.py --port 7878
# or
docker build -t cookwala-hub -f hub/Dockerfile . && docker run -p 7878:7878 cookwala-hubWhat it does, in the order Core requires:
POST /v1/executionschecks the Idempotency-Key, the Core version, the recipe hash, recalls, the agent mandate scope and allergen blocks, then dry-runs the recipe against the device's capabilities. If any step cannot be verified it answersrefusedwith the reason and the step, before anything heats up.- Accepted executions advance
accepted → preparing → running → completedon a clock (default 20 simulated seconds per real second). Steps a person must do or confirm pause the execution inneeds_human;POST …/resumewithIf-Matchcontinues. - Medium temperatures reported in
GET /v1/executions/{id}stay inside the operation envelopes fromvocab/ops.json. POST …/stopalways works and ends instoppedwith anaborted_safelog.GET …/logreturns anExecutionLogwith no personal data andconsent.dataset: none.GET /v1/safety-limitsreturns the limits pack the hub enforces. No request can change it.
Try the refusal first, then add a person:
H=$(python tools/cookwala_ref.py hash examples/shakshuka.cookwala.json)
curl -s -X POST localhost:7878/v1/executions -H 'Content-Type: application/vnd.cookwala+json' -H 'Idempotency-Key: demo-00000001' \
-d "{\"core\":\"0.2.0\",\"kind\":\"ExecuteRequest\",\"id\":\"ex-1\",\"recipe\":\"cw:cookwala.ai:example-shakshuka\",\"recipeHash\":\"$H\",\"requestedBy\":\"person-1\",\"idempotencyKey\":\"demo-00000001\"}"
# → "state": "refused", "reason": "needs_human_present" (cutting may not run unattended)
curl -s -X POST localhost:7878/v1/executions -H 'Content-Type: application/vnd.cookwala+json' -H 'Idempotency-Key: demo-00000002' \
-d "{\"core\":\"0.2.0\",\"kind\":\"ExecuteRequest\",\"id\":\"ex-2\",\"recipe\":\"cw:cookwala.ai:example-shakshuka\",\"recipeHash\":\"$H\",\"requestedBy\":\"person-1\",\"idempotencyKey\":\"demo-00000002\",\"x-hub-human-present\":true}"
# → "state": "accepted" with a plan per step; then GET /v1/executions/ex-2 to watch it runx-hub-human-present is a hub extension field (Core allows x- fields); a real hub learns presence from its own sensors.
Limits: one device, one process, in-memory state, no TLS, no pairing. It is a test bed, not a product; see docs/CERTIFICATION.md for what a real executor must also prove.
Authentication, CORS and the network #
--token TOKEN(orCOOKWALA_HUB_TOKEN): every request must carryAuthorization: Bearer TOKENor gets401with a problem document. Without it the hub is an open test bed and printsauth=NONEat start-up.POST /v1/executions/{id}/stopnever requires the token or anIdempotency-Keyheader (Core 6.2: a stop is never refused once the caller can reach the executor).--cors ORIGIN: send CORS headers for that one browser origin. Default: no CORS headers at all.--bind 0.0.0.0to listen on the network; the default is127.0.0.1.- Status documents validate against
ExecutionStatus:requestis the request id, the running step is understep, and the hub's own plan and simulated medium reading travel asx-hub-planandx-hub-mediumTempC.ETagis a quoted entity-tag;If-Matchaccepts it quoted or bare. POST /v1/incidentsvalidates the body againstIncidentReportand answers400otherwise.- Before accepting, the hub runs the same dry run as the CLI with its SafetyLimits: a target outside the operation envelope, a non-numeric temperature, a heat level that cannot hold the envelope, or a value above a stricter local limit is refused (
envelope_out_of_range,safety_limit). Allergen blocks match the recipe's declared allergens in every scheme and on every ingredient.
Reference tools over HTTP (/v1/tools/*) #
Not part of the Core API. The hub exposes the reference library so a client in any language gets exactly the behaviour the conformance vectors test: POST /v1/tools/{hash|verify|dryrun|envelope|sms|constraints|convert|ladder|validate|humanitarian} and GET /v1/tools/{recipes|recipes/{id}|devices|vocab/ops|registry}. The arguments and answers are listed in scenarios/OPERATIONS.md; every SDK client (sdk/*) wraps them. validate resolves a document's kind inside container schemas, as tools/validate_specs.py does.