Runtime events
The named events Anglish spaces emit and consume — the substrate of declarative flow.
Anglish spaces communicate through named runtime events rather than function call chains. An event is a %name emitted by a task or space-native trigger; declarations bind tasks to events using vibe lines.
This is the substrate that makes the contract enforceable: every flow is observable, every transition is named, and the compiler can verify that all referenced events are produced somewhere.
Lifecycle events
Every space participates in a small set of lifecycle events:
%onEnter— the space has been entered (a UI panel gained focus, an IO stream opened, a data store mounted).%onExit— the space is shutting down or losing focus. A natural place to emit$rotateLogsor flush buffers.%onError— something went wrong. The space’s vibe block typically delegates to a recovery task.
In a :UI space, %onEnter is what fires when a panel becomes active. In :IO, it fires when a connection opens. In :DATA, it fires when the dataspace is first read or written in a session.
Submission and update events
UI spaces add a small vocabulary for user-driven flow:
%onSubmit— a form has been submitted.%onChange— an input value has changed.%dataUpdated— emitted by a:DATAspace when the contents at a path change.
@userSettings:UI
>>> Bind fields to %profileData.
>>> When %onEnter, trigger $ui_reader(out=%profileData).
>>> When %onSubmit, delegate to $validateProfile.
>>> On %onError from $validateProfile, send %profileErrors to $ui_writer.
Each binding (When %X, trigger Y; On %X, delegate to Y) is an explicit edge in the runtime graph.
Stream events
:IO spaces emit stream events as data flows:
%sensorUpdate— a new value arrived from a sensor or stream.%signalUpdate— generic stream tick for actuator or signal-emitting devices.
@camFeed:IO
>>> On %onEnter, trigger $io_reader(out=%jpgFrameStream).
>>> Each %sensorUpdate delegates to $decodeFrame(in=%jpgFrameStream).
:IO spaces are stateless between events; if you need to retain state, route through a :DATA space.
Outcome events
Tasks that produce a result emit named outcome events. The convention is %X{Success|Failure} or %X{Result|Error}:
%saveSuccess/%saveFailure— the persistence task completed.%orderSuccess/%orderFailed— order placement returned.%validationErrors— validation surfaced one or more issues.%rotationEvent— log rotation completed.
Outcome events are how composed spaces hear back from imported tasks without the parent needing to peek inside them.
Author-defined events
Every event is just a %name. Authors are encouraged to introduce domain-specific events whose names read clearly in vibe prose: %inventoryLow, %deviceResetCmd, %ticketEscalated. The compiler’s only requirement is that every consumed event is produced somewhere — referenced events must resolve, just like any other identifier.
Why events, not return values
Two reasons.
Reviewability. A function call chain hides flow inside the bodies of the functions. An event flow surfaces it: every transition is a line you can read in a vibe block. A reviewer can re-read the contract and know what runs after what.
Locality of change. Adding a new consumer of %saveSuccess does not require modifying the producer. Late binding is the default, not an opt-in.