iii-state
v0.13.0-next.1Distributed key-value state management with reactive change triggers.
skill doc
Store or replace a value at a scope and key
how-toWhen to use
Call state::set when you have a complete value (object, array, or scalar) that should be written to a scope/key slot, replacing whatever was there before. It is the right call for first-time inserts and idempotent upserts where the new value is fully known.
Reach for it when:
- You are persisting a freshly-built record (user profile, order, session) under a known key.
- You want to publish a snapshot of a value so other workers can read it via
state::get. - You want to fan out a
state:createdorstate:updatedevent to every registeredstatetrigger.
Use state::update instead when you only need to change specific fields, increment a counter, or append to an array — set always replaces the entire value at key.
Inputs
{
"scope": "users", // required. Namespace that groups related keys.
"key": "user-123", // required. Identifier within the scope.
"value": { // required. Any JSON-serializable value; replaces whatever is at scope/key.
"name": "Alice",
"email": "alice@example.com"
}
}scope, key, and value are all required. The engine also accepts data as a backward-compatible alias for value; new callers should prefer value.
Outputs
{
"old_value": null, // The previous value at scope/key, or null when the key did not exist.
"new_value": { // The value that was stored. Echoes the input value.
"name": "Alice",
"email": "alice@example.com"
}
}old_valueisnullexactly when the key was newly created. Use it to distinguish create from update without a priorstate::get.new_valuealways reflects what is now stored. For raw scalars,valueandnew_valueare the same scalar JSON.
Side effects
Every successful state::set invokes the engine's trigger fan-out for the state trigger type. Each matching trigger (filtered by optional scope, key, and condition_function_id on the trigger config) receives the following event payload:
{
"type": "state", // Always "state".
"event_type": "state:created", // "state:created" when old_value was null, otherwise "state:updated".
"scope": "users",
"key": "user-123",
"old_value": null, // Previous value, or null for newly created keys.
"new_value": { "name": "Alice" } // The stored value, matches the function's new_value.
}- Trigger invocations are spawned asynchronously after the adapter write returns, so the caller does not wait for handlers to finish.
- A failing handler does not roll back the write; the value remains stored.
Worked example
Persist a user profile so other functions can read it back:
{
"scope": "users",
"key": "user-123",
"value": {
"name": "Alice",
"email": "alice@example.com",
"preferences": { "theme": "dark" }
}
}Response when the key is brand new:
{
"old_value": null,
"new_value": {
"name": "Alice",
"email": "alice@example.com",
"preferences": { "theme": "dark" }
}
}Related
state::get— read the value back byscopeandkey.state::update— change individual fields without rewriting the whole document.state::delete— remove the key and firestate:deleted.state::list— enumerate every value in the scope after writing.- React to state changes — register a
statetrigger so another function runs when this write fires an event.