You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add declared event streams: named, agent-owned subscriptions that turn external-world changes (CI runs, PRs, timers, monitoring) into durable, deduplicated events in the owning agent's inbox, waking it through the existing delivery transports (DING / MCP push / app-server) untouched. This is the design issue that #137's ingress contract anticipated; the full intent layer lands as the docs/vrs/04-stream/ subsystem with two decision records and four executable experiment records.
A stream with a command lowers to one derived exec companion (stream-<name>) through the same seam as the generated DING — inheriting launch-with-agent, suspend/retire teardown, independent parking, crash surfacing to the supervisor. A stream without a command is the Add idempotent shell-driven event ingress over the native message bus #137 external-producer boundary (systemd timers, webhook bridges).
An event is an ordinary inbox record (same filename grammar, directories, archive semantics) carrying stream / event-id / optional key frontmatter. Old readers see a normal message; delivery paths are untouched; DING gains exactly one branch: the » marker.
event-id is mandatory and dedup scope is (stream, event-id): replays — concurrent or crash-interrupted — return the original filename and never re-notify. Dedup state is a bounded constant-size ring per stream; events do not write the Agent Sent ledger.
--supersede archives the stream's unread predecessor per key before publishing (log-compaction semantics), producer-side only — DING staged ownership is never touched.
Agents self-subscribe by editing their own declaration through the existing serialized authoring path (st2 stream add/rm, R25 authority).
Adapters (the world-specific logic) ship outside st2 (nix layer); st2 keeps the contract plus no-network example fakes. No cadence in v1: a timer is a sleeping adapter; the reserved schedule node and DQ1 scheduled work stay a separate track.
Why this shape — evidence
Four executable explorations back the two decision records (docs/vrs/.decisions/0004, 0005; experiments under docs/vrs/04-stream/.experiments/):
Ingress comparison (16 tests): both the message path and the service-principal path are exactly-once under 12-way concurrent replay; the message path cannot express a non-agent producer and writes one Agent Sent row per event (MESSAGE-R11); coalesce-to-latest cannot live in DING.
Lifecycle spike (27 tests): the derived-companion seam carries stream sources with zero changes to run/flapping/park/inventory; a content hash cannot distinguish replay-after-restart from a genuine repeat — the producer-supplied event-id is the contract.
Unification-pole design + spike (13 tests): one actor model/one ledger is crash-safe at all nine publication checkpoints even for non-agent senders — but imposes prove-what-I-said ledger machinery (permanent, O(history) validation) on machine producers.
Differentiation-pole design + spike (12 tests + DING proofs): producer-side supersession never re-pastes a DING-staged predecessor (24 supersedes in 146 ms → one poke, zero staged retries, one unread head); stream state stays constant-size; R15 holds.
Both poles converged independently on: events ride ordinary inbox files, one new glyph, fan-out fixed by scoping dedup per recipient, and the typed request/reply envelopes eventually absorbed (a reply to an event is an ordinary message reply; pending|replied derives from in-reply-to) — staged behind a deprecation window because the request wire types carry deny_unknown_fields (DQ-S4).
Relationship to existing anchors
Add idempotent shell-driven event ingress over the native message bus #137: the ingress acceptance criteria are satisfied by this design (evidence posted there earlier); the command-less stream is its external-producer boundary, and st2-supervised adapters natively cover its bootstrap-timer case.
Producer-identity from grammar for nested streams; stream-state path; ring bound K (measure, don't guess); request-absorption staging; top-level shared streams (defined as a generalization: a nested stream is a top-level stream whose owner and sole recipient is the enclosing agent); parked-stream owner notification; event body bounds vs #238.
Acceptance
Per DQ1's process bar: the executable evidence exists (four experiment records with named tests, all invariant suites green, pre-existing failure sets verified against baseline); upstream review requested — especially on decision 0004 (record kind) and 0005 (locality + vocabulary) before implementation lands.
Summary
Add declared event streams: named, agent-owned subscriptions that turn external-world changes (CI runs, PRs, timers, monitoring) into durable, deduplicated events in the owning agent's inbox, waking it through the existing delivery transports (DING / MCP push / app-server) untouched. This is the design issue that #137's ingress contract anticipated; the full intent layer lands as the
docs/vrs/04-stream/subsystem with two decision records and four executable experiment records.The design in one screen
st2 event emit dev3.demo --stream gh-ci \ --event-id run-812 --key pr-42 --supersede \ --subject 'CI: failure on PR #42'commandlowers to one derived exec companion (stream-<name>) through the same seam as the generated DING — inheriting launch-with-agent, suspend/retire teardown, independent parking, crash surfacing to the supervisor. A stream without acommandis the Add idempotent shell-driven event ingress over the native message bus #137 external-producer boundary (systemd timers, webhook bridges).stream/event-id/ optionalkeyfrontmatter. Old readers see a normal message; delivery paths are untouched; DING gains exactly one branch: the»marker.(stream, event-id): replays — concurrent or crash-interrupted — return the original filename and never re-notify. Dedup state is a bounded constant-size ring per stream; events do not write the Agent Sent ledger.--supersedearchives the stream's unread predecessor perkeybefore publishing (log-compaction semantics), producer-side only — DING staged ownership is never touched.st2 stream add/rm, R25 authority).schedulenode and DQ1 scheduled work stay a separate track.Why this shape — evidence
Four executable explorations back the two decision records (
docs/vrs/.decisions/0004,0005; experiments underdocs/vrs/04-stream/.experiments/):Both poles converged independently on: events ride ordinary inbox files, one new glyph, fan-out fixed by scoping dedup per recipient, and the typed request/reply envelopes eventually absorbed (a reply to an event is an ordinary
message reply;pending|repliedderives fromin-reply-to) — staged behind a deprecation window because the request wire types carrydeny_unknown_fields(DQ-S4).Relationship to existing anchors
main's--idempotency-key+ durable sender ledger (details in the Add idempotent shell-driven event ingress over the native message bus #137 comment); disposition stays with its author.everyremains rejected; a future declared cadence would extend restart policy, not add an in-process loop.04-stream/open-questions.md(DQ-S7 for Deliver bounded inbox bodies for one-inference DING handling #238; the event-sidekeyaxis is deliberately not Topic/thread projection over the native message bus? #49's message-side topic).Open questions (spec DQ-S1..S7)
Producer-identity
fromgrammar for nested streams; stream-state path; ring bound K (measure, don't guess); request-absorption staging; top-level shared streams (defined as a generalization: a nested stream is a top-level stream whose owner and sole recipient is the enclosing agent); parked-stream owner notification; event body bounds vs #238.Acceptance
Per DQ1's process bar: the executable evidence exists (four experiment records with named tests, all invariant suites green, pre-existing failure sets verified against baseline); upstream review requested — especially on decision 0004 (record kind) and 0005 (locality + vocabulary) before implementation lands.
Posted on behalf of @schickling
agent_toolagent_modelworktreemachine