Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
@tutti-os/event-stream-core
Catalog-agnostic transport core for the business event stream (daemon ↔ renderer over WebSocket). It owns the parts that have nothing to do with a concrete event catalog:
- connection lifecycle (
connect/dispose) - heartbeat (ping/pong) and exponential-backoff reconnect
- frame encode/decode and the subscription registry
connectionStateobservability- topic + scope multiplexing over a single socket
Everything catalog-specific — the concrete topics, payload validators, protocol
version/revision, and the scope axis — is injected via an
EventStreamProtocol. The core never imports a concrete catalog, so multiple
products can bind their own:
import { createEventStreamClient } from "@tutti-os/event-stream-core";
const client = createEventStreamClient<MyClientEvent, MyServerEvent, MyScope>({
resolveUrl: () => "ws://127.0.0.1:7790/v1/events/ws",
protocol: {
protocolVersion,
catalogRevision,
assertValidClientFrame,
assertValidServerFrame,
createClientEvent,
normalizeScope,
scopeKey,
eventMatchesScope
}
});
The scope type S is generic: tutti binds it to { workspaceId }, other products
(e.g. group chat) can bind it to { roomId }. The transport is identical.