Skip to content

Emit sessions.changed for store-mutating in-chat commands (/name, /goal) #88598

Description

@BSG2000

Summary

Store-mutating in-chat slash commands that change session metadata do not broadcast a sessions.changed event. As a result, already-open session lists (web session picker, TUI, SDK subscribers) stay stale until the next reload/refresh.

This was surfaced by the Codex review on #88581 (the new /name command, P2). It is not specific to /name — the peer command /goal behaves identically. Both write the session store directly through the auto-reply command pipeline, which has no gateway broadcast context.

Current behavior

  • /name <topic> (and /goal …) update SessionEntry fields in the store and persist them correctly.
  • Open clients only see the change after a reload, because no sessions.changed event is emitted for command-driven metadata changes.
  • By contrast, the sessions.patch RPC (used by the web admin/session-picker inline rename) does emit sessions.changed via emitSessionsChanged.

Why it isn't a one-line fix

There is currently no single call site that has both the command reply result and the gateway broadcast context:

  • The reply pipeline (getReplyFromConfig) runs deep in the auto-reply / infra layer. Its caller (src/infra/heartbeat-runner.ts, web wrapper src/library.ts) has no broadcastToConnIds / session-subscriber registry in scope.
  • The broadcast context (broadcastToConnIds + session-event subscribers) lives in src/gateway/server-chat.ts closures (the lifecycle sessions.changed broadcasts around lines ~526 and ~1199), but those closures do not invoke the reply pipeline.
  • emitSessionsChanged in src/gateway/server-methods/sessions.ts (~line 316) is module-private.

Proposed approach (for discussion)

Thread a "session metadata changed" signal from the command handler up to a place that has broadcast context, then emit sessions.changed for all store-mutating commands uniformly:

  1. In the command handler, tag the resulting ReplyPayload with a metadata marker (e.g. a new optional field on ReplyPayloadMetadata, set via setReplyPayloadMetadata, carrying { sessionKey, reason: "command-metadata" }).
  2. Bubble that marker up through getReplyFromConfig's return to a caller that holds gateway broadcast context.
  3. At that site, read getReplyPayloadMetadata(reply) and call a (newly exported/shared) emitSessionsChanged-equivalent.

This is a cross-layer gateway change with non-trivial blast radius on core event semantics, so it deserves a dedicated design rather than being folded into the small /name command PR (#88581).

Acceptance criteria

  • /name and /goal (and any future store-mutating chat command) emit sessions.changed so open web/TUI/SDK session lists update live, without reload.
  • Event payload matches the existing sessions.patch shape (includes sessionKey + updated row incl. label).
  • Tests assert the broadcast is emitted for command-driven metadata changes (model on src/gateway/server.sessions.list-changed.test.ts).
  • Docs in docs/tools/slash-commands.md updated to state live refresh once implemented (currently documents refresh-on-reload).

References


Note for maintainers/triagers: suggested labels — enhancement, gateway. (Opened by a non-triage contributor who cannot set labels.)

Metadata

Metadata

Assignees

Labels

P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions