Skip to content

2.0: Scope event subscriptions by client interest #36443

Open

Description

@kitlangton

Parent: #36441

Problem

/api/event currently subscribes every connected client to the process-global EventV2 bus. Every TUI receives events for unrelated locations, workspaces, and sessions, so server and aggregate client work scale with all connected TUIs rather than interested TUIs.

Goal

Introduce explicit event subscription scope so clients receive only events they need, while preserving a small, well-defined channel for truly global events.

Requirements

  • Define subscription identity in terms of project/location, optional workspace, and optional session interest.
  • Filter before events enter subscriber queues and before schema encoding/JSON serialization.
  • Define how a client updates its interest as the active route/session changes.
  • Avoid overlapping streams or duplicate delivery during scope changes.
  • Preserve global events such as server lifecycle/update notifications through an explicit global scope.
  • Document reconnect and resume semantics.

Acceptance criteria

  • A client scoped to session A does not receive session B events.
  • A client scoped to one location does not receive unrelated location events.
  • One event is delivered exactly once to each eligible client.
  • Opening unrelated TUIs does not increase serialization count for an active session.
  • Tests cover 11 concurrent clients with disjoint and overlapping scopes.
  • A fan-out benchmark demonstrates cost proportional to interested subscribers, not total subscribers.

Activity

  1. added
    perfIndicates a performance issue or need for optimization
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Jul 11, 2026
  2. kitlangton commented on Jul 19, 2026

    @kitlangton
    ContributorAuthor

    A current next-15834 capture confirms this failure mode with nine TUIs and eight running sessions: unrelated clients received identical stream-byte deltas while each consumed sustained CPU, and the TUI data reducer created/reactively mutated foreign-session message state. Full process, network, database, and origin/v2 source evidence is in #36441: #36441 (comment). The server now encodes each event once, but queue/write, client parsing/dispatch, and projection still scale with total subscribers.

  3. kitlangton commented on Jul 19, 2026

    @kitlangton
    ContributorAuthor

    #37792 tracks the client-side complement to scoped delivery. At the pinned next-15834 revision, DataProvider.handleEvent accepts every emitted event, and message.update(sessionID) creates a transcript array plus retained message-index Map for an unseen event-owned Session. Other handlers create foreign active, pending, input, permission, and form state or trigger location refreshes.

    Server-side scoping remains the primary fix here. The separate TUI issue defines the defense-in-depth rule and tests: an event for Session A must not create keys or HTTP side effects in a client following only Session B, while explicitly followed cross-location child Sessions must continue to work.

  4. self-assigned this
    on Jul 19, 2026
  5. rektide commented on Sep 5, 2026

    @rektide
    Contributor

    I'm going to assess a little bit deeper what I ended up with, but I've burned a lot a lot a lot of tokens designing this out, just eager to share. This is a decent exploraiton that I am going to try to figure out how to deliver incrementally.

    https://github.com/rektide/opencode/tree/bus-smart

  6. raihan-js commented on Oct 12, 2026

    @raihan-js

    @thdxr research from a contributor workspace confirms the gap: GET /api/event takes no query parameters (packages/protocol/src/groups/event.ts:44-47) and its description says "across all server locations". This means every remote bot receives every event from every session on the host and filters client-side — a privacy and scaling problem. Already labeled perf/core/2.0 and part of epic #36441. The workspace finds this the single most impactful infrastructural gap for any chat-bot integration. Proposing to take the PR since it's pure infrastructure (no UI, perf-labelled, skips design-review gate).

  7. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the write-up. I checked the current event pipeline on dev (77a0fd6f). It works the way you describe, but by design:

    • The /api/event subscribe query only takes an optional types filter, and its schema says "When omitted, all events are sent" (packages/protocol/src/groups/event.ts).
    • EventFeed.make (packages/server/src/event-feed.ts) listens on the process-wide bus. It encodes each event once and pushes the shared string onto every connected subscriber whose types set matches. Nothing scopes delivery by location, workspace or session.

    This is documented behaviour, not a defect I can reproduce, so I'm treating it as feature/design work under #36441. The scoping, update and reconnect semantics, plus the 11-client tests and fan-out benchmark from the acceptance criteria, would all be new work in those two files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

2.0coreAnything pertaining to core functionality of the application (opencode server stuff)perfIndicates a performance issue or need for optimizationtui

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions