@yuru7/pi-auto-title
A Pi extension that manages the terminal tab title: an AI-generated session title plus a running/idle status indicator
Package details
Install @yuru7/pi-auto-title from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@yuru7/pi-auto-title- Package
@yuru7/pi-auto-title- Version
0.1.0- Published
- Oct 13, 2026
- Downloads
- 378/mo · 7/wk
- Author
- yuru7
- License
- MIT
- Types
- extension
- Size
- 90.6 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./extensions/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-auto-title
English | 日本語
A Pi Coding Agent extension that manages the terminal tab title: an AI-generated session title plus a running/idle/stalled status indicator.
Repository: yuru7/my-pi-extensions
Pi - web-app (startup, before the agent runs)
⏳ Pi - Lambdaフォーム公開API (agent running)
⏸️ Pi - Lambdaフォーム公開API (a watched tool has been silent too long)
✅ Pi - Lambdaフォーム公開API (idle, waiting for input)
With several Pi sessions open side by side, each tab shows what that session is working on and whether it is still running. The title body is generated by AI from the session's first user message, and falls back to the startup directory name before (and instead of) that.
Install
pi install npm:@yuru7/pi-auto-title
Tab title
At startup the title is Pi - <title>. Once the agent has run at least once,
the status marker leads it: <status> Pi - <title>.
<status>is⏳while the agent runs,⏸️while a watched tool has been silent too long (see Stall detection), and✅while it is idle. The markers can be customized or turned off (see Configuration), and they only appear after the agent's first run.<title>is the AI-generated title once one exists, otherwise the trailing name of the directory Pi was started in (/home/user/projects/web-appbecomesweb-app). When a path has no trailing name (a filesystem root),workspaceis used.
The AI title part is limited to 30 Unicode characters; Pi - and the status
marker are not counted against it. The directory name is fixed at session start
and does not follow later working-directory changes.
AI title generation
- One title is generated per session, on the session's first user message. A run that is already titled never sends another request, so long sessions do not accumulate title cost.
- Only that first user message is sent (capped at 2000 characters). No tool output, file contents, or system prompt is included.
- The generated title is limited to 30 characters and normalized: wrapping quotes, Markdown decoration, and control characters are removed. An empty or unusable answer keeps the directory name instead.
- Generation runs on its own request with a 30-second deadline covering the
whole run, authentication and fallback included. The main agent never waits
for it, and its result only replaces the
<title>part, never the status marker. - The title is stored inside the Pi session with
pi.appendEntry()and restored when the session is resumed; restored titles are validated like generated ones. No separate global file is written.
Privacy: the first user message of a session is sent to the model configured
for title generation (autoTitle.model), which may be a third-party provider.
That request is separate from Pi's own conversation, but the text can still
contain personal or confidential information. Set autoTitle.enabled to false
to turn generation off entirely.
Configuration
The configuration file is optional and fixed at <agent dir>/pi-auto-title.json
(~/.pi/agent/pi-auto-title.json by default; the directory is Pi's
getAgentDir(), so PI_CODING_AGENT_DIR is respected). Without the file the
defaults below are used;
the file is never created on its own. Missing fields fall back to the defaults,
explicit false values are kept, and unknown fields are ignored. Invalid JSON
falls back to the defaults entirely; a wrong field type falls back per field, so
a deliberate setting such as autoTitle.enabled: false survives an error in an
unrelated field. A single warning names every invalid field, and the file is
never repaired or overwritten. Use /reload after editing it.
{
"autoTitle": {
"enabled": true,
"model": "CURRENT",
"thinkingLevel": "CURRENT",
"fallbackToCurrentModel": true
},
"statusIndicator": {
"enabled": true,
"running": "⏳",
"idle": "✅",
"stalled": "⏸️",
"stallDetection": {
"enabled": true,
"thresholdSeconds": 30
}
}
}
autoTitle
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled |
boolean | true |
Generate AI titles at all |
model |
string | "CURRENT" |
Model used for title generation |
thinkingLevel |
string | "CURRENT" |
Thinking level used for title generation |
fallbackToCurrentModel |
boolean | true |
Fall back to the current session model when the configured one cannot be used |
model accepts CURRENT (the session's active model at generation time) or an
explicit provider/model-id reference such as anthropic/claude-sonnet-4-5.
Only models Pi knows and can authenticate are usable.
thinkingLevel accepts CURRENT (the session's active level at generation
time) or a Pi thinking level such as off, minimal, low, medium, high,
xhigh, or max. When the model does not support the requested level it is
adjusted to the nearest supported one using Pi's own clamping rules, and the
adjustment happens silently. Title generation never changes the session's model or
thinking level.
statusIndicator
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled |
boolean | true |
Show the status marker |
running |
string | "⏳" |
Marker while the agent runs |
idle |
string | "✅" |
Marker while the agent is idle |
stalled |
string | "⏸️" |
Marker while a watched tool is stalled |
stallDetection.enabled |
boolean | true |
Watch running tools for inactivity |
stallDetection.thresholdSeconds |
number | 30 |
Seconds of tool silence before the stalled marker shows (finite, at least 1) |
running, idle, and stalled are used verbatim; an empty string shows no
marker for that state. With enabled: false the marker is omitted entirely.
thresholdSeconds must be a finite number of at least 1; anything else falls
back to the default with one warning.
Stall detection
While the agent runs, every tool execution is watched by its toolCallId, no
matter what kind of tool it is. When a tool has produced no event for
stallDetection.thresholdSeconds, the status marker switches to stalled;
any progress event resets that tool's clock and returns the marker to
running. Parallel tools are judged independently: a single stalled tool is
enough for the stalled marker, and it clears as soon as none of the remaining
tools is stalled. Model reasoning without a running tool is never judged as
stalled.
The stalled state is an estimate from the silence duration, not a verdict: long builds, network waits, or a tool waiting for user input all look the same. Nothing is cancelled or retried automatically.
When the agent settles (a run ends, is aborted, or errors), the watches are
dropped and the marker returns to idle — a stalled marker never survives
into the next run or session. stallDetection.enabled: false restores the
two-state running/idle indicator.
Commands
/pi-auto-title init
init is offered as the argument completion right after /pi-auto-title .
Writes the default configuration to <agent dir>/pi-auto-title.json, creating
parent directories as needed. When the file already exists, a selector asks
whether to overwrite it, with No as the first choice so a plain Enter cannot
clobber the file; choosing No or pressing Esc changes nothing. The new
settings apply immediately, without restarting Pi, and a title that was
already generated is kept.
Running /pi-auto-title without init, or with any other argument, shows the
available commands.
Model fallback
With fallbackToCurrentModel: true, a title request falls back to the current
session model when the configured model is unknown, has no credentials, or its
request fails. The fallback is announced as soon as it starts, naming both
models and a fixed reason category (model not registered, no credentials,
timeout, or request failed), and it happens at most once. The announcement is
written into the conversation history as a custom entry, so it stays visible
but never reaches the agent — custom entries are outside the LLM context.
Thinking-level adjustments are announced with the model and the requested
level; a give-up is announced with a fixed reason category only. Provider error
text is never displayed or persisted, and nothing is written to stderr.
When fallback is off, or when the fallback cannot help either, generation is given up for that session: the directory name stays in the title and the agent keeps working normally.
Behavior notes
- The tab title is set in interactive and RPC sessions. In UI-less modes (JSON,
print) the extension switches itself off entirely at the first
session_start: every event handler is disposed, so there are no title writes, no stall watches or timers, and no AI requests for the rest of the process. - Pi writes its own terminal title (
π - <dir>) right after extensions bind. The extension re-asserts its own title at short delays (immediately, 250ms, 1s) after startup, session name changes, and tree navigation, and re-applies it on the next prompt input as a safety net. There is no event for Pi's write, so keeping the title is best effort, not a guarantee. - Quitting Pi sets the terminal title to the empty string. Pi writes its own
title again while tearing down its UI, right after the extension sees the
shutdown, so the empty title is written once more at process exit and is the
last title write. Depending on the terminal this shows its own default
again, or leaves the tab title empty; the previous title is not readable, so
it cannot be brought back. Only a normal quit does this;
/reloadand session switches keep the title for the session that follows. A killed process cannot clear anything. /reloadreloads the configuration. A session switch, fork, tree navigation, or reload cancels an in-flight title request, and results that come back afterwards are dropped.- A title generation failure never fails the agent run. The title part keeps showing the previous value (usually the directory name), and the reason is announced in the history like the fallback announcement.
Development
pnpm install
pnpm run check # typecheck, lint, tests
Tests use node:test; linting and formatting use Biome.