diff --git a/ui/src/styles/components.css b/ui/src/styles/components.css
index 27dfe62d1..9a93cbaae 100644
--- a/ui/src/styles/components.css
+++ b/ui/src/styles/components.css
@@ -1484,3 +1484,23 @@
flex-wrap: wrap;
gap: 8px;
}
+
+/* Chat controls label input */
+.chat-controls__label {
+ width: 120px;
+ padding: 4px 8px;
+ font-size: 13px;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ background: var(--surface);
+ color: var(--text);
+}
+
+.chat-controls__label:focus {
+ outline: none;
+ border-color: var(--primary);
+}
+
+.chat-controls__label::placeholder {
+ color: var(--muted);
+}
diff --git a/ui/src/ui/app-render.helpers.ts b/ui/src/ui/app-render.helpers.ts
index c2190e1c9..d2b2d3e5e 100644
--- a/ui/src/ui/app-render.helpers.ts
+++ b/ui/src/ui/app-render.helpers.ts
@@ -6,6 +6,7 @@ import { iconForTab, pathForTab, titleForTab, type Tab } from "./navigation";
import { icons } from "./icons";
import { loadChatHistory } from "./controllers/chat";
import { refreshChat } from "./app-chat";
+import { patchSession } from "./controllers/sessions";
import { syncUrlWithSessionKey } from "./app-settings";
import type { SessionsListResult } from "./types";
import type { ThemeMode } from "./theme";
@@ -46,6 +47,10 @@ export function renderChatControls(state: AppViewState) {
state.sessionsResult,
mainSessionKey,
);
+ const activeSession = state.sessionsResult?.sessions?.find(
+ (row) => row.key === state.sessionKey,
+ );
+ const sessionLabel = activeSession?.label ?? "";
const disableThinkingToggle = state.onboarding;
const disableFocusToggle = state.onboarding;
const showThinking = state.onboarding ? false : state.settings.chatShowThinking;
@@ -81,13 +86,32 @@ export function renderChatControls(state: AppViewState) {
${repeat(
sessionOptions,
(entry) => entry.key,
- (entry) =>
- html``,
+ (entry) => {
+ const base = entry.displayName ?? entry.key;
+ // Only append label if it differs from displayName
+ const showLabel = entry.label && entry.label !== entry.displayName;
+ const text = showLabel ? `${base} — ${entry.label}` : base;
+ return html``;
+ },
)}
+ {
+ const value = (e.target as HTMLInputElement).value.trim();
+ void patchSession(
+ state as Parameters[0],
+ state.sessionKey,
+ { label: value || null },
+ );
+ }}
+ />