SLOPSHOPPER

session-namer

Prefixes every Claude Code session title with its project folder: 'Bee Buzz · fix login flow'.

new
v0.1.0MITupdated 2026-10-09vigneshbarani24/claude-session-namer
A shopper browsing a rack in a slop shop
README

session-namer

ci

Claude Code session titles that start with the project folder.

Fix login flow          →  Bee Buzz · Fix login flow
Triage flaky eval       →  guardian · Triage flaky eval

When you run five sessions across three repos, /resume and the session list stop being a wall of near-identical titles.

Install

At the prompt of a Claude Code terminal session:

/plugin install session-namer --marketplace vigneshbarani24/claude-session-namer

Answer y to add the marketplace, then pick a scope (user scope covers every project). It's active immediately.

Uninstall with /plugin uninstall session-namer.

How it works

The mod hooks SessionStart and UserPromptSubmit and returns sessionTitle with the project folder put in front of the title the session already has, whether Claude Code generated it or you set it with /rename.

  • No title yet: it does nothing, so Claude Code's own naming still runs.
  • Already prefixed: it does nothing, so the prefix is applied once.
  • Worktrees: a session in <repo>/.claude/worktrees/<name> is named after <repo>.
  • Failure: a hook error passes the event through, so naming never blocks a prompt.

Options

Set them in /config or under pluginConfigs.session-namer.options in settings.

OptionDefaultEffect
depth1Trailing folders to show. 2 gives Amazon Build 2026/Bee Buzz.
separator · Text between the folder and the name.

Requirements

A Claude Code build with function hooks (mods). Built and tested on Claude Code 2.1.295.

Limitations

  • In a fresh session the prefix appears from the second prompt: the first prompt is what Claude Code names the session from.
  • The mod API is early access in Claude Code and may change between releases.

Develop

claude plugin validate .
claude plugin test .
claude --plugin-dir .

Once Claude Code has loaded the mod it lays its types in .claude-plugin/types/, and npx tsc -p . type-checks it.

License

MIT

Source 1 files
hooks/register.ts 35 lines
1import type { Register } from 'claude-code'
2
3// A worktree session runs in <repo>/.claude/worktrees/<name>; the repo folder is the useful name.
4const WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/][^\\/]+[\\/]?$/
5
6export function projectLabel(cwd: string, depth: number): string {
7  const segments = cwd.replace(WORKTREE, '').split(/[\\/]+/).filter(s => s !== '' && !/^[A-Za-z]:$/.test(s))
8  return segments.slice(-Math.max(1, Math.floor(depth))).join('/')
9}
10
11export function prefixedTitle(title: string | undefined, label: string, separator: string): string | undefined {
12  const name = title?.trim()
13  if (!name || label === '') return undefined
14  if (name === label || name.startsWith(label + separator)) return undefined
15  return label + separator + name
16}
17
18export const register: Register = (on, options) => {
19  const depth = typeof options.depth === 'number' ? options.depth : 1
20  const separator = typeof options.separator === 'string' && options.separator !== '' ? options.separator : ' · '
21
22  // Only prefix a title that exists: setting one where there is none would pre-empt Claude Code's own naming.
23  on('classic.SessionStart', async ($, e, next) => {
24    const result = await next(e)
25    const sessionTitle = prefixedTitle(result.sessionTitle ?? e.session_title, projectLabel(e.cwd, depth), separator)
26    return sessionTitle === undefined ? result : { ...result, sessionTitle }
27  }).catch(($, e, next) => next(e)) // a naming failure must never hold up a session or a prompt
28
29  on('classic.UserPromptSubmit', async ($, e, next) => {
30    const result = await next(e)
31    const sessionTitle = prefixedTitle(result.sessionTitle ?? e.session_title, projectLabel(e.cwd, depth), separator)
32    return sessionTitle === undefined ? result : { ...result, sessionTitle }
33  }).catch(($, e, next) => next(e))
34}
35