Repository navigation
feat: opt-in conversation tab titles - #14
Conversation
After the first agent turn of a conversation, rename the current cmux tab to a 2-5 word topic title summarized by a headless pi --print --no-tools run. Tab-only (never touches the workspace name), /name overrides the automatic title, /new resets it. Disabled by default. Three guards keep the headless summarizer safe: a ctx.mode gate so headless children never re-enter the naming pass, a sanitized child env (CMUX_SURFACE_ID/CMUX_TAB_ID/CMUX_PANEL_ID removed, CMUX_PI_HOOKS_DISABLED=1) so it cannot re-enter cmux hooks, and ignored stdin because headless pi waits for stdin EOF.
A headless `pi --print` summarizer had three costs: it wrote a real session file (polluting `pi -r`), it re-loaded extensions and re-fired cmux notifications for the naming pass itself, and it paid the full pi system prompt (AGENTS.md, skills, tools) in tokens. Replace it with a single standalone LLM call inside the pi process, using completeSimple from pi-ai (the same primitive compaction's completeSummarization wraps) with a compact transcript and a short system prompt. Resolve the model via the session model registry (PI_CMUX_AUTOTITLE_MODEL or ctx.model) and auth via modelRegistry.getApiKeyAndHeaders. The old child-process guards (env sanitization, stdin EOF, recursion gate) are gone with the child; the TUI mode gate stays. The naming pass now aborts when the user starts a new turn. Also bump devDependency pi-coding-agent to 0.83.0 (+ pi-ai) to match the running pi and pass the repo typecheck.
Important content in a message tends to sit at the start (the request, the error) and the end (the outcome, the question); the middle is usually detail. So instead of a hard head-only cut at 1500 chars, compress each cached message to ~300 chars with a 60/40 head/tail split around an ellipsis.
"pi-cmux": { "autotitle": true } in ~/.pi/agent/settings.json or
project-local .pi/settings.json (project wins), the same settings
pattern pi-cmux.commands uses. The env var still works and either
source enables the feature. Bad files/sections are ignored, never
fatal.
Users don't discover opt-in features; on-by-default with an escape
hatch gives the feature a chance to be seen. Flip the default:
- No env, no settings: enabled.
- PI_CMUX_AUTOTITLE_DISABLED=1 opts out (env).
- "pi-cmux": { "autotitle": false } opts out (settings, project wins).
- PI_CMUX_AUTOTITLE=1 still force-enables (kept for compatibility).
1be452a to
562642d
Compare
|
Rebased onto the latest One design point I'd like your input on before you dig in: the feature is on by default, with opt-out via Reviewing tip: the core logic is contained in |
Merge current main. Generate titles off the settlement path through Pi's model registry, honor project overrides and manual names, cancel stale work, verify cmux before requesting a title, and restore persisted titles across session changes. Add regression coverage and remove the unnecessary Pi AI dependency.
|
Pushed maintainer fixes in 611a55f and merged current main into this branch without rewriting contributor history. These changes supersede the original implementation details above; automatic titles are now opt-in.
Validated with pinned dependencies on Node 22.19.0: typecheck, npm test (431 passed, six optional installed-CLI tests skipped), and pack:check. Provider and cmux behavior was tested with stubs, not paid live requests. This PR has not been merged into main. |
|
Thank you! |
What
Conversation-driven tab titles, on by default. After the first agent turn of a conversation, the current cmux tab is renamed to a short (2-5 word) topic title, generated by a single in-process LLM call that reuses the session's model, auth, and model registry.
PI_CMUX_AUTOTITLE_DISABLED=1or"pi-cmux": { "autotitle": false }in Pi settings (project-local.pi/settings.jsonwins over the global file).PI_CMUX_AUTOTITLE_MODELoptionally selects the summarizer model (resolved via the model registry; falls back to the current model)./nameoverrides the automatic title;/newclears it so the next conversation gets a fresh one.Why
pi-cmux already owns tab naming for the splits it spawns (
renameSurfaceTab), but the tab hosting the current session keeps the defaultπ - <folder>title forever. cmux's native auto-naming (automation.workspaceAutoNaming) cannot fill this gap for users who set workspace names: the spawn gate skips user-owned workspaces, and when it does run it renames the workspace (window title) as well.Enabled by default because opt-in features stay undiscovered — users who never read the README never meet them. The escape hatches above make it safe to default on.
Implementation notes
The title is generated with one standalone
completeSimplecall (pi-ai's completion primitive, the same one compaction'scompleteSummarizationwraps): a compact transcript (last 4 messages, each compressed to ~300 chars with a head/tail split around an ellipsis — requests and outcomes live at message edges, detail in the middle) with a short system prompt, model resolved fromctx.modelRegistry, auth fromgetApiKeyAndHeaders,maxTokenscapped,cacheRetention: "none", and anAbortControllerwith a timeout. Input for the naming request is ~1k tokens even for resumed long sessions.An earlier iteration used a headless
pi --print --no-toolschild. That approach was rejected for three reasons, each a real failure mode:pi -rpollution — the headless child writes a real session file, so every titled conversation leaves a junk entry in the resume list.cmux notify. Env-var kill switches only cover extensions that know about them.The in-process call has none of these: no session file, no re-loaded extensions, and only the compact transcript is sent.
Failure budget: any failure (model resolution, auth, network, empty output, lost race with a closed tab) leaves state untouched so the next
agent_endretries; nothing surfaces to the user and nothing blocks the conversation.Verification (done locally against cmux 0.64.22 / pi 0.83.0 on macOS)
/newre-titles the next conversation;/namewins; tab-only, workspace untouched.pi -rstays clean (no summarizer session files); cmux notifications fire only for the main conversation.pi --printsmoke test); config precedence verified unit-style (env force-on, env opt-out, settings true/false, bad JSON ignored).tsc --noEmit ... --strict extensions/*.ts) against@earendil-works/pi-coding-agent0.83.0 (devDependency bumped to match; adds@earendil-works/pi-aiat the same version).Docs
README config table + usage paragraph, CHANGELOG
[Unreleased]entry.