19 KiB
status, created, owner
| status | created | owner |
|---|---|---|
| shipped | 2026-07-02 | kandev |
Quick Chat Sessions, Persistence, and Expiration
Why
Utility conversations need to remain available across page reloads without becoming detached backend tasks. Configuration conversations need a compact Settings surface for in-context changes and an explicit handoff to the larger Quick Chat dialog for reports and clarification questions, while retaining the elevated tools that distinguish them from ordinary quick chats.
What
- Quick Chat presents ordinary and configuration conversations as typed sessions in one session
store and one tab model. A session has
kind: "chat" | "config". - Configuration sessions are clearly identified with a sparkle/configuration indicator and an accessible label wherever their tab kind is presented.
- Settings Configuration Chat opens a floating configuration panel. The Command Palette Configuration Chat command opens the same typed setup/session in the Quick Chat modal.
- The Settings panel can transfer its current setup or session into the Quick Chat modal without creating a second task, losing messages, or replaying the initial prompt.
- Blank setup tabs use client-local workspace-and-kind-scoped identities, so ordinary and configuration setup can coexist without crossing workspace boundaries.
- Configuration setup retains its configuration-agent selection, introductory copy, suggestion
prompts, and
Ask anything about your configuration...prompt. It explains that the agent can manage workflows, agent profiles, and MCP configuration. - Configuration setup never offers repository or branch selectors. Ordinary quick-chat setup retains the optional repository context defined by Quick Chat Repository Context.
- Creating an ordinary chat remains the default behavior when Quick Chat first opens. The tab-bar
+action opens that setup directly. The setup always explains when to use Quick Chat instead of a tracked task and offers configuration mode in the form while the workspace has no existing or pending configuration session. - A workspace currently presents one configuration session. Configuration entry points reopen that session when it exists, and the Settings floating panel shows it without a tab strip or new-session action. The larger Quick Chat dialog retains tabs so the configuration session can coexist with ordinary chats and be deleted through the established tab lifecycle.
- Desktop Settings uses the compact floating configuration panel until the user expands it. Mobile Settings uses a viewport-bounded floating panel and the existing full-screen Quick Chat layout after expansion, with the same creation, tab, clarification, and deletion capabilities.
- Pending clarification questions remain inline below a visible message history. The clarification region is scrollable, resizable on pointer-capable desktop and mobile devices, and collapsible so a user can recover conversation context without dismissing the question.
- Closing the modal or switching tabs preserves every real session. Closing a persisted tab asks for confirmation and deletes its backing ephemeral task through the existing task deletion path. Closing a blank setup tab only removes that client-side placeholder.
- When a setup start is superseded before its backend response arrives, the returned ephemeral task is deleted instead of reopening the abandoned tab.
- Restorable utility sessions are reconstructed from backend task/session state for the active workspace after a reload. They are available as tabs while the modal itself starts closed.
- Hydration resolves the workspace represented by the current route. On
/t/:idand/office/tasks/:id, the task workspace takes precedence over a stale active-workspace setting. - Ordinary quick chats expire after seven days of inactivity through the existing task deletion path. Configuration sessions do not use that idle expiration policy and remain until explicitly deleted or their workspace is deleted.
- Ordinary and configuration sessions can coexist without sharing setup state, initial prompts, repository choices, or workspace state.
Decision: ADR-2026-07-14-typed-utility-chat-sessions. Repository-backed ordinary chats additionally follow ADR 0038.
Data model
No database migration is required. Both session kinds use existing tasks and task_sessions
rows. A restorable utility-chat task satisfies all of these predicates:
tasks.is_ephemeral = true
tasks.workflow_id = ""
tasks.origin != "automation_run"
tasks.archived_at IS NULL
primary task_session exists
The persisted discriminator is task metadata, not the task title:
metadata.config_mode == true -> kind = "config"
otherwise -> kind = "chat"
The unified frontend/boot session shape is:
type QuickChatSession = {
kind: "chat" | "config";
sessionId: string;
workspaceId: string;
name?: string;
agentProfileId?: string;
};
For backward compatibility, a session object without kind is normalized to kind: "chat".
Blank setup tabs use the same frontend shape with a generated workspace-and-kind-scoped
sessionId, but are never persisted or included in boot state.
Ordinary-chat last activity is the greater of tasks.updated_at and the newest associated
task_sessions.updated_at. An ordinary chat is eligible for deletion when that timestamp is more
than seven days old and none of its sessions is active. Configuration sessions are excluded from
this query by metadata.config_mode.
API surface
The creation endpoints remain distinct because they grant different backend capabilities:
POST /api/v1/workspaces/:id/quick-chatcreates an ordinary ephemeral chat and retains the optional repository contract from Quick Chat Repository Context.POST /api/v1/workspaces/:id/config-chatcreates an ephemeral task withmetadata.config_mode=true, selects the requested/workspace configuration agent profile, and prepares a session with configuration MCP tools.- Both return
{ "task_id": string, "session_id": string }.
The SPA boot payload includes the active workspace's sessions and primary session DTOs:
{
"quickChat": {
"isOpen": false,
"sessions": [
{
"kind": "config",
"sessionId": "session-id",
"workspaceId": "workspace-id",
"name": "Config Chat",
"agentProfileId": "profile-id"
}
],
"activeSessionId": null
},
"taskSessions": {
"items": {
"session-id": { "id": "session-id", "task_id": "task-id" }
}
}
}
Sessions are sorted by last activity, newest first. Boot classification always derives kind from
metadata.config_mode; titles are display values only.
State machine
| State | Trigger | Result |
|---|---|---|
| Closed, restored sessions available | Quick Chat or command action | Modal opens on an eligible session or typed setup tab in the active workspace. |
| Settings configuration panel closed | Settings FAB | Floating panel opens on an eligible configuration session or configuration setup. |
| Floating setup/session | Open in Quick Chat | Floating panel closes and the same setup/session becomes active in the large dialog without creating a task. |
| Existing configuration session | Configuration entry point | Existing session opens; no second configuration setup is created. |
Blank chat setup |
Start succeeds | Placeholder is replaced by a persisted chat session. |
Blank config setup |
Prompt/profile submit succeeds | The task session is seeded and the typed persisted tab opens. ACP prompts are delivered once after the chat subscription is ready; passthrough prompts are delivered once by the backend launch path before the terminal attaches. |
| Persisted session open | Switch tab or close modal | Session remains persisted and restorable. |
| Persisted tab close requested | User confirms | Backing task is deleted, then the tab is removed or reconciled by task deletion state. |
| Blank setup tab close requested | User closes tab/modal | Placeholder is removed without a backend request. |
| Ordinary chat idle longer than seven days | Expiration sweep | Existing task deletion path removes task, sessions, workspace materialization, and tab. |
| Configuration chat idle | Expiration sweep | Session is retained. |
Permissions
Configuration capabilities continue to be granted by the backend's config-mode task/session
preparation. A frontend kind: "config" label does not itself grant tools. Workspace scoping and
the existing task/session authorization rules apply to creation, restoration, continuation, and
deletion.
Failure modes
- A failed ordinary or configuration start leaves its setup visible with an error. Any task that was created before launch failed is deleted through the existing rollback path.
- A non-passthrough configuration prompt is held only until its created session is available to
QuickChatContent; it is sent once after subscription and is not replayed by tab switches or rerenders. A passthrough prompt is included in the config-chat start request because that session renders a terminal instead ofQuickChatContent. - A boot-state query failure omits utility sessions for that response and logs the error. It does not alter or delete persisted tasks.
- A task without a primary session is not restored as a tab.
- A tab-delete failure surfaces an error and leaves the backend task eligible for restoration; it must not be converted into a permanently hidden client-only config session.
- A workspace change closes or re-scopes the visible modal before sessions from another workspace can be activated. Launch and tab actions reject or ignore cross-workspace session state.
- An expiration candidate query failure deletes nothing. A single ordinary-chat delete failure is logged and does not stop later candidates from being evaluated.
Persistence guarantees
- Persisted ordinary and configuration tasks, their primary sessions, messages, agent profile identity, and display names available from task/local name state survive browser reloads and backend restarts.
- The modal starts closed after boot. Opening it reveals only the restored sessions for the active workspace.
- Blank setup tabs, unsent setup input, and a collapsed clarification presentation state do not survive reloads.
- Ordinary quick chats remain subject to the seven-day inactivity deletion policy.
- Configuration chats are not automatically expired. Explicit tab deletion and workspace deletion use established task cleanup so they do not leave unrecoverable ephemeral tasks.
Scenarios
- GIVEN an ordinary quick chat and a configuration chat in one workspace, WHEN the user opens Quick Chat, THEN both appear as tabs and the configuration tab has a visible and accessible configuration indicator.
- GIVEN a configuration agent is selected in Settings, WHEN the user starts Configuration Chat from the Settings FAB, THEN a floating configuration setup/session opens and the created task retains config-mode MCP tools.
- GIVEN the floating configuration setup is open, WHEN its empty state renders, THEN the panel header is the only Configuration Chat title, the composer action remains visible, and no separate cancel footer is rendered.
- GIVEN a floating configuration conversation, WHEN the user chooses Open in Quick Chat, THEN the floating panel closes and the large dialog shows the same session, history, task, and pending initial prompt.
- GIVEN the Quick Chat modal has no configuration session, WHEN the user starts a new chat, THEN its setup explains Quick Chat versus a tracked task and offers configuration mode inside the panel.
- GIVEN a workspace already has a configuration session, WHEN the user starts a new Quick Chat, THEN configuration mode is not offered and configuration entry points reopen the existing session.
- GIVEN Settings Configuration Chat is open, WHEN setup or the existing conversation is shown, THEN the floating panel has no session tabs or new-configuration-session action.
- GIVEN any application route, WHEN the user chooses Configuration Chat from the Command Palette, THEN the same unified configuration setup/session opens in Quick Chat.
- GIVEN a configuration setup tab, WHEN it renders, THEN it shows configuration copy, suggestions, the configuration profile choice, and no repository controls.
- GIVEN an ordinary setup tab, WHEN it renders, THEN optional repository/branch controls and the existing isolated repository behavior remain available.
- GIVEN a configuration prompt starts an ACP session, WHEN the frontend subscribes to the created task session, THEN the prompt is delivered exactly once and its response appears in that tab.
- GIVEN a passthrough configuration profile, WHEN its session starts, THEN the backend launch receives the initial prompt exactly once and the unified tab renders the passthrough terminal.
- GIVEN a completed configuration conversation, WHEN the browser reloads and Quick Chat is reopened, THEN the configuration tab and prior messages are restored and the conversation can continue.
- GIVEN Quick Chat is closed with a configuration tab active, WHEN the generic Quick Chat action reopens the dialog, THEN that configuration tab remains active regardless of chat kind.
- GIVEN restored sessions with different activity times, WHEN boot state is built, THEN eligible ordinary and configuration sessions are ordered newest first with the correct kind.
- GIVEN config-mode, automation-run, workflow-bound ephemeral, and ordinary quick-chat tasks, WHEN boot state is built, THEN only the config-mode and ordinary utility chats are restored.
- GIVEN sessions belonging to two workspaces, WHEN either workspace is active, THEN only that workspace's sessions can be shown or activated.
- GIVEN a task route whose workspace differs from the persisted active-workspace setting, WHEN the page reloads, THEN the task workspace's utility sessions are restored.
- GIVEN an agent clarification is pending, WHEN the Quick Chat tab is visible, THEN the question remains inline in a scrollable region, meaningful preceding message context remains visible, and the user can resize or collapse the question before answering it.
- GIVEN a narrow mobile viewport and a pending clarification, WHEN the user expands, scrolls, collapses, or answers it, THEN the primary question actions remain visible and usable without horizontal clipping.
- GIVEN a real ordinary or configuration session, WHEN the user switches tabs or closes the modal, THEN no backing task is deleted.
- GIVEN a real configuration tab, WHEN the user confirms its close action, THEN its backing ephemeral task is deleted through the Quick Chat deletion path and does not return after reload.
- GIVEN a blank typed setup tab, WHEN it is closed or the modal is dismissed, THEN only that placeholder is removed and no task deletion request is issued.
- GIVEN a quick-chat session object from an older boot/client shape without
kind, WHEN it is hydrated, THEN it behaves as an ordinarychatsession. - GIVEN a configuration chat idle for more than seven days, WHEN the expiration sweep runs, THEN it is retained.
- GIVEN an ordinary quick chat idle for more than seven days with no active session, WHEN the expiration sweep runs, THEN its task, sessions, and workspace materialization are deleted.
Out of scope
- Redesigning the agent protocol, configuration MCP tools, or config-chat creation endpoint.
- A new persistence table for UI tabs or duplicating task/session history in frontend storage.
- A separate configuration session store, message renderer, or backend conversation.
- A general task/chat navigation redesign.
- Multiple configuration sessions per workspace.
- Repository context for configuration sessions.
- A user-configurable ordinary-chat retention window or automatic expiration for config sessions.