Changelog

Release notes, project updates, and announcements from the Pi team.

Release notes

Pi 0.42.0

New version of pi. Download from npm or view release on GitHub.

Added

  • Added OpenCode Zen provider support. Set OPENCODE_API_KEY env var and use opencode/<model-id> (e.g., opencode/claude-opus-4-5).

Read more

Release notes

Pi 0.41.0

New version of pi. Download from npm or view release on GitHub.

Added

  • Anthropic OAuth support is back! Use /login to authenticate with your Claude Pro/Max subscription.

Read more

Release notes

Pi 0.40.0

New version of pi. Download from npm or view release on GitHub.

Added

  • Documentation on component invalidation and theme changes in docs/tui.md

Read more

Release notes

Pi 0.39.1

New version of pi. Download from npm or view release on GitHub.

Fixed

  • setTheme() now triggers a full rerender so previously rendered components update with the new theme colors
  • mac-system-theme.ts example now polls every 2 seconds and uses osascript for real-time macOS appearance detection

Read more

Release notes

Pi 0.39.0

New version of pi. Download from npm or view release on GitHub.

Breaking Changes

  • before_agent_start event now receives systemPrompt in the event object and returns systemPrompt (full replacement) instead of systemPromptAppend. Extensions that were appending must now use event.systemPrompt + extra pattern. (#575)
  • discoverSkills() now returns { skills: Skill[], warnings: SkillWarning[] } instead of Skill[]. This allows callers to handle skill loading warnings. (#577 by @cv)

Added

  • ctx.ui.getAllThemes(), ctx.ui.getTheme(name), and ctx.ui.setTheme(name | Theme) methods for extensions to list, load, and switch themes at runtime (#576)
  • --no-tools flag to disable all built-in tools, allowing extension-only tool setups (#557 by @cv)
  • Pluggable operations for built-in tools enabling remote execution via SSH or other transports (#564). Interfaces: ReadOperations, WriteOperations, EditOperations, BashOperations, LsOperations, GrepOperations, FindOperations
  • user_bash event for intercepting user !/!! commands, allowing extensions to redirect to remote systems (#528)
  • setActiveTools() in ExtensionAPI for dynamic tool management
  • Built-in renderers used automatically for tool overrides without custom renderCall/renderResult
  • ssh.ts example: remote tool execution via --ssh user@host:/path
  • interactive-shell.ts example: run interactive commands (vim, git rebase, htop) with full terminal access via !i prefix or auto-detection
  • Wayland clipboard support for /copy command using wl-copy with xclip/xsel fallback (#570 by @OgulcanCelik)
  • Experimental: ctx.ui.custom() now accepts { overlay: true } option for floating modal components that composite over existing content without clearing the screen (#558 by @nicobailon)
  • AgentSession.skills and AgentSession.skillWarnings properties to access loaded skills without rediscovery (#577 by @cv)

Read more

Release notes

Pi 0.38.0

New version of pi. Download from npm or view release on GitHub.

Breaking Changes

  • ctx.ui.custom() factory signature changed from (tui, theme, done) to (tui, theme, keybindings, done) for keybinding access in custom components
  • LoadedExtension type renamed to Extension
  • LoadExtensionsResult.setUIContext() removed, replaced with runtime: ExtensionRuntime
  • ExtensionRunner constructor now requires runtime: ExtensionRuntime as second parameter
  • ExtensionRunner.initialize() signature changed from options object to positional params (actions, contextActions, commandContextActions?, uiContext?)
  • ExtensionRunner.getHasUI() renamed to hasUI()
  • OpenAI Codex model aliases removed (gpt-5, gpt-5-mini, gpt-5-nano, codex-mini-latest). Use canonical IDs: gpt-5.1, gpt-5.1-codex-mini, gpt-5.2, gpt-5.2-codex. (#536 by @ghoulr)

Added

  • --no-extensions flag to disable extension discovery while still allowing explicit -e paths (#524 by @cv)
  • SDK: InteractiveMode, runPrintMode(), runRpcMode() exported for building custom run modes. See docs/sdk.md.
  • PI_SKIP_VERSION_CHECK environment variable to disable new version notifications at startup (#549 by @aos)
  • thinkingBudgets setting to customize token budgets per thinking level for token-based providers (#529 by @melihmucuk)
  • Extension UI dialogs (ctx.ui.select(), ctx.ui.confirm(), ctx.ui.input()) now support a timeout option with live countdown display (#522 by @nicobailon)
  • Extensions can now provide custom editor components via ctx.ui.setEditorComponent(). See examples/extensions/modal-editor.ts and docs/tui.md Pattern 7.
  • Extension factories can now be async, enabling dynamic imports and lazy-loaded dependencies (#513 by @austinm911)
  • ctx.shutdown() is now available in extension contexts for requesting a graceful shutdown. In interactive mode, shutdown is deferred until the agent becomes idle (after processing all queued steering and follow-up messages). In RPC mode, shutdown is deferred until after completing the current command response. In print mode, shutdown is a no-op as the process exits automatically when prompts complete. (#542 by @kaofelix)

Read more

Release notes

Pi 0.37.6

New version of pi. Download from npm or view release on GitHub.

Added

  • Extension UI dialogs (ctx.ui.select(), ctx.ui.confirm(), ctx.ui.input()) now accept an optional AbortSignal to programmatically dismiss dialogs. Useful for implementing timeouts. See examples/extensions/timed-confirm.ts. (#474)
  • HTML export now shows bridge prompts in model change messages for Codex sessions (#510 by @mitsuhiko)

Read more

Release notes

Pi 0.37.5

New version of pi. Download from npm or view release on GitHub.

Added

  • ExtensionAPI: setModel(), getThinkingLevel(), setThinkingLevel() methods for extensions to change model and thinking level at runtime (#509)
  • Exported truncation utilities for custom tools: truncateHead, truncateTail, truncateLine, formatSize, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, TruncationOptions, TruncationResult
  • New example truncated-tool.ts demonstrating proper output truncation with custom rendering for extensions
  • New example preset.ts demonstrating preset configurations with model/thinking/tools switching (#347)
  • Documentation for output truncation best practices in docs/extensions.md
  • Exported all UI components for extensions: ArminComponent, AssistantMessageComponent, BashExecutionComponent, BorderedLoader, BranchSummaryMessageComponent, CompactionSummaryMessageComponent, CustomEditor, CustomMessageComponent, DynamicBorder, ExtensionEditorComponent, ExtensionInputComponent, ExtensionSelectorComponent, FooterComponent, LoginDialogComponent, ModelSelectorComponent, OAuthSelectorComponent, SessionSelectorComponent, SettingsSelectorComponent, ShowImagesSelectorComponent, ThemeSelectorComponent, ThinkingSelectorComponent, ToolExecutionComponent, TreeSelectorComponent, UserMessageComponent, UserMessageSelectorComponent, plus utilities renderDiff, truncateToVisualLines
  • docs/tui.md: Common Patterns section with copy-paste code for SelectList, BorderedLoader, SettingsList, setStatus, setWidget, setFooter
  • docs/tui.md: Key Rules section documenting critical patterns for extension UI development
  • docs/extensions.md: Exhaustive example links for all ExtensionAPI methods and events
  • System prompt now references docs/tui.md for TUI component development

Read more

Release notes

Pi 0.37.4

New version of pi. Download from npm or view release on GitHub.

Added

  • Session picker (pi -r) and --session flag now support searching/resuming by session ID (UUID prefix) (#495 by @arunsathiya)
  • Extensions can now replace the startup header with ctx.ui.setHeader(), see examples/extensions/custom-header.ts (#500 by @tudoroancea)

Changed

  • Startup help text: fixed misleading "ctrl+k to delete line" to "ctrl+k to delete to end"
  • Startup help text and /hotkeys: added !! shortcut for running bash without adding output to context

Read more

Release notes

Pi 0.37.3

New version of pi. Download from npm or view release on GitHub.

Added

  • Extensions can now replace the footer with ctx.ui.setFooter(), see examples/extensions/custom-footer.ts (#481)
  • Session ID is now forwarded to LLM providers for session-based caching (used by OpenAI Codex for prompt caching).
  • Added blockImages setting to prevent images from being sent to LLM providers (#492 by @jsinge97)
  • Extensions can now send user messages via pi.sendUserMessage() (#483)

Read more

Release notes

Pi 0.37.2

New version of pi. Download from npm or view release on GitHub.

Fixed

  • Extension directories in settings.json now respect package.json manifests, matching global extension behavior (#480 by @prateekmedia)
  • Share viewer: deep links now scroll to the target message when opened via /share
  • Bash tool now handles spawn errors gracefully instead of crashing the agent (missing cwd, invalid shell path) (#479 by @robinwander)

Read more

Release notes

Pi 0.37.1

New version of pi. Download from npm or view release on GitHub.

Fixed

  • Share viewer: copy-link buttons now generate correct URLs when session is viewed via /share (iframe context)

Read more

Release notes

Pi 0.37.0

New version of pi. Download from npm or view release on GitHub.

Added

  • Share viewer: copy-link button on messages to share URLs that navigate directly to a specific message (#477 by @lockmeister)
  • Extension example: add claude-rules to load .claude/rules/ entries into the system prompt (#461 by @vaayne)
  • Headless OAuth login: all providers now show paste input for manual URL/code entry, works over SSH without DISPLAY (#428 by @ben-vargas, #468 by @crcatala)

Changed

  • OAuth login UI now uses dedicated dialog component with consistent borders
  • Assume truecolor support for all terminals except dumb, empty, or linux (fixes colors over SSH)
  • OpenAI Codex clean-up: removed per-thinking-level model variants, thinking level is now set separately and the provider clamps to what each model supports internally (initial implementation in #472 by @ben-vargas)

Read more

Release notes

Pi 0.36.0

New version of pi. Download from npm or view release on GitHub.

Added

  • Experimental: OpenAI Codex OAuth provider support: access Codex models via ChatGPT Plus/Pro subscription using /login openai-codex (#451 by @kim0)

Read more

Release notes

Pi 0.35.0

New version of pi. Download from npm or view release on GitHub.

Changes

This release unifies hooks and custom tools into a single "extensions" system and renames "slash commands" to "prompt templates". (#454)

Before migrating, read:

Extensions Migration

Hooks and custom tools are now unified as extensions. Both were TypeScript modules exporting a factory function that receives an API object. Now there's one concept, one discovery location, one CLI flag, one settings.json entry.

Automatic migration:

  • commands/ directories are automatically renamed to prompts/ on startup (both ~/.pi/agent/commands/ and .pi/commands/)

Manual migration required:

  1. Move files from hooks/ and tools/ directories to extensions/ (deprecation warnings shown on startup)
  2. Update imports and type names in your extension code
  3. Update settings.json if you have explicit hook and custom tool paths configured

Directory changes:

# Before
~/.pi/agent/hooks/*.ts       →  ~/.pi/agent/extensions/*.ts
~/.pi/agent/tools/*.ts       →  ~/.pi/agent/extensions/*.ts
.pi/hooks/*.ts               →  .pi/extensions/*.ts
.pi/tools/*.ts               →  .pi/extensions/*.ts

Extension discovery rules (in extensions/ directories):

  1. Direct files: extensions/*.ts or *.js → loaded directly
  2. Subdirectory with index: extensions/myext/index.ts → loaded as single extension
  3. Subdirectory with package.json: extensions/myext/package.json with "pi" field → loads declared paths
// extensions/my-package/package.json
{
  "name": "my-extension-package",
  "dependencies": { "zod": "^3.0.0" },
  "pi": {
    "extensions": ["./src/main.ts", "./src/tools.ts"]
  }
}

No recursion beyond one level. Complex packages must use the package.json manifest. Dependencies are resolved via jiti, and extensions can be published to and installed from npm.

Type renames:

  • HookAPI → ExtensionAPI
  • HookContext → ExtensionContext
  • HookCommandContext → ExtensionCommandContext
  • HookUIContext → ExtensionUIContext
  • CustomToolAPI → ExtensionAPI (merged)
  • CustomToolContext → ExtensionContext (merged)
  • CustomToolUIContext → ExtensionUIContext
  • CustomTool → ToolDefinition
  • CustomToolFactory → ExtensionFactory
  • HookMessage → CustomMessage

Import changes:

// Before (hook)
import type { HookAPI, HookContext } from "@mariozechner/pi-coding-agent";
export default function (pi: HookAPI) { ... }

// Before (custom tool)
import type { CustomToolFactory } from "@mariozechner/pi-coding-agent";
const factory: CustomToolFactory = (pi) => ({ name: "my_tool", ... });
export default factory;

// After (both are now extensions)
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
export default function (pi: ExtensionAPI) {
  pi.on("tool_call", async (event, ctx) => { ... });
  pi.registerTool({ name: "my_tool", ... });
}

Custom tools now have full context access. Tools registered via pi.registerTool() now receive the same ctx object that event handlers receive. Previously, custom tools had limited context. Now all extension code shares the same capabilities:

  • pi.registerTool() - Register tools the LLM can call
  • pi.registerCommand() - Register commands like /mycommand
  • pi.registerShortcut() - Register keyboard shortcuts (shown in /hotkeys)
  • pi.registerFlag() - Register CLI flags (shown in --help)
  • pi.registerMessageRenderer() - Custom TUI rendering for message types
  • pi.on() - Subscribe to lifecycle events (tool_call, session_start, etc.)
  • pi.sendMessage() - Inject messages into the conversation
  • pi.appendEntry() - Persist custom data in session (survives restart/branch)
  • pi.exec() - Run shell commands
  • pi.getActiveTools() / pi.setActiveTools() - Dynamic tool enable/disable
  • pi.getAllTools() - List all available tools
  • pi.events - Event bus for cross-extension communication
  • ctx.ui.confirm() / select() / input() - User prompts
  • ctx.ui.notify() - Toast notifications
  • ctx.ui.setStatus() - Persistent status in footer (multiple extensions can set their own)
  • ctx.ui.setWidget() - Widget display above editor
  • ctx.ui.setTitle() - Set terminal window title
  • ctx.ui.custom() - Full TUI component with keyboard handling
  • ctx.ui.editor() - Multi-line text editor with external editor support
  • ctx.sessionManager - Read session entries, get branch history

Settings changes:

// Before
{
  "hooks": ["./my-hook.ts"],
  "customTools": ["./my-tool.ts"]
}

// After
{
  "extensions": ["./my-extension.ts"]
}

CLI changes:

# Before
pi --hook ./safety.ts --tool ./todo.ts

# After
pi --extension ./safety.ts -e ./todo.ts

Prompt Templates Migration

"Slash commands" (markdown files defining reusable prompts invoked via /name) are renamed to "prompt templates" to avoid confusion with extension-registered commands.

Automatic migration: The commands/ directory is automatically renamed to prompts/ on startup (if prompts/ doesn't exist). Works for both regular directories and symlinks.

Directory changes:

~/.pi/agent/commands/*.md    →  ~/.pi/agent/prompts/*.md
.pi/commands/*.md            →  .pi/prompts/*.md

SDK type renames:

  • FileSlashCommand → PromptTemplate
  • LoadSlashCommandsOptions → LoadPromptTemplatesOptions

SDK function renames:

  • discoverSlashCommands() → discoverPromptTemplates()
  • loadSlashCommands() → loadPromptTemplates()
  • expandSlashCommand() → expandPromptTemplate()
  • getCommandsDir() → getPromptsDir()

SDK option renames:

  • CreateAgentSessionOptions.slashCommands → .promptTemplates
  • AgentSession.fileCommands → .promptTemplates
  • PromptOptions.expandSlashCommands → .expandPromptTemplates

SDK Migration

Discovery functions:

  • discoverAndLoadHooks() → discoverAndLoadExtensions()
  • discoverAndLoadCustomTools() → merged into discoverAndLoadExtensions()
  • loadHooks() → loadExtensions()
  • loadCustomTools() → merged into loadExtensions()

Runner and wrapper:

  • HookRunner → ExtensionRunner
  • wrapToolsWithHooks() → wrapToolsWithExtensions()
  • wrapToolWithHooks() → wrapToolWithExtensions()

CreateAgentSessionOptions:

  • .hooks → removed (use .additionalExtensionPaths for paths)
  • .additionalHookPaths → .additionalExtensionPaths
  • .preloadedHooks → .preloadedExtensions
  • .customTools type changed: Array<{ path?; tool: CustomTool }> → ToolDefinition[]
  • .additionalCustomToolPaths → merged into .additionalExtensionPaths
  • .slashCommands → .promptTemplates

AgentSession:

  • .hookRunner → .extensionRunner
  • .fileCommands → .promptTemplates
  • .sendHookMessage() → .sendCustomMessage()

Session Migration

Automatic. Session version bumped from 2 to 3. Existing sessions are migrated on first load:

  • Message role "hookMessage" → "custom"

Breaking Changes

  • Settings: hooks and customTools arrays replaced with single extensions array
  • CLI: --hook and --tool flags replaced with --extension / -e
  • Directories: hooks/, tools/ → extensions/; commands/ → prompts/
  • Types: See type renames above
  • SDK: See SDK migration above

Changed

  • Extensions can have their own package.json with dependencies (resolved via jiti)
  • Documentation: docs/hooks.md and docs/custom-tools.md merged into docs/extensions.md
  • Examples: examples/hooks/ and examples/custom-tools/ merged into examples/extensions/
  • README: Extensions section expanded with custom tools, commands, events, state persistence, shortcuts, flags, and UI examples
  • SDK: customTools option now accepts ToolDefinition[] directly (simplified from Array<{ path?, tool }>)
  • SDK: extensions option accepts ExtensionFactory[] for inline extensions
  • SDK: additionalExtensionPaths replaces both additionalHookPaths and additionalCustomToolPaths

Read more

Release notes

Pi 0.34.1

New version of pi. Download from npm or view release on GitHub.

Added

  • Hook API: ctx.ui.setTitle(title) allows hooks to set the terminal window/tab title (#446 by @aliou)

Changed

  • Expanded keybinding documentation to list all 32 supported symbol keys with notes on ctrl+symbol behavior (#450 by @kaofelix)

Read more

Release notes

Pi 0.34.0

New version of pi. Download from npm or view release on GitHub.

Added

  • Hook API: pi.getActiveTools() and pi.setActiveTools(toolNames) for dynamically enabling/disabling tools from hooks
  • Hook API: pi.getAllTools() to enumerate all configured tools (built-in via --tools or default, plus custom tools)
  • Hook API: pi.registerFlag(name, options) and pi.getFlag(name) for hooks to register custom CLI flags (parsed automatically)
  • Hook API: pi.registerShortcut(shortcut, options) for hooks to register custom keyboard shortcuts using KeyId (e.g., Key.shift("p")). Conflicts with built-in shortcuts are skipped, conflicts between hooks logged as warnings.
  • Hook API: ctx.ui.setWidget(key, content) for status displays above the editor. Accepts either a string array or a component factory function.
  • Hook API: theme.strikethrough(text) for strikethrough text styling
  • Hook API: before_agent_start handlers can now return systemPromptAppend to dynamically append text to the system prompt for that turn. Multiple hooks' appends are concatenated.
  • Hook API: before_agent_start handlers can now return multiple messages (all are injected, not just the first)
  • /hotkeys command now shows hook-registered shortcuts in a separate "Hooks" section
  • New example hook: plan-mode.ts - Claude Code-style read-only exploration mode:
    • Toggle via /plan command, Shift+P shortcut, or --plan CLI flag
    • Read-only tools: read, bash, grep, find, ls (no edit/write)
    • Bash commands restricted to non-destructive operations (blocks rm, mv, git commit, npm install, etc.)
    • Interactive prompt after each response: execute plan, stay in plan mode, or refine
    • Todo list widget showing progress with checkboxes and strikethrough for completed items
    • Each todo has a unique ID; agent marks items done by outputting [DONE:id]
    • Progress updates via agent_end hook (parses completed items from final message)
    • /todos command to view current plan progress
    • Shows ⏸ plan indicator in footer when in plan mode, 📋 2/5 when executing
    • State persists across sessions (including todo progress)
  • New example hook: tools.ts - Interactive /tools command to enable/disable tools with session persistence
  • New example hook: pirate.ts - Demonstrates systemPromptAppend to make the agent speak like a pirate
  • Tool registry now contains all built-in tools (read, bash, edit, write, grep, find, ls) even when --tools limits the initially active set. Hooks can enable any tool from the registry via pi.setActiveTools().
  • System prompt now automatically rebuilds when tools change via setActiveTools(), updating tool descriptions and guidelines to match the new tool set
  • Hook errors now display full stack traces for easier debugging
  • Event bus (pi.events) for tool/hook communication: shared pub/sub between custom tools and hooks
  • Custom tools now have pi.sendMessage() to send messages directly to the agent session without needing the event bus
  • sendMessage() supports deliverAs: "nextTurn" to queue messages for the next user prompt

Changed

  • Removed image placeholders after copy & paste, replaced with inserting image file paths directly. (#442 by @mitsuhiko)

Read more

Release notes

Pi 0.33.0

New version of pi. Download from npm or view release on GitHub.

Breaking Changes

  • Key detection functions removed from @mariozechner/pi-tui: All isXxx() key detection functions (isEnter(), isEscape(), isCtrlC(), etc.) have been removed. Use matchesKey(data, keyId) instead (e.g., matchesKey(data, "enter"), matchesKey(data, "ctrl+c")). This affects hooks and custom tools that use ctx.ui.custom() with keyboard input handling. (#405)

Added

  • Clipboard image paste support via Ctrl+V. Images are saved to a temp file and attached to the message. Works on macOS, Windows, and Linux (X11). (#419)
  • Configurable keybindings via ~/.pi/agent/keybindings.json. All keyboard shortcuts (editor navigation, deletion, app actions like model cycling, etc.) can now be customized. Supports multiple bindings per action. (#405 by @hjanuschka)
  • /quit and /exit slash commands to gracefully exit the application. Unlike double Ctrl+C, these properly await hook and custom tool cleanup handlers before exiting. (#426 by @ben-vargas)

Read more