Redis Session as Shared State: Coordinating AI Components Without a Message Bus
Two AI processes need to share state for the same session — one primary, one observer running async. Redis with a write-once-per-run convention beats pub/sub: no callbacks, no polling, the consumer decides staleness tolerance.

IP/NDA FILTER V.1 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
The problem
When you have two AI processes that both need to read and write state for the same user session — one acting as the primary interface, one running as a background observer — you need a shared store. The naive approach is to pass state in API calls between them. The problem: the observer runs asynchronously in a thread pool, fires on its own schedule, and the primary process doesn't know when it's done. You can't block on it.
The approach
The solution we're using is Redis as the shared session store, with a write-once-per-run key naming convention. The primary process owns a session dict keyed by session_id. The observer writes two fields into that dict — \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (a JSON blob with \x00\x00\x00\x00\x00\x00\x00\x00, issues, follow-up suggestions, summary) and \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (a timestamp). Both writes are atomic from the primary process's perspective: it reads the whole session, the observer may or may not have written its fields, and the tool checks for their presence before using them.
This avoids all coordination overhead. There's no pub/sub, no callback, no polling. The observer is fire-and-forget: it gets a copy of the transcript, runs its analysis, writes back to Redis, and exits. The next tool call from the primary process picks up whatever is there. If the observer hasn't run yet, the tool returns {"ready": false} and the primary process continues without it.
What I learned
The interesting edge case is stale observer notes. If a session is long and the observer ran early, the notes may no longer reflect the current conversation state. We handle this with \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00: the primary process can check how old the notes are and decide whether to trust them. This is a pattern borrowed from cache invalidation — the data isn't wrong, it's just possibly stale, and the consumer decides the tolerance.
The other thing: writing partial updates to a Redis JSON blob requires reading the whole object, mutating in Python, and writing back — there's no atomic merge operation unless you use RedisJSON. For session state at this scale (hundreds of concurrent sessions, each a few KB) the read-modify-write cycle is fast enough and the simplicity is worth it. RedisJSON would add a dependency and a new failure mode for marginal gain.
filter applied by Reel CMO reel@bridgestack.systems
