Remember between runs: state
Every run starts from nothing — unless it keeps something. State is a small key/value store that belongs to one script or flow and survives between runs: the place for a cursor (the last id you processed), a counter, or the list of messages already handled. Values are JSON, writes are kept even if the run fails afterwards, and you can read and edit every key in the State tab.
- Read and write state from Python, TypeScript, JavaScript, C and C++
- Count safely with incr and change a value safely with update
- Inspect, edit and reset state in the State tab
- Know whose state a flow step uses, and the limits
What state is
A script’s state is its own: another script never sees it. Inside a flow, every step reads and writes the flow’s state, so the steps share one store — a step can leave a value for a later step, or for the next run of the flow. Runs started from the editor use the same state as scheduled, API and event runs: a test that moves a cursor moves it for real.
1from waiso import state2 3def main():4 n = state.incr("runs")5 last = state.get("last_note", "none yet")6 state.set("last_note", f"run {n}")7 return {"run": n, "previous": last}last_note5 h ago · run #8E6A00Added runs5 h ago · run #8E6A00Set last_note6 h ago · run #41C2D7Your first stateful script
- Save the script
Create
counterwith the code below. State belongs to a saved item: code that was never saved has none, and a call fails withstate_unavailable. - Run it twice
Press Run. The first output is
{"run": 1, "previous": "none yet"}; run again and it reads{"run": 2, "previous": "run 1"}. - Open the State tab
Pick State on the side rail:
runsholds2andlast_noteholds"run 2", each with the run that wrote it. Recent changes lists the writes as Added and Set.
from waiso import state
def main():
n = state.incr("runs") # atomic: two runs at once never lose a count
last = state.get("last_note", "none yet")
state.set("last_note", f"run {n}")
return {"run": n, "previous": last}{
"run": 2,
"previous": "run 1"
}The calls
In Python use waiso.state (or from waiso import state). In TypeScript and JavaScript import state from waiso; every call returns a promise. C has waiso_state_*, returning WAISO_OK or a negative code, with values as JSON text; C++ has waiso::state, which throws WaisoError.
| Call | What it does | C / C++ |
|---|---|---|
get(key, default) | The value, or the default when the key was never set. | waiso_state_get · state::get |
set(key, value) | Writes the value; kept even if the run fails afterwards. | waiso_state_set · state::set |
incr(key, by=1) | Adds atomically and returns the new number; runs at once never lose a count. | waiso_state_incr · state::incr |
cas(key, expected, value) | Writes only if the key still holds expected (null = absent), and says whether it did. | waiso_state_cas · state::cas |
update(key, fn, default) | Reads, applies fn, writes back only if nothing changed meanwhile; 5 tries, then state_conflict. Returns the value written. | — (use cas in a loop) |
delete(key) | Removes the key and says whether it existed. | waiso_state_delete · state::del |
all() | Every key and value as one object. | waiso_state_all · state::all |
Changing a value two runs may touch
A get followed by a set loses a write when two runs overlap: both read the same list, both write their own version. incr solves it for numbers; for anything else, update wraps your change in a compare-and-set and retries.
from waiso import state
def main(numbers: list = [1, 2, 3, 4, 5]):
seen = state.get("seen", [])
fresh = [n for n in numbers if n not in seen]
# update() re-reads and retries if another run changed "seen" meanwhile
state.update("seen", lambda s: s + [n for n in fresh if n not in s], default=[])
return {"new": fresh}The State tab
In the script editor, State is a side tab; on a flow page it is one of the tabs on the right; the script’s operator page shows it too. It lists every key with its value and who last wrote it (run … or by a person), and how much of the space is used. Add key and Edit value take any JSON (text needs quotes), Delete key removes one, and Reset deletes every key after a confirmation — the next run starts from its defaults. Recent changes shows the last 50 writes as Set, Added, Deleted or Reset.
Limits and error codes
- Each script or flow keeps at most 1 MB and 1,000 keys; a key is 1–200 characters without line breaks.
- The change log keeps the last 50 writes; values are not copied into it.
- Deleting the script or flow deletes its state.
| Code | When |
|---|---|
state_too_large | A write would pass 1 MB or 1,000 keys. |
state_conflict | update found the value changed on all 5 tries. |
state_invalid_value | The value is not JSON, or incr met a non-number. |
state_key_invalid | Empty key, over 200 characters, or with control characters. |
state_unavailable | The run belongs to no saved script or flow. |