@yuru7/pi-auto-title

A Pi extension that manages the terminal tab title: an AI-generated session title plus a running/idle status indicator

Packages

Package details

extension

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-app becomes web-app). When a path has no trailing name (a filesystem root), workspace is 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; /reload and session switches keep the title for the session that follows. A killed process cannot clear anything.
  • /reload reloads 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.

License

MIT