diff --git a/.changeset/title-footer-toggle.md b/.changeset/title-footer-toggle.md
new file mode 100644
index 0000000000..139a270d6b
--- /dev/null
+++ b/.changeset/title-footer-toggle.md
@@ -0,0 +1,5 @@
+---
+"@moonshot-ai/kimi-code": minor
+---
+
+Add the /titleon and /titleoff slash commands to toggle showing the current session title in the footer after the git branch. The toggle is session-only: it is not persisted to tui.toml and resets when switching to another session or starting a new one.
diff --git a/apps/kimi-code/src/tui/commands/dispatch.ts b/apps/kimi-code/src/tui/commands/dispatch.ts
index dcfb904733..ce0b53ad00 100644
--- a/apps/kimi-code/src/tui/commands/dispatch.ts
+++ b/apps/kimi-code/src/tui/commands/dispatch.ts
@@ -51,6 +51,8 @@ import {
handleForkCommand,
handleInitCommand,
handleTitleCommand,
+ handleTitleOffCommand,
+ handleTitleOnCommand,
} from './session';
import { handleSwarmCommand } from './swarm';
import { handleUndoCommand } from './undo';
@@ -89,6 +91,8 @@ export {
handleForkCommand,
handleInitCommand,
handleTitleCommand,
+ handleTitleOffCommand,
+ handleTitleOnCommand,
} from './session';
export { handleUndoCommand } from './undo';
export { handleWebCommand } from './web';
@@ -330,6 +334,12 @@ async function handleBuiltInSlashCommand(
case 'title':
await handleTitleCommand(host, args);
return;
+ case 'titleon':
+ handleTitleOnCommand(host);
+ return;
+ case 'titleoff':
+ handleTitleOffCommand(host);
+ return;
case 'yolo':
await handleYoloCommand(host, args);
return;
diff --git a/apps/kimi-code/src/tui/commands/index.ts b/apps/kimi-code/src/tui/commands/index.ts
index 7449dba9bc..bf630a7877 100644
--- a/apps/kimi-code/src/tui/commands/index.ts
+++ b/apps/kimi-code/src/tui/commands/index.ts
@@ -28,7 +28,13 @@ export { handlePluginsCommand } from './plugins';
export { handleReloadCommand, handleReloadTuiCommand } from './reload';
export { handleGoalCommand, parseGoalCommand } from './goal';
export { goalArgumentCompletions } from './registry';
-export { handleForkCommand, handleInitCommand, handleTitleCommand } from './session';
+export {
+ handleForkCommand,
+ handleInitCommand,
+ handleTitleCommand,
+ handleTitleOffCommand,
+ handleTitleOnCommand,
+} from './session';
export { handleUndoCommand } from './undo';
export { handleWebCommand } from './web';
export {
diff --git a/apps/kimi-code/src/tui/commands/registry.ts b/apps/kimi-code/src/tui/commands/registry.ts
index 063bcd7bfe..4da4ce7ebf 100644
--- a/apps/kimi-code/src/tui/commands/registry.ts
+++ b/apps/kimi-code/src/tui/commands/registry.ts
@@ -318,6 +318,20 @@ export const BUILTIN_SLASH_COMMANDS = [
argumentHint: '
',
availability: 'always',
},
+ {
+ name: 'titleon',
+ aliases: [],
+ description: 'Show session title in the footer (this session only)',
+ priority: 60,
+ availability: 'always',
+ },
+ {
+ name: 'titleoff',
+ aliases: [],
+ description: 'Hide session title from the footer',
+ priority: 60,
+ availability: 'always',
+ },
{
name: 'usage',
aliases: [],
diff --git a/apps/kimi-code/src/tui/commands/session.ts b/apps/kimi-code/src/tui/commands/session.ts
index 2f0870db0d..f9f48dac50 100644
--- a/apps/kimi-code/src/tui/commands/session.ts
+++ b/apps/kimi-code/src/tui/commands/session.ts
@@ -46,6 +46,40 @@ export async function handleTitleCommand(host: SlashCommandHost, args: string):
host.showStatus(`Session title set to: ${newTitle}`);
}
+// Narrowed host for the /titleon and /titleoff footer toggles (mirrors the
+// UpdatePreferenceHost pattern in config.ts) so tests can use a plain fake.
+type SessionTitleFooterHost = {
+ readonly state: {
+ readonly appState: Pick<
+ SlashCommandHost['state']['appState'],
+ 'showSessionTitleInFooter'
+ >;
+ };
+ setAppState(patch: Pick): void;
+ showStatus(msg: string, color?: string): void;
+ track: SlashCommandHost['track'];
+};
+
+export function handleTitleOnCommand(host: SessionTitleFooterHost): void {
+ if (host.state.appState.showSessionTitleInFooter) {
+ host.showStatus('Session title is already shown in the footer.');
+ return;
+ }
+ host.setAppState({ showSessionTitleInFooter: true });
+ host.track('session_title_footer_changed', { visible: true });
+ host.showStatus('Session title now shown in the footer (this session only).');
+}
+
+export function handleTitleOffCommand(host: SessionTitleFooterHost): void {
+ if (!host.state.appState.showSessionTitleInFooter) {
+ host.showStatus('Session title is already hidden from the footer.');
+ return;
+ }
+ host.setAppState({ showSessionTitleInFooter: false });
+ host.track('session_title_footer_changed', { visible: false });
+ host.showStatus('Session title hidden from the footer.');
+}
+
export async function handleForkCommand(host: SlashCommandHost, args: string): Promise {
void args;
const session = host.session;
diff --git a/apps/kimi-code/src/tui/components/chrome/footer.ts b/apps/kimi-code/src/tui/components/chrome/footer.ts
index a2e8d7adee..876f32833f 100644
--- a/apps/kimi-code/src/tui/components/chrome/footer.ts
+++ b/apps/kimi-code/src/tui/components/chrome/footer.ts
@@ -30,6 +30,7 @@ import {
} from '#/utils/usage/usage-format';
const MAX_CWD_SEGMENTS = 3;
+const MAX_FOOTER_TITLE_LENGTH = 40;
const GOAL_TIMER_INTERVAL_MS = 1_000;
// Toolbar tips — rotates every 10s. Most tips are short and pair up (two
@@ -308,6 +309,17 @@ export class FooterComponent implements Component {
left.push(formatFooterGitBadge(git, colors));
}
+ if (state.showSessionTitleInFooter && state.sessionTitle) {
+ // /title accepts pasted multiline text; keep the footer on one line
+ // (same collapse as the session picker's singleLine).
+ const title = state.sessionTitle.replaceAll(/\s+/g, ' ').trim();
+ if (title.length > 0) {
+ left.push(
+ chalk.hex(colors.textDim)(truncateToWidth(title, MAX_FOOTER_TITLE_LENGTH, '…')),
+ );
+ }
+ }
+
const leftLine = left.join(' ');
const leftWidth = visibleWidth(leftLine);
diff --git a/apps/kimi-code/src/tui/controllers/auth-flow.ts b/apps/kimi-code/src/tui/controllers/auth-flow.ts
index a7acc77ce8..2400c11543 100644
--- a/apps/kimi-code/src/tui/controllers/auth-flow.ts
+++ b/apps/kimi-code/src/tui/controllers/auth-flow.ts
@@ -60,6 +60,7 @@ export class AuthFlowController {
maxContextTokens: 0,
contextUsage: 0,
sessionTitle: null,
+ showSessionTitleInFooter: false,
});
this.host.appendStartupNotice(OAUTH_LOGIN_REQUIRED_STARTUP_NOTICE);
this.host.setStartupReady();
@@ -110,6 +111,7 @@ export class AuthFlowController {
sessionId: '',
model: '',
sessionTitle: null,
+ showSessionTitleInFooter: false,
});
await this.host.refreshSkillCommands();
await this.host.refreshPluginCommands();
diff --git a/apps/kimi-code/src/tui/kimi-tui.ts b/apps/kimi-code/src/tui/kimi-tui.ts
index 14951c6ed8..79398561a5 100644
--- a/apps/kimi-code/src/tui/kimi-tui.ts
+++ b/apps/kimi-code/src/tui/kimi-tui.ts
@@ -233,6 +233,7 @@ function createInitialAppState(input: KimiTUIStartupInput): AppState {
availableModels: {},
availableProviders: {},
sessionTitle: null,
+ showSessionTitleInFooter: false,
goal: null,
mcpServersSummary: null,
banner: undefined,
@@ -1736,6 +1737,8 @@ export class KimiTUI {
async switchToSession(session: Session, statusMessage: string): Promise {
this.resetSessionRuntime();
await this.setSession(session);
+ // /titleon is session-only: a session switch (including /fork) resets it.
+ this.setAppState({ showSessionTitleInFooter: false });
await this.syncRuntimeState(session);
this.updateTerminalTitle();
try {
@@ -1808,7 +1811,8 @@ export class KimiTUI {
this.resetSessionRuntime();
await this.setSession(session);
- this.setAppState({ sessionId: session.id });
+ // /titleon is session-only: a new session resets it.
+ this.setAppState({ sessionId: session.id, showSessionTitleInFooter: false });
try {
await this.activateRuntime();
await this.syncRuntimeState(session);
diff --git a/apps/kimi-code/src/tui/types.ts b/apps/kimi-code/src/tui/types.ts
index d895b11e12..f7bad5487f 100644
--- a/apps/kimi-code/src/tui/types.ts
+++ b/apps/kimi-code/src/tui/types.ts
@@ -55,6 +55,9 @@ export interface AppState {
availableModels: Record;
availableProviders: Record;
sessionTitle: string | null;
+ /** Session-only toggle (/titleon, /titleoff): show the session title in the
+ * footer after the git badge. Not persisted; resets on session switch. */
+ showSessionTitleInFooter: boolean;
/** Current goal snapshot for the footer badge; null/undefined when no active goal. */
goal?: GoalSnapshot | null;
mcpServersSummary: string | null;
diff --git a/apps/kimi-code/test/tui/commands/registry.test.ts b/apps/kimi-code/test/tui/commands/registry.test.ts
index bc4c5894fc..8e10c713c7 100644
--- a/apps/kimi-code/test/tui/commands/registry.test.ts
+++ b/apps/kimi-code/test/tui/commands/registry.test.ts
@@ -171,6 +171,8 @@ describe('built-in slash command registry', () => {
'status',
'theme',
'title',
+ 'titleoff',
+ 'titleon',
'undo',
'usage',
'version',
diff --git a/apps/kimi-code/test/tui/commands/session.test.ts b/apps/kimi-code/test/tui/commands/session.test.ts
new file mode 100644
index 0000000000..61234a7f0e
--- /dev/null
+++ b/apps/kimi-code/test/tui/commands/session.test.ts
@@ -0,0 +1,64 @@
+import { describe, expect, it, vi } from 'vitest';
+
+import { handleTitleOffCommand, handleTitleOnCommand } from '#/tui/commands/session';
+
+function fakeHost(showSessionTitleInFooter: boolean) {
+ return {
+ state: {
+ appState: { showSessionTitleInFooter },
+ },
+ setAppState: vi.fn(),
+ showStatus: vi.fn(),
+ track: vi.fn(),
+ };
+}
+
+describe('/titleon', () => {
+ it('enables the footer session title for the current session only', () => {
+ const host = fakeHost(false);
+
+ handleTitleOnCommand(host);
+
+ expect(host.setAppState).toHaveBeenCalledWith({ showSessionTitleInFooter: true });
+ expect(host.track).toHaveBeenCalledWith('session_title_footer_changed', { visible: true });
+ expect(host.showStatus).toHaveBeenCalledWith(
+ 'Session title now shown in the footer (this session only).',
+ );
+ });
+
+ it('is idempotent when the title is already shown', () => {
+ const host = fakeHost(true);
+
+ handleTitleOnCommand(host);
+
+ expect(host.setAppState).not.toHaveBeenCalled();
+ expect(host.track).not.toHaveBeenCalled();
+ expect(host.showStatus).toHaveBeenCalledWith(
+ 'Session title is already shown in the footer.',
+ );
+ });
+});
+
+describe('/titleoff', () => {
+ it('disables the footer session title', () => {
+ const host = fakeHost(true);
+
+ handleTitleOffCommand(host);
+
+ expect(host.setAppState).toHaveBeenCalledWith({ showSessionTitleInFooter: false });
+ expect(host.track).toHaveBeenCalledWith('session_title_footer_changed', { visible: false });
+ expect(host.showStatus).toHaveBeenCalledWith('Session title hidden from the footer.');
+ });
+
+ it('is idempotent when the title is already hidden', () => {
+ const host = fakeHost(false);
+
+ handleTitleOffCommand(host);
+
+ expect(host.setAppState).not.toHaveBeenCalled();
+ expect(host.track).not.toHaveBeenCalled();
+ expect(host.showStatus).toHaveBeenCalledWith(
+ 'Session title is already hidden from the footer.',
+ );
+ });
+});
diff --git a/apps/kimi-code/test/tui/components/chrome/footer.test.ts b/apps/kimi-code/test/tui/components/chrome/footer.test.ts
index 2fe6f3e52e..33a8f80e18 100644
--- a/apps/kimi-code/test/tui/components/chrome/footer.test.ts
+++ b/apps/kimi-code/test/tui/components/chrome/footer.test.ts
@@ -1,4 +1,8 @@
import chalk from 'chalk';
+import { execFileSync } from 'node:child_process';
+import { mkdtempSync, rmSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { FooterComponent } from '#/tui/components/chrome/footer';
@@ -38,6 +42,7 @@ const appState: AppState = {
additionalDirs: [],
sessionId: 'ses-1',
sessionTitle: null,
+ showSessionTitleInFooter: false,
model: 'kimi-k2',
permissionMode: 'manual',
thinkingEffort: 'off',
@@ -187,3 +192,172 @@ describe('FooterComponent displayName override', () => {
expect(footer.render(120).join('\n')).not.toContain('Remote Name');
});
});
+
+const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
+
+function stripAnsi(text: string): string {
+ return text.replaceAll(ANSI_PATTERN, '');
+}
+
+describe('FooterComponent session title', () => {
+ const previousChalkLevel = chalk.level;
+
+ beforeEach(() => {
+ chalk.level = 3;
+ });
+
+ afterEach(() => {
+ chalk.level = previousChalkLevel;
+ });
+
+ it('hides the session title when the toggle is off', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'My session',
+ showSessionTitleInFooter: false,
+ };
+ const footer = new FooterComponent(state);
+
+ expect(stripAnsi(footer.render(120).join('\n'))).not.toContain('My session');
+ });
+
+ it('collapses a multiline session title to a single line', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'first line\nsecond line',
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const rendered = footer.render(120);
+ const line1 = stripAnsi(rendered[0] ?? '');
+ expect(line1).toContain('first line second line');
+ // The newline must not leak into later footer lines either.
+ expect(stripAnsi(rendered.join('\n'))).not.toContain('\nsecond line');
+ });
+
+ it('collapses tabs and runs of whitespace in the session title', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'my\t session title',
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const line1 = stripAnsi(footer.render(120).join('\n')).split('\n')[0] ?? '';
+ expect(line1).toContain('my session title');
+ expect(line1).not.toContain('\t');
+ });
+
+ it('shows the session title after the git badge when the toggle is on', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'My session',
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const rendered = stripAnsi(footer.render(120).join('\n'));
+ expect(rendered).toContain('My session');
+ // Line 1 joins items with two spaces: cwd, then title (no git repo here).
+ const line1 = rendered.split('\n')[0] ?? '';
+ const cwdIndex = line1.indexOf('/tmp/project');
+ const titleIndex = line1.indexOf('My session');
+ expect(cwdIndex).toBeGreaterThanOrEqual(0);
+ expect(titleIndex).toBeGreaterThan(cwdIndex);
+ });
+
+ it('renders no empty segment when the toggle is on but the title is null', () => {
+ const withToggle: AppState = {
+ ...appState,
+ sessionTitle: null,
+ showSessionTitleInFooter: true,
+ };
+ const withoutToggle: AppState = {
+ ...appState,
+ sessionTitle: null,
+ showSessionTitleInFooter: false,
+ };
+
+ expect(new FooterComponent(withToggle).render(120).join('\n')).toBe(
+ new FooterComponent(withoutToggle).render(120).join('\n'),
+ );
+ });
+
+ it('renders the title right after the git branch badge', () => {
+ const repoDir = mkdtempSync(join(tmpdir(), 'kimi-footer-title-'));
+ try {
+ execFileSync('git', ['init', '-b', 'trunk', repoDir]);
+ const state: AppState = {
+ ...appState,
+ workDir: repoDir,
+ sessionTitle: 'My session',
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const line1 = stripAnsi(footer.render(160).join('\n')).split('\n')[0] ?? '';
+ const branchIndex = line1.indexOf('trunk');
+ const titleIndex = line1.indexOf('My session');
+ expect(branchIndex).toBeGreaterThanOrEqual(0);
+ expect(titleIndex).toBeGreaterThan(branchIndex);
+ } finally {
+ rmSync(repoDir, { recursive: true, force: true });
+ }
+ });
+
+ it('renders a title of exactly 40 columns without an ellipsis', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'a'.repeat(40),
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const rendered = stripAnsi(footer.render(200).join('\n'));
+ expect(rendered).toContain('a'.repeat(40));
+ expect(rendered).not.toContain('…');
+ });
+
+ it('truncates a 41-column title to width 40 with an ellipsis', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'a'.repeat(41),
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const rendered = stripAnsi(footer.render(200).join('\n'));
+ // Width-aware: 39 columns of text + the 1-column ellipsis.
+ expect(rendered).toContain(`${'a'.repeat(39)}…`);
+ expect(rendered).not.toContain('a'.repeat(40));
+ });
+
+ it('caps wide titles by display width, not character count', () => {
+ const state: AppState = {
+ ...appState,
+ sessionTitle: 'a'.repeat(50),
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const rendered = stripAnsi(footer.render(200).join('\n'));
+ expect(rendered).toContain(`${'a'.repeat(39)}…`);
+ expect(rendered).not.toContain('a'.repeat(40));
+ });
+
+ it('caps CJK titles by display width (2 columns per character)', () => {
+ const state: AppState = {
+ ...appState,
+ // 25 CJK characters = 50 columns, over the 40-column cap.
+ sessionTitle: '汉'.repeat(25),
+ showSessionTitleInFooter: true,
+ };
+ const footer = new FooterComponent(state);
+
+ const rendered = stripAnsi(footer.render(200).join('\n'));
+ // 19 CJK chars (38 columns) + the 1-column ellipsis = 39 columns.
+ expect(rendered).toContain(`${'汉'.repeat(19)}…`);
+ expect(rendered).not.toContain('汉'.repeat(20));
+ });
+});
diff --git a/apps/kimi-code/test/tui/components/chrome/welcome.test.ts b/apps/kimi-code/test/tui/components/chrome/welcome.test.ts
index bc1b754fb6..f81ee24301 100644
--- a/apps/kimi-code/test/tui/components/chrome/welcome.test.ts
+++ b/apps/kimi-code/test/tui/components/chrome/welcome.test.ts
@@ -15,6 +15,7 @@ const appState: AppState = {
additionalDirs: [],
sessionId: 'ses-1',
sessionTitle: null,
+ showSessionTitleInFooter: false,
model: 'kimi-k2',
permissionMode: 'manual',
thinkingEffort: 'off',
diff --git a/apps/kimi-code/test/tui/create-tui-state.test.ts b/apps/kimi-code/test/tui/create-tui-state.test.ts
index 0899cf0702..434af4df60 100644
--- a/apps/kimi-code/test/tui/create-tui-state.test.ts
+++ b/apps/kimi-code/test/tui/create-tui-state.test.ts
@@ -30,6 +30,7 @@ function fakeInitialAppState(): AppState {
availableModels: {},
availableProviders: {},
sessionTitle: null,
+ showSessionTitleInFooter: false,
mcpServersSummary: null,
};
}
diff --git a/apps/kimi-code/test/tui/message-replay.test.ts b/apps/kimi-code/test/tui/message-replay.test.ts
index 20d825ce04..bb9903d661 100644
--- a/apps/kimi-code/test/tui/message-replay.test.ts
+++ b/apps/kimi-code/test/tui/message-replay.test.ts
@@ -16,6 +16,7 @@ import { describe, expect, it, vi } from 'vitest';
import { KimiTUI, type KimiTUIStartupInput, type TUIState } from '#/tui/kimi-tui';
import type { SessionEventHandler } from '#/tui/controllers/session-event-handler';
import type { StreamingUIController } from '#/tui/controllers/streaming-ui';
+import type { AppState } from '#/tui/types';
import { AgentGroupComponent } from '#/tui/components/messages/agent-group';
import { AssistantMessageComponent } from '#/tui/components/messages/assistant-message';
import { StepSummaryComponent } from '#/tui/components/messages/step-summary';
@@ -41,7 +42,10 @@ interface ReplayDriver {
readonly streamingUI: StreamingUIController;
readonly sessionEventHandler: SessionEventHandler;
init(): Promise;
+ setAppState(patch: Partial): void;
switchToSession(session: Session, statusMessage: string): Promise;
+ reloadCurrentSessionView(session: Session, statusMessage: string): Promise;
+ createNewSession(): Promise;
}
function makeStartupInput(): KimiTUIStartupInput {
@@ -1311,3 +1315,32 @@ describe('KimiTUI resume message replay', () => {
expect(transcript).toContain('final text 4');
});
});
+
+describe('session title footer toggle lifecycle', () => {
+ it('resets showSessionTitleInFooter on session switch', async () => {
+ const driver = await replayIntoDriver([]);
+ driver.setAppState({ showSessionTitleInFooter: true });
+
+ await driver.switchToSession(makeSession([]), 'Switched session.');
+
+ expect(driver.state.appState.showSessionTitleInFooter).toBe(false);
+ });
+
+ it('resets showSessionTitleInFooter on a new session', async () => {
+ const driver = await replayIntoDriver([]);
+ driver.setAppState({ showSessionTitleInFooter: true });
+
+ await driver.createNewSession();
+
+ expect(driver.state.appState.showSessionTitleInFooter).toBe(false);
+ });
+
+ it('preserves showSessionTitleInFooter across /reload (same-session reload)', async () => {
+ const driver = await replayIntoDriver([]);
+ driver.setAppState({ showSessionTitleInFooter: true });
+
+ await driver.reloadCurrentSessionView(makeSession([]), 'Session reloaded.');
+
+ expect(driver.state.appState.showSessionTitleInFooter).toBe(true);
+ });
+});
diff --git a/docs/en/reference/slash-commands.md b/docs/en/reference/slash-commands.md
index 75c8033564..ec1c37a615 100644
--- a/docs/en/reference/slash-commands.md
+++ b/docs/en/reference/slash-commands.md
@@ -31,6 +31,8 @@ Some commands are only available in the idle state. Executing these commands whi
| `/tasks` | `/task` | Browse the background task list | Yes |
| `/fork` | — | Fork a new session from the current one, preserving the full conversation history | No |
| `/title []` | `/rename` | Without arguments, display the current session title; with an argument, set a new title (max 200 characters) | Yes |
+| `/titleon` | — | Show the current session title in the footer after the git branch (session-only, not persisted) | Yes |
+| `/titleoff` | — | Hide the session title from the footer | Yes |
| `/compact []` | — | Compact the current conversation context to free up token usage; an optional custom instruction can hint to the model what to preserve | No |
| `/undo []` | — | Undo recent prompts from the active context. Without a count, opens a selector; with a count, undoes that many prompts. Prompts before the last compaction cannot be undone | No |
| `/reload` | — | Reload the current session and apply the latest `config.toml` settings (providers, models, etc.) and `tui.toml` UI preferences, without restarting the CLI | No |
diff --git a/docs/zh/reference/slash-commands.md b/docs/zh/reference/slash-commands.md
index ec4d2b79dc..6a197a8f62 100644
--- a/docs/zh/reference/slash-commands.md
+++ b/docs/zh/reference/slash-commands.md
@@ -31,6 +31,8 @@
| `/tasks` | `/task` | 浏览后台任务列表 | 是 |
| `/fork` | — | 基于当前会话 fork 一份新会话,保留完整对话历史 | 否 |
| `/title []` | `/rename` | 不带参数时显示当前会话标题;带参数时设置为新标题(最长 200 字符) | 是 |
+| `/titleon` | — | 在页脚 git 分支后显示当前会话标题(仅当前会话生效,不持久化) | 是 |
+| `/titleoff` | — | 在页脚隐藏会话标题 | 是 |
| `/compact []` | — | 压缩当前对话上下文,释放 token 占用;可附带自定义指令,提示模型压缩时保留哪些信息 | 否 |
| `/undo []` | — | 从当前上下文撤销最近的提示词。不带数量时打开选择器;带数量时撤销对应条数。最后一次上下文压缩之前的提示词不能撤销 | 否 |
| `/init` | — | 分析当前代码库并生成 `AGENTS.md` | 否 |