Files
kandev/docs/specs/tasks/quick-chat-expiration.md
T
2026-07-18 22:58:18 +01:00

276 lines
19 KiB
Markdown

---
status: shipped
created: 2026-07-02
owner: 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](quick-chat-repository-context.md).
- 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/:id` and
`/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](../../decisions/2026-07-14-typed-utility-chat-sessions.md). Repository-backed ordinary
chats additionally follow [ADR 0038](../../decisions/0038-quick-chat-repository-isolation.md).
## 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:
```text
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:
```text
metadata.config_mode == true -> kind = "config"
otherwise -> kind = "chat"
```
The unified frontend/boot session shape is:
```ts
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-chat` creates an ordinary ephemeral chat and retains the
optional repository contract from [Quick Chat Repository Context](quick-chat-repository-context.md).
- `POST /api/v1/workspaces/:id/config-chat` creates an ephemeral task with
`metadata.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:
```json
{
"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 of `QuickChatContent`.
- 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 ordinary `chat` session.
- **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.