The Q Vernal webchat and Sanctum Tasks needed to talk to each other in a way that survived a user closing the tab and coming back the next day. They were not talking to each other in that way. Each Tasks session was producing a new Letta identity, which meant a returning user was a stranger to the system, the conversation history from yesterday was orphaned, and the memory blocks had to be reconstructed every time. In May we shipped the q_vernal_webchat plugin as a pull-model bridge and fixed the identity mapping so one Tasks user maps to exactly one Letta identity, regardless of how many sessions they open. This post covers the architectural decision, the evidence that the prior model was failing, what the two commits actually do, and what the operator-level effects are.

Decision
The framing decision was about identity granularity. The prior model was per-session: every time a webchat session opened, a new Letta identity was minted for it. The model was simple and it was wrong. The right model is per-user: one Tasks user maps to one Letta identity, and sessions are views onto that identity, not containers for new ones.

The decision sounds small and it is not. Identity is the foundation that conversation history, memory, and continuity sit on. If the foundation is per-session, the structure built on top has to work around the churn. If the foundation is per-user, the structure inherits continuity for free.
The secondary decision was about the bridge model itself. The q_vernal_webchat plugin is pull-model, meaning Tasks pulls from Q Vernal on a defined cadence rather than Q Vernal pushing into Tasks. The pull model puts the cadence and the failure handling on the side that has the most context about its own state, and it makes the bridge a regular plugin that can be updated independently of either product.
Evidence
The evidence for the identity problem was visible in three places. The first was conversation history: a Tasks user who returned the next day had no history. The second was memory: a memory block that took ten minutes of conversation to build yesterday was empty today. The third was operator triage: when a user reported a problem with the agent's behavior, the operator had no stable identifier to look up, only a session id that no longer resolved to anything.
The pull-model evidence was a different shape. The previous bridge was push-model from Q Vernal into Tasks, with Q Vernal maintaining the connection state. When Q Vernal's connection state drifted from Tasks's state, the bridge would either drop messages or duplicate them, and there was no clean way to recover. A pull-model bridge, where Tasks reads on a schedule, makes the failure mode local to the bridge and recoverable from either side.
Implementation
4d12478 (2026-05-22) adds the q_vernal_webchat plugin. The plugin lives alongside the rest of the chat surface code and registers as a Tasks pull-model bridge. It exposes the bridge protocol that Tasks expects, and it talks to Q Vernal through the same internal API that the rest of the chat surface uses. The plugin is a separate code path from the rest of Broca, which means it can be updated, rolled back, and reasoned about independently.
af0a19d (2026-05-22) is the identity fix. The mapping is now one Tasks user to one Letta identity, stored as a stable relationship in the bridge's user table. When a Tasks user opens a session, the bridge resolves them to their existing Letta identity. When the user has never talked to the agent before, a new identity is created exactly once and reused for every future session. The per-session identity minting is gone.
The two commits ship together because the bridge without the identity fix is just a faster way to create orphan identities. The identity fix without the bridge is just a stable identity with no reliable way to reach it. The architectural shape requires both, and they are sequenced the way they are for that reason.
What this means architecturally
The architectural implication is that identity is now a property of the user, not a property of the conversation. That is the same shift that happened in the early days of single-page apps, when identity moved from a session cookie to a user object. The surface of the system does not look different. The way the system reasons about its own state is different.
A second implication is that the bridge is now a stable integration surface. The plugin contract is fixed, the protocol is fixed, and the failure modes are local. Either side can change its internal implementation without breaking the other, as long as the bridge contract holds. This is what makes the bridge a bridge rather than a tightly-coupled adapter.
A third implication is that the operator surface gets a stable identifier. The user table is the source of truth. An operator triaging a ticket can look up the user, see their history, see their memory state, and see which sessions are open. The session id is still useful for debugging, but it is no longer the only handle on the user.
What the operator sees
Three things changed for operators in the week after the ship.
First, conversation history is now continuous. A user who came back the next day could scroll back through yesterday's session, and the agent had access to the same history. The first thing operators noticed was that users stopped restating context. The agent had the context.
Second, memory blocks persist. A user who had established a working relationship with the agent β preferences, tone, working style β kept that relationship across sessions. The agent remembered. The user felt remembered. The operator no longer had to mediate the re-onboarding.
Third, triage got faster. An operator looking up a user found a stable record, not a list of dead session ids. The ticket-to-resolution path shortened, and the handoff between operators on the same user got cleaner.
Next
The next round of work covers three surfaces. First, the bridge is moving to a stateful channel, where Tasks can hold an open connection to Q Vernal for the duration of a session and avoid the polling overhead. The pull model stays the default for reliability, but the stateful channel is a faster path for the common case. Second, the identity mapping table is moving to a shared internal service, so the same user identity can be reused across other chat surface plugins and not just Q Vernal. Third, the operator surface is getting a memory-block inspector, so an operator can see what the agent remembers about a user and edit it when it's wrong.
The commits covered here are 4d12478 and af0a19d, shipped on 2026-05-22.