> Status: draft. Part of the Harmovela 0.2 transport-redis-streams profile.
Define how Harmovela runs over Redis Streams, supporting append-only event logs with consumer-group delivery, per-entry acknowledgement, and entry-ID-based replay.
Harmovela over Redis Streams stores each Harmovela event as one stream entry:
XADD and carries the Harmovela envelope as entry fields.body field; selected envelope fields are stored as flat fields for server-side filtering and inspection.XADD entries carry the following fields, in addition to the body field holding the complete JSON-encoded event:
| Field | Harmovela Field | Type |
|---|---|---|
body | (entire envelope) | JSON string |
aep-type | type | string |
aep-source | source | string |
aep-session | session_id | string |
aep-conversation | conversation_id | string |
aep-task | task_id | string |
aep-correlation | correlation_id | string |
aep-causation | causation_id | string |
aep-delivery-mode | delivery.mode | string |
Flat fields let consumers route or filter without deserializing body.
| Harmovela context | Redis stream key | Example |
|---|---|---|
Type pattern task.* | aep.type.<type> | aep.type.task.progress |
Source agent:researcher | aep.source.<source> | aep.source.agent:researcher |
| Session | aep.sess.<session_id> | aep.sess.sess_01 |
| All events | aep.events | Single-stream deployment |
The default stream prefix is aep. Implementations should allow per-envelope stream routing or a single-stream deployment with field-based filtering.
In Redis Cluster, a stream key hashes to one slot. To co-locate related events on the same node, use hash tags in the stream key (e.g., aep.{task_01}.type.task.progress). Entries within a single stream are always totally ordered by entry ID.
| Harmovela Delivery Mode | Redis Streams Mechanism |
|---|---|
best_effort | XADD with MAXLEN capped; consumers read the tail with XREAD and do not track a group |
at_least_once | Consumer group with XREADGROUP; XACK only after Harmovela event.acknowledged is emitted |
replayable | Consumers store a cursor entry ID and replay with XRANGE/XREAD from that ID |
XREADGROUP GROUP <group> <consumer> COUNT n STREAMS <key> >.XACK.XACK only after the Harmovela event.acknowledged event is produced.XAUTOCLAIM (or XCLAIM) reassigns idle pending entries to another consumer.<ms>-<seq>).group:key:entry_id.XRANGE <key> <entry_id> + or XREAD ... STREAMS <key> <entry_id>.MAXLEN/MINID retention dictates the maximum replay window.Harmovela sessions map to Redis Stream consumer groups:
| Session | Consumer Group |
|---|---|
sess_01 | aep-sess_01 |
| (no session) | aep-default |
| Multiple agents sharing a session | Same group — entries distributed across members |
| Independent sessions | Separate groups — each receives the full stream |
Groups are created with XGROUP CREATE <key> <group> $ MKSTREAM (or 0 to consume history).
Entries within a single stream key are totally ordered by entry ID:
aep.events).| Redis State | Session State |
|---|---|
Consumer created, group joined (XGROUP CREATECONSUMER) | CREATED |
First XREADGROUP returns assignment | OPENED |
| First entry consumed | READY |
Consumer deleted (XGROUP DELCONSUMER) | CLOSED |
| Consumer idle beyond claim timeout | ERROR |
go-redis (Go), ioredis/node-redis (Node.js), redis-py (Python), Jedis/Lettuce (Java).XADD ... MAXLEN ~ <n> or trim with XTRIM MINID.XAUTOCLAIM on a background interval.MKSTREAM, not silently implicit.XACK, XAUTOCLAIM, and entry-ID replay are Redis-native concepts mapped to Harmovela semantics.