Skip to content

feat: auto-name sessions from first prompt - #376

Open
shenlvkang-collab wants to merge 1 commit into
Ark0N:masterfrom
shenlvkang-collab:feat/auto-session-names-upstream
Open

feat: auto-name sessions from first prompt#376
shenlvkang-collab wants to merge 1 commit into
Ark0N:masterfrom
shenlvkang-collab:feat/auto-session-names-upstream

Conversation

@shenlvkang-collab

Copy link
Copy Markdown
Contributor

Problem

New sessions are initially named with generic project/sequence labels, so it is difficult to identify their purpose in the session manager.

Solution

  • Derive a bounded local title from the first submitted prompt.
  • Ignore slash commands and terminal control sequences.
  • Persist whether a name is auto or manual.
  • Never overwrite an explicit rename.
  • Update mux metadata and broadcast the new name immediately.

No prompt text is sent to an additional model or written to logs.

Verification

  • typecheck
  • lint
  • build
  • frontend syntax check
  • focused input/listener tests: 23/23 passed

The implementation was also adapted and validated against the older Codeman deployment on silverdou.

@Ark0N

Ark0N commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Thanks for this. Naming a tab after what the session is actually doing is a genuinely nice idea, and the ownership plumbing (nameSource, the listener wiring, the restore path) is the right shape. The keystroke tracker is where it comes apart: it sits on the raw byte stream, and the byte stream carries a lot more than the user's prompt. I reproduced five separate ways it names a tab something wrong.

First, CI is red on your own hunk: format:check fails on src/session.ts:686, where Prettier at printWidth 120 wants the _nameSource assignment on one line. npx prettier --write src/session.ts.

Then, in rough order of how often each will bite:

1. It renames on every prompt, not the first (src/session.ts:1227). applyAutoName never changes _nameSource after applying, so the session stays auto and every later Enter renames it again. Prompts "fix the login bug" then "1" leave the tab named 1. The PR title, the description and the wiki paragraph all say first prompt, and test/session-submit-anchor.test.ts:77 currently pins the every-prompt behaviour. Mark the session after the first successful auto-name so later prompts no longer qualify, and update that test.

2. There is no mode or origin gate (src/session.ts:3333). Both write() and writeViaMux() feed the tracker, and the listener applies it for every mode:

  • Shell sessions match isGeneratedSessionName (s<n>-<case>), so a shell tab is renamed after every command. ls -la then cd src leaves the tab called cd src.
  • Ralph (ralph-routes.ts:500) and respawn kickstarts (respawn-controller.ts:1626) go through writeViaMux, so every Ralph and respawn tab becomes Read @ralph_prompt.md and follow the instructions. and they all look identical.
  • Cron launch commands (cron-service.ts:580) and Approvals text answers (approval-routes.ts:60) count too.

Emit promptSubmitted only for user-originated input (ws-routes.ts:188 and POST /input), or pass an origin flag through _trackSubmit, and skip shell mode explicitly.

3. A bare Esc eats the next prompt's first character (src/session-auto-name.ts:25). After \x1b the tracker stays in escape mode until a byte in 0x40-0x7e. A lone Esc is one of the most common inputs to Claude Code: interrupt, double-Esc clear, the mobile accessory Esc key, and Approvals deny, which sends exactly \x1b at approval-routes.ts:47. Confirmed: Esc then "fix the login bug" submits ix the login bug. Esc then a CJK prompt submits nothing at all, because no CJK code point is in 0x40-0x7e, and the following "add tests" then becomes dd tests. Esc followed by digits and punctuation grew escapeSequence to 19001 characters with no cap. Only enter sequence mode when \x1b is followed by [, O, ] or P, treat any other byte after \x1b as a finished Alt chord, and cap the buffer.

4. Newlines inside a bracketed paste are treated as Enter (src/session-auto-name.ts:41). The tracker recognises the \x1b[200~/\x1b[201~ markers but does not remember it is inside a paste. Pasting three lines then typing " plus typed" and Enter emits three separate submissions. Keep an inPaste flag and turn newlines into spaces inside it.

5. Default-on for every session with no setting, and the tab loses its case identity (src/web/session-listener-wiring.ts:459). Comparable behaviours here ship behind a setting (agentSkillEnabled, approvalsInboxEnabled, readMyMindEnabled, sessionLineageLines), and no issue or discussion preceded this. Replacing the whole name also removes the case from the tab, and _nextCaseSessionStartNumber() in session-ui.js derives the next w<n> from live names, so every new session in a case becomes w1-<case> again. Worth knowing: parseSessionPrefix() (app.js:316, from #232) already renders w1-case: description as just the description with the prefix in the tooltip, and the counter regex still matches it, so naming the session <prefix>: <title> keeps the counter, the case identity and the tooltip. I would like a synced autoNameSessions setting, and I lean toward the prefix form. Say if you disagree on the prefix, it is a judgement call and I would rather hear the argument than have you build something you think is worse.

Smaller:

  • src/web/session-listener-wiring.ts:462: prompt text now flows into /api/search (search-service.ts:131 matches on sessionName), mux-sessions.json, every session:updated broadcast, the TUI and both home screens. Read My Mind deliberately keeps prompts 0600 and out of /api/search because prompts can contain secrets, so "not written to logs" in the description is narrower than what actually happens. At 72 characters the risk is low, but it is one more reason for the setting.
  • src/session-auto-name.ts:29: any CSI clears the buffer, including the SGR wheel reports Codeman forwards to claude >= 2.1.187 on every wheel tick, as does Tab (the @ mention autocomplete). "fix the " + a wheel report + "login bug" gives login bug; "look at @src/ses" + Tab + "sion.ts and fix it" gives sion.ts and fix it. Mouse reports and Tab should not clear.
  • src/web/routes/session-routes.ts:1776: the Shift/Ctrl+Enter newline goes through POST /send-key and never touches the tracker, so a two-line prompt is joined with no separator: Fix the login bugAlso add tests.
  • Tests: the session-auto-name.ts unit tests sit in the submit-anchor file and belong in test/session-auto-name.test.ts. Nothing covers nameSource surviving toState() plus the recovery constructor, or PUT /api/sessions/:id/name flipping to manual and persisting it, and nothing covers Esc, paste, wheel/Tab or shell/Ralph input.
  • Docs: the wiki paragraph describes first-prompt semantics the code does not implement. A new Session event, a new state field and a new rule about which inputs count need a line in CLAUDE.md and docs/architecture-invariants.md. nameSource on /api/sessions is additive and fine under the versioning policy.
  • Title heuristics (src/session-auto-name.ts:85): "e.g. fix this now" becomes e.g., "! npm test" becomes !, and "/home/me/notes.txt what is this" is dropped as a slash command. /^\/[a-z-]+(\s|$)/ separates /clear from /home/..., and a minimum length before cutting at the first period fixes "e.g.".

The ownership flag, the listener wiring and the restore path are fine and can stay as they are. Please answer the setting-and-prefix question in your next comment along with the fixes, so you only rework this once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants