Changelog
Release notes

Pi 1.5.0

New Features

  • Extension update changelogs: see what changed in installed extension packages on the next fresh launch after an update. Package authors can choose the changelog path, and collapseChangelog condenses the notices. See Show a changelog.
  • Faster streaming: large tool calls are parsed incrementally, and code-heavy answers and tool rows reuse highlighting and rendered Markdown instead of repeating the work on every update. See Keep rendering responsive.
  • Custom self-update commands: use PI_SELF_UPDATE_COMMAND or selfUpdateCommand to update pi through a wrapper or another package manager. See Custom update command.
  • GPT-6.1 Terra: available through OpenAI, Azure OpenAI Responses, and OpenAI Codex, with tool search, mid-conversation thinking-level changes, and thinking off. Codex offers a 500K context window. See Models.

Breaking Changes

  • Tool argument validation runs on @earendil-works/pi-schema. TypeBox features outside JSON Schema (Type.Refine(), Type.BigInt(), Type.Undefined(), codecs, Format.Set() formats) no longer apply to tool arguments; see Tool parameter schemas and TypeBox. Plain JSON Schema tools, including MCP tools, now get the same coercion as TypeBox tools, such as converting numeric strings and wrapping a single value into an array. Validation failures the model sees list pi-schema's messages (- path: missing, - limit: expected number, got string) instead of TypeBox's (must have required properties path, must be number).

Added

  • Extension packages can now show their changelog after an update. Pi reads pi.changelogPath from the package's package.json, or CHANGELOG.md in the package root, and on the next fresh launch shows entries newer than the last seen version under "Extension Updates". The collapseChangelog setting condenses this to one line per package (#5958, #8790)
  • pi.exec() accepts a maxBuffer option that limits stdout and stderr combined, and its result has a truncated field that is true when output exceeded the limit (#11360)
  • Device-code login (for example GitHub Copilot) now opens the verification page and copies the code when you press Enter. Providers can turn either action off with openBrowserOnConfirm: false or copyCodeOnConfirm: false (#9282, #9301)
  • pi update can update Pi through a wrapper or another package manager. Set PI_SELF_UPDATE_COMMAND (for example mise use -g npm:{packageName}@{version}) or the global selfUpdateCommand setting; pi update runs it when pi.dev reports a newer release and fills {packageName}, {version}, and {installSpec} from that release. See Custom update command (#7756, #5607)
  • Extensions can format the user's configured keybindings with keyText() and keyHint() from the tool render context and the message and entry renderer options. Importing these functions from @earendil-works/pi-coding-agent can resolve the extension's own copy of the package, which does not see pi's keybindings, so hints such as keyHint("app.tools.expand", "to expand") rendered without the key. The docs now recommend the injected functions (#4748)
  • Added persisted session-entry messageId and ISO timestamp to MarkdownTransformContext. They are available when rendering saved entries and undefined for live rendering (#7952 by @vipentti)
  • Added a blocked option to inline ctx.ui.custom() components so approval prompts and other custom dialogs can report that pi is waiting for user input. Overlays ignore the option. See Custom screens and overlays (#11428)
  • Added Usage.cost.totalFromProvider to distinguish billed totals from catalog estimates in SDK and extension usage data; combined usage is marked provider-reported only when every part is (#11178)
  • Added concrete responseModel metadata to messages from pi-messages providers such as Radius, including when a virtual model is requested. See AssistantMessage (#11265)
  • Added GPT-6.1 Terra for OpenAI, Azure OpenAI Responses, and OpenAI Codex, with tool search and mid-conversation thinking-level changes. It supports thinking off; Codex offers a 500K context window

Changed

  • Extensions keep importing Type, Static and TSchema from @earendil-works/pi-ai: Pi maps that import to pi-ai's compat entry plus the TypeBox it bundles, now that pi-ai itself no longer re-exports TypeBox, and its StringEnum there stays a TypeBox TUnsafe<T>. The built-in tool factories (createReadTool() and the others) return TypeBoxAgentTool<typeof schema>, which keeps params typed for TypeBox.
  • Tightened system prompt
  • pi update for installs from the pi.dev installer no longer passes --min-release-age=0 to npm ci. The release lockfile pins every package, so the flag had no effect, and security scanners that block it stopped the update (#11262)
  • /model and /scoped-models now show a model's name next to its ID when the name adds words the ID lacks, such as a renamed models.json override (#5916, #11347)
  • MCP OAuth sign-in now uses pi's Client ID Metadata Document by default when the authorization server supports it for public clients, and registers a client dynamically otherwise, like Codex, Claude Code, and opencode. Clients registered before stay in use while their redirect URI matches. The new default oauth.clientRegistration: "auto" registers when clientName or a non-default callbackUrl is set; "dcr" always registers. pi mcp add --oauth-client-registration sets the mode (#11426)
  • Changed the default OpenAI model from gpt-5.5 to gpt-6.1-sol, including after ChatGPT sign-in when no model is selected (#11442)
  • Updated the built-in model catalog to models.dev v2. Realtime and image-only models are no longer offered as chat models; newer OpenAI and Google chat models are included

Fixed

  • Updated glob matching to prevent denial of service from amplified glob patterns.
  • Fixed a saved "Do not trust" decision being ignored for projects without trust-requiring resources, for example a folder with only AGENTS.md. pi auto-trusted such projects, so ctx.isProjectTrusted() returned true and package commands treated them as trusted. A saved decision in trust.json now takes precedence; auto-trust applies only when no decision is saved (#10947)
  • Fixed Shift+Enter queueing a follow-up instead of inserting a newline in Apple Terminal setups that send ESC + Return. pi now checks the local Shift key state for that sequence, as it already did for plain Return; Alt+Enter without Shift still queues a follow-up (#11559)
  • Fixed the working status (OSC 7501) disappearing in Rex and iTerm2 during runs in regular TUI mode. Rendered messages wrote OSC 133 prompt markers to the terminal, which the terminal treats as a new shell prompt; regular mode no longer writes them (#11519)
  • Fixed compaction, branch summaries, and bug-report summaries in SDK sessions passing the stored OAuth token back to the model runtime as an explicit API key. Provider auth that treats explicit keys differently from stored OAuth now sees the OAuth login, as normal prompts do (#11520)
  • Fixed a redundant system prompt update (tools, rules) when an extension set the same active tools in a different order, for example a reversed pi.setActiveTools() list. Tools that stay active now keep their order and newly activated tools are appended (#11495)
  • Fixed pi.exec() crashing pi with RangeError: Invalid string length when a command printed more output than fits in a string. The default output cap is the smaller of 256 MiB and the runtime string limit; past the cap, the command is terminated and the result has truncated: true and a nonzero exit code (#11360)
  • Fixed pi.exec() never returning when a command ignored SIGTERM after a timeout or abort. pi now sends SIGKILL 5 seconds later, as intended
  • Fixed pi install and pi remove adding ever deeper nested entries to the npm package-lock.json when the agent directory is reached through a symlink, such as ~/.pi linked into a dotfiles repo. pi now passes the resolved real path to npm (#11358)
  • MCP sign-in now rejects authorization endpoints and other OAuth metadata URLs that are not http: or https:. Before, a malicious MCP server could supply a file: or custom protocol URL, which pi passed to the platform URL handler.
  • Automatic fd and rg downloads no longer fetch x86-64 binaries on ARM32 and other architectures without a prebuilt release. pi now warns and recommends installing the tool with the system package manager (#11209)
  • Fixed /model search ranking letters scattered over an earlier part of an entry above a real match, for example opus listing gpt-oss-120b and claude-sonnet-4.5 before claude-opus-4.1 (#11220, #11296)
  • Fixed /resume search matching scattered letters anywhere in session messages and IDs, for example 1024 matching inside a session UUID. Session names and working directories still match fuzzily; IDs and message text now match only as exact substrings (#11220, #11024, #11296)
  • Fixed HTML export showing a blank page for sessions with thousands of entries (#11225, #11293)
  • Fixed HTML export not showing system messages: the system prompt and tools, and later section updates such as after /reload. pi --export now includes the system prompt and tools too (#11261, #3464, #11290)
  • Fixed aborting a bash command on macOS sometimes running the next command of a list such as long_step; next_step. pi now stops the process group before killing it (#11252, #11289)
  • Fixed large streamed tool calls taking excessive CPU time and memory because every delta re-parsed the accumulated arguments. Providers and agent proxy streams now parse each delta once, grammar tools no longer copy their entire input per delta, and interactive tool renderers run at most once per frame (#9265)
  • Fixed the login dialog opening sign-in URLs that are not web URLs, and printing control characters from sign-in, device-code, and info URLs, which could end a terminal hyperlink and send escape sequences to the terminal
  • Fixed tui.select.pageUp and tui.select.pageDown being ignored in slash command and file autocomplete, /settings, and the model, scoped models, login, fork, /mcp, and llama.cpp selectors. In fullscreen mode, PageUp/PageDown now move an open list or autocomplete menu instead of scrolling the transcript, and a page key bound to Ctrl+V pages autocomplete instead of pasting an image (#7629, based on #7680 by @muyiyr)
  • Fixed tool output and ! command output showing the parameters of control sequences with a <, = or > prefix as text, for example 35;59;1M from a mouse report ESC[<35;59;1M or 0;276;0c from a terminal reply ESC[>0;276;0c. Text after the keypad-mode sequences ESC= and ESC> is still kept (#11377)
  • Fixed pi -e npm:<pkg> staying on the version from the first download. On each start and /reload, pi now reinstalls an -e npm package without an exact version when the registry has a newer matching version. pi -e git:<repo>@<branch> likewise stayed on its first checkout and is now fetched and reset to the branch; a commit-hash ref that is already checked out is not fetched. Offline mode and failed checks keep the cached copy (#11375, #11590)
  • Fixed Windows paths being compared case-sensitively. When the working directory and home directory differed only in drive-letter casing (c:\Users\me vs C:\Users\me), skills in ~/.agents/skills loaded twice, as project and user skills, and were reported as name collisions. The same mismatch also re-asked for saved project trust, hid sessions in a custom session directory from --continue and /resume, and stopped pi remove from matching configured local packages (#10488)
  • Fixed paths next to the home directory being shown with a broken ~ prefix, for example /home/me2/project shown as ~2/project when home is /home/me
  • Fixed pi mcp login -l and pi mcp logout -l failing with Unknown option --local. although pi mcp add and pi mcp remove accept -l. With -l, they now require the server to be a project server. Unknown options are now reported as typed, and a mistyped server name gets a suggestion, for example Did you mean "gurker"?
  • Fixed pi update naming pnpm for installs that only live under PNPM_HOME, for example a wrapper under $PNPM_HOME/global-nub/. pi said "not managed by a global pnpm install"; it now names the package manager only when that manager owns the install (#7756)
  • Fixed image paste, copy, and opening the browser for sign-in failing silently on WSL when the working directory is deep. Windows programs such as powershell.exe and explorer.exe cannot start from a directory whose \\wsl.localhost\... path exceeds 260 characters; pi now starts these helpers from / (#11592)
  • Fixed the external editor failing silently, for example when the editor command is wrong or a Windows editor cannot start from a deep WSL directory. pi now shows a status message such as External editor exited with code 1; prompt unchanged (#11592)
  • Fixed tool_search and codemode searchTools() ranking a tool below tools that only mention its name in their descriptions, for example peekaboo app ranking mcp__peekaboo__app 14th. A tool matching more of the query's words now ranks above one matching fewer, a query word in a tool's name scores more than any number of mentions in its description, a tool whose whole name is in the query gets a large bonus, and long server instructions no longer lower the scores of that server's tools (#11331)
  • Fixed tool_search and codemode searchTools() finding nothing for Chinese, Japanese, Thai, and other non-ASCII queries, because the tokenizer kept only ASCII letters and digits. Words in any script now match, text without spaces between words such as 搜索记录 is split into words, and canonically equivalent text such as café and cafe\u0301 matches (#10816, #11037 by @haoqixu)
  • Fixed pi update stopping with git clean -fdx failed with code 1 on Windows when another pi session had a git extension's native module or executable open. Windows cannot delete such files, so the update left the new code with the old dependencies. pi now warns, installs the dependencies anyway, and retries the clean on the next update (#11597)
  • Fixed tool rows and streamed answers highlighting the same code again on every redraw. A running codemode row highlighted its whole script on every progress update and timer tick, a complete write row its whole file on every update and expand toggle, a streamed write its first 50 lines on every delta, and a streamed answer every earlier code block on every delta. Rows now reuse their last highlighting until the code, theme, or loaded grammars change, and assistant messages keep their rendered Markdown blocks while streaming (#10971)
  • Fixed resized photos being sent as multi-megabyte PNGs even when JPEG was much smaller, causing large requests to fail or time out. Image resizing now tries the smaller encoding first (#11551)
  • Fixed pi update --extensions reporting success without warning when npm's stale registry metadata left a package at its old version. pi now reports the installed and expected versions (#11536)
  • Fixed skill validation warnings being labeled [Skill conflicts] even when there was no name collision. They are now shown under [Skill warnings] (#11521)
  • Fixed codemode tool descriptions including entire union and multi-line output types in every request. Object unions now summarize their fields and discriminators; other multi-line types point to describeTool() for the full declaration (#11501)
  • Fixed the model-scope startup notice being left in the shell after exiting fullscreen mode. It now appears inside pi's fullscreen header (#11508)
  • Fixed startup from a deleted working directory crashing with an uncaught uv_cwd stack trace. pi now asks the user to change to an existing directory (#11509)
  • Fixed failed session writes leaving entries in memory that were absent from disk, so later entries pointed to missing parents and resumed sessions lost earlier history and tools (#11460)
  • Fixed /tree branch summaries ignoring the session's thinking level, which could make reasoning models reject summary requests with an unsupported none effort (#11444)
  • Fixed hidden thinking with an empty hidden-thinking label still adding blank rows before answers and tool calls (#11402)
  • Fixed package installation and removal printing npm audit and funding advice, including npm audit fix instructions that could install a second copy of pi into the package directory (#11409)
  • Fixed replacing an extension editor while a dialog was open hiding the dialog and leaving it unanswerable. The new editor now appears after the dialog closes (#11431)
  • Fixed grep context lines being offset from ripgrep's match line numbers when a file contains a lone carriage return (#11398)
  • Fixed --model <provider>/<id> failing for provider IDs containing slashes, such as URL-derived llama.cpp provider IDs (#11394)
  • Fixed slow session forking on filesystems where opening files is expensive by writing the fork through one file handle (#11253)
  • Fixed pi.exec() corrupting UTF-8 characters split across stdout or stderr chunks (#11312)
  • Fixed pi.exec() returning empty stderr when a command could not be spawned, such as a missing executable. It now preserves the spawn error message (#11257 by @muyiyr)
  • Fixed a configured package failing to install crashing startup. pi now skips the package, reports an extension warning, and retries on the next start or /reload; explicit install and update commands still fail with a nonzero exit (#11304 by @Lincoln504)
  • Fixed the todo extension example crashing the TUI when a tool call failed argument validation (#8057 by @cyzlmh)
  • Updated undici to 8.12.3 and the Gondolin extension example to 0.14.0 for security advisories
  • Fixed OpenRouter cost totals using catalog estimates instead of reported billing for Chat Completions and Anthropic Messages. BYOK totals include both OpenRouter charges and reported upstream costs; component costs remain catalog estimates (#9980)
  • Fixed OpenCode Zen and OpenCode Go requests using shared endpoints instead of their protocol-specific OpenAI, Anthropic, Google, and System One endpoints (#11434 by @vimtor)
  • Fixed Zhipu/Z.ai usage-limit errors (code 1308) being treated as transient HTTP 429 errors, causing automatic retries that cannot succeed until the usage cap resets (#11537)
  • Fixed LiteLLM's ContextWindowExceededError not being recognized as context overflow (#11492)
  • Fixed Gemini tool schemas sending unsupported const keywords. They are now converted to single-value enum schemas without rewriting literal data in defaults, examples, or enum values, or losing properties named __proto__ (#11308)
  • Fixed the faux provider counting simulated cache-write tokens as both input and cache writes
  • Fixed Orca terminals falling back to text for inline images. Orca is now recognized as supporting true color and hyperlinks, and Kitty images when it advertises ORCA_IMAGE_PROTOCOL=kitty (#9329 by @XRX193)
  • Fixed bare Markdown URLs swallowing following CJK punctuation and text; explicit Markdown links and angle autolinks are unchanged (#10934 by @haoqixu)
  • Fixed Kitty-protocol F1–F12 shortcuts, including modified function keys, not being recognized, and F13+ and other functional keys inserting invisible private-use characters into the editor (#11419, #11345)
  • Fixed Kitty images inside padded or colored boxes disappearing when their first row scrolled above the fullscreen viewport. Partially visible images are now cropped correctly, including beside other text
  • Fixed deeply nested Markdown blockquotes producing exponentially many lines, hanging or crashing rendering once their borders exhausted the available width (#11272)
  • Fixed Claude sessions failing with role 'system' must precede an 'assistant' message when a system update was followed by an empty or reasoning-only assistant reply (#11091)
  • Fixed Claude mid-conversation thinking-level changes failing with Invalid effort level on accounts whose organization caps effort below high (#10063)
  • Fixed Kimi K3.1 Pro models using Kimi K2 request settings on Kimi Coding, Moonshot, and OpenCode Go. They now send the correct reasoning effort, preserve earlier thinking, accept tools added mid-conversation, and use K3-family pricing
  • Fixed OpenCode DeepSeek V4.1 Flash requests failing when long cache retention sent the unsupported prompt_cache_retention parameter
  • Fixed GPT-5.4 and GPT-5.5 failing with Missing namespace for function_call after switching from a model that had called tools (#11415)
  • Fixed Bedrock Claude requests failing when preferred strict tools exceed the provider's strict-tool limits. Requests now retry once with preferred tools non-strict while keeping required strict tools strict (#11416)
  • Fixed OpenRouter's ~anthropic/claude-*-latest aliases losing earlier thinking after tool calls by using the Anthropic Messages API (#9534)
  • Fixed terminal titles containing control characters being able to inject terminal escape sequences, and pi-messages streams accepting invalid content-block indices
  • Fixed fullscreen double-click selection splitting paths and tokens at ~, ., \, and +; word characters now match iTerm2's defaults (#10980)
  • Fixed display math wider than the content area being split apart by line wrapping; it now falls back to raw LaTeX (#11483)
  • Fixed styled words ending exactly at the wrap width adding a leading space on the next line, and strikethrough leaking into wrapped-line padding (#10925)
  • Fixed /tree branch summaries including failed assistant replies and original content that context edits had hidden or replaced. Summaries now honor the same context edits as live requests and compaction (#11602)

Removed