How It Works
Quick Start
1
Subscribe and publish
2
Global bus with an agent
Both
publish() / publish_event() and publish_async() always record into history, whether or not subscribers are attached — get_history() returns every event you publish (capped at the 1000 most recent). The fast path still skips the subscriber walk when nothing is listening, so publishing to a bare bus stays cheap. Wrap expensive payload construction in a has_subscribers check, since that work is genuinely skipped when nothing is listening. Changed for sync in PR #4958; the async parity fix landed in PR #5258.Event Types
Durable Persistence
Attach a durable sink to persist every published event to SQLite across processes. In-memoryget_history() already records every event; a durable sink adds cross-process persistence on top. See Durable Event Log for the full story.
EventBus.attach_sink(sink) / detach_sink(sink) -> bool / has_sinks manage sinks; a sink is any object implementing EventLogProtocol.append(event).
Common Patterns
Async subscriber:Best Practices
Check has_subscribers before heavy work
Check has_subscribers before heavy work
Building summaries or embeddings for events nobody listens to wastes CPU — guard with
bus.has_subscribers.get_history() works without subscribers
get_history() works without subscribers
Every published event lands in history regardless of subscribers, so
get_history() is reliable for after-the-fact debugging on a bare bus. Since PR #4958 you no longer need a no-op subscriber to capture a record on the sync path; PR #5258 closed the same gap for publish_async(), so async lifecycle events fired before an observability subscriber attaches are no longer lost. For cross-process persistence, attach a durable sink (see Durable Event Log).Filter by event_types
Filter by event_types
Pass
event_types= to subscribe() so handlers only run for relevant events.Use get_default_bus for cross-component wiring
Use get_default_bus for cross-component wiring
The shared default bus lets agents, memory, and hooks emit events without passing a bus instance everywhere.
Prefer sync handlers unless you need async
Prefer sync handlers unless you need async
Sync callbacks run inline; async handlers are awaited during
publish_async only.Related
Durable Event Log
Persist events to SQLite and query per session
Hook Events
Hook lifecycle events alongside the bus
Spawn & Announce
Sub-agent events and coordination

