@oh-my-pi/pi-coding-agent 15.13.0 → 15.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +1656 -613
  2. package/dist/cli.js +12765 -12731
  3. package/dist/types/autolearn/managed-skills.d.ts +1 -1
  4. package/dist/types/capability/mcp.d.ts +2 -1
  5. package/dist/types/cli/args.d.ts +2 -0
  6. package/dist/types/cli/flag-tables.d.ts +126 -0
  7. package/dist/types/cli/profile-alias.d.ts +29 -0
  8. package/dist/types/cli/profile-bootstrap.d.ts +55 -0
  9. package/dist/types/commands/launch.d.ts +6 -0
  10. package/dist/types/config/model-roles.d.ts +3 -2
  11. package/dist/types/config/settings-schema.d.ts +2 -0
  12. package/dist/types/edit/file-snapshot-store.d.ts +14 -0
  13. package/dist/types/extensibility/extensions/runner.d.ts +11 -0
  14. package/dist/types/mcp/manager.d.ts +5 -1
  15. package/dist/types/mcp/oauth-credentials.d.ts +17 -0
  16. package/dist/types/mcp/oauth-flow.d.ts +41 -0
  17. package/dist/types/mcp/types.d.ts +2 -0
  18. package/dist/types/modes/components/background-tan-message.d.ts +9 -0
  19. package/dist/types/modes/components/mcp-add-wizard.d.ts +9 -5
  20. package/dist/types/modes/interactive-mode.d.ts +4 -0
  21. package/dist/types/modes/types.d.ts +3 -0
  22. package/dist/types/sdk.d.ts +1 -1
  23. package/dist/types/session/messages.d.ts +8 -0
  24. package/dist/types/session/session-manager.d.ts +6 -0
  25. package/dist/types/tools/builtin-names.d.ts +2 -0
  26. package/dist/types/tools/index.d.ts +3 -2
  27. package/dist/types/utils/external-editor.d.ts +11 -1
  28. package/package.json +12 -12
  29. package/src/autolearn/managed-skills.ts +3 -5
  30. package/src/capability/mcp.ts +2 -1
  31. package/src/cli/args.ts +61 -103
  32. package/src/cli/completion-gen.ts +2 -2
  33. package/src/cli/flag-tables.ts +270 -0
  34. package/src/cli/profile-alias.ts +338 -0
  35. package/src/cli/profile-bootstrap.ts +243 -0
  36. package/src/cli.ts +83 -16
  37. package/src/commands/launch.ts +7 -0
  38. package/src/config/mcp-schema.json +4 -0
  39. package/src/config/model-roles.ts +17 -4
  40. package/src/config/settings-schema.ts +2 -0
  41. package/src/discovery/builtin.ts +15 -9
  42. package/src/discovery/helpers.ts +25 -0
  43. package/src/discovery/mcp-json.ts +1 -0
  44. package/src/discovery/omp-extension-roots.ts +2 -2
  45. package/src/edit/file-snapshot-store.ts +43 -0
  46. package/src/eval/__tests__/agent-bridge.test.ts +3 -2
  47. package/src/eval/__tests__/helpers-local-roots.test.ts +1 -1
  48. package/src/eval/js/shared/runtime.ts +54 -0
  49. package/src/extensibility/extensions/runner.ts +25 -2
  50. package/src/goals/runtime.ts +4 -1
  51. package/src/internal-urls/docs-index.generated.ts +6 -6
  52. package/src/mcp/manager.ts +108 -71
  53. package/src/mcp/oauth-credentials.ts +104 -0
  54. package/src/mcp/oauth-flow.ts +67 -0
  55. package/src/mcp/types.ts +2 -0
  56. package/src/modes/components/agent-hub.ts +6 -0
  57. package/src/modes/components/background-tan-message.ts +36 -0
  58. package/src/modes/components/mcp-add-wizard.ts +17 -10
  59. package/src/modes/components/model-selector.ts +50 -6
  60. package/src/modes/components/tool-execution.ts +12 -0
  61. package/src/modes/controllers/input-controller.ts +21 -10
  62. package/src/modes/controllers/mcp-command-controller.ts +184 -112
  63. package/src/modes/controllers/tan-command-controller.ts +27 -11
  64. package/src/modes/interactive-mode.ts +6 -0
  65. package/src/modes/types.ts +3 -0
  66. package/src/modes/utils/ui-helpers.ts +6 -0
  67. package/src/prompts/bench.md +9 -4
  68. package/src/sdk.ts +6 -5
  69. package/src/session/agent-session.ts +30 -1
  70. package/src/session/messages.ts +9 -0
  71. package/src/session/session-manager.ts +7 -2
  72. package/src/tiny/text.ts +5 -1
  73. package/src/tools/ast-grep.ts +5 -1
  74. package/src/tools/builtin-names.ts +35 -0
  75. package/src/tools/index.ts +3 -2
  76. package/src/tools/read.ts +9 -0
  77. package/src/tools/search.ts +5 -1
  78. package/src/tts/tts-worker.ts +13 -5
  79. package/src/utils/external-editor.ts +15 -2
  80. package/src/utils/title-generator.ts +1 -1
  81. package/src/workspace-tree.ts +46 -6
  82. package/dist/types/utils/tools-manager.test.d.ts +0 -1
  83. package/src/utils/tools-manager.test.ts +0 -25
package/CHANGELOG.md CHANGED
@@ -2,18 +2,38 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.13.1] - 2026-06-15
6
+
5
7
  ### Added
6
8
 
9
+ - Added isolated profile support via `--profile <name>` / `OMP_PROFILE` and shell alias bootstrap via `--alias <command>`, including launch/ACP bootstrap handling, extension-flag-safe parsing, profile-scoped user config discovery, and symlinked extension-directory discovery.
7
10
  - Fixed paste and image placeholders crashing when the editor renders before theme initialization.
8
- - Added `ModelRegistry.create(authStorage, modelsPath?)` async factory that runs the JSON → YAML migration step on `models.{yml,yaml}` asynchronously ahead of the sync constructor's bundled-model load. The sync `new ModelRegistry(...)` constructor still works (tests rely on it); production boot paths now use the factory so the migration's I/O lands off the event-loop hot path.
9
- - Added `ConfigFile.tryLoadAsync()`, `ConfigFile.loadAsync()`, `ConfigFile.loadOrDefaultAsync()`, `ConfigFile.getMtimeMsAsync()`, and `ConfigFile.warmup(file)` so the rest of the codebase can migrate config reads off the sync path.
11
+
12
+ ### Changed
13
+
14
+ - Replaced the `omp bench` default prompt with a concrete query-planning trace that requires deriving selectivities, cardinalities, and I/O/CPU costs from given schema and data. The old prompt was open-ended prose recall, which rewarded not-thinking: adaptive-thinking models (Opus 4.6+/Sonnet 4.6+) minimized reasoning on the trivial task and streamed faster, skewing throughput comparisons. The new task forces multi-step reasoning so adaptive thinking engages and the benchmark measures generation under real cognitive load. The prompt also demands explicit upfront deliberation and exhaustive enumeration/costing of every join order, so adaptive-thinking models cannot short-circuit to a quick answer and each model is measured over a sustained generation up to the token cap.
10
15
 
11
16
  ### Fixed
12
17
 
18
+ - Fixed hashline edits from `read`, `search`, and `ast-grep` so replacements are rejected when they target lines not shown in the tool output
19
+ - Fixed `/tan` refusing to launch while the main response was still streaming. The command exists to fork tangential work *alongside* an active session, so it now dispatches mid-stream and queues its handoff breadcrumb for the next turn instead of steering the in-flight one.
20
+ - Fixed `/tan` background agents never staying in the Agent Hub. The forked clone now uses an `<agentId>.jsonl` session file (so the persisted-subagent scan keys it by the same id the live ref uses) and is parked rather than unregistered on completion, so it stays listed and its transcript stays readable.
21
+ - Fixed the `/tan` dispatch breadcrumb rendering its full raw `<system-notice>` block in the transcript. It now shows a single compact line (`Tangent dispatched [task] <jobId> — <work>`), styled as a sibling of the "Background job completed" line.
22
+ - Fixed profile bootstrap parsing so built-in string flags like `--plan` no longer consume the profile-boundary marker and drop the trailing user message
23
+ - Fixed a bug where goal mode was incorrectly deactivated/set to 'none' on every wall-clock-only update (when tokenDelta <= 0) during tool execution flushes, preventing OMP from writing a mode change to 'none' in the session history database while keeping in-memory/UI state fresh.
24
+ - Fixed a bug where Gemini MALFORMED_FUNCTION_CALL tool-generation errors (which are transient) surfaced as terminal error blocks. Added "malformed function call" to the transient transport error classifier so the session automatically retries the turn.
25
+ - Fixed Ctrl+C teardown waiting up to 30s when an extension's `session_shutdown` handler hung — observed on Windows with `omp-discord-presence` 0.1.2 stuck on a stale Discord IPC pipe. `ExtensionRunner.emit` previously shared the generic 30s `EXTENSION_HANDLER_TIMEOUT_MS` budget for every event, including the fire-and-forget teardown event extensions cannot observe. `session_shutdown` now uses a dedicated 2s `SESSION_SHUTDOWN_HANDLER_TIMEOUT_MS` cap routed through a per-event `handlerTimeoutForEvent()` lookup, so a hung third-party handler can no longer hold dispose hostage. As a defence-in-depth ladder, a Ctrl+C arriving while interactive shutdown is already running now hard-exits with code 130 (the session JSONL has already been sync-flushed by the first press), surfaced via a new read-only `InteractiveModeContext.isShuttingDown` ([#2600](https://github.com/can1357/oh-my-pi/issues/2600)).
26
+ - Fixed the external editor flow (Ctrl+G, plan editor, `/todo edit`) warning `No editor configured` on Windows even when the user expected the system's native editor. `getEditorCommand()` now falls back to `notepad` on `win32` after consulting `$VISUAL`/`$EDITOR` (and trims those values so accidental whitespace is ignored), so Windows users get a working editor out of the box while POSIX still warns to nudge configuration ([#2604](https://github.com/can1357/oh-my-pi/issues/2604)).
27
+ - Fixed Kokoro TTS setup loading the workspace/global `@huggingface/transformers` runtime before the side-installed Kokoro runtime, which could leave `onnxruntime-node@1.26.0` bound to an older `libonnxruntime.so.1` and fail with `VERS_1.26.0` missing ([#2591](https://github.com/can1357/oh-my-pi/issues/2591)).
28
+ - Fixed `scripts/ci-release-notes.ts` stranding curated changelog entries from intervening *silent* tags (a `vX.Y.Z` tag pushed without a GitHub Release, e.g. the `v15.12.5`/`v15.12.6` casualties of the pre-#2564 release-cancellation bug). The generator now walks `(latest-published-release, target]` — resolved via `gh release list` from the `release_github` CI job — and merges every in-range `## [X.Y.Z]` section per package, grouped by `### <category>` with bullet-level dedupe so post-release changelog flattening cannot duplicate entries. Falls back to the legacy single-version extraction when no prior published release resolves, and `OMP_RELEASE_NOTES_FLOOR=v15.12.4` overrides the lookup for manual rebuilds ([#2596](https://github.com/can1357/oh-my-pi/issues/2596)).
13
29
  - Fixed `Test & smoke (TS)` CI timeouts caused by parallel test files racing on the process-global Settings singleton. `CustomEditor` now accepts a `magicKeywordsEnabledOverride` injection point so the shimmer-gate test can assert behaviour without calling `resetSettingsForTest()` / `Settings.init()`; the "streaming tool call preview height" describe drops its gratuitous Settings reset+init. Production wiring is unchanged ([#2582](https://github.com/can1357/oh-my-pi/issues/2582))
14
- - Fixed MCP OAuth fallback rendering to show a short terminal hyperlink and keep the raw authorization URL on one unwrapped copy line ([#2121](https://github.com/can1357/oh-my-pi/issues/2121)).
15
- - Fixed `omp dry-balance --bench` to recover from 401 token failures by re-minting the failing OAuth credential in place before switching accounts
16
- - Fixed selector-style UI components to honor `tui.select.up` and `tui.select.down` keybindings instead of hard-coding raw Up/Down arrow bytes ([#1535](https://github.com/can1357/oh-my-pi/issues/1535)).
30
+ - Fixed a collapsed, still-streaming tool preview (an `eval`/`bash`/`ssh` box with output streaming in) reading as "weirdly truncated" — top border and head rows missing — once its box outgrew the viewport, snapping back to whole only while expanded with `ctrl+o` and breaking again when collapsed. A streaming preview was classified commit-unstable whenever collapsed, so the transcript offered none of its rows to native scrollback; once the box outgrew the window its head fell into the gap between the commit boundary and the window top, committed nowhere and repainted nowhere. The `provisionalPendingPreview` flag now applies only to the pending call preview (before any result) — once a streaming result exists the result renderer is the live, top-anchored shape and the block is commit-stable in both collapsed and expanded states, so its durable head always reaches scrollback.
31
+ - Fixed a crash in subagent task execution and extensions when a string (instead of a string array) was returned or set for the system prompt. Gracefully wrap string values in arrays.
32
+ - Fixed the todo completion reminder escalating 1/3 → 2/3 → 3/3 within a single user pause: `#checkTodoCompletion` appended a `<system-reminder>` and then scheduled `agent.continue()`, so a text-only acknowledgement ("paused at your instruction") triggered another `agent_end` that re-ran the same check and fired the next reminder — no user input required. `AgentSession` now tracks `#todoReminderAwaitingProgress`: a reminder sets it, any `toolResult` (real progress) or a new user prompt clears it, and `#checkTodoCompletion` stays silent while it is set. Escalation through `todo.reminders.max` still works when the agent makes tool-level progress between stops ([#2590](https://github.com/can1357/oh-my-pi/issues/2590)).
33
+ - Fixed profile bootstrap so an extension-shadowed `--plan` flag no longer swallows a following global `--profile`.
34
+ - Fixed MCP OAuth URL-keyed credentials to stay profile-scoped under shared auth-broker storage and to clear discovered definition-only server auth during `/mcp unauth`.
35
+ - Fixed `/mcp unauth` deleting another profile's MCP OAuth credential row under broker-backed auth storage: when a shared `mcp.json` pins an explicit `auth.credentialId` scoped to a different profile (`mcp_oauth:profile:<other>:<url>`), removal now skips ids scoped to a non-active profile, mirroring the read path that already refuses to *use* a foreign profile's id. Legacy url-keyed (`mcp_oauth:<url>`) and active-profile ids are still cleared.
36
+ - Fixed auto-learn managed skills to use the active profile's agent directory, so authored profile skills keep priority over managed fallbacks.
17
37
 
18
38
  ## [15.13.0] - 2026-06-14
19
39
 
@@ -41,7 +61,6 @@
41
61
  - Added live (streaming) speech-to-text: with `stt.enabled` on, transcription now appears in the composer *as you speak* instead of all at once after you stop. The recorder streams raw 16 kHz mono PCM from sox/ffmpeg/arecord stdout to the warm STT worker, where an energy-based endpointer (no extra model) splits speech into segments at natural pauses; each finalized segment is committed into the editor while the in-progress segment shows a live volatile preview that refreshes in place and is kept out of the undo history. Works with both the default Parakeet (sherpa-onnx) and the Whisper (transformers.js) tiers. Recorders that cannot stream to a pipe (the Windows PowerShell mci fallback) transparently fall back to single-shot transcription.
42
62
  - Added `skills.enableAgentsUser` and `skills.enableAgentsProject` settings (default on) so the canonical OMP-native `~/.agent[s]/skills` and project-walkup `.agent[s]/skills` are configurable independently from the third-party Claude/Codex/Pi toggles.
43
63
  - Added a read-only `ctx.models` facade for extensions: `list()` (authenticated models), `current()` (live session model), `resolve(spec)` (a model string or role alias → `Model`, using the same settings-backed aliases and match preferences as core selection), and `family(model)` (opaque canonical-identity lineage token for cross-family comparisons). Lets extension tools select models the way core does without reaching into the mutable registry ([#2406](https://github.com/can1357/oh-my-pi/issues/2406))
44
-
45
64
  - Added RPC prompt lifecycle hints so hosts can distinguish scheduled agent turns from local-only slash commands via `data.agentInvoked` and `prompt_result`.
46
65
  - Added extension lifecycle events for tool approval prompts: `tool_approval_requested` before the approval wait and `tool_approval_resolved` after approve, deny, or approval prompt failure.
47
66
 
@@ -54,7 +73,6 @@
54
73
  - Changed speech-to-text to run fully local on-device with a tiered, multi-engine model picker. Transcription runs in a subprocess worker (mirroring the tiny-model worker; the native ONNX addons are hard-killed on shutdown to dodge the Bun NAPI-finalizer segfault) instead of shelling out to Python `openai-whisper`, keeps the model warm across recordings, and decodes WAV to 16 kHz mono float32 in-process. `stt.modelName` now selects on-device tiers across two engines: `parakeet` (default) — NVIDIA Parakeet TDT 0.6B v3 (25 languages) via the native `sherpa-onnx-node`, the Open ASR Leaderboard accuracy + throughput leader (lower WER than, and ~20× faster decoding than, Whisper large-v3) — plus `fast`/`balanced`/`turbo` mapping to Whisper base/small/large-v3-turbo (multilingual, up to 99 languages) via `@huggingface/transformers`. `omp setup speech` no longer mentions pip/python-whisper and reports recorder + model-cache readiness.
55
74
  - Changed the speech-to-text trigger from the `Alt+H` keybinding to a hold-`Space` push-to-talk gesture. Holding the space bar emits an OS auto-repeat burst; once more than 5 spaces land in the editor it recognizes the hold, deletes (tracks back) those inserted spaces, and starts recording, then stops and transcribes when the repeats stop (the space bar is released). `app.stt.toggle` is now unbound by default but can be rebound to a chord for press-to-toggle; the gesture is gated on `stt.enabled`, and `Shift+Space` still inserts a literal space.
56
75
  - `task.eager` ("Prefer Task Delegation") and `todo.eager` ("Create Todos Automatically") are now three-level enums (`default` / `preferred` / `always`) instead of booleans. For `todo.eager`, `preferred` renders a soft first-message reminder while `always` forces the `todo` tool (the previous "on" behavior); for `task.eager`, `preferred` adds a soft (SHOULD) delegation nudge to the system prompt while `always` uses hard (MUST/ONLY) wording plus a first-turn delegation reminder. Existing boolean configs migrate automatically (`true → always`, `false → default`). On models that cannot be forced to call `todo`, `todo.eager: "always"` now emits the first-turn reminder without forcing the call (previously such models received nothing) ([#2539](https://github.com/can1357/oh-my-pi/issues/2539), [#2540](https://github.com/can1357/oh-my-pi/pull/2540) by [@metaphorics](https://github.com/metaphorics)).
57
-
58
76
  - Fixed `/model`-switching to a non-default OpenRouter model returning `404 No route: POST /chat/completions` when the provider is routed through the auth-gateway broker. The background catalog refresh re-ran `mergeDiscoveredModel` on every openrouter entry; for models whose bundled record already existed, the merge re-applied `baseUrl`, `headers`, and `compat` but dropped `transport: pi-native` because the raw `/v1/models` payload carries no transport hint. The next `/model` switch then picked the now-transport-less entry and routed through the default openai-completions client to `${baseUrl}/chat/completions` — a path the auth-gateway never serves. `mergeDiscoveredModel` now propagates the override/existing transport on the rediscovery branch ([#2555](https://github.com/can1357/oh-my-pi/issues/2555)).
59
77
 
60
78
  ### Fixed
@@ -88,12 +106,9 @@
88
106
  - Fixed the Agent Hub opening on its own from a stray mouse click. The double-tap-← gesture (empty editor) fired on any two `left` keys within 500ms, but terminals with "click to move cursor" / pointer features (iTerm2 option-click, WezTerm, kitty, tmux) synthesize a burst of arrow keys on click — delivered sub-millisecond apart in one stdin read — so a single click could pop the hub with no key ever pressed. The gesture now requires the second tap to land a human-plausible interval after the first (≥40ms, <500ms) and ignores any third-or-later rapid tap, so synthesized bursts are rejected while a deliberate double-tap still works. The same hardening applies to the focused-subagent ←← "return to main" gesture.
89
107
  - Fixed the `ctrl+p` model-role cycle indicator (the `default / gpt / fable / …` chip track) stacking duplicate copies in the scrollback when other chat activity landed between two cycles. The track was emitted through `showStatus`, whose back-to-back coalescing only merges when the previous status is still the last transcript child; any interleaved append broke that identity check and appended a second track. It now renders into a dedicated anchored container above the editor (cleared and rebuilt in place each cycle, like the Todos HUD) and auto-clears after a short linger, so rapid presses or concurrent activity can never duplicate it.
90
108
  - Fixed the `Working…` loader vanishing for the rest of a turn after an auto-compaction (context-overflow recovery) or auto-retry. Those overlays took over the shared status container with a bare `statusContainer.clear()`, which detached the working loader but left `loadingAnimation` set; the resumed turn's `agent_start` → `ensureLoadingAnimation()` is guarded by `if (!this.loadingAnimation)`, so it skipped re-attaching the loader and the spinner stayed gone while the agent kept streaming. The overlay handlers now fully tear the working loader down (stop + dereference) via `#stopWorkingLoader()`, so the next `agent_start` recreates and re-attaches it.
91
-
92
109
  - Fixed JS eval helper optional arguments rejecting Python-style positional calls. `read(path, offset, limit)` now works alongside `read(path, { offset, limit })`, `null`/`undefined` skip optional positional slots, and non-local URI reads such as `artifact://...` delegate through the read tool so line slicing works on spilled artifacts.
93
110
  - Fixed legacy extension compatibility remapping for `@*-pi-ai/utils/oauth` imports so background workers load the relocated `@oh-my-pi/pi-ai/oauth` exports instead of resolving missing `src/utils/oauth/*` files ([#2566](https://github.com/can1357/oh-my-pi/issues/2566)).
94
-
95
111
  - Fixed eager todo initialization prompting GPT-5.5 to emit unsupported task metadata fields, which could leave fresh sessions stuck on the forced first `todo` call ([#2561](https://github.com/can1357/oh-my-pi/issues/2561)).
96
-
97
112
  - Fixed Windows plan-mode task fan-out crashing the TUI when nested async task progress formed a cycle; task rendering now cuts recursive snapshots and long Windows `local://` roots are shortened under temp storage ([#2551](https://github.com/can1357/oh-my-pi/issues/2551)).
98
113
  - Fixed a band of streaming assistant output being lost from native scrollback — committed nowhere, repainted nowhere — once a reply grew taller than the viewport. Markdown whose layout keeps changing above the streaming tail (most visibly a table whose columns re-align as rows arrive) never earns a byte-stable commit-safe end, so as its head scrolled above the window the rows fell into the gap between the commit boundary and the window top and vanished. `TranscriptContainer` now reports a `getNativeScrollbackSnapshotSafeEnd()` for commit-stable live blocks (their whole body is durable content), and the renderer commits those scrolled-off rows audit-exempt — a later layout change of an already-committed row freezes a slightly-stale row in scrollback (duplication never loss) instead of dropping it. Provisional blocks (collapsing tool/edit previews) are unaffected.
99
114
  - Fixed unknown `--`-prefixed flags being silently consumed as prompt text, which let a stale or typoed flag start a real agent session (connecting to MCP servers, waiting on the model) instead of failing fast. `parseArgs` now tracks unrecognized flag-shaped tokens and `runRootCommand` calls `reportUnrecognizedFlags` immediately after the post-extension reparse, exiting `2` with `Error: unknown flag: --…` before any session, MCP, or initial-message work runs. Extension-registered flags still pass cleanly since the validation runs after the extension-aware reparse, and `--` is honored as a POSIX positional separator so flag-shaped prompts (`omp -p -- --explain-this`) survive the new guard ([#2459](https://github.com/can1357/oh-my-pi/issues/2459)).
@@ -257,7 +272,7 @@
257
272
 
258
273
  - Updated collab link handling to accept compact `roomId#key` links and relay hosts without explicit scheme when joining or starting sessions
259
274
  - Added `/collab stop` and `/collab status` options to control and inspect active shared sessions
260
- - Added `/collab`, `/join`, and `/leave` for live session sharing: the host shares an end-to-end encrypted link (AES-256-GCM key only in the link fragment; the relay sees opaque bytes) and guests render the session natively in their own TUI — streaming text, tool cards, footer state, ctrl+o expansion, `/dump` — and can prompt or interrupt the host's agent. Guest prompts render with an author badge; session-mutating commands stay host-only. Defaults to the public `my.omp.sh` relay (`collab.relayUrl`)
275
+ - Added `/collab`, `/join`, and `/leave` for live session sharing: the host shares an end-to-end encrypted link (AES-256-GCM key only in the link fragment; the relay sees opaque bytes) and guests render the session natively in their own TUI — streaming text, tool cards, footer state, ctrl+o expansion, `/dump` — and can prompt or interrupt the host's agent. Guest prompts render with an author badge; session-mutating commands stay host-only. Defaults to the public `relay.omp.sh` relay (`collab.relayUrl`); a self-hostable Go relay lives in the pi-www repo as `omp-collab-relay`
261
276
  - Added `collab.relayUrl` and `collab.displayName` settings plus a `collab` status-line segment showing the participant count (host) or guest role. Guests mirror the host's real model/thinking state into their replica agent and the host's subagent ecosystem end-to-end: the live subagent HUD, the Agent Hub table with live progress, hub chat/kill/revive (routed to the host), and on-demand subagent transcript viewing
262
277
  - Added `omp join <link>` subcommand that launches the interactive TUI and immediately runs `/join <link>`
263
278
 
@@ -337,159 +352,6 @@
337
352
  - `/context` (TUI panel and ACP report) now shows estimated snapcompact wire savings when `snapcompact.systemPrompt` or `snapcompact.toolResults` is enabled — per-feature text → frames token deltas, the reason a swap does not apply (savings margin, image budget, or text-only model), and the estimated size of the next request. The estimate and the live provider-request transform share one planner (`planInlineSwaps`) so displayed numbers cannot drift from wire behavior.
338
353
  - Added `/debug dump-request` and `/debug next-request` as aliases for `/debug dump-next-request` when arming a one-shot AI provider request dump
339
354
  - Added `/debug dump-next-request <path>` to dump the next AI provider HTTP request JSON to a chosen file.
340
- - Added mouse-driven interaction to `/settings`, including tab and setting row hover highlighting, wheel scrolling, and left-click activation for entries and submenus
341
- - Added fullscreen `/settings` mouse-event handling so scrolling and clicks work in an alternate-screen overlay
342
- - `ModelRegistry.resolver` now accepts a model directly — `resolver(model, sessionId)` — deriving `provider`, `baseUrl`, and `modelId` from it; all model-scoped call sites migrated from the verbose `resolver(model.provider, { sessionId, baseUrl, modelId })` form.
343
- - Added experimental `snapcompact.systemPrompt` and `snapcompact.toolResults` settings (off by default, `/settings` → Context → Experimental) that render the system prompt and large historical tool results as dense snapcompact PNG frames on vision-capable models to cut token cost. Frames are built per-request in the provider-context transform, cached across turns, capped by a per-provider image budget, and gated on a token-savings estimate — they never reach `session.jsonl`.
344
- - Added a Personality selector to `/settings` (Model → Prompt): `default` (the previous built-in reply style), `friendly`, `pragmatic`, or `none`. The selected spec renders into a dedicated `<personality>` system-prompt block (extracted from the former `<reply-guidelines>` section) and applies to the live session immediately; subagents always omit the block.
345
- - Added `mnemopi.polyphonicRecall` and `mnemopi.enhancedRecall` config.yml settings (off by default, `/settings` → Memory → Mnemopi) that enable the mnemopi 4-voice polyphonic recall engine and the tiered query result cache without environment variables; `MNEMOPI_POLYPHONIC_RECALL` / `MNEMOPI_ENHANCED_RECALL` still override the configured values when set ([#2323](https://github.com/can1357/oh-my-pi/issues/2323)).
346
- - Added the Expert Elixir language server (`expert`, invoked as `expert --stdio`) to the built-in LSP server list, auto-detected for Mix projects (`mix.exs`/`mix.lock`). When both are installed, `elixir-ls` remains the primary navigation server (Expert is ordered after it).
347
- - Added `magicKeywords.enabled` and per-keyword `magicKeywords.ultrathink`, `magicKeywords.orchestrate`, and `magicKeywords.workflow` settings to disable hidden magic-keyword notices and ultrathink auto-thinking escalation ([#1796](https://github.com/can1357/oh-my-pi/issues/1796)).
348
- - Added external-editor support for Plan Review section annotations, preserving multiline feedback for Refine plan ([#2305](https://github.com/can1357/oh-my-pi/issues/2305)).
349
- - Added plain-RPC slash command discovery with command source metadata and startup/update notifications ([#2261](https://github.com/can1357/oh-my-pi/issues/2261)).
350
- - Added the `statusLine.transparent` appearance setting (default off): when enabled, the status line skips the theme's `statusLineBg` fill and powerline end caps so the bar inherits the terminal's default background — useful in Ghostty and other terminals whose theme background does not match the theme's hardcoded status-line color ([#2306](https://github.com/can1357/oh-my-pi/issues/2306))
351
- - Snapcompact compaction now passes the session model so frames render in the provider-optimal shape (unscii `8x8r-bw` for Anthropic-family/unknown APIs, `8x8r-sent` for Google, Lanczos-stretched `6x6u-sent` with `detail: "original"` for OpenAI), per the snapcompact 200k-token evals
352
- - Added per-turn supersede pruning of stale `read` results: when a file is re-read, older copies of the same path/selector are pruned from context at cache-favorable moments (small suffix, idle gap, or alongside overflow pruning). Gated by the new `compaction.supersedeReads` setting (default on)
353
- - Added soft request budgets for task subagents (explore/quick_task 40, others 90, configurable via `task.softRequestBudget`, 0 disables): crossing the budget injects a one-time wrap-up steer into the child; crossing 1.5× aborts the run gracefully
354
- - Added cancelled/aborted subagent salvage: instead of `(no output)`, merged task results now carry the child's last activity snippet plus request/token stats, and per-child stats lines include request counts
355
- - Added a repeat-read notice to the `read` tool: the third and later reads of the same file in a session append a one-line note suggesting range re-reads or the context echoed in edit results
356
- - Added a hard inline byte cap (~50KB) at the bash and browser tool-result boundaries with head/tail elision and an `artifact://` footer for the full output, closing paths that previously let 100KB+ results land inline
357
- - Added the Agent Hub overlay (`ctrl+s`, `alt+a`, or double-tap left arrow on an empty editor): a live table of registered subagents (status, unread IRC count, current task, last activity) with per-agent chat — Enter opens a transcript + input line that steers a running agent, prompts an idle one, and revives a parked one; `r` revives and `x` aborts/releases the selected agent
358
- - Added the `snapcompact` compaction strategy (`compaction.strategy: "snapcompact"`): history is archived onto dense bitmap "snapcompact" frames a vision model reads back directly, instead of an LLM-generated summary — instant, free, and verbatim. Auto compaction (including overflow recovery) and manual `/compact` both honor it; falls back to context-full with a visible warning notice when the current model is text-only (e.g. Codex API surfaces) or when `/compact` is given custom instructions. Frames survive context rebuilds and later compactions (budget eviction is middle-out: the session-head frame is pinned); the expanded compaction message notes the attached frame count
359
- - Added a persistent subagent lifecycle: finished subagents stay live as `idle`, are parked to disk after `task.agentIdleTtlMs` (default 7 minutes; `0` keeps them live until exit), and are revived automatically when messaged or prompted from the Agent Hub
360
- - Added the `history://` protocol: `history://` lists every registered agent and `history://<agentId>` renders a concise markdown transcript (tool calls collapsed to one line each, thinking elided) for live and parked agents alike
361
- - Added an IRC mailbox bus with bounded per-agent inboxes: `irc` `wait` blocks until a matching message arrives, `inbox` drains or peeks pending messages, and sending to an idle or parked agent wakes or revives it for a real turn
362
- - Added a dedicated TUI renderer for the `irc` tool: directional send/receive headers with delivery-outcome coloring, quoted message bodies with expand-aware truncation, per-recipient receipt trees for broadcasts and failures, and status-badged peer listings with unread counts
363
- - Added the `task.batch` setting (default on): the task tool's batch shape `{ agent, context, tasks[] }` spawns one subagent per item — each its own independent background job with the normal idle/parked lifecycle and optional per-item isolation — and prepends the required shared `context` to every spawned subagent's system prompt; disabling it restores the flat single-spawn schema
364
- - Added RPC subagent subscription frames, snapshots, and transcript catch-up APIs for desktop clients embedding `omp --mode rpc`.
365
- - Added opt-in `shellMinimizer.sourceOutlineLevel` and `shellMinimizer.legacyFilters` settings so shell minimization can tune source outlining and selectively fall back to conservative legacy routing.
366
- - Added repeatable `--config <path>` CLI overlays for temporary `config.yml`-style settings without editing the persistent global config ([#1733](https://github.com/can1357/oh-my-pi/issues/1733)).
367
- - Added `python.interpreter` to pin eval's Python backend to an explicit interpreter and skip automatic runtime discovery ([#1802](https://github.com/can1357/oh-my-pi/issues/1802)).
368
- - Added `!command` resolution for `models.yml` provider `apiKey` values and provider/model headers ([#1888](https://github.com/can1357/oh-my-pi/issues/1888)).
369
- - Documented the oMLX setup path through existing OpenAI-compatible local discovery ([#1957](https://github.com/can1357/oh-my-pi/issues/1957)).
370
- - Added `TITLE_SYSTEM.md` discovery so users can override the automatic session-title generation prompt for online and local tiny title models without patching installed prompt files. The override is re-discovered when the session working directory changes via `/cwd`.
371
- - Added a structured memory runtime surface for extensions and UI integrations to query backend status, search memories, and save explicit memories across the configured memory backend.
372
- - Added support for Git repositories using the `reftable` storage format by detecting `extensions.refStorage = reftable` in the repository configuration and falling back to shelling out to Git commands (`git symbolic-ref`, `git rev-parse`) for reference and HEAD resolution.
373
- - Added `/setup providers` (also available as `/setup` or `/providers`) to reopen the interactive provider setup scene from an active TUI session, letting users sign in and choose a web search provider without rerunning the full onboarding flow.
374
- - Added `supportsReasoningParams`, `alwaysSendMaxTokens`, `strictResponsesPairing`, and a recursive `whenThinking` overlay (alongside `streamIdleTimeoutMs`/`supportsLongPromptCacheRetention`/`requiresToolResultId`/`replayUnsignedThinking`) to the OpenAI/Anthropic `compat` schema so custom model entries can configure those provider-specific capabilities
375
- - Custom model `thinking` config now uses the catalog's explicit vocabulary: `efforts` (ordered list) plus optional `defaultLevel`, `effortMap`, and `supportsDisplay` overrides; the legacy `minLevel`/`maxLevel`/`levels` range shape is still accepted and normalized at parse time. Wire facts (`effortMap`/`supportsDisplay`) are backfilled from model identity when not set, so existing claude-proxy configs keep the 5-tier adaptive scale and summarized display without changes.
376
- - New `omp usage` command: a detailed per-account breakdown of provider usage limits (bars, windows, reset times, plan metadata) covering every stored credential — accounts with no usage endpoint are listed as "no usage data" rows. Each provider section ends with per-window capacity stats ("capacity: 5h → 2.40/5 accounts used (2.60× quota left)"). Flags: `--provider` to filter, `--json` for the broker-shaped report payload, and `--redact` to mask account emails/ids down to a two-char anchor plus a minimal middle-out differentiator (`ca*9*`) for screenshot-safe sharing.
377
- - Startup hangs are now self-diagnosing (speculative fix for the "zero output, hangs even on `omp -h`" report class): a watchdog prints a stderr line every 10s naming the deepest in-flight startup phase (via `logger.openSpanPath()`) until a mode runner takes over, pausing around legitimate interactive waits (fork/move prompts, the `--resume` session picker); `PI_DEBUG_STARTUP` is restored as streaming synchronous `[startup]` phase markers covering command-module imports and the native addon load, which the post-startup `PI_TIMING` tree structurally cannot show for a hang; and waiting on piped-stdin EOF announces itself after 1s instead of blocking silently.
378
- - npm installs now execute a prebundled single-file entry: the published `bin.omp` points at `dist/cli.js` (built by `scripts/bundle-dist.ts` during `prepack`, ~18MB minified, natives/transformers/mupdf external), cutting npm-install cold start by roughly 3x versus transpiling the raw TypeScript graph per launch; `src/**` stays published for SDK consumers and worker fallbacks. The on-repo manifest keeps `bin.omp` at `src/cli.ts` — release rewrites it via the `publishBin` override in `scripts/ci-release-publish.ts` — so source installs (`bun link`, `install.sh --source`) keep working without a build step
379
- - Plain interactive TTY launches print a dim two-line startup splash (`omp <version>` / `Initializing session…`) before session construction so first pixels appear immediately; suppressed for resume/fork/continue flows, quiet mode, `PI_TIMING`, and non-TTY stdio
380
- - Added `/stats` to launch the local stats dashboard from an active session, syncing session files first and opening the same browser dashboard as `omp stats`.
381
- - `/settings` now supports type-to-search filtering on setting labels, paths, descriptions, and values; Escape clears an active search before closing the panel.
382
- - Added a read-only `view` op to the `todo` tool that echoes the current list without mutating state, so the agent can recover exact task text instead of guessing it from memory.
383
- - Added an optional `fetch` option to `CustomToolContext` so custom tools can use a caller-provided HTTP implementation
384
- - Added optional `fetch` overrides to `ModelRegistry` construction and MCP/web search/tool network calls, enabling callers to inject custom HTTP clients instead of relying on global `fetch`
385
- - Added a `bash.enabled` setting to disable the model-facing bash tool while leaving user-initiated bang/RPC bash commands available.
386
- - Added an `@<upstream>` model-selector suffix to pin an aggregator model to a single upstream provider per invocation, e.g. `--model openrouter/z-ai/glm-4.7@cerebras` (sets OpenRouter `provider.only`; Vercel AI Gateway models map to `vercelGatewayRouting.only`). Resolved through `parseModelPattern`, so it works for `--model`/`--smol`, model roles, and the SDK, and composes with a trailing thinking level (`...@cerebras:high`). The base must resolve to an aggregator (`openrouter.ai` / `ai-gateway.vercel.sh`); otherwise the `@` stays part of the id, so ids that legitimately contain `@` (`claude-opus-4-8@default`, `workers-ai/@cf/...`) are unaffected.
387
- - Added a `/plan-review` command that manually (re-)opens the plan-review overlay while plan mode is active. Since there is no fixed plan filename, it reviews the newest `local://<slug>-plan.md` the agent wrote — useful for pulling the review back up after dismissing it, or reviewing a plan the agent wrote without calling `resolve`.
388
- - Added Homebrew and mise package-manager update paths to the self-update command so installations launched from those tools are updated through their native workflows
389
- - Added detection of Homebrew and mise install locations so self-update chooses the manager-specific updater when the active `omp` binary comes from a package-manager-managed path
390
- - Added `astCondition` to TTSR rule frontmatter as a syntax-aware alternative to regex `condition`, enabling AST-based matching for edit/write tool snapshots
391
- - Added a built-in `ts-redundant-clear-guard` rule that flags redundant guards around `clearTimeout`, `clearInterval`, and `clearImmediate` calls
392
- - Added a built-in `ts-no-test-timers` rule that flags real timers (`Bun.sleep`, `setTimeout`, `setInterval`) in `*.test.ts` files, steering toward fake timers (`vi.useFakeTimers()` / `vi.advanceTimersByTime()`)
393
- - Added support for paste marker highlighting with accent styling (`[Paste #N, +X lines]`/`[Paste #N, Y chars]`) in the prompt editor, matching the visual treatment of image references
394
- - Added pixel dimensions to pasted/loaded image placeholders in the prompt — the marker now reads `[Image #N, WxH]` (falling back to `[Image #N]` when the header can't be decoded).
395
- - The bundled shell now treats `nohup` as a builtin: `nohup … &` runs the command without masking `SIGHUP` or detaching it, so agent-started daemons stay tied to this agent's lifetime instead of leaking as orphans when the agent exits. Updated the bash tool prompt's daemon guidance to match (dropped the `nohup … & / setsid … & / disown` detach recommendation in favor of a large `timeout` plus the persistent session).
396
- - Added per-tool `tool.*` theme symbol keys (nerd/unicode/ascii presets) plus a quiet `status.done` glyph, so each tool's result header can carry a signature icon instead of a generic status mark
397
- - macOS release binaries are now signed with a Developer ID Application identity (hardened runtime + secure timestamp + JIT/library-validation entitlements) and notarized in CI when the `APPLE_*` signing secrets are configured; releases auto-fall back to ad-hoc signing until then. This makes the shipped binaries Gatekeeper-acceptable, unblocking an official Homebrew submission ([#776](https://github.com/can1357/oh-my-pi/issues/776)). See `docs/macos-signing-notarization.md`.
398
- - Added a Homebrew install path: `brew install can1357/tap/omp`. The [can1357/homebrew-tap](https://github.com/can1357/homebrew-tap) formula installs the prebuilt release binary, and a `release_brew` CI job regenerates it (version + per-asset sha256) from each published release via `scripts/ci-update-brew-formula.ts` ([#776](https://github.com/can1357/oh-my-pi/issues/776)).
399
- - Added clickable file path hyperlinks to read tool outputs (read-call rows, grouped summaries, and inline previews) using resolved or absolute file targets with selector-based line anchors for quick navigation
400
- - Added a resolved-span echo to `replace block`/`delete block` edits: a successful block op now prints `replace block N → resolved lines A-B (K lines)` between the section header and the diff preview, so the model can confirm tree-sitter matched the construct it intended (e.g. catch a decorator left outside the block) instead of inferring the span from the diff after the fact.
401
- - Added `raw-sse.txt` to debug report bundles, exporting recent raw provider SSE diagnostics when captured
402
- - Added `/model` visibility for auto-selected role defaults: inferred `pi/smol`/`pi/slow`/designer choices now show as compact `[ROLE auto]` badges, while explicitly configured roles keep the existing solid badges and thinking labels.
403
- - Added credential provenance to the `/login` and `/logout` provider picker: each authenticated provider now shows where its credential comes from — `(login)`, `(api key)`, `(env: VAR_NAME)`, `(config)`, `(--api-key)`, or `(custom provider)` — so a real OAuth login is distinguishable from an env var that merely aliases the provider (e.g. `COPILOT_GITHUB_TOKEN`). The origin is also matched by the picker's type-to-search filter.
404
- - Added `display.smoothStreaming` setting (default `true`) to let users enable or disable smooth assistant-stream text reveal
405
- - Added `/tan <work>` slash command to fork the current conversation into a background agent so tangential work can continue asynchronously while your main session stays active
406
- - Added a background `/tan` dispatch message that records the handoff in the transcript and marks the delegated work as non-blocking
407
- - Added `providerPromptCacheKey` support to `CreateAgentSessionOptions` so `/tan` background sessions can reuse the parent session’s prompt-cache lineage
408
- - Added session cloning for `/tan` runs with copied artifacts and shared MCP proxy tools
409
- - Added `SessionManager.forkFrom`’s optional `suppressBreadcrumb` mode to avoid breadcrumb updates when forking background `/tan` sessions
410
- - Added OSC 5522 enhanced paste handling in `InputController`, so terminal clipboard events are decoded as image or text payloads and inserted without passing raw paste sequences to the editor
411
- - Added bracketed image-path paste support in `CustomEditor` so a single pasted image file path (PNG/JPEG/GIF/WEBP) is loaded from disk and inserted as an image candidate
412
- - Added direct support for `Image #N` insertion from pasted local image paths by routing successful image-path pastes through the same image normalization and resize flow as clipboard image pastes
413
- - Added `/fresh` to rotate the provider-facing session id and clear in-memory provider stream/cache state without changing the local session file.
414
- - Added a `ChatBlock` transcript primitive (`modes/components/chat-block.ts`) and a single `ctx.present(...)` sink (with `ctx.resetTranscript()`) so chat output is mounted in one place instead of the repeated `chatContainer.addChild(...)` + `ui.requestRender()` pattern scattered across controllers. `ChatBlock` carries a React/Svelte-style lifecycle — `onMount` starts effects, `onCleanup` registers teardown, `finish()` self-completes (stops timers and freezes the block at its final content), and `dispose()`/`resetTranscript()` tears everything down — so animated blocks own their own resources instead of leaking `setInterval`/`requestRender` bookkeeping into callers. The MCP "Connecting…" spinner is now such a block.
415
- - Added a `framedBlock` output-block helper (`tui/output-block.ts`) plus a `borderColor` override and `applyBg: false` (no background fill) on output blocks, a `renderStatusLine` `iconOverride`, and an `icon.search` (magnifier) theme symbol — so tool renderers can draw self-contained muted-outline frames and search-family tools can show a magnifier instead of a checkmark.
416
- - Added a GitHub Actions read handler to the `read`/web-fetch GitHub scraper. Fetching `github.com/{owner}/{repo}/actions/runs/{id}` renders the run metadata plus a per-job breakdown (steps listed for any job that did not succeed), and `…/actions/runs/{id}/job/{id}` (also the API-style `…/jobs/{id}`) renders a single job's metadata, step table, and full plain-text logs. Logs are fetched via the `actions/jobs/{id}/logs` redirect using `GITHUB_TOKEN`/`GH_TOKEN` when present, with the per-line ISO timestamp prefix and leading BOM stripped; the section degrades to an explicit notice when logs are unavailable (no token, private repo, or expired/unfinalized run).
417
- - Added anonymous fallback for Perplexity web search, allowing `web_search` and explicit Perplexity provider usage when no Perplexity credentials are configured
418
- - Added `gallery` CLI command to render built-in tool renderer output across streaming, in-progress, success, and failure states
419
- - Added `omp gallery` filtering and rendering options (`--tool`, `--state`, `--width`, `--expanded`, and `--plain`) for focused renderer previews and plain-text output
420
- - Added `omp gallery` fidelity for tools whose renderers are attached on the tool instance (`lsp`, `task`): the gallery now drives them through the same custom-tool render branch production uses, so regressions in that path surface in the gallery rather than only in a live session.
421
- - Added `omp gallery --screenshot`, which renders the gallery through a real virtual terminal (VHS) and writes PNG screenshot(s) instead of ANSI, so agents (and anything that can only read raw bytes) can actually see the rendered output. The capture forces truecolor and matches the active theme/symbol preset; tall galleries split across multiple images (whole renderers are never cut). Tune with `--out`, `--font`, and `--font-size`; requires `vhs` on `PATH` and fails with install guidance when absent.
422
- - Added `app.display.reset`, bound to `Ctrl+L` by default, to force an immediate terminal display reset/redraw without resizing the window.
423
- - Added `timeout-pause` and `timeout-resume` eval bridge status events emitted around `agent()`/`llm()` operations
424
- - Added a `/copy` picker: `/copy` now opens a fullscreen, outlined tree of recent assistant messages with their code blocks nested beneath (like `/tree`). Navigate with ↑↓, and Enter copies the highlighted node — a whole message, an individual code block, "All N blocks", or a bash/eval command interleaved with the assistant turn that issued it. A live preview pane shows the selected target, wrapping prose and syntax-highlighting code/commands.
425
- - Added a persistent error banner pinned above the editor when an assistant turn ends on a provider error (e.g. Anthropic's "Output blocked by content filtering policy"). The transcript `Error: …` line scrolls away as the conversation grows, so terminal turns that ended on a stream error could pass unnoticed; the banner stays in the fixed region above the input and is cleared when the next turn starts.
426
- - Added bold, underlined, clickable `[Image #N]` placeholders in the draft editor and sent user-message bubbles, backed by extension-bearing blob-store sidecar files so terminal `file://` links open in image viewers.
427
- - Added the active model identifier (`provider/id`) to the system prompt's `<workstation>` block so the agent knows which model it is running as. Gated by the new `includeModelInPrompt` setting (default on); the base prompt is rebuilt on a mid-session model switch so the surfaced identifier stays current.
428
- - Added `OLLAMA_HOST` support for implicit local Ollama discovery when `OLLAMA_BASE_URL` is unset, so OMP picks up the same host setting used by Ollama.
429
- - Added `OLLAMA_CONTEXT_LENGTH` as a positive-integer context-window override for implicit local Ollama discovery, so users can correct OMP context budgeting without writing per-model overrides.
430
- - Added an encrypted local auth-broker snapshot cache for `discoverAuthStorage`, with `OMP_AUTH_BROKER_SNAPSHOT_TTL_MS` and `OMP_AUTH_BROKER_SNAPSHOT_CACHE`, so fresh cached broker credentials can boot without a blocking `/v1/snapshot` fetch and survive broker-down startup windows.
431
- - Added `dry-balance` CLI command to perform a dry-run OAuth account balancing check across configurable random session IDs, with sample and concurrency options, JSON output, and success/failure summary reporting
432
- - Added `--json` output mode and machine-readable result format to `omp dry-balance` for automated use
433
- - Added `omitMaxOutputTokens` to `models.yml` model definitions and `modelOverrides`, so users can opt a model out of the on-the-wire `max_output_tokens` / `max_tokens` cap while keeping the catalog `maxTokens` for local budgeting. Intended for Ollama-style proxies whose upstream output limit OMP cannot discover. ([#1881](https://github.com/can1357/oh-my-pi/issues/1881))
434
- - Added deferred session-title generation so greetings no longer become the session title. A first user message that is only a greeting / acknowledgement / filler ("hi", "thanks", "ok", a bare number, emoji-only, etc.) is now detected deterministically and skips titling entirely — no title model is invoked. Title generation then retries on each subsequent user message while the session stays unnamed, so the title is deduced from the first message that actually describes work. A capable online title model may additionally answer `none` to decline a non-greeting taskless message (normalized to "no title").
435
- - Added env-driven OpenTelemetry trace export. When `OTEL_EXPORTER_OTLP_ENDPOINT` (or `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`) is set, `omp` registers a global OTLP/proto trace exporter and switches on the agent loop's telemetry, so the `invoke_agent` / `chat` / `execute_tool` spans actually reach a collector instead of a no-op tracer. Honors the standard `OTEL_*` env contract (endpoint, headers, `OTEL_SERVICE_NAME`, `OTEL_SDK_DISABLED` and `OTEL_TRACES_EXPORTER=none` parsed case-insensitively) and the `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` capture toggle; it is a no-op when no endpoint is configured. Only the `http/protobuf` transport is supported — a `grpc` or `http/json` `OTEL_EXPORTER_OTLP*_PROTOCOL` declines rather than misrouting spans. This makes the existing telemetry usable from headless hosts that run `omp` as a spawned child process, where an in-process `TracerProvider` registered by the parent can't reach the child. Uses the `@opentelemetry/exporter-trace-otlp-proto` 2.x line, which exports cleanly under Bun.
436
- ## Fixed
437
-
438
- - Fixed the status line session name (and the editor border / status-line gap fill) being nearly illegible on light themes.
439
- - Added `IndexedSessionStorage` and `SessionStorageBackend` exports to support shared metadata-indexed session backends
440
- - Added the `tui.maxInlineImages` setting (default `8`) capping how many inline images render as live terminal graphics. Once a new image pushes the count past the cap, the oldest images are hidden via a full redraw — replaced by their `[Image: …]` text placeholder and purged from the terminal's graphics store — so long sessions with many screenshots/diagrams stop piling up images (and, on Kitty, stop leaving scrollback ghosts). Set to `0` to keep every image inline.
441
- - Added a "View: terminal state" item to the `/debug` menu that prints the detected terminal, live geometry and cell size, multiplexer, and the negotiated subprotocols actually in use — graphics (Kitty/iTerm2/Sixel), desktop notifications (BEL/OSC 9/OSC 99, plus whether OSC 99 was confirmed via a device-attributes probe), OSC 8 hyperlinks, 24-bit color, DECCARA rectangular-SGR background fills, and DEC 2026 synchronized output — alongside the scrollback-clear strategy (`CSI 22 J` vs `CSI 2 J` redraw / ED3 eager-erase risk) and the raw `TERM`/`TERM_PROGRAM`/`COLORTERM` detection signals.
442
- - Added a "Test: terminal protocols" item to the `/debug` menu that renders one live sample of every special escape protocol the renderer can emit — SGR text attributes (bold/italic/underline/strikethrough/inverse/dim), themed and 24-bit truecolor, OSC 8 hyperlinks, OSC 66 text sizing (large text), and an inline graphics swatch via the active image protocol (Kitty/iTerm2/Sixel, with a text fallback) — and fires a desktop notification, so you can eyeball which protocols the current terminal actually honors. The sample image is a gradient PNG generated in-process, so the graphics test needs no asset on disk.
443
- - Added the `tui.textSizing` setting (default off) that renders Markdown H1 headings at 2x scale via Kitty's OSC 66 text-sizing protocol. It replaces the undocumented `PI_TUI_TEXT_SIZING` env var with a real setting, and only takes effect on Kitty terminals (where OSC 66 is implemented) — it is ignored everywhere else so headings never emit raw escape bytes.
444
- - Added a lifecycle status to the `/resume` session picker. Each session's tail (last 32 KiB) is now read alongside the existing header window in a single pass, and its final message classified as `done` (the agent ended its turn and yielded control back), `interrupted` (a trailing tool call or tool result the loop never continued from), `aborted`, `error`, or `pending` (a trailing user message with no reply). The status renders as a colored segment on each session's metadata line. When the final message is larger than the tail window the status is omitted rather than guessed.
445
- - Added support for `disable-model-invocation: true` frontmatter field from the [Agent Skills standard](https://agentskills.io/specification). Skills using this field are now hidden from the system prompt listing, matching the behavior of `hide: true`.
446
- - Added a bundled TypeScript rule that warns against leaving `@deprecated` compatibility shims behind instead of finishing a refactor.
447
- - Added an all-projects scope to the session picker (`pi --resume` / `/resume`). Press `Tab` to toggle between the current folder's sessions and every session across all projects; the all-projects list is loaded lazily and shows each session's directory. When the current folder has no sessions the picker now opens straight into all-projects scope instead of printing "No sessions found".
448
- - Migrated the Kagi web search provider to Kagi's V1 Search API (`POST /api/v1/search`), replacing the sunset V0 endpoint while keeping the `kagi` provider id, `KAGI_API_KEY` credential, and `/login kagi` flow unchanged ([#1272](https://github.com/can1357/oh-my-pi/pull/1272) by [@thismat](https://github.com/thismat))
449
- - Added Anthropic `anthropic-ratelimit-unified-*` response-header warming for `/usage` and the status-line usage segment, throttled to reduce direct OAuth `/usage` probes during active use.
450
- - Added `ask` option descriptions so agents can keep short labels and render explanatory text as separate muted rows in the selector.
451
- - Added an extension API for rendering supplemental UI below visible assistant thinking blocks.
452
- - Added default-on `lsp.diagnosticsDeduplicate` support so post-edit LSP diagnostics already shown for a file are suppressed within the session and only new or changed diagnostics are surfaced.
453
- - Added support for decimal and `k`/`m` suffix turn-budget directives, enabling budgets like `+1.5k` and `+2m` in eval message parsing
454
- - Changed eval budget resolution to honor a user `+Nk` directive over an active Goal Mode limit while falling back to Goal Mode when no per-turn ceiling is set
455
- - Added `agent()` eval options `agent_type`/`agentType`, `model`, `context`, and `label`, and returned structured JSON when `schema` is provided in JS and Python eval cells
456
- - Added a live, Task-tool-style progress tree for eval `agent()` calls, drawn below the notebook (code cell) box. Each subagent surfaces as a status line (icon · id · tool count · context · cost, plus duration on completion) with its current tool/intent while running, and updates mid-execution rather than only at the cell's final result. Progress events coalesce per subagent id so the persisted event list stays bounded across many throttled ticks.
457
- - Added `agent()` to the `eval` runtime so JS and Python cells can spawn one subagent through the existing task executor; JS eval also gained bounded `parallel()` and `pipeline()` helpers for orchestrating subagent calls.
458
- - Added a `workflow` magic keyword (mirrors `orchestrate`/`ultrathink`): the standalone word glows amber→green in the editor and appends a hidden notice steering the model to author deterministic multi-subagent fan-outs in `eval` (agent/parallel/pipeline). Matching is whitespace-delimited and case-sensitive (lowercase only); the singular and plural both trigger, but capitalized forms, inflections like `workflowed`, and path-embedded occurrences like `workflow.ts` do not.
459
- - Added `parallel()` and `pipeline()` to the Python `eval` runtime (thread-pool over the synchronous `agent()` bridge), mirroring the JS helpers: bounded pool (default 4, max 16), input-order preservation, a barrier between every `pipeline` stage, and contextvar propagation so `agent()` works inside worker threads.
460
- - Added `log()`, `phase()`, and a `budget` object to both `eval` runtimes (Python and JS). `log`/`phase` emit progress/phase status lines; `budget.total`/`budget.spent()`/`budget.remaining()`/`budget.hard` expose a real per-turn output-token budget. A `+Nk` directive in the user's message sets an advisory budget (the model self-limits via `budget.remaining()`); `+Nk!` (or an active Goal Mode budget) makes it a hard ceiling that blocks further eval `agent()` spawns once reached. `budget.spent()` counts output tokens spent this turn across the main loop and all eval-spawned subagents.
461
- - Added search support for virtual internal URLs (including `omp://` roots) by resolving and scanning in-memory internal resources as search targets alongside filesystem paths
462
- - Added expansion of virtual internal URL search targets so `search` can match multiple internal documents when given `omp://`
463
- - Added `/omfg <complaint>` slash command that drafts a TTSR rule from a complaint, validates it against the current conversation, saves it to project or `~/.omp/agent/rules`, and registers it live.
464
- - Added `/shake` slash command and the `shake` / `shake-summary` compaction strategies that reduce context by mechanically dropping heavy content instead of LLM summarization. `/shake` (alias `/shake elide`) strips heavy tool-call results and large fenced/XML blocks, offloads the originals to one session artifact, and leaves a recoverable `artifact://<id>` placeholder; `/shake summary` compresses the same regions with a local on-device model (`providers.shakeSummaryModel`, default `qwen3-1.7b`) and falls back to elide per region when the model is unavailable; `/shake images` strips image blocks. Auto-maintenance honors the `shake` / `shake-summary` strategies (16k protect window); on context overflow a shake that reclaims nothing falls back to context-full summarization.
465
- - Added `providers.shakeSummaryModel` setting selecting the local on-device model used by `/shake summary` and the `shake-summary` compaction strategy. Runs entirely on-device (downloads on first use) and never calls a remote/cloud LLM.
466
- - Added `providers.autoThinkingModel` setting so users can choose the `auto` thinking classifier backend (online smol or local tiny-memory model)
467
- - Added an `auto` thinking level that classifies each real user turn and resolves to a concrete low-through-xhigh effort, with online smol classification by default and an opt-in local on-device classifier.
468
- - Added a `Web search` setup tab that lets users choose the preferred `providers.webSearch` provider during onboarding
469
- - Added manual authorization-code/redirect URL prompts for OAuth providers that require non-callback login in the setup wizard
470
- - Added an `omp completions <bash|zsh|fish>` command that prints a shell completion script generated from the live command/flag metadata, so completions never drift from the actual CLI. Subcommands, flags, and enum values complete statically; `--model`/`--smol`/`--slow`/`--plan` resolve against the bundled model catalog and `--resume` against on-disk sessions via a hidden `__complete` helper.
471
- - Added a `/switch` slash command that opens the temporary model selector for the current session, mirroring the `alt+p` keybinding.
472
- - Added `replace block N:` and `delete block N` operators to the `edit` tool: they resolve the syntactic block beginning on line N via tree-sitter (native `blockRangeAt`) and replace or delete its full line span, so a construct can be rewritten or removed without counting its closing line. Unresolvable blocks (unsupported language, blank/closing-delimiter line, or a parse error) are rejected with guidance to use an explicit `replace N..M:` / `delete N..M` range.
473
- - Added an animated pending border for `bash` and `eval` execution blocks: while a command/cell is running, a single dark segment glides clockwise around the block's outer edge (top → right → bottom → left), replacing the previous static accent border. Motion is eased per edge (decelerating into each corner) and timed against a fixed lap duration mapped onto the live perimeter, so streaming a new output line or resizing the terminal nudges the segment proportionally instead of resetting its position. Driven by the existing spinner cadence and gated on the `display.shimmer` setting (no motion when `disabled`).
474
- - Added `providers.tinyModelDevice` and `providers.tinyModelDtype` settings (Providers tab) controlling local tiny-model acceleration for session titles and Mnemopi memory tasks. `providers.tinyModelDevice` selects the ONNX execution provider (`default` keeps the platform pick — DirectML on Windows, CUDA on Linux x64, CPU elsewhere); `providers.tinyModelDtype` selects quantization/precision (`default` keeps each model's shipped `q4`, e.g. `fp16` trades speed for fidelity). The `PI_TINY_DEVICE` / `PI_TINY_DTYPE` env vars override the matching setting. Also added `PI_TINY_DTYPE` as the env counterpart to `PI_TINY_DEVICE`; an unrecognized device/precision fails loudly at worker startup instead of silently loading a different one.
475
- - Added a bundled set of default rules shipped with the agent (TypeScript/Rust convention rules registered as TTSR conditions). They load via the new lowest-priority `builtin-defaults` discovery provider, so any user/project/tool rule of the same name overrides the bundled copy. Disable the whole set with `ttsr.builtinRules: false`, or drop individual rules (bundled or your own) by name via `ttsr.disabledRules`.
476
- - Added a `symbols.spinnerFrames` field to custom theme JSON so themes can override the loader/tool-execution spinner. Accepts either a flat `string[]` (used for both spinner types) or `{ "status"?: string[], "activity"?: string[] }` to override each independently; anything not specified falls back to the symbol preset. Documented in `docs/theme.md` and validated by `theme-schema.json`. ([#1553](https://github.com/can1357/oh-my-pi/issues/1553))
477
- - Added prompt-mode autocomplete for supported internal URL schemes (`skill://`, `rule://`, `agent://`, `artifact://`, `local://`, `memory://`, and `omp://`) so typing those tokens now suggests existing resources as completion candidates
478
- - Added fuzzy matching and ranked suggestion ordering for internal URL completion, including rule and skill descriptions, with accepted completion replacing just the typed token and inserting the chosen URL followed by a space
479
- - Changed internal URL completions now include nested `local://` path suggestions from the configured local workspace
480
- - Added Mnemopi memory inference model selection with an online mode or local transformers.js options (`qwen3-1.7b`, `gemma-3-1b`, `qwen2.5-1.5b`, `lfm2-1.2b`) so memory extraction and consolidation can run via the shared tiny-model worker
481
- - Changed memory tiny-model handling to route local memory prompts through the same queueed tiny-model worker pipeline with bounded completion output
482
- - Added a Providers → Tiny Model setting for session titles, defaulting to the online `pi/smol` path with five optional local CPU transformers.js models. A local model — and the one-time `@huggingface/transformers` runtime install in compiled binaries — is downloaded and loaded only when explicitly selected (or via `omp tiny-models download`); the default online path never spawns the title worker for inference. Selecting a local model adds a delayed `pi/smol` fallback so titles never block, plus in-chat download progress.
483
- - Added a persistent live agent roster pinned below the editor (focus it with `Ctrl+S` or `Alt+Down`), including view-as switching into delegated agent sessions with human-readable delegate names and UI pinning to suppress idle reaping while viewed. The roster stays hidden until at least one delegated agent exists and releases focus back to the editor once the last one is gone.
484
- - Recorded the originating session ID alongside each prompt in `history.db` (new `session_id` column, surfaced as `HistoryEntry.sessionId`), so recalled prompts can be traced back to the session they came from. Existing history databases gain the column automatically on next launch.
485
- - Added compact inline TUI renderers for the `retain`, `recall`, and `reflect` memory tools. `retain` now shows one themed bullet line per stored item (truncated to width) under a status header with the stored/queued count, and `recall`/`reflect` collapse to a single query header (recall reports the match count and hides recalled memories until expanded) instead of dumping the raw JSON argument tree.
486
- - Added a randomly picked tip beneath the welcome screen, sourced from an embedded `tips.txt` (one tip per line). The line is italicized with a purple `Tip:` label and a dimmed light-blue body, and the tip is chosen once per welcome instance so intro-animation and LSP re-renders don't shuffle it.
487
- - Added a Mnemopi-only `memory_edit` agent tool for updating, forgetting, or invalidating recalled memories by id, and added `/memory stats` plus `/memory diagnose` slash commands for backend maintenance visibility.
488
- - Added an `orchestrate` magic keyword that mirrors `ultrathink`: dropping the standalone word in a message paints it with a cool teal→violet gradient in the editor and appends a hidden system notice that switches the model into the multi-phase, parallel-subagent orchestration contract. Matching is word-bounded and case-insensitive, so `orchestrated`/`orchestrating` never trigger it.
489
- - Added a model-tier slider to the plan-approval prompt ("Plan mode - next step"). Left/right arrows move it from any list position to pick which configured role model (`cycleOrder`, e.g. `smol › default › slow`) executes the approved plan, with each tier colored by its role and the resolved model name shown beneath the track. The chosen tier is applied before dispatch and carries through the fresh/compacted execution session; the slider is hidden when fewer than two role models resolve.
490
- - `omp plugin install` now accepts GitHub/GitLab/Bitbucket shorthand (`github:user/repo`, `gitlab:user/repo`, …) and full git URLs (`https://github.com/user/repo`, `git@github.com:user/repo`, …) in addition to npm specs and marketplace refs.
491
- - Added `ModelRegistry.create(authStorage, modelsPath?)` async factory that runs the JSON → YAML migration step on `models.{yml,yaml}` asynchronously ahead of the sync constructor's bundled-model load. The sync `new ModelRegistry(...)` constructor still works (tests rely on it); production boot paths now use the factory so the migration's I/O lands off the event-loop hot path.
492
- - Added `ConfigFile.tryLoadAsync()`, `ConfigFile.loadAsync()`, `ConfigFile.loadOrDefaultAsync()`, `ConfigFile.getMtimeMsAsync()`, and `ConfigFile.warmup(file)` so the rest of the codebase can migrate config reads off the sync path.
493
355
 
494
356
  ### Changed
495
357
 
@@ -542,7 +404,6 @@
542
404
  - Image-generation (Antigravity, xAI, OpenRouter, Gemini) and xAI TTS request failures now throw pi-ai's typed `ProviderHttpError` carrying status and response headers instead of `Object.assign`-patched `Error`s.
543
405
  - Collapsed bash, ssh, and eval previews now cap the command/code section to a viewport-sized tail window (terminal rows minus a chrome reserve) that renders identically while streaming and after completion, with `ctrl+o` as the only way to uncap. Previously bash/ssh capped the command only while streaming and snapped it fully open the moment the tool finished, and eval never capped cell code at all.
544
406
  - The `job` renderer now shimmers running-job labels while the poll block is live, freezing to static once the block seals, and drops the id column when the label repeats it — task jobs label themselves with their agent id, so rows read `⟨task⟩ SessionTree` instead of `SessionTree ⟨task⟩ SessionTree`.
545
-
546
407
  - Task progress rows now render static text with the task icon instead of shimmering the description or showing the pending/hourglass status glyph.
547
408
  - `app.clipboard.pasteImage` (`Ctrl+V`) now falls back to pasting clipboard text when no image is present, so hosts that deliver only that chord (VS Code's integrated terminal forwarding `Ctrl+V`, Windows clipboard history via `Win+V`) cover both payload kinds; WSL text reads now reach the Windows clipboard through host PowerShell like image reads already did ([#1628](https://github.com/can1357/oh-my-pi/issues/1628)).
548
409
  - Changed `/usage` to show the OAuth account currently selected for the active model provider when usage reports include multiple accounts, making multi-account sessions easier to verify without marking unrelated providers.
@@ -706,7 +567,7 @@
706
567
  ### Changed
707
568
 
708
569
  - Bash execution now preserves minimized shell output inline while saving the untouched capture as an `artifact://…` footer when shell minimization rewrites a command's output.
709
- - Task tool agent lists now render in runtime-ascending order in both the live progress view (finished agents, sorted by runtime, above pending/running ones) and the finalized result view, so rows no longer reshuffle when the call finalizes.
570
+ - Task tool live progress now renders finished subagents first and keeps unfinished (pending/running) ones pinned at the bottom of the list.
710
571
  - `OutputSink` artifact files (`~/.omp/agent/artifacts/<id>.<tool>.log`) are unbounded by default again, so `artifact://<id>` references preserve the complete raw stream. The head + rolling-tail capping machinery from [#2081](https://github.com/can1357/oh-my-pi/issues/2081) (with its `[ARTIFACT TRUNCATED: …]` close notice) remains available as an opt-in via `artifactMaxBytes`, and the head window now closes permanently on first overflow so later small chunks cannot be written out of order before the tail replay.
711
572
 
712
573
  ### Fixed
@@ -741,7 +602,7 @@
741
602
  - New `omp usage` command: a detailed per-account breakdown of provider usage limits (bars, windows, reset times, plan metadata) covering every stored credential — accounts with no usage endpoint are listed as "no usage data" rows. Each provider section ends with per-window capacity stats ("capacity: 5h → 2.40/5 accounts used (2.60× quota left)"). Flags: `--provider` to filter, `--json` for the broker-shaped report payload, and `--redact` to mask account emails/ids down to a two-char anchor plus a minimal middle-out differentiator (`ca*9*`) for screenshot-safe sharing.
742
603
  - Startup hangs are now self-diagnosing (speculative fix for the "zero output, hangs even on `omp -h`" report class): a watchdog prints a stderr line every 10s naming the deepest in-flight startup phase (via `logger.openSpanPath()`) until a mode runner takes over, pausing around legitimate interactive waits (fork/move prompts, the `--resume` session picker); `PI_DEBUG_STARTUP` is restored as streaming synchronous `[startup]` phase markers covering command-module imports and the native addon load, which the post-startup `PI_TIMING` tree structurally cannot show for a hang; and waiting on piped-stdin EOF announces itself after 1s instead of blocking silently.
743
604
  - npm installs now execute a prebundled single-file entry: the published `bin.omp` points at `dist/cli.js` (built by `scripts/bundle-dist.ts` during `prepack`, ~18MB minified, natives/transformers/mupdf external), cutting npm-install cold start by roughly 3x versus transpiling the raw TypeScript graph per launch; `src/**` stays published for SDK consumers and worker fallbacks. The on-repo manifest keeps `bin.omp` at `src/cli.ts` — release rewrites it via the `publishBin` override in `scripts/ci-release-publish.ts` — so source installs (`bun link`, `install.sh --source`) keep working without a build step
744
- - Plain interactive TTY launches print a dim two-line startup splash (`omp <version>` / `Initializing session…`) before session construction so first pixels appear immediately; suppressed for resume/fork/continue flows, quiet mode, `PI_TIMING`, and non-TTY stdio
605
+ - Plain interactive TTY launches render the full welcome box (logo held on the intro's first frame, model, tips, LSP servers, recent-sessions loading placeholder) before session construction, clearing the screen so the TUI's first paint replaces it in place; the welcome box now reserves fixed slot counts (4 recent sessions, 4 LSP servers) so its height no longer shifts between the splash, loading, and loaded states. First-run launches keep the dim two-line splash (`omp <version>` / `Initializing session…`); resume/fork/continue flows, quiet mode, `PI_TIMING`, and non-TTY stdio still skip it
745
606
  - Added `/stats` to launch the local stats dashboard from an active session, syncing session files first and opening the same browser dashboard as `omp stats`.
746
607
  - `/settings` now supports type-to-search filtering on setting labels, paths, descriptions, and values; Escape clears an active search before closing the panel.
747
608
  - Added a read-only `view` op to the `todo` tool that echoes the current list without mutating state, so the agent can recover exact task text instead of guessing it from memory.
@@ -792,7 +653,7 @@
792
653
  - Fixed pasting into the ask tool's "Other (type your own)" text box (and hook input/editor dialogs) on terminals with OSC 5522 enhanced paste (kitty protocol): the enhanced-paste focus routing only targets components exposing a `pasteText` hook, and the dialog wrappers had none, so the payload was stuffed into the main prompt editor hidden behind the dialog. `HookEditorComponent` and `HookInputComponent` now forward `pasteText` to their inner editor/input (pasting also resets the input dialog's timeout countdown like any keystroke).
793
654
  - Fixed auto-retry giving up after one attempt ("Provider requested Xms wait, exceeds retry.maxDelayMs") on a usage-limit 429 when every sibling account was only momentarily blocked: the retry delay now waits for the earliest sibling unblock when that comes sooner than the provider's multi-hour retry-after, so the next attempt picks up the recovered account instead of failing fast.
794
655
  - Fixed Hindsight `per-project-tagged` mental-model seeding so each project gets its own conventions/decisions models and session context only injects active-project or untagged models ([#2218](https://github.com/can1357/oh-my-pi/issues/2218)).
795
- - Fixed Windows stdio MCP `.cmd` commands by wrapping batch shims such as `npx.cmd` and `codegraph.cmd` with hidden `cmd.exe /d /s /c` launches using the outer command quotes required by `cmd /s`, while preserving literal `%` and quoted JSON arguments ([#2220](https://github.com/can1357/oh-my-pi/issues/2220), [#2287](https://github.com/can1357/oh-my-pi/issues/2287)).
656
+ - Fixed Windows stdio MCP `.cmd` commands by wrapping batch shims with `cmd.exe /d /s /c` using the outer command quotes required by `cmd /s`, while preserving literal `%` and quoted JSON arguments for Codegraph MCP ([#2220](https://github.com/can1357/oh-my-pi/issues/2220)).
796
657
  - Fixed the bundled `explore` agent's `thinking-level: med` frontmatter — not a valid effort (`minimal`/`low`/`medium`/`high`/`xhigh`), so it silently parsed to undefined and the agent ran without its intended thinking level
797
658
  - Discovery context-file reads (`~/.claude`, `~/.cursor`, project trees, `@`-imports) now stat-gate to regular files before reading: a FIFO/socket/char device dropped where a context file is expected previously blocked startup forever on a read that can never see EOF.
798
659
  - Fixed the read tool's provider-visible `path` schema and docs so web URLs and internal URI targets (`omp://`, `issue://`, `pr://`, etc.) are advertised alongside local files ([#2215](https://github.com/can1357/oh-my-pi/issues/2215)).
@@ -849,14 +710,38 @@
849
710
  - Removed the `clearOnShrink` setting and its `PI_CLEAR_ON_SHRINK` environment variable: the rewritten renderer always clears shrunken rows exactly, so the flicker/perf tradeoff the setting controlled no longer exists. Existing config entries are ignored.
850
711
  - Removed the prompt-submit native-scrollback reconciliation checkpoint and the eager streaming render mode from the interactive controllers — the renderer's append-only contract made both obsolete.
851
712
 
713
+ ## [15.10.10] - 2026-06-09
714
+
715
+ ### Added
716
+
717
+ - Added a read-only `view` op to the `todo` tool that echoes the current list without mutating state, so the agent can recover exact task text instead of guessing it from memory.
718
+
719
+ ### Changed
720
+
721
+ - Rewrote the bash tool's coreutils guidance (tool prompt and system prompt) around an explicit litmus: pipelines that compute a new fact (`wc -l`, `sort | uniq -c`, `comm`, `diff`) are legitimate bash, while commands that merely move, page, or trim bytes a dedicated tool can fetch remain banned — output trimming destroys data the `artifact://` capture would have saved.
722
+
723
+ ### Fixed
724
+
725
+ - Fixed the model selector dropping an immediate Enter when cached models were available but the selector's offline refresh was still pending.
726
+ - Fixed dynamic `import(...)` inside functions passed to the browser tool's `tab.evaluate`/`page.evaluate` failing with `__omp_import__ is not defined`. The eval/browser JS runtime rewrites dynamic-import callees to the worker-injected `__omp_import__` helper, but puppeteer serializes evaluate callbacks with `Function.prototype.toString()` and re-runs them inside the page, where the helper does not exist. The rewriter now substitutes a guarded shim that falls back to native dynamic import when the helper is absent, so serialized code works in the page realm while in-worker imports keep resolving against the session cwd.
727
+ - Transcript block freezing is now unconditional instead of gated on ED3-risk terminal detection: every finalized block replays its frozen snapshot once it crosses out of the live region, on all terminals including Windows, because the rewritten renderer's committed scrollback is immutable everywhere. Still-mutating blocks (pending tools, streaming messages, async thinking renderers) anchor the live region and keep repainting until they finalize, which structurally fixes stale/duplicated output from late async expansions ([#1823](https://github.com/can1357/oh-my-pi/issues/1823)).
728
+ - Fixed the edit tool's post-edit diff preview occasionally echoing a context line twice with out-of-order numbering. Block-boundary context injection classified space-prefixed diff rows as old-file-only, so an unchanged line sitting in a net-offset region (old N / new N+k) was missing from the new file's visibility window; `findBlockContextLines` then re-surfaced it under its post-edit number and the row was spliced in after the adjacent change run. New-file boundary lines are now translated back to pre-edit numbers (the compact-preview renumbering contract) and merged into a single old-numbered insertion pass — also fixing closers below a net-offset edit being dropped or renumbered incorrectly.
729
+ - Fixed the Anthropic web-search provider claiming the Claude Code identity on API-key requests: the CC billing header + system instruction were injected whenever the model wasn't Haiku 3.5, regardless of auth mode. Injection is now OAuth-gated like the streaming path, and OAuth search requests patch the billing header's `cch` attestation (via `wrapFetchForCch`) instead of shipping the `cch=00000` placeholder.
730
+ - Fixed long streamed content appearing cut off mid-run: scrolled-off rows were erased from the viewport without ever being appended to terminal history. The transcript's commit boundary (`deriveLiveCommitState`) was all-or-nothing per block — one perpetually rewriting row (a task tool's ticking progress tree, per-agent cost/tool counters, spinner stats) suspended scrollback commits for the entire block, so once the block outgrew the viewport its static head (e.g. a task's prompt/context markdown) was neither committed nor on screen until the tool sealed, and was lost outright if the session ended mid-run. A stable-prefix ratchet now promotes leading rows that stayed visibly identical for a full 30-frame window as commit-safe, so the settled head reaches native scrollback while only the genuinely volatile tail stays deferred; a rewrite above the promoted run retreats the boundary and the engine audit recommits (duplication, never loss).
731
+ - Fixed local tiny-title worker stdout/stderr leaking raw native model output such as `</title>` and cache/status lines into the interactive TUI scrollback ([#2206](https://github.com/can1357/oh-my-pi/issues/2206)).
732
+ - Fixed task-agent discovery advertising Claude Code custom agents from `.claude/agents/*.md` as OMP subagents; direct task-agent discovery now only loads OMP-native `.omp` agent roots, while Claude marketplace plugin agents keep their existing provider path ([#2209](https://github.com/can1357/oh-my-pi/issues/2209)).
733
+
734
+ ### Removed
735
+
736
+ - Removed the `clearOnShrink` setting and its `PI_CLEAR_ON_SHRINK` environment variable: the rewritten renderer always clears shrunken rows exactly, so the flicker/perf tradeoff the setting controlled no longer exists. Existing config entries are ignored.
737
+ - Removed the prompt-submit native-scrollback reconciliation checkpoint and the eager streaming render mode from the interactive controllers — the renderer's append-only contract made both obsolete.
738
+
852
739
  ## [15.10.9] - 2026-06-09
853
740
 
854
741
  ### Fixed
855
742
 
856
743
  - Fixed streaming thinking (and other styled assistant content) vanishing from native scrollback once it scrolled past the viewport top during a foreground turn. The transcript's append-only commit detector compared raw row bytes, so a styled paragraph wrapping onto a new row (the span-closing SGR and width padding move while the visible cells stay identical) or a streamed token pushing the last word down a line flagged the block as permanently volatile — the commit boundary froze and every later row that crossed the viewport top was committed nowhere. Rows are now compared by visible content, a wrap-shrink of the in-flight bottom line counts as append-only, and a genuine one-off interior rewrite only suspends commits until the block re-earns append-only (30 clean frames), after which the pinned emitter backfills the stalled gap contiguously. Periodically rewriting blocks (spinners, collapsing tool previews) never re-earn and stay deferred.
857
-
858
744
  - Fixed bracketed pastes containing multiple image file paths so each image is attached in order instead of treating the whole paste as one unreadable path.
859
-
860
745
  - Fixed MCP OAuth fallback prompts so the "Click here to authorize" label emits an auth-safe terminal hyperlink even when hyperlink auto-detection is unavailable, keeping non-browser MCP setup usable ([#2196](https://github.com/can1357/oh-my-pi/issues/2196)).
861
746
  - Fixed `task`-spawned subagents repeating filesystem scans the parent had already completed. `ExecutorOptions` and the `createAgentSession()` call inside `runSubprocess()` did not forward `rules`, the discovered extension paths, or the discovered `.omp/tools/` paths, so each subagent re-ran `loadCapability<Rule>()`, `discoverAndLoadExtensions()`, and the full `.omp/tools/` walk. The toolsession now caches `session.rules`, `session.extensionPaths`, and `session.customToolPaths`; `runSubprocess()` threads them through; and `createAgentSession()` accepts new `preloadedExtensionPaths` and `preloadedCustomToolPaths` options backed by new exported `discoverExtensionPaths()` and `discoverCustomToolPaths()` helpers. Crucially, only path lists are forwarded — never loaded instances. Each session rebuilds its own `Extension` and `LoadedCustomTool` objects so the per-session `ExtensionAPI`/`CustomToolAPI` (cwd, eventBus, runtime, exec, pushPendingAction, UI) targets the right session; forwarding loaded instances would have routed extension handlers and custom-tool execution back through the parent. The CLI's `preloadedExtensions` short-circuit is preserved for same-process reuse and now shallow-clones the caller's `extensions` array so inline-extension augmentation (autoresearch + custom-tools wrapper) cannot bleed back into it ([#2190](https://github.com/can1357/oh-my-pi/issues/2190)).
862
747
  - Fixed SSH tool cancellation hanging behind OpenSSH ControlMaster streams that stayed open after an Esc/user interrupt ([#2180](https://github.com/can1357/oh-my-pi/issues/2180)).
@@ -898,6 +783,7 @@
898
783
  - Fixed `/login` API-key prompts (OpenCode Zen, Perplexity OTP, GitHub Enterprise URL, manual OAuth redirect URL, …) silently dropping pasted content on kitty/Linux/Wayland — and any other terminal supporting OSC 5522 enhanced paste. `InputController` enables kitty's enhanced clipboard protocol on TUI start and consumes the resulting OSC 5522 packets in an `addInputListener` that runs before focus dispatch, so the paste never reached the modal `Input`'s bracketed-paste handler; the routing then stuffed the text into the main `CustomEditor` unconditionally, even when `selector-controller` had detached the editor and focused a temporary OAuth input. The pasted API key accumulated in the hidden editor and only resurfaced in the main prompt when the user dismissed the modal with Enter or Esc. The enhanced-paste callback now consults `ui.getFocused()` and routes the text to the focused component when it exposes a `pasteText` hook, falling back to the editor only when no modal target is in focus; image pastes refuse with a status message instead of stuffing a binary blob into the hidden editor. ([#2127](https://github.com/can1357/oh-my-pi/issues/2127))
899
784
  - Fixed an auto-compaction dead loop when `compaction.strategy` was `shake` and the configured threshold was low enough that a single shake pass could not bring the context below it (e.g. a 50K-token threshold on a session well above it). Each pass auto-continued, the next agent turn re-triggered the threshold check, and the second shake had nothing new to drop, so the session spun forever. The shake recovery path now estimates post-shake context and, when it is still above the threshold (or shake reclaimed nothing on overflow recovery), surfaces a one-shot warning and falls back to the summarization-driven `context-full` compaction so progress actually resumes ([#2119](https://github.com/can1357/oh-my-pi/issues/2119)).
900
785
  - Fixed `/skill:` prompts so magic keywords and turn-budget directives in skill args inject the same hidden notices as normal user prompts, matching the editor highlight behavior ([#2128](https://github.com/can1357/oh-my-pi/issues/2128)).
786
+ - Fixed MCP OAuth fallback rendering to show a short terminal hyperlink and keep the raw authorization URL on one unwrapped copy line ([#2121](https://github.com/can1357/oh-my-pi/issues/2121)).
901
787
  - Fixed the `task` tool rendering a success bullet and a `success` frame state for detail-less error results (e.g. an argument-validation failure that never executes): the header now shows the error glyph with an error border and `error` state, and surfaces the dispatched agent name.
902
788
  - Fixed Agent Control Center new-agent creation so Windows Ctrl+Enter sequences submitted as a single LF generate the agent instead of inserting a newline ([#2118](https://github.com/can1357/oh-my-pi/issues/2118)).
903
789
  - Fixed plan-mode subagents preserving read-only specialty tools such as `report_finding` while still stripping mutating tools ([#1998](https://github.com/can1357/oh-my-pi/issues/1998)).
@@ -1063,7 +949,7 @@
1063
949
  - Fixed the Python `read(path, offset, limit)` prelude helper rejecting documented positional arguments with `TypeError: read() takes 1 positional argument but 3 were given`. The signature was keyword-only (`def read(path, *, offset=1, limit=None)`) while the eval helper table advertises positional optional args; agents that called `read("file.py", 10, 20)` literally crashed. The `*` is removed so both `read("f", 10, 20)` and `read("f", offset=10, limit=20)` work.
1064
950
  - Fixed `eval` reset cells failing with `"Python kernel reset already in progress"` / `"JS context reset already in progress"` when two cells happened to overlap on the same session (e.g. a rapid resubmit, or a parallel-cell race). The executor now coalesces concurrent resets — additional callers wait for the in-flight reset to finish and then run on the freshly restarted kernel — instead of throwing a user-visible error for what is purely an internal coordination state.
1065
951
  - Fixed the `eval` tool description advertising the `agent()` helper unconditionally even in subagent sessions whose parent forbids spawning. When `getSessionSpawns()` returns `""`, the prelude doc now omits `agent()` so the model is not promised a helper that can only ever throw "Cannot spawn 'task'. Allowed: none (spawns disabled for this agent)".
1066
- - Fixed plan mode rejecting `local://` plan-artifact edits when addressed via the absolute path the `read` tool echoes back in the `[path#tag]` header. `enforcePlanModeWrite` now accepts bracketed hashline headers as well as clean absolute paths whose realpath resolves inside the session's local sandbox root, so the absolute spelling, the `[absolute#tag]` edit header, and the `local://` spelling are interchangeable in plan mode. ([#2472](https://github.com/can1357/oh-my-pi/issues/2472))
952
+ - Fixed plan mode rejecting `local://` plan-artifact edits when addressed via the absolute path the `read` tool echoes back in the `[path#tag]` header. `enforcePlanModeWrite` previously only matched the literal `local://` scheme; it now also accepts any absolute path whose realpath resolves inside the session's local sandbox root, so the absolute spelling and the `local://` spelling are interchangeable in plan mode.
1067
953
  - Fixed snapshot tags freshly minted by `read` being rejected as stale by a subsequent `edit` against the same file when the two sides reached the file via symlink-equivalent spellings (e.g. macOS `/tmp/…` vs `/private/tmp/…`, or `read local://foo.md` recording under the file's `fs.realpath` while `edit local://foo.md` looked up under the raw `path.resolve(localRoot, …)` form). The file snapshot store now keys every record/lookup through a `realpath`-canonicalized key (`canonicalSnapshotKey`), fusing all spellings of the same on-disk file onto one snapshot entry.
1068
954
  - Fixed `read` of a `github.com/<owner>/<repo>` URL with `:raw` returning the full JS-rendered HTML shell. Repo roots now resolve to the decoded README via the GitHub API (`/repos/<owner>/<repo>/readme`), falling back to the raw HTML only when the API returns no usable payload.
1069
955
  - Fixed `issue://` and `pr://` reads returning stale OPEN/CLOSED state after a successful `gh issue close` / `gh pr merge` (or any other state-changing `gh` invocation) in the same session. The `bash` tool now invalidates the matching `github-cache` rows before executing any `gh (issue|pr) <close|reopen|merge|delete|edit|comment|lock|unlock|pin|unpin|transfer|develop|ready|review>` command.
@@ -1108,9 +994,7 @@
1108
994
  ### Changed
1109
995
 
1110
996
  - Changed the bash tool frame to use a plain top rule instead of repeating "Bash" in the title bar, and folded minimizer raw-output artifact links into the status footer as `Artifact: <id>`.
1111
-
1112
997
  - Changed grouped `read` output to use a white filled-circle mark for the group/single-read success state and omit duplicate per-file success marks inside multi-read groups.
1113
-
1114
998
  - Changed assistant streaming output to reveal text incrementally at 30 FPS with grapheme-safe adaptive catch-up, instead of replacing the whole message chunk-by-chunk
1115
999
  - Changed shimmer-driven TUI animations (working text, pending bash/eval borders, and theme activity-spinner documentation) to render at 30fps instead of 60fps.
1116
1000
  - Changed running `task` tool agent rows to use a static `•` marker and shimmer only the subagent name, leaving descriptions, stats, and nested tool detail text solid while removing the rotating status glyph from those rows.
@@ -1137,7 +1021,6 @@
1137
1021
  ### Fixed
1138
1022
 
1139
1023
  - Fixed inline `find` and `search` result blocks to align with grouped `read` output and render their success headers with the normal tool-title color instead of accent blue.
1140
-
1141
1024
  - Fixed the working-status shimmer to opt into the loader's 30fps animated-message repaint path while keeping both the status spinner and pending bash/eval tool spinners on their normal 80 ms glyph cadence.
1142
1025
  - Fixed consecutive `read` tool calls failing to collapse into a single grouped block when a reasoning model emits one read per completion (`[thinking, read]`). The read group was reset on every assistant `message_start`, so each read rendered as its own one-entry `Read …` line; now a read run accretes across completions and is broken only by a rendered non-empty text/thinking block, a non-read tool, or a user/IRC message — matching the transcript-rebuild path. `ReadToolGroupComponent` now reports its live/finalized state so the growing `Read (N)` header repaints correctly on native-scrollback (risk) terminals.
1143
1026
  - Fixed the `task` tool shared-context brief rendering raw Markdown headings (`# Goal`, `# Constraints`) inside framed call/result blocks instead of using the normal Markdown renderer.
@@ -1151,6 +1034,7 @@
1151
1034
  - Fixed tool-output file paths not being clickable OSC 8 `file://` hyperlinks in several renderers. `read` titles for plain text and image files (the common case) emitted no link at all because the renderer only linked when a `resolvedPath` was recorded — which the ordinary file/image read paths never set, keeping the absolute path only in `meta.source`; the renderer now falls back to that source path. `write` headers were never wrapped in a hyperlink and now link to the absolute path written (file, archive entry, SQLite, and conflict resolutions). `edit`/`apply_patch` headers wrapped the model-supplied (often cwd-relative) argument path, producing a root-anchored `file:///rel/path` URI; they now link the absolute `details.path` instead. Finally, `search`, `ast_grep`, and `ast_edit` produced doubled link targets (`/proj/src/src/file.ts`) for searches scoped to a subdirectory, because the renderer resolved the cwd-relative display paths against the scope directory rather than cwd — the scoped-search base is now the session cwd (with the scoped file's absolute path still seeding single-file body lines).
1152
1035
  - Fixed `omp dry-balance --bench` to recover from 401 token failures by re-minting the failing OAuth credential in place before switching accounts
1153
1036
  - Fixed the bash tool corrupting commands that embed multi-byte UTF-8 (e.g. `✓`/`×` inside a `grep -E` pattern) ahead of a trailing `| head`/`| tail`. The `bash.stripTrailingHeadTail` rewrite cut at char-offset positions reported by `brush-parser` while slicing the command by byte offset, so the trailing-pipe strip landed mid-pattern and dropped the closing quote — turning `… |✓|×|XCTAssert" | tail -80` into `… |✓|×-80` and making execution fail with `pi-natives:command: unterminated double quote`. Fixed in `pi_shell::fixup` (`@oh-my-pi/pi-natives`).
1037
+ - Fixed `omp dry-balance --bench` to recover from 401 token failures by re-minting the failing OAuth credential in place before switching accounts
1154
1038
  - Fixed duplicate file entries in grouped outputs for `find`, `search`, `ast_grep`, `ast_edit`, and `lsp` diagnostics when the same path appeared multiple times
1155
1039
  - Fixed search, grep, and edit output rendering so repeated directory group blank-line boundaries no longer break nested path/link reconstruction
1156
1040
  - Fixed `omp dry-balance --bench` flooding the terminal with staircased, duplicated spinner/status lines (and an indented summary) when the tty has ONLCR/OPOST disabled (raw mode). The interactive progress region separated rows with a bare LF and repositioned with a column-preserving `\x1b[<n>A` cursor-up, both of which only land at column 0 when the terminal translates LF→CRLF; with that translation off, every 80 ms redraw cascaded down and to the right into scrollback. The live region now carriage-returns before every cleared row, terminates each row with CRLF, and caps each row to the terminal width so a wrapped line cannot desync the cursor-up from the logical line count.
@@ -1261,7 +1145,6 @@
1261
1145
  ### Added
1262
1146
 
1263
1147
  - Added a persistent error banner pinned above the editor when an assistant turn ends on a provider error (e.g. Anthropic's "Output blocked by content filtering policy"). The transcript `Error: …` line scrolls away as the conversation grows, so terminal turns that ended on a stream error could pass unnoticed; the banner stays in the fixed region above the input and is cleared when the next turn starts.
1264
-
1265
1148
  - Added bold, underlined, clickable `[Image #N]` placeholders in the draft editor and sent user-message bubbles, backed by extension-bearing blob-store sidecar files so terminal `file://` links open in image viewers.
1266
1149
  - Added the active model identifier (`provider/id`) to the system prompt's `<workstation>` block so the agent knows which model it is running as. Gated by the new `includeModelInPrompt` setting (default on); the base prompt is rebuilt on a mid-session model switch so the surfaced identifier stays current.
1267
1150
  - Added `OLLAMA_HOST` support for implicit local Ollama discovery when `OLLAMA_BASE_URL` is unset, so OMP picks up the same host setting used by Ollama.
@@ -1354,7 +1237,6 @@
1354
1237
  - Fixed Exa web search with no stored or environment credential to use the public Exa MCP fallback again, preserving the auth storage → `EXA_API_KEY` → `mcp.exa.ai` resolution order ([#1860](https://github.com/can1357/oh-my-pi/issues/1860)).
1355
1238
  - Fixed ACP plan-mode writes to `local://PLAN.md` so session-local plan artifacts are written to OMP's local artifact root instead of being routed through the editor `writeTextFile` bridge, avoiding Zen's `Internal error` and making the plan readable after creation ([#1863](https://github.com/can1357/oh-my-pi/issues/1863)).
1356
1239
  - Fixed ACP plan mode stranding the agent at plan approval: entering `mode: "plan"` now registers a standing `resolve` handler so the agent's `resolve { action: "apply" }` no longer fails with `No pending action to resolve. Nothing to apply or discard.` The handler validates the plan file, asks the ACP client to confirm via `unstable_createElicitation` when the client supports forms, renames the approved plan to `local://<title>.md`, and exits plan mode so the agent regains write tools for execution ([#1869](https://github.com/can1357/oh-my-pi/issues/1869)).
1357
-
1358
1240
  - Fixed `provider.appendOnlyContext: "auto"` staying inactive for Xiaomi Token Plan/SGLang endpoints, preserving prefix-cache hits without forcing append-only mode globally ([#1851](https://github.com/can1357/oh-my-pi/issues/1851)).
1359
1241
  - Fixed `models.yml` compatibility parsing to preserve `compat.cacheControlFormat: "anthropic"` for custom OpenAI-compatible Claude proxies. ([#1845](https://github.com/can1357/oh-my-pi/issues/1845))
1360
1242
  - Fixed the TUI's `Settings → Plugins` panel reporting "No plugins installed" when only marketplace plugins were installed. The panel now merges `PluginManager.list()` with `MarketplaceManager.listInstalledPlugins()` — the same data source the `/plugins list` slash command and `omp plugin list` CLI already used — and tags each row with an `[npm]` / `[marketplace]` kind badge, a scope tag, and a shadow indicator for project-shadowed user installs. Selecting a marketplace row opens a new `MarketplacePluginDetailComponent` whose single `Enabled` toggle calls `MarketplaceManager.setPluginEnabled(pluginId, enabled, scope)`, with read-only metadata (version, install path, installed-at, last-updated, git commit SHA) listed below the toggle. The empty-state now lists both install commands (`omp plugin install <package>` and `omp plugin install <name>@<marketplace>`) ([#1842](https://github.com/can1357/oh-my-pi/issues/1842)).
@@ -1374,7 +1256,6 @@
1374
1256
 
1375
1257
  - Added env-driven OpenTelemetry trace export. When `OTEL_EXPORTER_OTLP_ENDPOINT` (or `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`) is set, `omp` registers a global OTLP/proto trace exporter and switches on the agent loop's telemetry, so the `invoke_agent` / `chat` / `execute_tool` spans actually reach a collector instead of a no-op tracer. Honors the standard `OTEL_*` env contract (endpoint, headers, `OTEL_SERVICE_NAME`, `OTEL_SDK_DISABLED` and `OTEL_TRACES_EXPORTER=none` parsed case-insensitively) and the `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` capture toggle; it is a no-op when no endpoint is configured. Only the `http/protobuf` transport is supported — a `grpc` or `http/json` `OTEL_EXPORTER_OTLP*_PROTOCOL` declines rather than misrouting spans. This makes the existing telemetry usable from headless hosts that run `omp` as a spawned child process, where an in-process `TracerProvider` registered by the parent can't reach the child. Uses the `@opentelemetry/exporter-trace-otlp-proto` 2.x line, which exports cleanly under Bun.
1376
1258
  ## Fixed
1377
-
1378
1259
  - Fixed the status line session name (and the editor border / status-line gap fill) being nearly illegible on light themes.
1379
1260
  - Added `IndexedSessionStorage` and `SessionStorageBackend` exports to support shared metadata-indexed session backends
1380
1261
  - Added the `tui.maxInlineImages` setting (default `8`) capping how many inline images render as live terminal graphics. Once a new image pushes the count past the cap, the oldest images are hidden via a full redraw — replaced by their `[Image: …]` text placeholder and purged from the terminal's graphics store — so long sessions with many screenshots/diagrams stop piling up images (and, on Kitty, stop leaving scrollback ghosts). Set to `0` to keep every image inline.
@@ -1413,7 +1294,7 @@
1413
1294
 
1414
1295
  ### Changed
1415
1296
 
1416
- - Changed the `todo` prompt to require initializing every item from a user-supplied multi-step plan as an individual todo task before execution
1297
+ - Changed the `todo-write` prompt to require initializing every item from a user-supplied multi-step plan as an individual todo task before execution
1417
1298
  - Changed context compaction (prune/shake) to protect reads of the active plan file the same way it already protects `skill://` reads, so the plan stays intact through automatic and manual compaction. Both the canonical `local://PLAN.md` alias and the session's current plan reference path (e.g. a titled `local://<title>.md` after approval) are kept, tolerating read selectors and `local:/` scheme spelling.
1418
1299
 
1419
1300
  ## [15.8.2] - 2026-06-03
@@ -1431,7 +1312,6 @@
1431
1312
  ### Changed
1432
1313
 
1433
1314
  - Changed the JJ utility API to mirror Git's scoped helpers: repository operations now live under `jj.repo` (`root`, `resolve`, `is`, `clearRootCache`), and diff file listing is available as `jj.diff.changedFiles`.
1434
-
1435
1315
  - Changed the `search_tool_bm25` tool description to name the hidden discoverable built-in tools (e.g. `write`, `find`, `search`, `lsp`, `task`) when `tools.discoveryMode: "all"` is active, so a model can form a targeted discovery query by name instead of guessing or falling back to shell. `mcp-only` mode is unchanged (no built-ins are advertised) and the `Total discoverable tools available: N` count still includes them.
1436
1316
 
1437
1317
  ## [15.8.1] - 2026-06-02
@@ -1503,7 +1383,6 @@
1503
1383
  - Fixed `read local://<file>` resolving to the wrong session's artifacts directory in multi-session ACP hosts (e.g. cmux). `LocalProtocolHandler.resolve` now honors `context.localProtocolOptions` supplied by the calling tool before falling back to the process-wide override or the first `main`-kind session in the global `AgentRegistry`; `read`, `find`, `search`, `ast_grep`, and `ast_edit` thread their session's options through so a `local://PLAN.md` lookup hits the calling session's `local` root instead of a sibling session's ([#1608](https://github.com/can1357/oh-my-pi/issues/1608)).
1504
1384
  - Fixed `omp` segfaulting on exit on Windows after the tiny title/memory model loaded `onnxruntime-node` (issue [#1606](https://github.com/can1357/oh-my-pi/issues/1606)). The tiny model now runs in a Bun subprocess instead of a Worker thread, so the NAPI finalizer that crashes during shutdown never executes in the agent's address space; the subprocess is `SIGKILL`'d on dispose to skip every native destructor on every platform.
1505
1385
  - Fixed unbounded MCP reconnect loop that could fork-bomb the host when a stdio MCP server completes the `initialize`/`tools/list` handshake and then exits. `MCPManager` now enforces a per-server crash circuit breaker (5 reconnects per 30 s window) on the automatic `transport.onClose` path; manual `/mcp reconnect` resets the window so users can recover after fixing the misconfiguration ([#1592](https://github.com/can1357/oh-my-pi/issues/1592)).
1506
- - Fixed auto context maintenance to include the pending prompt in the pre-send token estimate, so large user turns compact history before the provider rejects an over-limit request ([#1618](https://github.com/can1357/oh-my-pi/issues/1618)).
1507
1386
 
1508
1387
  ## [15.7.4] - 2026-05-31
1509
1388
 
@@ -1550,8 +1429,6 @@
1550
1429
  ### Fixed
1551
1430
 
1552
1431
  - Fixed Ctrl+O tool-result expansion on POSIX terminals so offscreen tool blocks rebuild native scrollback instead of leaving stale collapsed rows above the viewport.
1553
- - Fixed auto-discovered OpenAI-compatible / Ollama / llama.cpp / new-api proxy models defaulting to `maxTokens: 8192`, which made providers drop the streaming connection mid-response on large `write`/`edit` tool calls and surfaced as Bun's opaque `socket connection was closed unexpectedly`. The discovery cap is now `32_768` (`DISCOVERY_DEFAULT_MAX_TOKENS` in `packages/coding-agent/src/config/model-registry.ts`) and `min(contextWindow, …)` still honors smaller advertised context windows ([#1528](https://github.com/can1357/oh-my-pi/issues/1528)).
1554
- - Removed the `/drop-images` slash command; use `/shake images`, which strips every image from the session through the same `dropImages()` path.
1555
1432
  - Fixed final `agent()` completion status emissions in eval cells so the last live progress snapshot now preserves accumulated subagent metrics such as tool count and cost
1556
1433
  - Fixed `agent()` in eval to enforce plan-mode, spawn allowlist, and disabled-agent checks before launching subagents
1557
1434
  - Fixed recursive `agent()` calls from eval by enforcing the existing max subagent depth limit
@@ -1565,6 +1442,10 @@
1565
1442
  - Fixed the streaming edit diff preview rendering a tall, half-empty box (and the earlier "box grows and shrinks repeatedly" stutter). A whole-file Myers re-diff is recomputed on every streamed chunk and its alignment is not monotonic in payload length, so a hunk-aware window that kept whole change segments gained and lost rows tick to tick; the prior high-water row reservation hid that stutter but padded the reserved height with blank rows, leaving a large empty rectangle whenever the diff shrank below its peak. The preview now pins a fixed-height trailing window to the bottom of the diff ("accept from the back"), so the box stays a steady, full window of real diff context instead of blank padding.
1566
1443
  - Fixed duplicated/stale scrollback above a streaming tool result on POSIX terminals (macOS/Linux). A tool whose output grows and re-lays-out (e.g. an edit diff gaining hunks) re-renders rows that already scrolled into native scrollback; the unknown-viewport anti-yank deferral left the old copy in place while the new one rendered below, showing the block twice. The event controller now enables the TUI's eager native-scrollback rebuild while a foreground tool is executing (`setEagerNativeScrollbackRebuild`), so those offscreen re-renders rebuild history cleanly — a snap to the tail is acceptable mid-tool. Background-running tools and plain assistant-text streaming keep the no-yank deferral; the mode resets at each turn start.
1567
1444
 
1445
+ ### Removed
1446
+
1447
+ - Removed the `/drop-images` slash command; use `/shake images`, which strips every image from the session through the same `dropImages()` path.
1448
+
1568
1449
  ## [15.7.2] - 2026-05-31
1569
1450
 
1570
1451
  ### Added
@@ -1585,7 +1466,6 @@
1585
1466
  - Bypassed auto classifier for `ultrathink` prompts and resolved directly to the highest supported auto effort
1586
1467
  - Fixed the JavaScript `eval` kernel crashing the whole process with a segfault (`SIGTRAP`, `getImportedModule` on a null record) when imported code reached a local module whose relative-import graph contains a cycle — e.g. `await import("…/edit/streaming.ts")`, or any workspace path with cyclic re-exports. The `LocalModuleLoader` linked and evaluated each local module individually inside the recursive `vm.SourceTextModule` linker callback, which re-entered Bun's `node:vm` module linker mid-instantiation and detonated JSC on the first cycle. The loader now constructs the entire local module graph first and drives a single `link()` + `evaluate()` from the graph root, so cyclic graphs instantiate in one pass; external (`node_modules`) modules stay eagerly loaded since they carry no imports and cannot form a cycle.
1587
1468
  - Fixed the streaming `edit` preview rendering a blank box for hashline edits whose payload sits on the trailing in-flight line (the common single-op `replace`/`insert` case). The preview path trimmed that still-typing line before diffing, so a single-payload op collapsed to a "No changes" result — shown as an empty box — for almost the entire stream. Hashline previews now feed the raw in-flight text through `applyPartialTo`, whose streaming-tolerant parser drops a payload-less trailing op and projects a partially-typed payload line as it grows, so the diff appears and fills in live. Transient errors from the actively-typed trailing section are also suppressed while streaming (regardless of section count) so a mid-typed op can't wipe an already-good preview frame; real errors still surface once args are complete.
1588
- - Fixed hashline edit previews to accept live content-hash matches and session snapshot recovery, so `search`/`read`-anchored edits no longer flash stale "re-read" errors before applying successfully.
1589
1469
 
1590
1470
  ## [15.7.0] - 2026-05-31
1591
1471
 
@@ -1597,9 +1477,8 @@
1597
1477
  - Added a `/switch` slash command that opens the temporary model selector for the current session, mirroring the `alt+p` keybinding.
1598
1478
  - Added `replace block N:` and `delete block N` operators to the `edit` tool: they resolve the syntactic block beginning on line N via tree-sitter (native `blockRangeAt`) and replace or delete its full line span, so a construct can be rewritten or removed without counting its closing line. Unresolvable blocks (unsupported language, blank/closing-delimiter line, or a parse error) are rejected with guidance to use an explicit `replace N..M:` / `delete N..M` range.
1599
1479
  - Added an animated pending border for `bash` and `eval` execution blocks: while a command/cell is running, a single dark segment glides clockwise around the block's outer edge (top → right → bottom → left), replacing the previous static accent border. Motion is eased per edge (decelerating into each corner) and timed against a fixed lap duration mapped onto the live perimeter, so streaming a new output line or resizing the terminal nudges the segment proportionally instead of resetting its position. Driven by the existing spinner cadence and gated on the `display.shimmer` setting (no motion when `disabled`).
1600
- - Added `providers.tinyModelDevice` and `providers.tinyModelDtype` settings (Providers tab) controlling local tiny-model acceleration for session titles and Mnemopi memory tasks. `providers.tinyModelDevice` selects the ONNX execution provider (`default` keeps the platform pick — DirectML on Windows, CUDA on Linux x64, CPU elsewhere); `providers.tinyModelDtype` selects quantization/precision (`default` keeps each model's shipped `q4`, e.g. `fp16` trades speed for fidelity). The `PI_TINY_DEVICE` / `PI_TINY_DTYPE` env vars override the matching setting. Also added `PI_TINY_DTYPE` as the env counterpart to `PI_TINY_DEVICE`; an unrecognized device/precision fails loudly at worker startup instead of silently loading a different one.
1480
+ - Added `providers.tinyModelDevice` and `providers.tinyModelDtype` settings (Providers tab) controlling local tiny-model acceleration for session titles and Mnemosyne memory tasks. `providers.tinyModelDevice` selects the ONNX execution provider (`default` keeps the platform pick — DirectML on Windows, CUDA on Linux x64, CPU elsewhere); `providers.tinyModelDtype` selects quantization/precision (`default` keeps each model's shipped `q4`, e.g. `fp16` trades speed for fidelity). The `PI_TINY_DEVICE` / `PI_TINY_DTYPE` env vars override the matching setting. Also added `PI_TINY_DTYPE` as the env counterpart to `PI_TINY_DEVICE`; an unrecognized device/precision fails loudly at worker startup instead of silently loading a different one.
1601
1481
  - Added a bundled set of default rules shipped with the agent (TypeScript/Rust convention rules registered as TTSR conditions). They load via the new lowest-priority `builtin-defaults` discovery provider, so any user/project/tool rule of the same name overrides the bundled copy. Disable the whole set with `ttsr.builtinRules: false`, or drop individual rules (bundled or your own) by name via `ttsr.disabledRules`.
1602
- - Added a `symbols.spinnerFrames` field to custom theme JSON so themes can override the loader/tool-execution spinner. Accepts either a flat `string[]` (used for both spinner types) or `{ "status"?: string[], "activity"?: string[] }` to override each independently; anything not specified falls back to the symbol preset. Documented in `docs/theme.md` and validated by `theme-schema.json`. ([#1553](https://github.com/can1357/oh-my-pi/issues/1553))
1603
1482
 
1604
1483
  ### Changed
1605
1484
 
@@ -1630,45 +1509,45 @@
1630
1509
  - Added prompt-mode autocomplete for supported internal URL schemes (`skill://`, `rule://`, `agent://`, `artifact://`, `local://`, `memory://`, and `omp://`) so typing those tokens now suggests existing resources as completion candidates
1631
1510
  - Added fuzzy matching and ranked suggestion ordering for internal URL completion, including rule and skill descriptions, with accepted completion replacing just the typed token and inserting the chosen URL followed by a space
1632
1511
  - Changed internal URL completions now include nested `local://` path suggestions from the configured local workspace
1633
- - Added Mnemopi memory inference model selection with an online mode or local transformers.js options (`qwen3-1.7b`, `gemma-3-1b`, `qwen2.5-1.5b`, `lfm2-1.2b`) so memory extraction and consolidation can run via the shared tiny-model worker
1512
+ - Added Mnemosyne memory inference model selection with an online mode or local transformers.js options (`qwen3-1.7b`, `gemma-3-1b`, `qwen2.5-1.5b`, `lfm2-1.2b`) so memory extraction and consolidation can run via the shared tiny-model worker
1634
1513
  - Changed memory tiny-model handling to route local memory prompts through the same queueed tiny-model worker pipeline with bounded completion output
1635
1514
  - Added a Providers → Tiny Model setting for session titles, defaulting to the online `pi/smol` path with five optional local CPU transformers.js models. A local model — and the one-time `@huggingface/transformers` runtime install in compiled binaries — is downloaded and loaded only when explicitly selected (or via `omp tiny-models download`); the default online path never spawns the title worker for inference. Selecting a local model adds a delayed `pi/smol` fallback so titles never block, plus in-chat download progress.
1636
1515
  - Added a persistent live agent roster pinned below the editor (focus it with `Ctrl+S` or `Alt+Down`), including view-as switching into delegated agent sessions with human-readable delegate names and UI pinning to suppress idle reaping while viewed. The roster stays hidden until at least one delegated agent exists and releases focus back to the editor once the last one is gone.
1637
1516
  - Recorded the originating session ID alongside each prompt in `history.db` (new `session_id` column, surfaced as `HistoryEntry.sessionId`), so recalled prompts can be traced back to the session they came from. Existing history databases gain the column automatically on next launch.
1638
1517
  - Added compact inline TUI renderers for the `retain`, `recall`, and `reflect` memory tools. `retain` now shows one themed bullet line per stored item (truncated to width) under a status header with the stored/queued count, and `recall`/`reflect` collapse to a single query header (recall reports the match count and hides recalled memories until expanded) instead of dumping the raw JSON argument tree.
1639
1518
  - Added a randomly picked tip beneath the welcome screen, sourced from an embedded `tips.txt` (one tip per line). The line is italicized with a purple `Tip:` label and a dimmed light-blue body, and the tip is chosen once per welcome instance so intro-animation and LSP re-renders don't shuffle it.
1640
- - Added a Mnemopi-only `memory_edit` agent tool for updating, forgetting, or invalidating recalled memories by id, and added `/memory stats` plus `/memory diagnose` slash commands for backend maintenance visibility.
1519
+ - Added a Mnemosyne-only `memory_edit` agent tool for updating, forgetting, or invalidating recalled memories by id, and added `/memory stats` plus `/memory diagnose` slash commands for backend maintenance visibility.
1641
1520
  - Added an `orchestrate` magic keyword that mirrors `ultrathink`: dropping the standalone word in a message paints it with a cool teal→violet gradient in the editor and appends a hidden system notice that switches the model into the multi-phase, parallel-subagent orchestration contract. Matching is word-bounded and case-insensitive, so `orchestrated`/`orchestrating` never trigger it.
1642
1521
  - Added a model-tier slider to the plan-approval prompt ("Plan mode - next step"). Left/right arrows move it from any list position to pick which configured role model (`cycleOrder`, e.g. `smol › default › slow`) executes the approved plan, with each tier colored by its role and the resolved model name shown beneath the track. The chosen tier is applied before dispatch and carries through the fresh/compacted execution session; the slider is hidden when fewer than two role models resolve.
1643
- - `omp plugin install` now accepts GitHub/GitLab/Bitbucket shorthand (`github:user/repo`, `gitlab:user/repo`, …) and full git URLs (`https://github.com/user/repo`, `git@github.com:user/repo`, …) in addition to npm specs and marketplace refs.
1644
1522
 
1645
1523
  ### Changed
1646
1524
 
1647
1525
  - Changed `irc` to treat the attached human as a first-class `User` peer, merging human prompts into `irc call User` with optional structured question payloads and adding `/dm <agent> <message>` for user-to-agent routing without switching views.
1648
1526
  - Changed the `--resume` session picker (and the in-session resume selector) to also rank sessions by prompt-history matches from `history.db`, not just the session-list metadata. Because the session list only indexes the first 4KB of each file, this surfaces sessions by prompts typed deep into long conversations. Sessions matched by both signals lead, then metadata-only matches, then history-only matches — no metadata match is dropped.
1649
1527
  - Changed the `task` tool's streaming call preview to list each dispatched agent's `id` and UI description as a tree instead of a bare `N agents` count, so the individual agents are visible while the tool-call arguments are still streaming. The collapsed view caps at 12 entries (`… N more agents`); the expanded view shows all.
1650
- - Changed Mnemopi `recall` tool output to include memory ids for explicit recall results so agents can target `memory_edit`; auto-injected memory context and `reflect` remain id-free.
1528
+ - Changed Mnemosyne `recall` tool output to include memory ids for explicit recall results so agents can target `memory_edit`; auto-injected memory context and `reflect` remain id-free.
1651
1529
  - Changed the system prompt to advertise `memory://root` only when the local memory backend is active.
1652
- - Changed `todo` result rendering to animate completed items in place: the checkbox flips checked first, then the strikethrough reveals across the task text.
1530
+ - Changed `todo_write` result rendering to animate completed items in place: the checkbox flips checked first, then the strikethrough reveals across the task text.
1531
+
1532
+ ### Removed
1533
+
1534
+ - Removed the standalone `ask`, `task`, and `yield` tools along with their obsolete prompts, docs, and tests; delegation now routes through persistent `delegate` agents plus IRC coordination.
1535
+ - Removed the `/orchestrate` slash command; orchestration is now triggered by the `orchestrate` keyword (see Added) so the contract rides alongside the user's own prompt instead of replacing it.
1536
+ - Removed the sticky Todos panel all-done drop/collapse animation; completed todo state now stays visible until the next explicit todo update changes it.
1653
1537
 
1654
1538
  ### Fixed
1655
1539
 
1656
- - Fixed Mnemopi session shutdown to flush queued memory extractions before exit so the last turn’s facts are not lost
1540
+ - Fixed Mnemosyne session shutdown to flush queued memory extractions before exit so the last turn’s facts are not lost
1657
1541
  - Fixed a native crash (`malloc: pointer being freed was not allocated` / `NAPI FATAL ERROR`) when quitting after the local transformers.js title model had run. The tiny-title worker no longer calls `pipeline.dispose()` on shutdown — disposing the onnxruntime session freed native memory that Bun's worker/NAPI teardown then freed again. The worker is torn down immediately after, so the OS reclaims the model memory regardless.
1658
1542
  - Fixed the tiny-title download progress bar flashing on every first message even when the local model was already downloaded. A cached model emits the same `download`/`progress` events as a real download, so the bar is now revealed only when in-flight progress events keep arriving past a short grace window — cache hits finish (or fall silent during onnxruntime init) before then and never show the bar.
1659
- - Fixed the Mnemopi memory backend lifecycle so auto-retain counts the full session transcript, delegated agents inherit the parent Mnemopi state, `/memory clear` removes scoped project-bank databases, session disposal closes Mnemopi SQLite handles, session switches rekey/reset Mnemopi tracking, and project bank names include an absolute-root hash with safe bank-name sanitization.
1543
+ - Fixed the Mnemosyne memory backend lifecycle so auto-retain counts the full session transcript, delegated agents inherit the parent Mnemosyne state, `/memory clear` removes scoped project-bank databases, session disposal closes Mnemosyne SQLite handles, session switches rekey/reset Mnemosyne tracking, and project bank names include an absolute-root hash with safe bank-name sanitization.
1660
1544
  - Fixed the streaming edit preview showing no diff for single-line hashline edits. The preview-diff coalescing keyed only on the arg text, so the final (args-complete) pass — which computes an untrimmed diff — was skipped because the payload was byte-identical to the last streamed chunk whose trailing line had been trimmed. The dedup key now pairs the streaming state with a content hash.
1661
1545
  - Fixed `Esc` in a delegated agent view returning to the main session instead of aborting the delegated agent's active turn.
1662
1546
  - Fixed the subagent stats line to separate the cost with the theme dot separator (was a stray literal `.`) and to render context usage as `<pct>%/<window>` (e.g. `21.3%/272K`) matching the status line gauge, via a shared `formatContextUsage` helper now used by the footer, status-line segment, session observer overlay, and `task` renderer.
1663
1547
  - Fixed the agent roster staying pinned under the editor when all delegated agents are idle or dormant; it now reappears when explicitly focused with `Alt+Down` / session observe.
1664
1548
  - Fixed selector-style UI components to honor `tui.select.up` and `tui.select.down` keybindings instead of hard-coding raw Up/Down arrow bytes ([#1535](https://github.com/can1357/oh-my-pi/issues/1535)).
1665
1549
  - Fixed the bash (and `recipe`) tool result footer not rendering for failed commands. A non-zero exit threw a `ToolError`, which dropped the result details, so the styled `⟨Wall … | Timeout …⟩` footer was replaced by the raw `Wall time: … seconds` / `Command exited with code N` lines. Non-zero exits now resolve as a non-throwing error result that keeps `wallTimeMs`/`timeoutSeconds`/`exitCode`, and the footer shows `⟨Wall … | Timeout … | Exit: N⟩` with the textual notices folded out of the output pane. Aborts, timeouts, and missing-exit-status still throw as before.
1666
-
1667
- ### Removed
1668
-
1669
- - Removed the standalone `ask`, `task`, and `yield` tools along with their obsolete prompts, docs, and tests; delegation now routes through persistent `delegate` agents plus IRC coordination.
1670
- - Removed the `/orchestrate` slash command; orchestration is now triggered by the `orchestrate` keyword (see Added) so the contract rides alongside the user's own prompt instead of replacing it.
1671
- - Removed the sticky Todos panel all-done drop/collapse animation; completed todo state now stays visible until the next explicit todo update changes it.
1550
+ - Fixed selector-style UI components to honor `tui.select.up` and `tui.select.down` keybindings instead of hard-coding raw Up/Down arrow bytes ([#1535](https://github.com/can1357/oh-my-pi/issues/1535)).
1672
1551
 
1673
1552
  ## [15.5.15] - 2026-05-30
1674
1553
 
@@ -1693,15 +1572,14 @@
1693
1572
 
1694
1573
  ### Fixed
1695
1574
 
1696
- - Fixed a rewind/restore loop (and a follow-on handoff failure) caused by assistant turns whose tool results are off the resolved conversation path — e.g. selecting such a turn in `/tree`, restoring a session whose head is a mid-batch turn, or branching a new message in right after a turn whose tool calls hadn't resolved on that branch. `buildSessionContext` walks the leaf→root path, so any turn whose `tool_result` children live on a sibling branch (or below the leaf) ends up with **dangling** `tool_use` blocks. `transformMessages` then fabricated one synthetic `"aborted"`/`"No result provided"` result per dangling call plus a `<turn-aborted>` developer note, which both rendered as phantom failed calls on a turn that "hadn't run anything yet" and re-injected the failed batch into the model's context, prompting it to re-issue the batch (the spiral). `buildSessionContext` now rewrites **every** assistant turn on the resolved path that has dangling `tool_use`: it drops the unpaired `tool_use` blocks, drops `redacted_thinking` blocks, and clears `thinking` signatures (the provider encoder then emits them as plain text), dropping a turn entirely if no content remains. Turns whose tool calls *are* paired on the path are left untouched. Stripping the calls alone was insufficient — a *modified* assistant turn that still carried signed `thinking`/`redacted_thinking` was rejected by Anthropic with `messages.N.content.M: 'thinking' or 'redacted_thinking' blocks in the latest assistant message cannot be modified`, which surfaced as `Handoff generation failed: 400` on navigation. Live turns are unaffected — their results persist on the same path before any context rebuild.
1697
-
1575
+ - Fixed a rewind/restore loop when the session leaf lands on an assistant turn that emitted tool calls (e.g. selecting such a turn in `/tree`, or restoring a session whose head is a mid-batch turn). That turn's tool results are persisted as its children *below* the leaf so they fall off the leaf→root path that `buildSessionContext` walks, leaving the assistant turn's `tool_use` blocks dangling as the final message. `transformMessages` then fabricated one synthetic `"aborted"`/`"No result provided"` result per call plus a `<turn-aborted>` developer note, which both rendered as phantom failed calls on a turn that "hadn't run anything yet" and re-injected the whole failed batch into the model's context, prompting it to re-issue the batch (the spiral). `buildSessionContext` now strips dangling `tool_use` blocks from a trailing assistant turn (dropping the turn entirely if nothing else remains), so a rewound turn resumes cleanly from its reasoning/text. Live turns are unaffected — their results persist and the leaf advances past the assistant before any rebuild.
1698
1576
  - Fixed external extension loading on Windows compiled binaries: bare `@oh-my-pi/pi-*` value imports (e.g. `import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai"`) failed with `Cannot find package '\$bunfs\root\packages\…'` because `legacy-pi-compat.ts` built shim override paths from a hardcoded POSIX `/$bunfs/root/packages` literal. Win32 normalised the leading slash to a backslash and the resulting path never resolved against the real bunfs mount (`<drive>:\~BUN\root\…`). The bunfs package root is now derived from `import.meta.dir`, so override paths stay platform-native on Windows, Linux, and macOS ([#1514](https://github.com/can1357/oh-my-pi/issues/1514)).
1699
1577
  - Fixed the interactive prompt showing no cursor in Ghostty. A prior change wired the editor's cursor mode to a new `getUseTerminalCursorMarker()` (which always reported the *requested* preference) instead of the resolved hardware-cursor visibility, so when Ghostty force-hid the hardware cursor the editor stayed in terminal-cursor (marker-only) mode and drew no glyph — leaving no visible caret with either `showHardwareCursor`/`PI_HARDWARE_CURSOR` value. The editor now follows `ui.getShowHardwareCursor()`: a hidden hardware cursor falls back to the steady software-cursor glyph (which still emits `CURSOR_MARKER` for IME positioning).
1700
1578
 
1701
1579
  ### Changed
1702
1580
 
1703
1581
  - Changed the `eval` tool's `display()` JSON tree in the transcript to use the shared `renderJsonTreeLines` renderer (the same one behind tool args, MCP results, and subagent output) instead of its own format. This drops the redundant `Object(N)` / `Array(N)` type labels and the per-output `JSON output N` header in favor of type icons plus bare keys; the `display[N]` header is now shown only when a cell emits more than one `display()` value.
1704
- - Reverted the sticky `Todos` panel task glyphs to the pre-15.5.12 checkbox icons: completed tasks render `theme.checkbox.checked` (not `theme.status.success`) and in-progress tasks render `theme.checkbox.unchecked` (not the running glyph). Removed the animated spinner entirely — in-progress tasks and pending tasks with a matching in-flight subagent still highlight via the `accent` colour, but the panel now paints once per state change instead of on an 80 ms timer. Subagent auto-checkmarking, the advancing window (`selectStickyTodoWindow`), `todoMatchesAnyDescription` highlighting, and the all-done close animation are unchanged.
1582
+ - Removed the animated spinner from the sticky `Todos` panel. In-progress tasks and pending tasks with a matching in-flight subagent still highlight (accent colour + the static `theme.status.running` glyph), but no longer tick through `theme.spinnerFrames`, so the panel paints once per state change instead of on an 80 ms timer. Subagent auto-checkmarking, the advancing window (`selectStickyTodoWindow`), `todoMatchesAnyDescription` highlighting, and the all-done close animation are unchanged.
1705
1583
 
1706
1584
  ## [15.5.13] - 2026-05-29
1707
1585
 
@@ -1728,7 +1606,7 @@
1728
1606
 
1729
1607
  ### Changed
1730
1608
 
1731
- - Changed the sticky `Todos` panel above the editor to advance as tasks close, instead of pinning to the first 5 tasks of the active phase. `selectStickyTodoWindow` now shows up to 5 open (pending / in_progress) tasks in original phase order and reports the count of remaining open tasks for the `+N more` hint, so every `todo` flip produces a visible row shift. Closed-phase tail falls back to the last 5 tasks (with the `+N more` line suppressed) until `getActivePhase` walks to the next phase.
1609
+ - Changed the sticky `Todos` panel above the editor to advance as tasks close, instead of pinning to the first 5 tasks of the active phase. `selectStickyTodoWindow` now shows up to 5 open (pending / in_progress) tasks in original phase order and reports the count of remaining open tasks for the `+N more` hint, so every `todo_write` flip produces a visible row shift. Closed-phase tail falls back to the last 5 tasks (with the `+N more` line suppressed) until `getActivePhase` walks to the next phase.
1732
1610
  - Linked the sticky `Todos` panel to the live `SessionObserverRegistry` so pending todos that have an in-flight subagent doing their work light up green with an animated spinner — the same `theme.spinnerFrames` ("status" preset) the `task` tool uses for its agent rows — instead of staying greyed out as if nothing is happening. A new exported `todoMatchesAnyDescription(content, descriptions)` does case- and whitespace-insensitive equality first with a 6-char minimum-overlap substring fallback in either direction, so "Sonnet #2: shallow bug scan" and a subagent description of "Sonnet #2" still link up. Completed todos now render with `theme.status.success` (✔ / `\uf00c` / `[ok]` per symbol preset, still wrapped in the `success` colour so themed palettes can keep their purple/green/whatever) and in_progress rows render with `theme.status.running`, matching the `task` tool's icon vocabulary. The spinner interval only ticks while at least one visible open todo has a matched active subagent, and self-stops once subagents finish, so plain in_progress todos do not animate forever in the absence of subagent activity.
1733
1611
  - Extracted the top-level CLI command table from `src/cli.ts` into a side-effect-free `src/cli-commands.ts` so test code can introspect the registered subcommands without triggering the entrypoint's top-level await.
1734
1612
 
@@ -1758,7 +1636,6 @@
1758
1636
  ### Fixed
1759
1637
 
1760
1638
  - Fixed compaction surfacing raw HTTP 401/403 envelopes (e.g. `Compaction failed: 401 {"type":"error","error":{"type":"authentication_error",…}}`) instead of routing to an authenticated fallback model. The compaction layer now attaches the provider-reported HTTP status onto the thrown error, and `AgentSession`'s auth-failure detector branches on `error.status === 401 || 403` in addition to the existing `auth_unavailable` regex. When a fallback model role (e.g. `modelRoles.smol`) is configured, compaction retries it transparently; otherwise the user sees the actionable "Compaction requires usable credentials for …" hint instead of the raw provider envelope.
1761
- - Fixed compiled-binary legacy plugin loading for `@earendil-works/*` imports of bundled package roots such as `@earendil-works/pi-coding-agent`; compat now rewrites all bundled pi package roots to bunfs entrypoints and resolves fallback peer dependencies through the canonical `@oh-my-pi/*` specifier.
1762
1639
 
1763
1640
  ## [15.5.8] - 2026-05-28
1764
1641
 
@@ -1769,7 +1646,6 @@
1769
1646
  ### Added
1770
1647
 
1771
1648
  - Added `vault.enabled` setting (Tools → Obsidian Vault, default `false`) gating the `vault://` internal URL. When disabled, `VaultProtocolHandler.resolve` / `write`, `resolveVaultUrlToPath`, and `hasObsidian()` all refuse — the latter hides the `vault://` entry from the system prompt's Handlebars `{{#if hasObsidian}}` block. Tests can opt in via `vi.spyOn(vaultProtocol, "isVaultEnabled").mockReturnValue(true)`.
1772
-
1773
1649
  - Added support for `vault://` URLs in path resolution utilities, including plan mode and internal selector parsing so `read` and edit paths can target Obsidian vault files directly
1774
1650
  - Added `vault://` internal URLs for editable Obsidian vault files, with filesystem-backed read/write/listing and CLI-backed vault index operations.
1775
1651
  - Added strict-mode indicators to `omp auth-gateway check` output by appending `[strict]` to strict-mode text headers and adding a top-level `strict` field in `--json` output
@@ -1817,7 +1693,6 @@
1817
1693
  ### Added
1818
1694
 
1819
1695
  - `providers.openrouterVariant` setting (Settings → Providers → "OpenRouter Routing") to default OpenRouter requests to a routing-variant suffix (`:nitro`, `:floor`, `:online`, `:exacto`). Selectors that already name a variant (e.g. `openrouter/anthropic/claude-haiku:nitro`) keep precedence.
1820
-
1821
1696
  - `generate_image` supports xAI Grok Imagine via `providers.image=xai`. Supports `grok-imagine-image` (default) and `grok-imagine-image-quality` at aspect ratios `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`. Uses the xAI Grok OAuth credential when available, otherwise `XAI_API_KEY`.
1822
1697
  - New `tts` tool synthesises speech via xAI Grok Voice behind the disabled-by-default `tts.enabled` setting. Built-in voices `ara`, `eve` (default), `leo`, `rex`, `sal`; custom voice IDs also accepted. Output codec inferred from the `output_path` suffix (`.wav` → `wav`, else `mp3`). Up to 15,000 characters per request.
1823
1698
 
@@ -1870,19 +1745,12 @@
1870
1745
  - Changed multi-section hashline `edit` execution to defer LSP diagnostics flushing until the final section is written
1871
1746
  - Changed read to return verbatim contents for files shorter than `read.summarize.minTotalLines` instead of summarizing them
1872
1747
  - Changed `search` path line-range filtering to include only matches and context lines that fall inside the requested ranges
1873
- - Changed `MemorySessionStorage`'s mirror to a chunks-based representation. `writeLineSync` now appends to a `string[]` in O(1) (previously read the whole file and concatenated, giving O(N²) growth per session). `statSync` reports true UTF-8 byte length instead of character count. `readTextPrefix` walks chunks until the byte budget is exhausted instead of materialising the full mirror.
1874
- - Changed `ToolExecutionComponent.updateArgs` to drop the per-delta `structuredClone` of streaming tool arguments. Callers (`event-controller.ts`, `ui-helpers.ts`) already spread their input into a fresh object on each delta, so cloning here was dead work on the rendering hot path. Added a reference-equality short-circuit so repeat calls with the same args object skip the preview-diff and display refresh.
1875
- - Changed `ConfigFile`'s constructor to defer the JSON → YAML migration until first `tryLoad`/`tryLoadAsync` and to cache (jsonPath, ymlPath) pairs already migrated this process, so `relocate()` / repeated loads do not re-run the migration.
1876
- - Changed all production `new ModelRegistry(...)` call sites (`main.ts`, `sdk.ts`, `task/executor.ts`, `commit/pipeline.ts`, `commit/agentic/index.ts`, the SDK example) to `await ModelRegistry.create(...)`.
1877
1748
 
1878
1749
  ### Fixed
1879
1750
 
1880
- - Fixed a race in `withFileLock` where a contender losing the `mkdir` race could wipe the winner's freshly-created lock directory before the winner finished writing its info file. Every lock now carries a per-process UUID token; `releaseLock(path, expectedToken)` verifies ownership before `fs.rm`, and `isLockStale` no longer returns `true` for a dir whose info file is absent but whose mtime is still inside the staleness window (or whose dir vanished mid-check).
1881
- - Fixed `formatErrorMessage` not sanitising tabs or truncating oversized error strings before painting them through the theme. Errors that embedded raw file content (apply_patch failures, hashline mismatches, etc.) could break terminal alignment via raw `\t` chars or overflow the line width.
1882
1751
  - Fixed multi-section hashline edits to reject duplicate canonical targets and preflight write guards before any section is committed
1883
1752
  - Fixed `createAgentSession()` dropping the hidden `resolve` tool from the registry when no active tool sets `deferrable: true`, even though plan mode dispatches the plan-approval `resolve { action: "apply", ... }` call through a standing handler. Read-only plan-mode toolsets (e.g. `read`, `search`, `find`, `web_search`) silently activated plan mode without `resolve`, leaving the agent unable to submit the finalized plan and forcing the user to exit plan mode manually. `resolve` is now kept whenever `plan.enabled` is true, so the standing handler always has a callable tool ([#1428](https://github.com/can1357/oh-my-pi/issues/1428))
1884
1753
  - Fixed `omp` startup and `/changelog` reading the host project's `CHANGELOG.md` as omp's — `getPackageDir()` no longer falls back to the user's `cwd` when no owning `package.json` is locatable, preventing spurious `lastChangelogVersion` writes ([#1423](https://github.com/can1357/oh-my-pi/issues/1423))
1885
- - Fixed hashline session-chain replay silently overwriting in-session edits when the model re-targeted a previously rewritten line with a stale file hash; replay now refuses unless every edit's anchor line content matches between the snapshot and the current file ([#1422](https://github.com/can1357/oh-my-pi/pull/1422))
1886
1754
 
1887
1755
  ## [15.5.3] - 2026-05-27
1888
1756
 
@@ -1894,10 +1762,6 @@
1894
1762
 
1895
1763
  - Warned when legacy inline `LINE:TEXT` lines are accepted as payload continuations only when inside a pending multi-line `A-B:` replacement
1896
1764
 
1897
- ### Fixed
1898
-
1899
- - Fixed runtime model registry refresh and cache loading so providers with authoritative dynamic catalogs, including Synthetic, do not re-add deprecated bundled model IDs after discovery ([#1417](https://github.com/can1357/oh-my-pi/issues/1417)).
1900
-
1901
1765
  ## [15.5.2] - 2026-05-26
1902
1766
 
1903
1767
  ### Breaking Changes
@@ -1953,7 +1817,7 @@
1953
1817
 
1954
1818
  ### Fixed
1955
1819
 
1956
- - Fixed Google Vertex cached project discovery replacing the bundled fallback catalog so `/models` does not keep showing outdated Gemini entries after authoritative Vertex discovery, while keeping the bundled fallback in place when the cached snapshot is stale or non-authoritative (e.g. after an ADC discovery failure) ([#1412](https://github.com/can1357/oh-my-pi/issues/1412)).
1820
+ - Fixed Google Vertex cached project discovery replacing the bundled fallback catalog so `/models` does not keep showing outdated Gemini entries after authoritative Vertex discovery ([#1412](https://github.com/can1357/oh-my-pi/issues/1412)).
1957
1821
 
1958
1822
  ## [15.4.2] - 2026-05-26
1959
1823
 
@@ -1982,9 +1846,6 @@
1982
1846
  - Added file-read snapshot caching with multi-snapshot ring per path for recovery from agent's own writes
1983
1847
  - Added delete operation (`!`) support to hashline grammar for explicit line deletion
1984
1848
  - Added structural bracket/brace balance warnings when deleting lines with unclosed constructs
1985
- - Added resource metadata URL (RFC 9728) support to OAuth discovery for chaining authorization server resolution from protected-resource metadata ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
1986
- - Added path-prefixed well-known URL fallback in OAuth discovery to support authorization servers behind gateways with sub-path routing ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
1987
- - Added relative URL resolution for `Mcp-Auth-Server` header values against the server URL ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
1988
1849
 
1989
1850
  ### Changed
1990
1851
 
@@ -2012,9 +1873,6 @@
2012
1873
  - Modified hashline grammar to accept optional file hash in headers and removed hash requirements from line anchors
2013
1874
  - Changed hashline diff preview format to use `LINE:content` instead of `LINE+HASH|content`
2014
1875
  - Updated prompt documentation to reflect new `¶PATH#HASH` header and bare line-number syntax
2015
- - Updated `discoverOAuthEndpoints` to accept `resourceMetadataUrl` parameter and prioritize the resource-metadata chain ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
2016
- - Updated `parseMcpAuthServerUrl` and `extractMcpAuthServerUrl` to accept optional `serverUrl` for relative URL resolution ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
2017
- - Updated `MCPOAuthFlow.#resolveRegistrationEndpoint` to try origin-root well-known first, then fall back to path-prefixed well-known ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
2018
1876
 
2019
1877
  ### Removed
2020
1878
 
@@ -2029,7 +1887,6 @@
2029
1887
 
2030
1888
  ### Fixed
2031
1889
 
2032
- - Fixed missing `await` on `#tryWellKnownForRegistration` call in `#resolveRegistrationEndpoint` that caused path-prefixed well-known fallback to never actually execute, returning the unresolved Promise object instead of the registration endpoint ([1407](https://github.com/can1357/oh-my-pi/pull/1407) by [@faizhasim](https://github.com/faizhasim))
2033
1890
  - Fixed JavaScript module reloading to refresh local re-exports when transitive dependency files are edited
2034
1891
  - Fixed Python tool calls in warm kernels to initialize once bridge environment variables appear after startup and to return a clear `tool bridge is unavailable` error when missing
2035
1892
  - Fixed IRC `send` handling to preserve recipient incoming messages when auto-reply timeouts instead of dropping them
@@ -2046,20 +1903,9 @@
2046
1903
 
2047
1904
  ### Added
2048
1905
 
2049
- - Added resolved subagent model badge to the task widget status line showing `<provider>/<id>` (with optional `:<thinkingLevel>` suffix when thinking is set explicitly), opt-in via `task.showResolvedModelBadge` Appearance setting (default off)
2050
1906
  - Added `codex` and `gemini` to the web search provider settings so users can configure OpenAI and Gemini web search directly from provider selection
2051
1907
  - Added OpenAI (`codex`) and Gemini web search options with updated setup descriptions for `omp /login openai-codex` and Gemini OAuth login
2052
1908
  - Added pretty-printing for wide JSON `data:` payloads in the raw provider-stream debug viewer so streamed event bodies expand across multiple `data:` lines instead of getting clipped by the per-line truncator, and updated the viewer header to read `raw provider stream (SSE + WS)` now that Codex WebSocket frames also flow through the buffer
2053
- - Added per-tool approval policies with a `--auto-approve` (alias `--yolo`) CLI flag to bypass confirmation prompts for automation. Each tool call resolves a policy of `allow` / `deny` / `prompt` via a six-level lookup: overriding action exceptions, validated user config, non-overriding action exceptions, built-in defaults, validated user `_default`, and a system `prompt` fallback.
2054
- - Added `tools.approval.<toolName>: allow | deny | prompt` user config support via the settings schema. Invalid values (non-strings, unknown literals) are now ignored and fall through to the built-in default instead of being silently honoured — preventing a typo from locking the user out of a tool or bypassing approval for one.
2055
- - Added action-based exception registry covering LSP read-only actions (`diagnostics`/`definition`/`references`/etc. → `allow`), DAP debug inspection actions (`threads`/`stack_trace`/`variables`/`scopes`/`read_memory`/etc. → `allow`), and critical bash patterns (`rm -rf /`, `sudo rm`, fork bombs, `chmod -R 777 /`, `chown -R user /`, `curl ... | bash`, `bash <(curl ...)`, writes to `/etc/passwd|shadow|sudoers`, `shutdown`/`reboot`/`halt`/`init 0`/`kill -9 1`, `nc -e`/`nc -c` reverse shells → always `prompt`, even when bash is user-allowed).
2056
- - Added approval check in `ExtensionToolWrapper.execute()` ahead of extension `tool_call` handlers, with an actionable error in non-interactive sessions (`--auto-approve` / `tools.approval.<tool>: allow` guidance).
2057
- - Added MCP-tool labelling and bash/ssh command truncation in the approval prompt so `mcp__<server>__<tool>` calls are tagged as MCP server tools and a heredoc-sized command body doesn't blow out the confirmation dialog.
2058
- - Added `docs/approval-mode.md` user guide and a 57-case unit suite covering the resolution order, every critical-bash pattern (with benign-keyword negatives to lock false-positives out), user-config validation, and prompt formatting.
2059
- - Added `tools.approvalMode` global setting (Interaction tab in `/settings`) with values `auto` | `prompt` | `custom`. Defaults to `auto` so the agent runs every tool call without interruption — matching the `--auto-approve` / `--yolo` CLI flag. `prompt` uses built-in per-tool defaults only (read/find/search auto-allow; bash/edit/write/eval/ssh require confirmation; `tools.approval.<tool>` config is ignored). `custom` makes the `tools.approval.<tool>` config the source of truth — your settings win over built-in defaults, which fall back only for tools you haven't configured. CLI `--auto-approve` always wins. Critical safety patterns (e.g. `rm -rf /`, `curl … | bash`, fork bombs) keep prompting even when the tool is user-allowed.
2060
- - Extended `CRITICAL_BASH_PATTERNS` to cover `source <(curl …)` / `. <(curl …)` and `eval "$(curl …)"` / `eval $(curl …)` / ``eval `curl …` `` (all common remote-fetch-then-execute shapes that the original `bash <(curl …)` regex missed), `chmod -R` symbolic modes (`u+x`, `u+rwx,o+w`) targeting filesystem root, and `tee` / `tee -a` writes to `/etc/{passwd,shadow,sudoers}`. Benign forms (`source ./local.sh`, `find . -name foo`, `chmod -R u+x ./build`, `tee /var/log/app.log`, `eval "$VAR"`) are pinned negative in the suite so future expansion can't regress false-positive rate.
2061
- - Extended `formatApprovalPrompt` with payload previews for `eval` (language + first cell's code), `task` (agent + first task's id + assignment), `ast_edit` (first op's pattern / replacement / paths), `browser` (action + tab + url + code), and `write` content (alongside path). Previously these all rendered as bare `Allow tool: <name>` lines, giving the user no signal about what they were authorizing.
2062
- - Decoupled the per-tool approval gate from extension-loading state: `ExtensionRunner` and the `ExtensionToolWrapper` per-tool gate are now constructed unconditionally in `createAgentSession`, regardless of whether any extensions are loaded. Previously the runner was created only when `extensionsResult.extensions.length > 0`, which silently disabled the entire approval system if no extensions (including `createAutoresearchExtension`) were loaded; a regression test in `approval-mode.test.ts` now locks the invariant.
2063
1909
 
2064
1910
  ### Changed
2065
1911
 
@@ -2072,34 +1918,13 @@
2072
1918
 
2073
1919
  ### Fixed
2074
1920
 
2075
- - Fixed `isMcpToolName` over-matching any tool name containing `__` (an extension legally named `my__feature` or `pkg__util__do` was getting falsely labelled `Origin: MCP server tool` in the approval prompt). Restricted to the canonical `mcp__` prefix only.
2076
1921
  - Fixed hashline inline payload parsing so same-line payloads containing whitespace, including tab-indented text, are preserved instead of being rejected
2077
1922
  - Fixed Bun HTTP/2 transport errors (`HTTP2StreamReset`, `HTTP2RefusedStream`, and `HTTP2EnhanceYourCalm`) to be treated as transient so the assistant now retries automatically instead of stopping on these recoverable failures
2078
1923
  - Fixed web search OAuth-backed providers (including Codex and Gemini) to use broker-managed token retrieval and account metadata, avoiding direct token-store refresh behavior that could cause search authentication failures
2079
1924
  - Updated Tavily missing-credential feedback to prompt users to configure an API-key provider setting instead of referencing `agent.db` directly
2080
1925
  - Refreshed expired OpenAI Codex OAuth tokens during `web_search` execution and persisted the updated credentials so searches continue working after token expiry
2081
- - Fixed the browser tool's existing-tab re-navigation path (`tab-supervisor.acquireTab`) still defaulting to `waitUntil: "networkidle2"` while the new-tab worker switched to `"load"`. Identical `acquireTab({url})` calls behaved differently depending on whether the named tab was fresh or being reused — fresh tabs returned quickly, second invocations hung on dev servers with persistent WebSocket / HMR connections. Both paths now agree on `"load"`.
2082
- - Fixed the `patch` tool's post-write verification `ToolError` embedding the absolute `resolvedPath` in its user-facing message; the outer composer in `executeSinglePathEntries` then prepended `Error editing ${path}: …`, double-embedding the path and leaking `$HOME` into the TUI. The error message now uses the caller-supplied relative `path` (matching the success branches); `resolvedPath` is retained only in the structured `context` metadata for log correlation.
2083
- - Fixed `splitInternalUrlSel` keeping `mcp://` resource URIs fully opaque, including selector-shaped suffixes like `:raw`, `:1-50`, and `/:raw`. `McpProtocolHandler` resolves resources by verbatim URI match (`r.uri === uri`), so peeling before resource lookup can make valid server-defined resource IDs unreachable. MCP read-selector support now requires a future resolver-aware path that can try the exact URI before interpreting any suffix as a selector; non-MCP internal URL selectors are unchanged.
2084
- - Fixed three correctness issues in the `find` tool. (1) `onMatch` guard checked the outer task `signal?.aborted` instead of `combinedSignal.aborted` (which also includes the per-call timeout signal), so late matches accumulated past the timeout. (2) Timeout-drained partial results were emitted in insertion order while the normal path sorts by mtime descending; callers relying on "most recently modified first" got an inconsistent ordering when the call timed out. The timeout drain now tracks per-entry mtime in a parallel array and applies the same comparator. (3) `validateFindPathInputs` now skips backslash-escaped commas (`\,`) when checking for top-level commas, matching `search.ts:containsTopLevelComma`.
2085
- - Fixed `throwPreferredDapStartError` using a single `await Promise.resolve()` (one microtask) to let a concurrent launch/attach rejection settle before deciding which error to surface. That worked for synchronous-rejection test fakes but not real adapter I/O: the launch failure arrives via socket and lands several ticks after the `configurationDone` failure. `DapStartRequestFailure` now carries a `settled?: Promise<void>` that resolves when the underlying request settles either way, and `throwPreferredDapStartError` races against it with a 50 ms ceiling. The preferred error message (the underlying launch/attach failure rather than the cascade) now surfaces under real I/O.
2086
- - Fixed `adapter: "debugpy"` over-promising in the `debug` tool. `resolveAdapter("debugpy", cwd)` only checks for `python` in `PATH`; it does not verify that the `debugpy` module is importable. Both failure modes — `python` missing and `debugpy` module missing — used to collapse onto a generic `"No suitable debug adapter found"` error. The launch/attach action now throws a targeted `ToolError` naming `python` when `resolveAdapter` returns null for an explicit `adapter: "debugpy"`, and the `DapSessionManager` spawn-catch detects `"No module named debugpy"` in adapter stderr and surfaces a `pip install debugpy` hint. The Python debug tool documentation lists the install hint so the prompt and runtime diagnostics agree.
2087
- - Fixed the LSP symbol-resolver `BARE_IDENTIFIER_RE` (`/^[A-Za-z_][\w]*$/`) rejecting `$`-prefixed identifiers (`$store`, `$count`, RxJS observables, Svelte stores, Angular signals). Without the word-boundary check, searching for `$store` on a line containing `bar$store` returned the offset inside the compound identifier rather than the standalone occurrence, feeding a wrong column to the LSP server. Pattern now `/^[$A-Za-z_][\w$]*$/`; the companion `IDENTIFIER_CHAR_RE` already contained `$`.
2088
- - Fixed `applyWorkspaceEdit` writing all text edits before walking `documentChanges` for resource operations. LSP §3.16.2 requires clients to apply `documentChanges` in declared order, so any server emitting `{kind: "create", uri: X}` followed by a `TextDocumentEdit` for `X` (e.g. "Extract to new file" code actions, some rename responses) broke: the edit ran against a non-existent file, then the create happened. `applyWorkspaceEdit` now walks `documentChanges` once in declared order; per-URI text edits are coalesced into a pending Map and flushed immediately before any subsequent resource op for the same URI. Legacy `changes`-map-only payloads are unchanged. Folder-level `rename`/`delete` ops now flush every pending URI under the affected subtree (not just the exact target) so child-file edits queued before a parent-folder move land at the original location instead of dangling against a non-existent path on the final flush. Rename ops additionally flush pending edits queued against `renameOp.newUri` (and its descendants) **before** `fs.rename` runs, so edits intended for the pre-rename target file are applied before the rename clobbers or replaces it (relevant under `options.overwrite`/`options.ignoreIfExists`). When a `WorkspaceEdit` payload supplies both `changes` and `documentChanges`, the `documentChanges` arm is now used exclusively per LSP §3.16.2 ("if documentChanges are supplied … servers should use them in preference to changes"); previously the two were merged.
2089
1926
  - Fixed built-in `explore` agent failing every invocation with `schema_violation: files.0.ref: must not be present` on releases prior to 15.3.2 by renaming the `files[].ref` property to `files[].path` in the agent's output schema; `ref` is a JTD-reserved keyword (RFC 8927) and collides with JSON Type Definition's schema-reference form, so the converter previously dropped it from the generated JSON Schema. Defense-in-depth alongside the 15.3.2 converter fix ([#1379](https://github.com/can1357/oh-my-pi/issues/1379)).
2090
1927
  - Increased the `yield` tool's schema-validation retry budget from 1 to 3 so subagents whose first structured-output attempt mismatches the declared output schema get up to three retries before the parent's post-mortem `schema_violation` check hard-fails the task. The tool now also surfaces remaining retry attempts and an explicit "call yield again with the corrected shape" directive in each rejection message, giving the model the context it needs to converge — particularly helpful for models like GLM that tend to invent per-element field names instead of following the declared schema.
2091
- - Fixed CLI PDF file arguments being decoded as raw bytes for local vision models; `.pdf` and other supported document files now go through the same Markit conversion path as the `read` tool before entering the prompt ([#1401](https://github.com/can1357/oh-my-pi/issues/1401)).
2092
- - Fixed the `bash` tool hanging until the 305 s hard timeout when a command writes a file via heredoc on Windows (bodies > ~4 KiB) or macOS (bodies > 16-64 KiB). Root cause was in the embedded brush shell; see `@oh-my-pi/pi-natives` changelog for the underlying fix.
2093
- - Fixed `/review` custom prompt orchestration text to use static prompt templates and consistently instruct reviewer task delegation.
2094
- - Fixed `/review` custom-instructions submission on terminals that cannot distinguish Ctrl+Enter by using prompt-style input where Enter submits and Shift+Enter inserts a newline.
2095
- - Fixed hook editor submissions sending large-paste placeholders such as `[paste #1 +27 lines]` instead of the pasted content.
2096
- - Added per-tool approval policies with a `--auto-approve` (alias `--yolo`) CLI flag to bypass confirmation prompts for automation. Each tool call resolves a policy of `allow` / `deny` / `prompt` via a six-level lookup: overriding action exceptions, validated user config, non-overriding action exceptions, built-in defaults, validated user `_default`, and a system `prompt` fallback.
2097
- - Added `tools.approval.<toolName>: allow | deny | prompt` user config support via the settings schema. Invalid values (non-strings, unknown literals) are now ignored and fall through to the built-in default instead of being silently honoured — preventing a typo from locking the user out of a tool or bypassing approval for one.
2098
- - Added action-based exception registry covering LSP read-only actions (`diagnostics`/`definition`/`references`/etc. → `allow`), DAP debug inspection actions (`threads`/`stack_trace`/`variables`/`scopes`/`read_memory`/etc. → `allow`), and critical bash patterns (`rm -rf /`, `sudo rm`, fork bombs, `chmod -R 777 /`, `chown -R user /`, `curl ... | bash`, `bash <(curl ...)`, writes to `/etc/passwd|shadow|sudoers`, `shutdown`/`reboot`/`halt`/`init 0`/`kill -9 1`, `nc -e`/`nc -c` reverse shells → always `prompt`, even when bash is user-allowed).
2099
- - Added approval check in `ExtensionToolWrapper.execute()` ahead of extension `tool_call` handlers, with an actionable error in non-interactive sessions (`--auto-approve` / `tools.approval.<tool>: allow` guidance).
2100
- - Added MCP-tool labelling and bash/ssh command truncation in the approval prompt so `mcp__<server>__<tool>` calls are tagged as MCP server tools and a heredoc-sized command body doesn't blow out the confirmation dialog.
2101
- - Added `docs/approval-mode.md` user guide and a 57-case unit suite covering the resolution order, every critical-bash pattern (with benign-keyword negatives to lock false-positives out), user-config validation, and prompt formatting.
2102
- - Added `tools.approvalMode` global setting (Interaction tab in `/settings`) with values `auto` | `prompt` | `custom`. Defaults to `auto` so the agent runs every tool call without interruption — matching the `--auto-approve` / `--yolo` CLI flag. `prompt` uses built-in per-tool defaults only (read/find/search auto-allow; bash/edit/write/eval/ssh require confirmation; `tools.approval.<tool>` config is ignored). `custom` makes the `tools.approval.<tool>` config the source of truth — your settings win over built-in defaults, which fall back only for tools you haven't configured. CLI `--auto-approve` always wins. Critical safety patterns (e.g. `rm -rf /`, `curl … | bash`, fork bombs) keep prompting even when the tool is user-allowed.
2103
1928
 
2104
1929
  ## [15.3.2] - 2026-05-25
2105
1930
 
@@ -2122,10 +1947,6 @@
2122
1947
  - Added `OMP_NO_WEBP` environment variable to disable WebP encoding in image resize, fixing HTTP 400 errors when attaching browser snapshots to vision models running on local llama.cpp (which uses STB library that lacks WebP support)
2123
1948
  - Fixed loop mode submitting the next prompt while a background async-job delivery turn (idle flush) was still pending, which could cause the job result to be silently dropped and make the session appear to keep firing while work was ongoing ([#1294](https://github.com/can1357/oh-my-pi/issues/1294))
2124
1949
  - Fixed clipboard image paste (Ctrl+V) silently failing on WSL2 by routing image reads through a `powershell.exe` bridge when WSL interop is detected, since `arboard` returns `ContentNotAvailable` under WSLg ([#1280](https://github.com/can1357/oh-my-pi/issues/1280))
2125
- - Fixed `bash` tool timeout and ESC cancellation getting stuck when native shell cleanup stalls; the JavaScript-side deadline now returns the tool result on schedule while native cleanup continues in the background ([#1347](https://github.com/can1357/oh-my-pi/issues/1347))
2126
- - Fixed reviewer agent always failing JTD validation with `findings.0.priority: expected number, received string` whenever `report_finding` surfaced a finding; the tool's `"P0"`-`"P3"` priority is now coerced to its numeric ordinal before populating the auto-injected `findings[]` ([#1350](https://github.com/can1357/oh-my-pi/issues/1350))
2127
- - Fixed config-only marketplace LSP plugins such as `csharp-lsp` not registering servers with the CLI when the plugin cache has only marketplace metadata and no package code ([#1352](https://github.com/can1357/oh-my-pi/issues/1352)).
2128
- - Fixed JTD-to-JSON-Schema conversion treating user-named properties as nested JTD forms when their keys collided with JTD keywords like `ref`, which broke the built-in explore agent's output validator with `schema_violation: files.0.ref: must not be present` ([#1345](https://github.com/can1357/oh-my-pi/issues/1345))
2129
1950
  - Fixed extension `ctx.ui.notify()` messages emitted during `session_start` being cleared before the first interactive render ([#1316](https://github.com/can1357/oh-my-pi/issues/1316)).
2130
1951
  - Fixed append-only context mode not being recomputed after model switches — the mode was frozen at session construction time using the initial model's provider, so `provider.appendOnlyContext=auto` left append-only enabled after switching away from DeepSeek (or disabled after switching to DeepSeek) for the rest of the session
2131
1952
 
@@ -2210,10 +2031,6 @@
2210
2031
 
2211
2032
  ## [15.1.9] - 2026-05-21
2212
2033
 
2213
- ### Added
2214
-
2215
- - Added OSC 8 terminal hyperlink support for file paths in tool output. When the terminal supports hyperlinks (kitty, Ghostty, WezTerm, iTerm2, Alacritty, VS Code) and the new `tui.hyperlinks` setting is `auto` (default) or `always`, OMP wraps file paths emitted by `read`, `find`, `search`, `edit`, `ast_grep`, and `ast_edit` renderers in `file:///abs/path` hyperlinks. `local://` and other fs-backed internal URLs resolve to their backing path. Set `tui.hyperlinks: off` to disable. ([#1244](https://github.com/can1357/oh-my-pi/issues/1244))
2216
-
2217
2034
  ### Fixed
2218
2035
 
2219
2036
  - Fixed `disabledProviders` still probing local discovery endpoints for Ollama, llama.cpp, and LM Studio during background model refresh. Disabled providers are now excluded before implicit and built-in discovery managers are created. ([#1232](https://github.com/can1357/oh-my-pi/issues/1232))
@@ -2228,10 +2045,16 @@
2228
2045
 
2229
2046
  - Fixed streaming edit previews for `apply_patch` and `hashline` jittering as the model typed `+added` lines. Two root causes addressed: (1) the trailing partial line of the streaming text input is now trimmed at each tick so a half-typed `+added` line no longer flickers; (2) the preview is rendered in the model's input order during streaming instead of re-deriving a unified diff via `Diff.structuredPatch`, whose coalescing previously reshuffled existing `+added` lines downward each time a new `-removed` line arrived. Existing additions now stay put and the preview only grows at the bottom while streaming. A residual trailing `-removed`/hunk-header block whose matching `+added` companion has not yet arrived is also suppressed until the additions land.
2230
2047
  - Fixed Perplexity web search appearing "logged out" roughly an hour after `omp auth login perplexity`. The search provider's `findOAuthToken` was honoring the bogus `expires = login_time + 1h` written by older logins (Perplexity JWTs typically omit `exp` because sessions are server-side) and silently dropping the credential. The loader now decodes the JWT's `exp` claim directly and only skips when the JWT itself is expired; tokens without an `exp` claim are treated as non-expiring.
2231
- - Fixed `legacy-pi-compat` failing to load plugin extensions (e.g. `pi-schedule-prompt@0.3.0`) that import `@mariozechner/pi-ai` when running from a compiled binary. `getResolvedSpecifier` called `Bun.resolveSync` against `import.meta.dir` inside `/$bunfs/root`, where the virtual FS exposes no resolvable `node_modules` tree at runtime; the throw silently dropped the plugin. The fix lets `rewriteLegacyPiImports` fall back gracefully on resolution failure so that `rewriteBareImportsForLegacyExtension` — which already runs immediately after — can resolve the original specifier against the plugin's own installed peer deps instead. The same fallback is applied to `resolveLegacyPiSpecifier` (the Bun plugin shim's `onResolve` handler) for tool/hook files loaded directly via Bun's import system. ([#1215](https://github.com/can1357/oh-my-pi/issues/1215))
2232
2048
 
2233
2049
  ## [15.1.7] - 2026-05-19
2234
2050
 
2051
+ ### Fixed
2052
+
2053
+ - Fixed `debug` launch/attach failures so `configurationDone` no longer masks the underlying DAP launch error, early stop-outcome watchers cannot emit unhandled rejections, and directory-valued launch programs are rejected before adapter selection. ([#1187](https://github.com/can1357/oh-my-pi/issues/1187))
2054
+ - Fixed hashline edit payloads that use a readability space after `~` by warning on separator-padding-shaped payload blocks and tightening the model prompt. ([#1166](https://github.com/can1357/oh-my-pi/issues/1166))
2055
+ - Fixed ACP bash permission requests to include execute tool metadata and command content so clients can render command approval prompts consistently. ([#1189](https://github.com/can1357/oh-my-pi/issues/1189))
2056
+ - Fixed the status-line fast-mode indicator (`⚡`) rendering for scoped service tiers (`openai-only`, `claude-only`) even when the active model's provider didn't realize them — e.g. `serviceTier: "openai-only"` would still show the indicator next to a Claude model the wire request couldn't apply fast mode to. The indicator now consults a new `AgentSession.isFastModeActive()` predicate that runs the configured tier through `resolveServiceTier(tier, model.provider)` and only lights up when the result is `"priority"` for the current model. `isFastModeEnabled()` keeps its scope-aware semantics so `/fast on|off|toggle` and `/fast status` continue to reflect the user's configured intent.
2057
+
2235
2058
  ### Added
2236
2059
 
2237
2060
  - Added scoped service tier values to the `serviceTier` setting: `priority (OpenAI only)` and `priority (Claude only)`. They let you opt into premium processing on one provider family without paying premium costs on the other when switching models mid-session. `/fast on` continues to set the unscoped `"priority"` (active everywhere supported); `/fast status` and `isFastModeEnabled()` now report `on` for any scoped value too.
@@ -2240,14 +2063,6 @@
2240
2063
 
2241
2064
  - Changed `/fast` to be a single provider-agnostic toggle: enabling the command sets `serviceTier: "priority"` for every provider, and the anthropic-messages provider translates `priority` into `speed: "fast"` plus the `fast-mode-2026-02-01` beta. Anthropic fast mode is currently supported on Claude Opus 4.6 and 4.7; the server rejects other models, which triggers the provider's auto-fallback (request retried without the priority signal, `providerSessionState.fastModeDisabled` persisted for the rest of the session). The session listens for the `"priority"` marker in `AssistantMessage.disabledFeatures`, syncs `/fast` off, and emits a warning notice. Re-running `/fast on` clears the per-session disable so the next request actually re-tries priority.
2242
2065
 
2243
- ### Fixed
2244
-
2245
- - Fixed `debug` launch/attach failures so `configurationDone` no longer masks the underlying DAP launch error, early stop-outcome watchers cannot emit unhandled rejections, and directory-valued launch programs are rejected before adapter selection. ([#1187](https://github.com/can1357/oh-my-pi/issues/1187))
2246
- - Fixed hashline edit payloads that use a readability space after `~` by warning on separator-padding-shaped payload blocks and tightening the model prompt. ([#1166](https://github.com/can1357/oh-my-pi/issues/1166))
2247
- - Fixed ACP bash permission requests to include execute tool metadata and command content so clients can render command approval prompts consistently. ([#1189](https://github.com/can1357/oh-my-pi/issues/1189))
2248
- - Fixed the status-line fast-mode indicator (`⚡`) rendering for scoped service tiers (`openai-only`, `claude-only`) even when the active model's provider didn't realize them — e.g. `serviceTier: "openai-only"` would still show the indicator next to a Claude model the wire request couldn't apply fast mode to. The indicator now consults a new `AgentSession.isFastModeActive()` predicate that runs the configured tier through `resolveServiceTier(tier, model.provider)` and only lights up when the result is `"priority"` for the current model. `isFastModeEnabled()` keeps its scope-aware semantics so `/fast on|off|toggle` and `/fast status` continue to reflect the user's configured intent.
2249
- - Fixed status-line context% computation freezing the UI for ~1.1 s every 2 s on long sessions (2,000+ messages). The earlier alignment fix (which uses `computeContextBreakdown` to match the `/context` slash command) was running on every agent event via `updateEditorTopBorder()` (event-controller.ts:163), and `computeContextBreakdown` walks every message through the native `countTokens` tokenizer (~0.5 ms each) — for the user's 2,312-message session this was ~1,120 ms synchronous blocking per cache miss, producing the user-visible "jittery rendering" and "status bar disappearing during streaming". `StatusLineComponent.getCachedContextBreakdown()` now uses an incremental per-message token cache: messages are walked ONCE during warm-up, and subsequent refreshes only compute tokens for the NEW messages appended since last call (typically 0–1 per refresh during streaming). The LAST message is always recomputed because its content may still be growing mid-stream; all prior messages are immutable once a newer message exists. Compaction (messages array shrinks) resets the cache. Non-message tokens (system prompt + tools + skills) are cached separately and invalidated via a cheap identity fingerprint. Result: 2,300-message warm refresh drops from ~1,120 ms to ~0.04 ms — 28,000× faster. Functional parity with the prior `computeContextBreakdown` path is preserved.
2250
-
2251
2066
  ## [15.1.6] - 2026-05-19
2252
2067
 
2253
2068
  ### Fixed
@@ -2266,14 +2081,12 @@
2266
2081
 
2267
2082
  - Fixed `normalizePlanTitle` rejecting plan titles that contain spaces or common punctuation (e.g. "My Feature Plan") — spaces are now converted to hyphens and other invalid characters are dropped, so models that produce natural-language plan titles no longer loop forever trying to call `resolve`. ([#1176](https://github.com/can1357/oh-my-pi/issues/1176))
2268
2083
  - Fixed `ask` tool prompt example showing the legacy `question`/`options` top-level format instead of the current `questions: [{id, question, options}]` array format; models that closely followed the example generated calls that always failed schema validation. ([#1176](https://github.com/can1357/oh-my-pi/issues/1176))
2269
-
2270
2084
  - Fixed ACP command and custom tool-call notifications to carry the original tool arguments in replayed and final updates, so command text is preserved and raw input is no longer wrapped
2271
2085
  - Fixed ACP async-job draining to be scoped by session owner so `getAsyncJobSnapshot` and `drainAsyncJobDeliveriesForAcp` no longer consume or expose jobs from other sessions
2272
2086
  - Fixed async job status reporting to include in-flight completions so queued/delivering indicators remain accurate while callbacks are still running
2273
2087
  - Fixed `deferAgentInitiatedTurns` handling during ACP async-job draining so background completion follow-up turns are delivered even when agent-initiated turns are deferred
2274
2088
  - Fixed ACP ordinary file-editing calls (`edit`, `write`, `ast_edit`) incorrectly requesting `session/request_permission` before every call, while keeping permission prompts for edit operations that delete or move files; permission requests now report the gated tool call as `pending` so clients can render the approval UI instead of returning `Permission request cancelled` without a visible prompt. ([#1134](https://github.com/can1357/oh-my-pi/pull/1134) by [@jiwangyihao](https://github.com/jiwangyihao))
2275
2089
  - Fixed the session tree selector to preserve a readable message column when deeply nested branch gutters would otherwise consume the viewport. ([#1144](https://github.com/can1357/oh-my-pi/issues/1144))
2276
- - Fixed the TUI model selector to keep provider tab labels separate from provider ids, so the human-readable Ollama Cloud tab refreshes and filters `ollama-cloud` models correctly. ([#1153](https://github.com/can1357/oh-my-pi/issues/1153))
2277
2090
 
2278
2091
  ## [15.1.3] - 2026-05-17
2279
2092
 
@@ -2317,7 +2130,6 @@
2317
2130
  - Fixed gateway usage reporting to include cached-token totals for OpenAI Chat/Responses and to serve the last good cached report during transient upstream usage fetch failures.
2318
2131
  - Fixed auth-gateway request cancellation for requests that are already aborted before dispatch.
2319
2132
  - Fixed `/login` and `/logout` provider selector overflowing tall provider lists off-screen on small terminals. The selector now scrolls a 10-item window centered on the highlighted entry, shows a `(n/total)` indicator when windowed, and accepts PageUp/PageDown for faster navigation.
2320
- - Fixed `.env` loading so malformed variable names and NUL-containing values are ignored before they can poison `Bun.env` and break bash/external process execution with `nul byte found in provided data`.
2321
2133
 
2322
2134
  ## [15.1.2] - 2026-05-15
2323
2135
 
@@ -2408,7 +2220,6 @@
2408
2220
 
2409
2221
  ### Fixed
2410
2222
 
2411
- - Fixed hashline pure inserts to drop a single echoed anchor line when `edit.hashlineAutoDropPureInsertDuplicates` is enabled and `+ ANCHOR` payloads start with the anchor line or `< ANCHOR` payloads end with it, while preserving intentional single-line duplicates by default. ([#1090](https://github.com/can1357/oh-my-pi/issues/1090))
2412
2223
  - Fixed bash command fixups to remove a redundant standalone trailing `2>&1` redirect when no other pipe or redirection remains
2413
2224
  - Fixed command-fixup notices to list all stripped segments instead of reporting only one
2414
2225
  - Fixed summarized `read` output stalling agents on elided regions by appending an explicit footer like `[NN lines across MM elided regions; read <path>:raw or a line range like <path>:1-9999 for verbatim content]`. The footer fires whenever the structural summarizer elided at least one span, so the model gets a concrete recovery selector instead of having to guess from a bare `...` / `{ .. }` marker. Surfaces `elidedLines` on `ReadToolDetails.summary` alongside the existing `elidedSpans`. ([#1046](https://github.com/can1357/oh-my-pi/issues/1046))
@@ -2435,7 +2246,6 @@
2435
2246
  - Added per-line column cap shared across streaming tool outputs (`bash`, `ssh`, `python`, `js eval`) and the `read` tool. Lines wider than `tools.outputMaxColumns` bytes (default **768**) are ellipsis-truncated at write time and remaining bytes up to the next `\n` are dropped — bounded memory even on multi-MB single-line outputs (e.g. `cat /dev/urandom`). The cap lives on `OutputSink` as the new `maxColumns` option, persists state across chunk boundaries so split-mid-line writes still respect the budget, and exposes `columnDroppedBytes` / `columnTruncatedLines` on `OutputSummary`. Middle-elision byte math subtracts column drops so the "elided from middle" count stays honest. `read` reuses the same setting but trims its already-collected lines via `truncateLine`. Skipped when the read selector is `:raw`. The artifact file (`artifact://<id>`) keeps the full uncapped stream. Set `tools.outputMaxColumns = 0` to disable.
2436
2247
  - Added Bun HTTP/2 fetch opt-in. Dev scripts (`bun run dev`, `bun run stats`) now pass `bun --experimental-http2-fetch` so every `fetch()` advertises `h2` in the TLS ALPN list and falls back to HTTP/1.1 when the server doesn't select it. Multiplexing collapses parallel requests to the same origin onto one TLS connection. For the installed `omp` binary, export `BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP2_CLIENT=1` in your shell to enable the same behavior (the flag has to be set before Bun starts; `process.env` from inside JS is too late). Requires Bun **1.3.14**.
2437
2248
  - Added per-subagent cost display (`$X.XX` in the task progress tree and the session-observer stats line). Cost is accumulated incrementally from `message_end` events and shown only when non-zero, using the `statusLineCost` theme color. Providers that do not report per-turn cost data (e.g. subscription/OAuth usage) continue to show nothing.
2438
- - Added ACP elicitation bridge so skills/extensions calling `select`, `confirm`, or `input` on the extension UI context now produce real `unstable_createElicitation` form requests to the ACP client (rather than always resolving to `undefined` / `false`). The `acpExtensionUiContext` constant is promoted to `createAcpExtensionUiContext(connection, getSessionId, clientCapabilities)` — invoked once per session inside `#configureExtensions`, with `getSessionId: () => string` so the live `record.session.sessionId` is read on every elicitation (the underlying id mutates when an extension command calls `ctx.newSession` / `ctx.switchSession`). Each method maps to a single-property `value` schema: `select` → `{type: "string", enum}`, `confirm` → `{type: "boolean"}` (joined `title` + `message` when the trimmed message is non-empty; otherwise just `title`), `input` → `{type: "string", description: placeholder?}` (ACP has no `placeholder` field on `StringPropertySchema`; empty / whitespace-only placeholders are treated as absent). `accept` responses narrow the returned `ElicitationContentValue` back to the method's declared type with a runtime `typeof` guard; `decline` / `cancel` / transport failures fall back to the prior stub return values. `dialogOptions.signal` is honored: an already-aborted signal short-circuits before any SDK round-trip, and an abort mid-flight races against the elicitation so the caller's promise resolves to the stub fallback (the ACP request itself keeps running on the client side — the SDK exposes no form-mode cancel surface; `unstable_completeElicitation` is URL-mode only — matching the in-flight pattern used by `requestRpcEditor`). `dialogOptions.timeout` is honored on parity with `RpcExtensionUIContext`: when the timer fires before the client responds, `onTimeout` is invoked and the caller resolves to the stub fallback. A throwing `onTimeout` is caught and logged (`logger.warn`) so the elicitation promise still settles. Late SDK rejections that arrive after abort/timeout are dropped silently to keep operator logs clean; transport failures still emit `logger.warn` with `{ sessionId, method, error }`. Calls are skipped when the client did not advertise `clientCapabilities.elicitation.form` during `initialize`, so non-elicitation clients are unaffected. `createAcpExtensionUiContext` is exported for tests.
2439
2249
 
2440
2250
  ### Changed
2441
2251
 
@@ -2478,7 +2288,7 @@
2478
2288
  - Added `pr://<N>/diff`, `pr://<N>/diff/<i>`, and `pr://<N>/diff/all` internal-URL shapes covering changed-file listings, per-file slices, and the full unified diff. They share one `pr-diff` SQLite cache row with the same TTL knobs as `pr://<N>` views (`github.cache.softTtlSec` / `github.cache.hardTtlSec` / `github.cache.enabled`). Single PR views now advertise the diff entry point via a `Diff: pr://<owner>/<repo>/<N>/diff` note. Cache schema bumped to `user_version = 3`; older rows are dropped on first open to add credential-scoped keys and relax the `kind` CHECK constraint.
2479
2289
  - Added `issue://` / `pr://` internal-URL schemes that share a SQLite-backed cache with the rest of the `github` tool. Single-item reads (`issue://<N>`, `issue://<owner>/<repo>/<N>`) return rendered markdown and within `github.cache.softTtlSec` (default 5 minutes) skip the `gh` round-trip entirely; within `github.cache.hardTtlSec` (default 7 days) the cached row is returned and a background refresh is scheduled. Root and repo-scoped reads (`issue://`, `pr://owner/repo`) issue a live `gh issue list` / `gh pr list` for browsing, supporting `?state=open|closed|all` for issues, `?state=open|closed|merged|all` for PRs, and `?limit=`, `?author=`, `?label=` query params. Rendered output lands in `~/.omp/cache/github-cache.db` (override via `OMP_GITHUB_CACHE_DB`); disable the cache entirely with `github.cache.enabled = false`. Cwd→default-repo lookups (`gh repo view`) are memoized per-process.
2480
2290
  - Added new `Approve and compact context` choice to the ExitPlanMode approval selector. Sits between `Approve and execute` (purge session) and `Approve and keep context` (full transcript) — runs `/compact` on the plan-mode transcript with a planning-specific summarization hint, then dispatches the plan-approved execution turn so it lands on a fresh cache anchor with the summarized rationale carried over. Cancelling the compaction (Esc or any other abort source) defers the execution dispatch and surfaces a warning so the operator can resubmit manually; non-abort failures proceed best-effort.
2481
- - Added `CompactionCancelledError` typed sentinel and `CompactionOutcome` (`"ok" | "cancelled" | "failed"`) return type to `@oh-my-pi/pi-agent-core/compaction`. `CommandController.executeCompaction` and `handleCompactCommand` now return the outcome instead of `void` so callers can discriminate user-driven aborts from generic failures without inspecting error messages.
2291
+ - Added `CompactionCancelledError` typed sentinel and `CompactionOutcome` (`"ok" | "cancelled" | "failed"`) return type to `@oh-my-pi/pi-coding-agent/session/compaction`. `CommandController.executeCompaction` and `handleCompactCommand` now return the outcome instead of `void` so callers can discriminate user-driven aborts from generic failures without inspecting error messages.
2482
2292
  - Added a `credential_disabled` extension event so extensions can subscribe via `pi.on("credential_disabled", handler)` and react when `AuthStorage` automatically soft-disables a credential (e.g. OAuth `invalid_grant`). Replaces the current `agent_end` errorMessage regex pattern downstream extensions have to match against. Handler payload is `{ type, provider, disabledCause }`. `createAgentSession()` subscribes the per-session extension runner to the shared `AuthStorage` via `authStorage.onCredentialDisabled(...)` at the very top of session creation — before any startup model probes run — so events fire on every disable regardless of whether the embedder also has a constructor `onCredentialDisabled` handler attached. The SDK forwards through `ExtensionRunner.emitCredentialDisabled(event)`, which buffers events until `runner.initialize(...)` runs in the mode controller and then flushes them through `emit()` so extension handlers see populated UI/runtime context (rather than the constructor's no-op default with `hasUI=false`, an unset model, and no-op runtime actions). On `session.dispose()` the subscription is unsubscribed; the embedder's constructor-attached listener keeps firing through its own permanent subscription. The outer `createAgentSession()` catch also releases the subscription if startup throws before the dispose-wrap is wired, so repeated retries don't accumulate dead listeners.
2483
2293
  - Added `omp acp` subcommand for launching as an ACP (Agent Client Protocol) server over stdio
2484
2294
  - Added explicit `type` discriminators to ACP `initialize` auth methods, including a `terminal` setup method gated on `clientCapabilities.auth.terminal`
@@ -2746,13 +2556,9 @@
2746
2556
 
2747
2557
  - Moved hashline APIs to the dedicated `@oh-my-pi/pi-coding-agent/hashline` module, moved hash helpers to `@oh-my-pi/pi-coding-agent/hashline/hash`, and removed the legacy `edit/modes/hashline` and `edit/line-hash` source subpaths.
2748
2558
 
2749
- ### Added
2559
+ ### Removed
2750
2560
 
2751
- - Added a debug-panel raw SSE stream viewer so stuck model/tool-call streams can be inspected live from the TUI.
2752
- - Added `get_login_providers` RPC command to list registered OAuth providers with their current authentication status (`id`, `name`, `available`, `authenticated`)
2753
- - Added `login` RPC command to trigger OAuth login for a given provider; emits an `open_url` extension UI event (fire-and-forget) carrying the auth URL and optional instructions so headless clients can open the browser, then resolves when the callback-server flow completes
2754
- - Added `open_url` variant to `RpcExtensionUIRequest` for the above
2755
- - Added `getLoginProviders()` and `login(providerId)` methods to `RpcClient`
2561
+ - Removed hashline auto-rebase. Anchor mismatches now reject immediately so the model re-reads instead of silently relocating an edit to a hash-collision within ±5 lines, which could otherwise apply the change to the wrong region. Stale-anchor recovery via the cached read snapshot is unaffected.
2756
2562
 
2757
2563
  ### Fixed
2758
2564
 
@@ -2769,9 +2575,13 @@
2769
2575
  - Fixed sub-agent dispatch silently routing to a model whose provider has no working credentials (e.g. an unqualified `modelRoles.task` id like `qwen3.6-plus-free` resolving to a provider the user is not authenticated against). Task dispatch now falls back to the parent session's active model — which by definition has working auth — when the resolved subagent model has none ([#985](https://github.com/can1357/oh-my-pi/issues/985)).
2770
2576
  - Fixed legacy Pi plugin extensions failing to load on Windows when their entry path contains a drive letter ([#990](https://github.com/can1357/oh-my-pi/pull/990) by [@jiwangyihao](https://github.com/jiwangyihao)).
2771
2577
 
2772
- ### Removed
2578
+ ### Added
2773
2579
 
2774
- - Removed hashline auto-rebase. Anchor mismatches now reject immediately so the model re-reads instead of silently relocating an edit to a hash-collision within ±5 lines, which could otherwise apply the change to the wrong region. Stale-anchor recovery via the cached read snapshot is unaffected.
2580
+ - Added a debug-panel raw SSE stream viewer so stuck model/tool-call streams can be inspected live from the TUI.
2581
+ - Added `get_login_providers` RPC command to list registered OAuth providers with their current authentication status (`id`, `name`, `available`, `authenticated`)
2582
+ - Added `login` RPC command to trigger OAuth login for a given provider; emits an `open_url` extension UI event (fire-and-forget) carrying the auth URL and optional instructions so headless clients can open the browser, then resolves when the callback-server flow completes
2583
+ - Added `open_url` variant to `RpcExtensionUIRequest` for the above
2584
+ - Added `getLoginProviders()` and `login(providerId)` methods to `RpcClient`
2775
2585
 
2776
2586
  ## [14.8.0] - 2026-05-09
2777
2587
 
@@ -2999,7 +2809,6 @@
2999
2809
  ### Fixed
3000
2810
 
3001
2811
  - Disabled repeated OSC 11 background-color polling under WSL to avoid Windows terminal tab crashes while keeping initial and event-driven appearance detection ([#914](https://github.com/can1357/oh-my-pi/issues/914))
3002
-
3003
2812
  - Fixed SSH ControlMaster socket paths to use OpenSSH's connection hash (`%C`) so connections to the same host with different users, ports, or jump hosts do not share a master session.
3004
2813
 
3005
2814
  ## [14.6.1] - 2026-05-02
@@ -3028,7 +2837,6 @@
3028
2837
  - Autoresearch sessions are now scoped to the git branch they were created on. Switching off the `autoresearch/*` branch hides the dashboard widget, detaches the experiment tools, and skips the autoresearch system prompt; switching back resumes seamlessly. `/autoresearch` on a fresh branch starts a fresh session instead of resurrecting a session bound to a different branch.
3029
2838
  - `log_experiment discard` no longer rewinds prior `keep` commits. On an `autoresearch/*` branch it now resets the worktree to `HEAD` (and `git clean`s untracked) instead of `git reset --hard $baseline_commit`. Discard reverts only the current iteration's uncommitted edits; previously kept improvements stay on the branch. `/autoresearch clear` continues to reset to the recorded baseline commit when explicitly requested.
3030
2839
  - Autoresearch SQLite storage is now created lazily on first `init_experiment`. Running `omp` in a project that never invokes `/autoresearch` no longer creates a per-folder DB.
3031
-
3032
2840
  - Changed `search`, `find`, `ast_grep`, and `ast_edit` to accept `paths: string[]` instead of comma- or whitespace-delimited path strings.
3033
2841
 
3034
2842
  ### Added
@@ -3094,8 +2902,6 @@
3094
2902
  ### Fixed
3095
2903
 
3096
2904
  - Fixed eval startup messaging to report `eval` as unavailable when Python is unreachable and JavaScript backend is disabled
3097
- - Stabilized MCP tool ordering so reconnects and refreshes no longer reorder the tools array sent to the model. Anthropic prompt caching is keyed on byte-identical tool definitions; previously, the order depended on connection sequence and a single MCP server reconnect could shuffle tools across servers and invalidate the tools cache breakpoint.
3098
- - Skipped redundant system-prompt rebuilds in `AgentSession.refreshMCPTools` when the active tool set is unchanged. MCP transport flapping (e.g. routine 5-minute SSE reconnects) used to call `rebuildSystemPrompt` on every reconnect even though the resulting prompt was byte-identical, eating CPU and risking cache misses if the rebuild ever became non-deterministic. The applied-tool signature also covers `customWireName` so a wire-name flip with the rest of the tool metadata constant still forces a rebuild.
3099
2905
 
3100
2906
  ## [14.5.12] - 2026-04-30
3101
2907
 
@@ -3127,9 +2933,9 @@
3127
2933
 
3128
2934
  ### Breaking Changes
3129
2935
 
3130
- - `todo`: renamed `replace` op to `init` and reshaped its input to `list: [{phase: string, items: string[]}]`. Tasks no longer accept a `status` field; all start `pending` and the first auto-promotes to `in_progress`. The `append` op's `items` is now `string[]` (was `{id, label}[]`)
3131
- - `todo`: removed the synthetic `task-N` / `phase-N` ids — task identity is now its `content` and phase identity is its `name`. The `task` field on `start`/`done`/`drop`/`note` and the `phase` field on `done`/`drop`/`rm`/`append` take those values directly
3132
- - `todo`: phase names no longer accept a numeric/roman prefix (`I.`, `1.`, `Phase 1:`, …). The renderer numbers phases visually (Ⅰ. Ⅱ. Ⅲ. …) and the model-facing state stores the bare noun phrase
2936
+ - `todo_write`: renamed `replace` op to `init` and reshaped its input to `list: [{phase: string, items: string[]}]`. Tasks no longer accept a `status` field; all start `pending` and the first auto-promotes to `in_progress`. The `append` op's `items` is now `string[]` (was `{id, label}[]`)
2937
+ - `todo_write`: removed the synthetic `task-N` / `phase-N` ids — task identity is now its `content` and phase identity is its `name`. The `task` field on `start`/`done`/`drop`/`note` and the `phase` field on `done`/`drop`/`rm`/`append` take those values directly
2938
+ - `todo_write`: phase names no longer accept a numeric/roman prefix (`I.`, `1.`, `Phase 1:`, …). The renderer numbers phases visually (Ⅰ. Ⅱ. Ⅲ. …) and the model-facing state stores the bare noun phrase
3133
2939
 
3134
2940
  ### Changed
3135
2941
 
@@ -3258,7 +3064,6 @@
3258
3064
 
3259
3065
  ### Added
3260
3066
 
3261
- - Added the `after_provider_response` extension event for observing provider response status, headers, and request IDs.
3262
3067
  - Added internal URL support to the `search` tool, allowing `artifact://`-style paths that resolve to local files to be searched directly
3263
3068
  - Added IRC relay observation in the main agent UI so every IRC exchange between agents is rendered in the main transcript, even when the main agent is not a direct participant
3264
3069
  - Added stateful `href`/`hrefr` prompt helpers that can reuse anchors remembered from prior `hline` helper calls
@@ -3355,7 +3160,7 @@
3355
3160
 
3356
3161
  ### Added
3357
3162
 
3358
- - Added `note` to todo operations so you can append follow-up text notes to a task via `op: "note"` and `text`
3163
+ - Added `note` to todo-write operations so you can append follow-up text notes to a task via `op: "note"` and `text`
3359
3164
  - Added markdown note-block support to `/todo export` and `/todo import` so task notes are written as blockquote lines and reloaded with the todo list
3360
3165
  - Added `/todo export <path>` to write the current todo list as Markdown to a file, defaulting to `TODO.md` when no path is provided
3361
3166
  - Added `/todo import <path>` to replace the current todo list from a Markdown file, defaulting to `TODO.md` when no path is provided
@@ -3419,7 +3224,7 @@
3419
3224
  - Removed multi-pattern array input from `ast_grep` by changing `pat` to a single pattern string, so call sites using `pat: [...]` must be updated to send one query per invocation
3420
3225
  - Removed `lang`, `glob`, and `sel` options from `ast_edit` and `ast_grep`, and moved those behaviors into the required `path` argument
3421
3226
  - Required `path` for `ast_edit` and `ast_grep`, so invocations that relied on implicit repo-root searching are no longer valid
3422
- - Changed `todo` from multi-field verb payloads to an ordered array of flat operations, while retaining `replace` for harness bootstrap compatibility
3227
+ - Changed `todo_write` from multi-field verb payloads to an ordered array of flat operations, while retaining `replace` for harness bootstrap compatibility
3423
3228
  - Renamed atom edit operations from `before` and `after` to `pre` and `post`, so existing `atom` payloads using the old operation keys must be updated
3424
3229
  - Changed the hashline anchor format from `LINE#ID:content` to `LINEID:content` (no `#` separator, colon between anchor and content, no padding on line numbers); expanded the bigram alphabet from 40 hand-picked English bigrams to the full 647 single-token 2-letter bigrams — invalidates every previously captured `LINE#ID` reference
3425
3230
  - Renamed the subagent completion contract from `submit_result` to `yield`, so subagent sessions must now finish with the `yield` tool and the `requireYieldTool` option; `submit_result`/`requireSubmitResultTool` and old completion calls are no longer recognized
@@ -3438,10 +3243,10 @@
3438
3243
 
3439
3244
  - Updated `atom` and `hashline` edit anchor validation to auto-rebase a stale anchor within ±2 lines when the same hash matches a unique nearby line, continuing the edit with a warning instead of immediate failure
3440
3245
  - Changed bash command output labels from `[full result: artifact://…]` to `[raw output: artifact://…]` for artifact references produced from large command output
3441
- - Changed `todo` `done`, `rm`, and `drop` operations to target all tasks when neither `task` nor `phase` is provided, and made `append` create the target phase automatically when missing
3246
+ - Changed `todo_write` `done`, `rm`, and `drop` operations to target all tasks when neither `task` nor `phase` is provided, and made `append` create the target phase automatically when missing
3442
3247
  - Updated `ast_edit` and `ast_grep` to pass file-selection intent through `path` (including inline globs and comma/space-separated path lists) instead of separate `glob` filters
3443
3248
  - Changed `ast_grep` pagination API from `offset` to `skip`
3444
- - Flattened `todo` operation arguments to `{ op, task?, phase?, items? }[]` and removed task details from the persisted todo shape
3249
+ - Flattened `todo_write` operation arguments to `{ op, task?, phase?, items? }[]` and removed task details from the persisted todo shape
3445
3250
  - Changed `grep` truncation output to report `Result limit reached; narrow path.` and label match/result caps as `first N`
3446
3251
  - Changed JSON tree output to truncate inline argument pairs by available width and add an ellipsis when values no longer fit in the display
3447
3252
  - Changed JSON tree rendering to hide harness-internal `intent` and `__partialJson` fields from top-level tool output
@@ -3464,12 +3269,12 @@
3464
3269
 
3465
3270
  - Removed line-range support from `atom` mode selectors, including `loc` values like `160sr-170ab`, so edits must target a single anchor (`160sr`, `^`, or `$`) per entry
3466
3271
  - Removed the atom `del` verb and now require anchored-line deletion to be requested with `set: []`
3467
- - Removed `todo` task details and the `add_notes` operation
3272
+ - Removed `todo_write` task details and the `add_notes` operation
3468
3273
 
3469
3274
  ### Fixed
3470
3275
 
3471
3276
  - Improved no-op edit diagnostics for `atom` and `hashline` operations so edits that leave content unchanged now fail with contextual details (edit index, locator, and reason), including guidance for `replace_range` no-op cases
3472
- - Wrapped `todo` operations in an `ops` object so Codex/OpenAI function schemas always use a JSON Schema object.
3277
+ - Wrapped `todo_write` operations in an `ops` object so Codex/OpenAI function schemas always use a JSON Schema object.
3473
3278
  - Fixed JSON tree rendering for tool arguments by excluding injected internal keys from displayed root records
3474
3279
  - Printed assistant `errorMessage` text in print mode output to stderr so message-level errors are visible during non-interactive runs
3475
3280
  - Displayed assistant `errorMessage` text in the assistant message component for completed tool responses with non-terminal stop reasons
@@ -3540,7 +3345,6 @@
3540
3345
  - Fixed Mermaid fenced markdown rendering in assistant messages on terminals without image protocol support ([#650](https://github.com/can1357/oh-my-pi/issues/650))
3541
3346
  - Fixed chunk edit path parsing so plan-mode edits to section-addressed `local://PLAN.md:<selector>` paths are classified as writes to the plan file
3542
3347
  - Fixed SQLite `read` helper queries to reject `where=` clauses with SQL control syntax that could override the structured selector's pagination; raw SQL remains available through `q=SELECT ...`
3543
- - Fixed `models` provider transport overrides so `headers`-only entries apply without requiring `baseUrl`, including runtime `registerProvider()` overrides that now persist across `refresh()` / `refreshProvider()`, preserve existing `baseUrl` on subsequent headers-only updates, clear stale transport overrides when a provider is re-registered under a different extension source, and keep runtime transport headers authoritative when `modelOverrides` set overlapping header keys
3544
3348
 
3545
3349
  ## [14.2.0] - 2026-04-23
3546
3350
 
@@ -3570,14 +3374,14 @@
3570
3374
 
3571
3375
  ### Breaking Changes
3572
3376
 
3573
- - Replaced the legacy `todo` `ops`-based API (`replace`, `update`, `add_task`, and `remove_task`) with direct top-level fields, requiring migration of any callers using the old request shape
3574
- - Removed in-place updates to existing task `content`, `details`, and `notes` via `todo`; note changes now append through `add_notes`
3575
- - Phased task definitions in `todo` now reject `notes` on initial creation, so notes must be added later with `add_notes`
3377
+ - Replaced the legacy `todo_write` `ops`-based API (`replace`, `update`, `add_task`, and `remove_task`) with direct top-level fields, requiring migration of any callers using the old request shape
3378
+ - Removed in-place updates to existing task `content`, `details`, and `notes` via `todo_write`; note changes now append through `add_notes`
3379
+ - Phased task definitions in `todo_write` now reject `notes` on initial creation, so notes must be added later with `add_notes`
3576
3380
 
3577
3381
  ### Added
3578
3382
 
3579
- - Added `complete`, `start`, `abandon`, `remove`, `add_notes`, and `add_tasks` parameters to `todo` so callers can complete, jump to, drop, and annotate tasks without op wrappers
3580
- - Added direct `add_phase` support as a top-level argument for inserting a new phase in `todo`
3383
+ - Added `complete`, `start`, `abandon`, `remove`, `add_notes`, and `add_tasks` parameters to `todo_write` so callers can complete, jump to, drop, and annotate tasks without op wrappers
3384
+ - Added direct `add_phase` support as a top-level argument for inserting a new phase in `todo_write`
3581
3385
  - Added `task.simple` with `default`, `schema-free`, and `independent` modes so the task tool can disable task-call `schema` and shared `context` inputs while preserving agent-defined and inherited subagent schemas
3582
3386
 
3583
3387
  ### Changed
@@ -3630,7 +3434,7 @@
3630
3434
  - Changed Vim page-scroll commands `C-f`, `C-b`, `C-u`, and `C-d` to move in viewport-height based increments instead of fixed constants
3631
3435
  - Changed `z` command behavior so `zt`, `zb`, and `z.` now align cursor movement to first non-blank in the line
3632
3436
  - Changed `:g`/`:v` global command handling to process matching lines safely by working in reverse order and preserving file structure
3633
- - Changed vim tab breadcrumb rendering from `→` to `→` in the editor view
3437
+ - Changed vim tab breadcrumb rendering from ` → ` to `→` in the editor view
3634
3438
  - Changed custom tool and task execution contexts to no longer expose a shared `searchDb` accessor, removing direct access to native grep/glob/fuzzyFind search backends from extension callbacks
3635
3439
  - Changed the `task` tool `schema` field to require JSON-encoded JTD schema text instead of a schema object, matching prompt guidance and task-subagent invocation
3636
3440
  - Changed chunk edit payloads to encode selectors as `path: "file:selector"` and updated chunk tool guidance and examples to match
@@ -3747,7 +3551,6 @@
3747
3551
  - Fixed stale child selector reuse to correctly match chunks by checksum when multiple sibling chunks with the same name exist under the same parent
3748
3552
  - Fixed stale diagnostics being reused after unrelated file publishes by clearing cached diagnostics before refreshing file state
3749
3553
  - Fixed Codex search to use streamed answer text when final answer is an image placeholder or empty
3750
- - Fixed MCP config docs and schema to use `~/.omp/agent/mcp.json` for user-scoped OMP-native MCP config while keeping project config at `<cwd>/.omp/mcp.json`
3751
3554
 
3752
3555
  ## [14.0.4] - 2026-04-10
3753
3556
 
@@ -3921,7 +3724,6 @@
3921
3724
  - Chunk-mode `read` output: recursive rendering with `$XXXX` checksum suffixes, inline large-chunk previews, and normalized `#path$XXXX` selectors between read and edit
3922
3725
  - Autoresearch: `init_experiment` options `new_segment`, `from_autoresearch_md`, `abandon_unlogged_runs`; `log_experiment` options `skip_restore` and broader `force`; `run_experiment` `force` (with warnings); pre-run dirty-path tracking; `abandonUnloggedAutoresearchRuns` and `abandonedAt` on runs
3923
3726
  - LSP: diagnostic versioning (`versionSupport`, stored document version per diagnostic set), and `waitForDiagnostics` / `getDiagnosticsForFile` options (`expectedDocumentVersion`, `allowUnversioned`)
3924
- - `/review` command now accepts inline args as custom instructions appended to the generated prompt for all structured review modes (PR-style, uncommitted, specific commit). When inline args are provided, option 4 (editor) is suppressed from the menu. The no-UI (Task tool) path forwards args as a focus hint.
3925
3727
 
3926
3728
  ### Changed
3927
3729
 
@@ -3956,7 +3758,18 @@
3956
3758
  - ACP session creation now uses a factory function to support creating new sessions for different working directories
3957
3759
  - ACP event mapping now accepts optional `getMessageId` callback for stable message ID assignment to assistant chunks
3958
3760
 
3959
- ### Fixed
3761
+ ### Removed
3762
+
3763
+ - Deleted `src/utils/prompt-format.ts` module; prompt formatting logic moved to `pi-utils`
3764
+ - Deleted `src/utils/frontmatter.ts` module; frontmatter parsing logic moved to `pi-utils`
3765
+ - Removed `waitForChildProcess` utility (child process termination now handled by native `killTree` from pi-natives)
3766
+ - `grep-chunk.md` (folded into unified grep template)
3767
+ - `startMacAppearanceObserver` export (use `MacAppearanceObserver.start()`)
3768
+ - `copyToClipboard` export from pi-natives
3769
+ - `PI_CHUNK_SPLICES` env and `chunkSplicesEnabled()`
3770
+ - Autoresearch `segmentFingerprint` and related config hashing
3771
+
3772
+ ### Fixed
3960
3773
 
3961
3774
  - Chunk edit parameter validation: corrected detection of chunk edit operations to check for `sel` field instead of `target`
3962
3775
  - Chunk edit streaming previews: updated to reference `sel` parameter instead of `target`
@@ -4023,17 +3836,6 @@
4023
3836
  - `/autoresearch` toggles like `/plan` when empty; slash completion no longer suggests `off`/`clear` on an empty prefix after the command
4024
3837
  - Chunk-mode read/edit edge cases (zero-width gap replaces, stale batch diagnostics, grouped Go receivers, line-count headers, parse error locations)
4025
3838
 
4026
- ### Removed
4027
-
4028
- - Deleted `src/utils/prompt-format.ts` module; prompt formatting logic moved to `pi-utils`
4029
- - Deleted `src/utils/frontmatter.ts` module; frontmatter parsing logic moved to `pi-utils`
4030
- - Removed `waitForChildProcess` utility (child process termination now handled by native `killTree` from pi-natives)
4031
- - `grep-chunk.md` (folded into unified grep template)
4032
- - `startMacAppearanceObserver` export (use `MacAppearanceObserver.start()`)
4033
- - `copyToClipboard` export from pi-natives
4034
- - `PI_CHUNK_SPLICES` env and `chunkSplicesEnabled()`
4035
- - Autoresearch `segmentFingerprint` and related config hashing
4036
-
4037
3839
  ## [13.19.0] - 2026-04-05
4038
3840
 
4039
3841
  ### Added
@@ -4081,7 +3883,6 @@
4081
3883
  - Fixed PR checkout tool to resolve symlinks in worktree paths, ensuring consistent path references in results and metadata
4082
3884
  - Fixed `read` output for file-backed internal URLs like `local://...` to include hashline prefixes in hashline edit mode, preserving usable line refs for follow-up edits
4083
3885
  - Fixed the plan review selector to support the external editor shortcut for opening and updating the current plan from the approval screen
4084
- - Fixed status line dropping git branch name when path is long by shrinking the path segment before dropping other segments
4085
3886
 
4086
3887
  ## [13.18.0] - 2026-04-02
4087
3888
 
@@ -4324,8 +4125,6 @@
4324
4125
 
4325
4126
  ### Added
4326
4127
 
4327
- - Added custom model roles/tags via config YAML
4328
- - Added ability to reorder model role/tag cycling via config YAML
4329
4128
  - Added prompt for tradeoff metrics during autoresearch setup to collect secondary metrics alongside primary metric
4330
4129
  - Added validation of contract path specifications to reject absolute paths and parent directory references
4331
4130
  - Added stricter benchmark command validation in `isAutoresearchShCommand()` to reject chained commands, pipes, and redirects
@@ -4379,11 +4178,22 @@
4379
4178
  - Added ACP (Agent Client Protocol) mode for headless agent operation via `--mode acp`
4380
4179
  - Added support for Agent Client Protocol SDK integration with session management, MCP server configuration, and streaming communication
4381
4180
  - Added `ensureOnDisk()` method to SessionManager to persist sessions immediately for ACP discovery
4382
- - Added multiline custom input for `ask` custom answers, using the prompt-style editor without inactivity timeout while composing ([#506](https://github.com/can1357/oh-my-pi/issues/506))
4383
- - Session observer overlay (`Ctrl+S`): view running subagent sessions with a picker and read-only transcript showing thinking, text, tool calls, and results
4384
4181
 
4385
4182
  ### Changed
4386
4183
 
4184
+ - Changed `isAutoresearchShCommand()` to use proper command-line argument parsing instead of regex, improving accuracy for complex shell invocations
4185
+ - Changed autoresearch initialization prompt to display collected tradeoff metrics in the setup summary
4186
+ - Changed `command-initialize.md` template to include guidance on preflight requirements, comparability invariants, and marking measurement-critical files as off-limits
4187
+ - Changed `command-initialize.md` to instruct users to write or update `autoresearch.program.md` with durable heuristics and repo-specific strategy
4188
+ - Changed autoresearch resume guidance to emphasize continuing on the current protected branch rather than switching branches
4189
+ - Changed autoresearch prompt to clarify that `autoresearch.md` holds durable conclusions while `autoresearch.ideas.md` is the scratch backlog
4190
+ - Changed autoresearch prompt guidance to require stable measurement harness and fixed benchmark inputs unless intentionally starting a new segment
4191
+ - Changed autoresearch prompt to recommend keeping equal or near-equal results when they materially simplify implementation
4192
+ - Changed `init_experiment` to reset pending run state (checks, duration, ASI, artifact directory) when initializing a new segment
4193
+ - Changed `log_experiment` to set `autoResumeArmed` flag after successfully logging a run to enable auto-resume on next agent turn
4194
+ - Changed `run_experiment` to set `autoResumeArmed` flag and update dashboard after completing a run
4195
+ - Changed auto-resume logic to only prompt when a new pending run exists or when `autoResumeArmed` is explicitly set, preventing duplicate prompts
4196
+ - Changed path normalization in contract validation to use `path.posix.normalize()` for consistent path handling
4387
4197
  - Changed autoresearch initialization to collect and validate benchmark command, metric definition, scope paths, off-limits list, and constraints before `init_experiment`
4388
4198
  - Changed `init_experiment` to require exact benchmark command, metric definition, scope, off-limits, and constraints matching collected contract
4389
4199
  - Changed `log_experiment` to record run number, benchmark command, scope paths, off-limits list, constraints, and segment fingerprint with each result
@@ -4424,21 +4234,23 @@
4424
4234
  - Changed session persistence logic to use atomic file rewrite when flushing unflushed sessions to prevent duplication
4425
4235
  - Removed hashline edit autocorrection for duplicated boundary lines; escaped-tab autocorrection remains available for leading `\\t` sequences
4426
4236
 
4237
+ ### Removed
4238
+
4239
+ - Removed `command-start.md` prompt template in favor of separate initialize and resume workflows
4240
+ - Removed auto-correction of off-by-one range edits that duplicated closing braces or boundary lines
4241
+ - Removed `shouldAutocorrect` function and related boundary line deduplication logic from hashline editor
4242
+ - Removed auto-correction of off-by-one range edits that duplicated closing braces or boundary lines
4243
+
4427
4244
  ### Fixed
4428
4245
 
4246
+ - Fixed boundary duplication warnings to always display when replacement lines match the next surviving line, even when auto-correction is disabled
4247
+ - Fixed secondary metrics validation to properly reject missing configured metrics and new metrics without force flag
4248
+ - Fixed ASI data cloning to prevent prototype pollution attacks by filtering reserved property names
4429
4249
  - Fixed autoresearch resume to detect and recover pending run artifacts that were left unlogged from previous sessions
4430
4250
  - Fixed dashboard overlay to display when running experiment even with zero completed results
4431
4251
  - Fixed tab character rendering in dashboard command display and tool output summaries
4432
4252
  - Fixed autoresearch logging to require durable ASI metadata (hypothesis, rollback_reason, next_action_hint) for every run including rollback context for discarded, crashed, and checks-failed experiments
4433
4253
  - Fixed autoresearch logging to require durable ASI metadata for every run, including rollback context for discarded, crashed, and checks-failed experiments
4434
- - Fixed resumed and session-switched GitHub Copilot/OpenAI Responses conversations replaying stale assistant native history from older saved sessions by sanitizing persisted assistant replay metadata on rehydration and resetting provider session state across live session boundaries ([#505](https://github.com/can1357/oh-my-pi/issues/505))
4435
-
4436
- ### Removed
4437
-
4438
- - Removed `command-start.md` prompt template in favor of separate initialize and resume workflows
4439
- - Removed auto-correction of off-by-one range edits that duplicated closing braces or boundary lines
4440
- - Removed `shouldAutocorrect` function and related boundary line deduplication logic from hashline editor
4441
- - Removed auto-correction of off-by-one range edits that duplicated closing braces or boundary lines
4442
4254
 
4443
4255
  ## [13.14.0] - 2026-03-20
4444
4256
 
@@ -4674,7 +4486,7 @@
4674
4486
  - Moved LSP settings (lsp.enabled, lsp.formatOnWrite, lsp.diagnosticsOnWrite, lsp.diagnosticsOnEdit) to the Editing tab
4675
4487
  - Moved bash interceptor settings to the Editing tab
4676
4488
  - Moved Python settings (python.toolMode, python.kernelMode, python.sharedGateway) to the Editing tab
4677
- - Moved task delegation settings (task.isolation.\*, task.eager, task.maxConcurrency, task.maxRecursionDepth) to the Tasks tab
4489
+ - Moved task delegation settings (task.isolation.*, task.eager, task.maxConcurrency, task.maxRecursionDepth) to the Tasks tab
4678
4490
  - Moved skill and command settings to the Tasks tab
4679
4491
  - Moved provider selection settings (providers.webSearch, providers.codeSearch, providers.image, etc.) to the Providers tab
4680
4492
  - Moved Exa settings to the Providers tab
@@ -4690,6 +4502,10 @@
4690
4502
  - Changed working directory paths in system prompt to use forward slashes for consistency across platforms
4691
4503
  - Modified bash executor to fall back to one-shot shell execution after a persistent session hard timeout, preventing subsequent commands from hanging
4692
4504
 
4505
+ ### Removed
4506
+
4507
+ - Removed bash executor hard timeout recovery test file (functionality already documented in existing entries)
4508
+
4693
4509
  ### Fixed
4694
4510
 
4695
4511
  - Fixed bash execution to fall back to one-shot shell runs after a persistent session hard timeout, preventing later commands from hanging until restart
@@ -4697,10 +4513,6 @@
4697
4513
  - Fixed AgentSession disposal to call SessionManager's `close()` method when available, ensuring proper cleanup of persistent writers
4698
4514
  - Removed redundant `path.join()` call wrapping `getHistoryDbPath()` in history-storage.ts
4699
4515
 
4700
- ### Removed
4701
-
4702
- - Removed bash executor hard timeout recovery test file (functionality already documented in existing entries)
4703
-
4704
4516
  ## [13.11.1] - 2026-03-13
4705
4517
 
4706
4518
  ### Added
@@ -4746,7 +4558,6 @@
4746
4558
  - Added `buildNamedToolChoice` utility function to build provider-aware tool choice constraints for named tools
4747
4559
  - Support for comma/space-separated path lists in `find`, `grep`, `ast_grep`, and `ast_edit` tools (e.g., `apps/,packages/,phases/` or `apps/ packages/ phases/`)
4748
4560
  - New `resolveMultiSearchPath` and `resolveMultiFindPattern` functions to handle multi-path search inputs with automatic common base path detection
4749
- - Added `display.showTokenUsage` setting to show per-turn token usage (input, output, cache) on assistant messages
4750
4561
 
4751
4562
  ### Changed
4752
4563
 
@@ -4782,10 +4593,6 @@
4782
4593
  - Added `refreshMCPOAuthToken()` for standard OAuth 2.0 refresh_token grants
4783
4594
  - Persisted `tokenUrl`, `clientId`, and `clientSecret` in MCP auth config for cross-session token refresh
4784
4595
 
4785
- ### Fixed
4786
-
4787
- - Respected `PI_CONFIG_DIR` when discovering native user config paths for slash commands and related config directories ([#349](https://github.com/can1357/oh-my-pi/issues/349))
4788
-
4789
4596
  ## [13.10.0] - 2026-03-10
4790
4597
 
4791
4598
  ### Fixed
@@ -4970,7 +4777,6 @@
4970
4777
  - Fixed model registry to preserve explicit thinking configuration on runtime-registered models
4971
4778
  - Fixed usage limit reset time calculation to use absolute `resetsAt` timestamps instead of deprecated `resetInMs` field
4972
4779
  - Fixed compaction summary message creation to no longer be automatically added to chat during compaction (now handled by session manager)
4973
- - Fixed Kagi web search errors to surface the provider's beta-access message and clarified that Kagi search requires Search API beta access
4974
4780
 
4975
4781
  ## [13.9.2] - 2026-03-05
4976
4782
 
@@ -5075,7 +4881,7 @@
5075
4881
  ### Changed
5076
4882
 
5077
4883
  - Updated hashline prompt documentation with clearer operation syntax and improved examples showing full edit structure with path and edits array
5078
- - Refactored `href` Handlebars helper to return JSON-quoted strings for safer embedding in JSON blocks within prompts
4884
+ - Refactored `hlineref` Handlebars helper to return JSON-quoted strings for safer embedding in JSON blocks within prompts
5079
4885
  - Improved `hashlineParseText` to correctly preserve blank lines and trailing empty strings in array input while stripping trailing newlines from string input
5080
4886
  - Optimized duplicate line detection in range replacements to use trimmed comparison, reducing false positives from whitespace differences
5081
4887
  - Refactored Kagi search provider to use shared Kagi API utilities from `web/kagi` module
@@ -5174,7 +4980,6 @@
5174
4980
  - Added `extractMcpAuthServerUrl()` function to parse and validate `Mcp-Auth-Server` URLs from error messages
5175
4981
  - Added support for `/.well-known/oauth-protected-resource` discovery endpoint to resolve authorization servers
5176
4982
  - Added recursive auth server discovery to follow `authorization_servers` references when discovering OAuth endpoints
5177
-
5178
4983
  - Added `omp agents unpack` CLI subcommand to export bundled subagent definitions to `~/.omp/agent/agents` by default, with `--project` support for `./.omp/agents`
5179
4984
 
5180
4985
  ### Changed
@@ -5307,7 +5112,7 @@
5307
5112
  - Expanded AST tool language support from 7 to all 25 ast-grep tree-sitter languages (Bash, C, C++, C#, CSS, Elixir, Go, Haskell, HCL, HTML, Java, JavaScript, JSON, Kotlin, Lua, Nix, PHP, Python, Ruby, Rust, Scala, Solidity, Swift, TSX, TypeScript, YAML)
5308
5113
  - AST find now emits all lines of multiline matches with hashline tags (LINE#HASH:content) consistent with read/grep output
5309
5114
  - Added AST pattern syntax reference (metavariables, wildcards, variadics) to system prompt
5310
- - Added examples and scoping guidance to ast-grep and ast-edit tool prompts
5115
+ - Added examples and scoping guidance to ast-find and ast-replace tool prompts
5311
5116
  - Added `provider-schema-compatibility.test.ts`: integration test that instantiates every builtin and hidden tool, runs their parameter schemas through `adaptSchemaForStrict`, `sanitizeSchemaForGoogle`, and `prepareSchemaForCCA`, and asserts zero violations against each provider's compatibility rules
5312
5117
 
5313
5118
  ### Fixed
@@ -5326,9 +5131,9 @@
5326
5131
 
5327
5132
  ### Added
5328
5133
 
5329
- - Added `ast_grep` tool for structural code search using AST matching via ast-grep, enabling syntax-aware pattern discovery across codebases
5330
- - Added `ast_edit` tool for structural AST-aware rewrites via ast-grep, enabling safe syntax-level codemods without text-based fragility
5331
- - Added `astGrep.enabled` and `astEdit.enabled` settings to control availability of AST tools
5134
+ - Added `ast_find` tool for structural code search using AST matching via ast-grep, enabling syntax-aware pattern discovery across codebases
5135
+ - Added `ast_replace` tool for structural AST-aware rewrites via ast-grep, enabling safe syntax-level codemods without text-based fragility
5136
+ - Added `astFind.enabled` and `astReplace.enabled` settings to control availability of AST tools
5332
5137
  - Added system prompt guidance to prefer AST tools over bash text manipulation (grep/sed/awk/perl) for syntax-aware operations
5333
5138
  - Extracted prompt formatting logic into reusable `formatPromptContent()` utility with configurable render phases and formatting options
5334
5139
  - Added `type_definition` action to navigate to symbol type definitions with source context
@@ -5355,10 +5160,10 @@
5355
5160
  - Updated HTML parsing API calls from `node-html-parser` to `linkedom` across all web scrapers (arXiv, IACR, Go pkg, Read the Docs, Twitter, Wikipedia)
5356
5161
  - Changed element text extraction from `.text` property to `.textContent` property for compatibility with linkedom DOM API
5357
5162
  - Optimized document link extraction to use regex-based parsing with deduplication and a 20-link limit instead of full DOM traversal
5358
- - Unified `path` parameter in ast_grep and ast_edit tools to accept files, directories, or glob patterns directly, eliminating the separate `glob` parameter
5359
- - Removed `strictness` parameter from ast_grep and ast_edit tools
5360
- - Removed `fail_on_parse_error` parameter from ast_edit tool (now always false)
5361
- - Updated ast_grep and ast_edit prompt guidance to clarify that `path` accepts glob patterns and no longer requires separate glob specification
5163
+ - Unified `path` parameter in ast_find and ast_replace tools to accept files, directories, or glob patterns directly, eliminating the separate `glob` parameter
5164
+ - Removed `strictness` parameter from ast_find and ast_replace tools
5165
+ - Removed `fail_on_parse_error` parameter from ast_replace tool (now always false)
5166
+ - Updated ast_find and ast_replace prompt guidance to clarify that `path` accepts glob patterns and no longer requires separate glob specification
5362
5167
  - Refactored prompt template rendering to use unified `formatPromptContent()` function with phase-aware formatting (pre-render vs post-render)
5363
5168
  - Updated `format-prompts.ts` script to use centralized prompt formatting utility instead of inline implementation
5364
5169
  - Replaced `column` parameter with `symbol` parameter for more intuitive position specification
@@ -5402,7 +5207,7 @@
5402
5207
  - Fixed workspace symbol search to query all configured LSP servers and filter out non-matching results
5403
5208
  - Fixed `references`/`rename`/`hover` symbol targeting to error when `symbol` is missing on the line or `occurrence` is out of bounds
5404
5209
  - Fixed `reload` without a file to reload all active configured language servers instead of only the first server
5405
- - Fixed `todo` task normalization to auto-activate the first remaining task and include explicit remaining-items output in tool results, removing the need for an immediate follow-up start update
5210
+ - Fixed `todo_write` task normalization to auto-activate the first remaining task and include explicit remaining-items output in tool results, removing the need for an immediate follow-up start update
5406
5211
 
5407
5212
  ## [13.3.7] - 2026-02-27
5408
5213
 
@@ -5526,22 +5331,6 @@
5526
5331
 
5527
5332
  - Made `description` field required in CustomTool interface
5528
5333
 
5529
- ### Changed
5530
-
5531
- - Reorganized imports from `@oh-my-pi/pi-utils/dirs` to consolidate with main `@oh-my-pi/pi-utils` exports for cleaner dependency management
5532
- - Renamed `loadSkillsFromDir` to `scanSkillsFromDir` with updated interface for improved clarity on skill discovery behavior
5533
- - Moved `tryParseJson` utility from local scrapers module to `@oh-my-pi/pi-utils` for centralized JSON parsing
5534
- - Simplified patch module exports by consolidating type re-exports with `export * from './types'`
5535
- - Removed `emitCustomToolSessionEvent` method from AgentSession for streamlined session lifecycle management
5536
- - Changed skill discovery from recursive to non-recursive (one level deep only) for improved performance and clarity
5537
- - Simplified skill loading logic by removing recursive directory traversal and consolidating ignore rule handling
5538
-
5539
- ### Removed
5540
-
5541
- - Removed `parseJSON` helper function from discovery module (replaced by `tryParseJson` from pi-utils)
5542
- - Removed backwards compatibility comment from `AskToolDetails.question` field
5543
- - Removed unused SSH resource cleanup functions `closeAllConnections` and `unmountAll` from session imports
5544
-
5545
5334
  ## [13.1.2] - 2026-02-23
5546
5335
 
5547
5336
  ### Breaking Changes
@@ -5550,10 +5339,6 @@
5550
5339
  - Renamed `job_ids` parameter to `jobs` in await tool schema
5551
5340
  - Removed `timedOut` field from await tool result details
5552
5341
 
5553
- ### Changed
5554
-
5555
- - Resolved docs index generation paths using path.resolve relative to the script directory
5556
-
5557
5342
  ## [13.1.1] - 2026-02-23
5558
5343
 
5559
5344
  ### Fixed
@@ -5601,7 +5386,7 @@
5601
5386
 
5602
5387
  - Changed todo state management from file-based (`todos.json`) to in-memory session cache for improved performance and consistency
5603
5388
  - Changed todo phases to sync from session branch history when branching or rewriting entries
5604
- - Changed `TodoTool` to update session cache instead of writing to disk, with automatic persistence through session entries
5389
+ - Changed `TodoWriteTool` to update session cache instead of writing to disk, with automatic persistence through session entries
5605
5390
  - Changed XML tag from `<swarm-context>` to `<context>` in subagent prompts and task rendering
5606
5391
  - Changed system reminder XML tags from underscore to kebab-case format (`<system-reminder>`)
5607
5392
  - Changed plan storage from `plan://` protocol to `local://PLAN.md` for draft plans and `local://<title>.md` for finalized approved plans
@@ -5713,7 +5498,7 @@
5713
5498
 
5714
5499
  - Changed custom UI hook cleanup to conditionally restore editor state only when not using overlay mode
5715
5500
  - Extracted environment variable configuration for non-interactive bash execution into reusable `NO_PAGER_ENV` constant
5716
- - Replaced custom timing instrumentation with logger.time() and logger.time() from pi-utils for consistent startup profiling
5501
+ - Replaced custom timing instrumentation with logger.timeAsync() and logger.time() from pi-utils for consistent startup profiling
5717
5502
  - Removed PI_DEBUG_STARTUP environment variable in favor of logger.debug() for conditional debug output
5718
5503
  - Consolidated timing calls throughout initialization pipeline to use unified logger-based timing system
5719
5504
 
@@ -5804,7 +5589,6 @@
5804
5589
 
5805
5590
  ### Changed
5806
5591
 
5807
- - Updated browser tool prompt to bias towards `observe` over `screenshot` by default
5808
5592
  - Changed auth credential removal to use soft-delete (disable) instead of hard-delete when OAuth refresh fails, keeping credentials in database for audit purposes
5809
5593
  - Changed default value of `tools.intentTracing` setting from false to true
5810
5594
 
@@ -5871,7 +5655,7 @@
5871
5655
  - Updated hashline reference format from `LINE:HASH` to `LINE#ID` throughout the codebase for improved clarity
5872
5656
  - Renamed hashline edit operations: `set_line` → `set`, `replace_lines` → `set_range`, `insert_after` → `insert` with support for `before` and `between` anchors
5873
5657
  - Changed hashline edit `body` field from string to array of strings for clearer multiline handling
5874
- - Updated handlebars helpers: renamed `hashline` to `href` and added `hline` for formatted line output
5658
+ - Updated handlebars helpers: renamed `hashline` to `hlineref` and added `hlinefull` for formatted line output
5875
5659
  - Improved insert operation to support `before`, `after`, and `between` (both anchors) positioning modes
5876
5660
  - Made autocorrect heuristics (boundary echo stripping, indent restoration) conditional on `PI_HL_AUTOCORRECT` environment variable
5877
5661
  - Updated SSH host discovery to load from managed omp config paths (.omp/ssh.json and ~/.omp/agent/ssh.json) in addition to legacy root-level ssh.json and .ssh.json files
@@ -5976,7 +5760,6 @@
5976
5760
  - Added `rules` option to CreateAgentSessionOptions for explicit rule configuration
5977
5761
  - Added `sessionDir` option to RpcClientOptions for specifying agent session directory
5978
5762
  - Added `Symbol.dispose` method to RpcClient for resource cleanup support
5979
- - Added `autocompleteMaxVisible` setting to configure the number of items shown in the autocomplete dropdown (3-20, default 5) ([#98](https://github.com/can1357/oh-my-pi/pull/98) by [@masonc15](https://github.com/masonc15))
5980
5763
  - Added `condition` and `scope` fields to rule frontmatter for advanced TTSR matching and stream filtering
5981
5764
  - Added `ttsr.interruptMode` setting to control when TTSR rules interrupt mid-stream vs inject warnings after completion
5982
5765
  - Added support for loading rules, prompts, commands, context files (AGENTS.md), and system prompts (SYSTEM.md) from ~/.agent/ directory (with fallback to ~/.agents/)
@@ -6038,51 +5821,55 @@
6038
5821
  - Improved `/changelog` performance by displaying only the most recent 3 versions by default, with a `--full` flag for the complete history ([#85](https://github.com/can1357/oh-my-pi/pull/85) by [@tctev](https://github.com/tctev))
6039
5822
  - Centralized builtin slash command definitions and handlers into a shared registry, replacing the large input-controller if-chain dispatch
6040
5823
 
5824
+ ## [12.7.5] - 2026-02-16
5825
+
5826
+ ### Changed
5827
+
5828
+ - Updated SMOL_MODEL_PRIORITY to include additional model variants (gpt-5.3-spark, cerebras/zai-glm-4.7, haiku-4-5, haiku-4.5) for improved fast model discovery
5829
+ - Updated SLOW_MODEL_PRIORITY to include additional model variants (gpt-5.3-codex, gpt-5.3, gpt-5.1-codex, gpt-5.1, opus-4.6, opus-4-6, opus-4.5, opus-4-5, opus-4.1, opus-4-1) for improved comprehensive model discovery
5830
+
5831
+ ## [12.7.3] - 2026-02-16
5832
+
5833
+ ### Fixed
5834
+
5835
+ - Suppressed hashline output for subagents without the edit tool (e.g. explore agents)
5836
+
5837
+ ## [12.7.1] - 2026-02-16
5838
+
5839
+ ### Changed
5840
+
5841
+ - Restructured execution procedure guidance to emphasize scope assessment and continuous tool-driven progress over planning-first approach
5842
+ - Updated task tracking instructions to prohibit metadata-only turns and require immediate completion marking of todo items
5843
+ - Clarified parallel execution guidance to distinguish between genuine parallelization and sequential work, with explicit criteria for Task tool usage
5844
+ - Modified output style requirements to mandate stating intent before tool calls and reordered style constraints for clarity
5845
+ - Reinforced requirement that every turn must include at least one tool call advancing the deliverable, with explicit failure condition for planning-only turns
5846
+
6041
5847
  ## [12.7.0] - 2026-02-16
6042
5848
 
6043
5849
  ### Added
6044
5850
 
6045
- - Added abort signal support to LSP file operations (`ensureFileOpen`, `refreshFile`) for cancellable file synchronization
6046
- - Added abort signal propagation through LSP request handlers (definition, references, hover, symbols, rename) enabling operation cancellation
6047
- - Added `shouldBypassAutocompleteOnEscape` callback to custom editor for context-aware escape key handling during active operations
6048
- - Added `contextPromotionTarget` model configuration option to specify a custom target model for context promotion
6049
- - Added automatic context promotion feature that switches to a larger-context model when approaching context limits
6050
- - Added `contextPromotion.enabled` setting to control automatic model promotion (enabled by default)
6051
- - Added `contextPromotion.thresholdPercent` setting to configure the context usage threshold for triggering promotion (default 90%)
6052
- - Added Brave web search provider as an alternative search option with recency filtering support
6053
- - Added `BRAVE_API_KEY` environment variable support for Brave web search authentication
6054
- - Added pagination support for fetching GitHub issue comments, allowing retrieval of all comments beyond the initial 50-comment limit
6055
- - Added comment count display showing partial results when not all comments could be fetched (e.g., '5 of 10 comments')
6056
- - Added secret obfuscation: env vars matching secret patterns and `secrets.json` entries are replaced with placeholders before sending to LLM providers, deobfuscated in tool call arguments
6057
- - Added `secrets.enabled` setting to toggle secret obfuscation
6058
- - Added full regex literal support for `secrets.json` entries (`"/pattern/flags"` syntax with escaped `/` handling, automatic `g` flag enforcement)
6059
-
6060
- ### Changed
6061
-
6062
- - Changed context promotion to trigger on context overflow instead of a configurable threshold, promoting to a larger model before attempting compaction
6063
- - Changed context promotion behavior to retry immediately on the promoted model without compacting, providing faster recovery from context limits
6064
- - Changed default grep context lines from 1 before/3 after to 0 before/0 after for more focused search results
6065
- - Changed escape key handling in custom editor to allow bypassing autocomplete dismissal when specified by parent controller
6066
- - Changed workspace diagnostics to support abort signals for cancellable diagnostic runs
6067
- - Changed LSP request cancellation to send `$/cancelRequest` notification to language servers when operations are aborted
6068
- - Changed input controller to bypass autocomplete on escape when loading animations, streaming, compacting, or running external processes
6069
- - Changed context promotion logic to use configured `contextPromotionTarget` when available, allowing per-model promotion customization
6070
- - Updated session compaction reserve token calculation to enforce a minimum 15% context window floor, ensuring more predictable compaction behavior regardless of configuration
6071
- - Improved session compaction to limit file operation summaries to 20 files per category, with indication of omitted files when exceeded
6072
- - Updated CLI update mechanism to support multiple native addon variants per platform, enabling fallback to baseline versions when modern variants are unavailable
6073
- - Updated web search provider priority order to include Brave (Exa → Brave → Jina → Perplexity → Anthropic → Gemini → Codex → Z.AI)
6074
- - Extended recency filter support to Brave provider alongside Perplexity
6075
- - Changed GitHub issue comment fetching to use paginated API requests with 100 comments per page instead of single request with 50-comment limit
5851
+ - Added Z.AI web search provider support via remote MCP endpoint (webSearchPrime)
5852
+ - Added `zai` as a selectable web search provider option in settings
5853
+ - Added Z.AI to automatic provider fallback chain for web search
6076
5854
 
6077
- ### Removed
5855
+ ## [12.6.0] - 2026-02-16
5856
+
5857
+ ### Added
6078
5858
 
6079
- - Removed `contextPromotion.thresholdPercent` setting as context promotion now triggers only on overflow
5859
+ - Added runtime tests covering extension provider registration and deferred model pattern resolution behavior.
5860
+
5861
+ ### Changed
5862
+
5863
+ - Improved welcome screen responsiveness to dynamically show or hide the right column based on available terminal width
5864
+ - Extended extension `registerProvider()` typing with OAuth provider support and source-aware registration metadata.
6080
5865
 
6081
5866
  ### Fixed
6082
5867
 
6083
- - Fixed LSP operations to properly respect abort signals and throw `ToolAbortError` when cancelled
6084
- - Fixed workspace diagnostics process cleanup to remove abort event listeners in finally block
6085
- - Fixed PTY-backed bash execution to enforce timeout completion when detached child processes keep the PTY stream open ([#88](https://github.com/can1357/oh-my-pi/issues/88))
5868
+ - Fixed welcome screen layout to gracefully handle small terminal widths and prevent rendering errors on narrow displays
5869
+ - Fixed welcome screen title truncation to prevent overflow when content exceeds available width
5870
+ - Fixed deferred `--model` resolution so extension-provided models are matched before fallback selection and unresolved explicit patterns no longer silently fallback.
5871
+ - Fixed CLI `--api-key` handling for deferred model resolution by applying runtime API key overrides after extension model selection.
5872
+ - Fixed extension provider registration cleanup to remove stale source-scoped custom API/OAuth providers across extension reloads.
6086
5873
 
6087
5874
  ## [12.5.1] - 2026-02-15
6088
5875
 
@@ -6662,7 +6449,6 @@
6662
6449
  ### Fixed
6663
6450
 
6664
6451
  - Fixed TUI crash when ask tool renders long user input exceeding terminal width by using Text component for word wrapping instead of raw line output
6665
- - Fixed TUI crash when todo tool renders long todo content exceeding terminal width by using Text component for word wrapping instead of truncation
6666
6452
 
6667
6453
  ## [11.5.0] - 2026-02-06
6668
6454
 
@@ -6717,7 +6503,7 @@
6717
6503
  - New `appendModeChange()` method in SessionManager to record mode transitions
6718
6504
  - New `mode` and `modeData` fields in SessionContext to track active agent mode
6719
6505
  - Support for `PI_PACKAGE_DIR` environment variable to override package directory (useful for Nix/Guix store paths)
6720
- - New keybindings for session management: `newSession`, `tree`, `fork`, and `resume` actions
6506
+ - New keybindings for session management: `toggleSessionNamedFilter` (Ctrl+N), `newSession`, `tree`, `fork`, and `resume` actions
6721
6507
  - Support for shell command execution in configuration values (API keys, headers) using `!` prefix, with result caching
6722
6508
  - New `clearOnShrink` display setting to control whether empty rows are cleared when content shrinks
6723
6509
  - New `SlashCommandInfo`, `SlashCommandLocation`, and `SlashCommandSource` types for extension slash command discovery
@@ -6906,7 +6692,7 @@
6906
6692
  - Added new subcommands to help text: `commit` for AI-assisted git commits, `stats` for AI usage statistics dashboard, and `jupyter` for managing the shared Jupyter gateway
6907
6693
  - Added `grep` subcommand to help text for testing the grep tool
6908
6694
  - Added `browser` tool documentation for browser automation using Puppeteer
6909
- - Added `todo` tool documentation for managing todo and task lists
6695
+ - Added `todo_write` tool documentation for managing todo and task lists
6910
6696
  - Added documentation for additional LLM provider API keys (Groq, Cerebras, xAI, OpenRouter, Mistral, z.ai, MiniMax, OpenCode, Cursor, Vercel AI Gateway) in environment variables reference
6911
6697
  - Added documentation for cloud provider configuration (AWS Bedrock, Google Vertex AI) in environment variables reference
6912
6698
  - Added documentation for search provider API keys (Perplexity, Anthropic Search) in environment variables reference
@@ -6966,7 +6752,7 @@
6966
6752
  - Changed `venvPath` property in PythonRuntime from nullable to optional (returns `undefined` instead of `null`)
6967
6753
  - Simplified notification settings from protocol-specific options (bell, osc99, osc9) to simple on/off toggle for `completion.notify` and `ask.notify`
6968
6754
  - Moved notification protocol detection and sending to `TERMINAL` API from local utility functions
6969
- - Changed task tool spawns configuration from "explore" to "\*" to allow subagents to spawn any agent type
6755
+ - Changed task tool spawns configuration from "explore" to "*" to allow subagents to spawn any agent type
6970
6756
  - Changed system prompt to enable parallel delegation guidance for all agents (removed coordinator-only restriction)
6971
6757
  - Changed task tool to automatically disable itself when maximum recursion depth is reached, preventing infinite nesting
6972
6758
  - Changed task concurrency from hardcoded constant to configurable setting via `task.maxConcurrency`
@@ -7058,7 +6844,7 @@
7058
6844
  - Tightened `ask` tool conditions to require multiple approaches with significantly different tradeoffs before prompting user
7059
6845
  - Strengthened `ask` tool guidance to default to action and only ask when genuinely blocked by decisions with materially different outcomes
7060
6846
  - Changed refactor workflow to automatically remove now-unused elements and note removals instead of asking for confirmation
7061
- - Enforced exclusive concurrency mode for all file-modifying tools (edit, write, bash, python, ssh, todo) to prevent concurrent execution conflicts
6847
+ - Enforced exclusive concurrency mode for all file-modifying tools (edit, write, bash, python, ssh, todo-write) to prevent concurrent execution conflicts
7062
6848
  - Updated `ask` tool guidance to prioritize proactive problem-solving and default to action, asking only when truly blocked by decisions that materially change scope or behavior
7063
6849
  - Changed Python kernel initialization to require shared gateway mode; local gateway startup has been removed
7064
6850
  - Changed shared gateway error handling to retry on server errors (5xx status codes) before failing
@@ -7099,7 +6885,7 @@
7099
6885
 
7100
6886
  - Added `find.enabled`, `grep.enabled`, `ls.enabled`, `notebook.enabled`, `fetch.enabled`, `web_search.enabled`, `lsp.enabled`, and `calc.enabled` settings to control availability of individual tools
7101
6887
  - Added conditional tool documentation in system prompt that dynamically lists only enabled specialized tools
7102
- - Added `todos.enabled` setting to control availability of the todo tool for task tracking
6888
+ - Added `todos.enabled` setting to control availability of the todo_write tool for task tracking
7103
6889
  - Added `tools` field to agent frontmatter for declaring agent-specific tool capabilities
7104
6890
 
7105
6891
  ### Changed
@@ -7596,7 +7382,7 @@
7596
7382
 
7597
7383
  ### Removed
7598
7384
 
7599
- - Removed git utility functions (\_git, git_status, git_diff, git_log, git_show, git_file_at, git_branch, git_has_changes) from IPython prelude
7385
+ - Removed git utility functions (_git, git_status, git_diff, git_log, git_show, git_file_at, git_branch, git_has_changes) from IPython prelude
7600
7386
 
7601
7387
  ## [8.2.0] - 2026-01-24
7602
7388
 
@@ -7663,10 +7449,10 @@
7663
7449
  - Changed Web Search result rendering to use renderOutputBlock with answer, sources, related questions, and metadata sections
7664
7450
  - Changed Find, Grep, and Ls tools to use renderFileList and renderTreeList for consistent file/item listing
7665
7451
  - Changed Calculator tool result rendering to use renderTreeList for result item display
7666
- - Changed Notebook and Todo tools to use new TUI rendering components for consistent output format
7452
+ - Changed Notebook and TodoWrite tools to use new TUI rendering components for consistent output format
7667
7453
  - Refactored render-utils to move tree-related utilities to TUI module (getTreeBranch, getTreeContinuePrefix)
7668
7454
  - Changed import organization in sdk.ts for consistency
7669
- - Changed tool result rendering to merge call and result displays, showing tool arguments (command, pattern, query, path) in result headers for Bash, Calculator, Fetch, Find, Grep, Ls, LSP, Notebook, Read, SSH, Todo, Web Search, and Write tools
7455
+ - Changed tool result rendering to merge call and result displays, showing tool arguments (command, pattern, query, path) in result headers for Bash, Calculator, Fetch, Find, Grep, Ls, LSP, Notebook, Read, SSH, TodoWrite, Web Search, and Write tools
7670
7456
  - Changed Read tool title to display line range when offset or limit arguments are provided
7671
7457
  - Changed worker instantiation to use direct URL import instead of pre-bundled worker files
7672
7458
  - Changed `omp commit` to use agentic mode by default with tool-based git inspection
@@ -7680,7 +7466,7 @@
7680
7466
  - Changed Calculator tool result display to show both expression and output (e.g., `2+2 = 4`) instead of just the result
7681
7467
  - Changed Python tool output to group status information under a labeled section for clearer organization
7682
7468
  - Changed SSH tool output to apply consistent styling to non-ANSI output lines
7683
- - Changed Todo tool to respect expanded/collapsed state and use standard preview limits
7469
+ - Changed Todo Write tool to respect expanded/collapsed state and use standard preview limits
7684
7470
  - Changed Web Search related questions to respect expanded/collapsed state instead of always showing all items
7685
7471
  - Changed empty and error state rendering across multiple tools (Find, Grep, Ls, Notebook, Calculator, Ask) to include consistent status headers
7686
7472
  - Changed split commit to support hunk selectors (all, indices, or line ranges) instead of whole-file staging
@@ -7782,12 +7568,12 @@
7782
7568
  - Updated all tools to use structured metadata instead of inline notices for truncation, limits, and diagnostics
7783
7569
  - Replaced manual error formatting with ToolError.render() and standardized error handling
7784
7570
  - Enhanced bash and python executors to save full output as artifacts when truncated
7785
- - Improved abort signal handling across <caution>ith consistent ToolAbortError
7571
+ - Improved abort signal handling across all tools with consistent ToolAbortError
7786
7572
  - Renamed task parameter from `vars` to `args` throughout task tool interface and updated template rendering to support built-in `{{id}}` and `{{description}}` placeholders
7787
- - Simplified todo tool by removing active_form parameter, using single content field for task descriptions
7573
+ - Simplified todo-write tool by removing active_form parameter, using single content field for task descriptions
7788
7574
  - Updated system prompt structure with `<important>` and `<avoid>` tags, clearer critical sections, and standardized whitespace handling
7789
7575
  - Renamed web_fetch tool to fetch and removed internal URL handling (use read tool instead)
7790
- - Standardized tool parameter names from camelCase to snake_case across edit, grep, python, and todo tools
7576
+ - Standardized tool parameter names from camelCase to snake_case across edit, grep, python, and todo-write tools
7791
7577
  - Unified timeout parameters across all tools with auto-conversion from milliseconds and reasonable clamping (1s-3600s for bash/ssh, 1s-600s for python/gemini-image)
7792
7578
  - Simplified web-search tool by removing advanced parameters (`max_tokens`, `model`, `search_domain_filter`, `search_context_size`, `return_related_questions`) and using `recency` instead of `search_recency_filter`
7793
7579
  - Restructured tool documentation with standardized `<instruction>`, `<output>`, `<critical>`, and `<avoid>` sections across all 18 tools
@@ -8069,7 +7855,7 @@
8069
7855
 
8070
7856
  - Patch application handles repeated context blocks, preserves original indentation on fuzzy match
8071
7857
  - Ambiguous context matching resolves duplicates using adjacent @@ anchor positioning
8072
- - Patch parser handles bare \*\*\* terminators, model hallucination markers, line hint ranges
7858
+ - Patch parser handles bare *** terminators, model hallucination markers, line hint ranges
8073
7859
  - Function context matching handles signatures with and without empty parentheses
8074
7860
  - Fixed session title generation to respect OMP_NO_TITLE environment variable
8075
7861
  - Fixed Python module discovery to use import.meta.dir for ES module compatibility
@@ -8216,7 +8002,7 @@
8216
8002
  - Enhanced Python kernel availability checking with faster validation
8217
8003
  - Optimized Python environment warming to avoid blocking during tool initialization
8218
8004
  - Reorganized settings interface into behavior, tools, display, voice, status, lsp, and exa tabs
8219
- - Migrated environment variables from PI* to OMP* prefix with automatic migration
8005
+ - Migrated environment variables from PI_ to OMP_ prefix with automatic migration
8220
8006
  - Updated model selector to use TabBar component for provider navigation
8221
8007
  - Changed role badges to inverted style with colored backgrounds
8222
8008
  - Added support for /models command alias in addition to /model
@@ -8333,6 +8119,12 @@
8333
8119
 
8334
8120
  - Replace sharp with wasm-vips for cross-platform image processing without native dependencies
8335
8121
 
8122
+ ## [4.8.1] - 2026-01-12
8123
+
8124
+ ### Fixed
8125
+
8126
+ - Prevent bun from statically resolving sharp import to fix runtime errors on arm64
8127
+
8336
8128
  ## [4.8.0] - 2026-01-12
8337
8129
 
8338
8130
  ### Fixed
@@ -8396,11 +8188,11 @@
8396
8188
 
8397
8189
  ### Added
8398
8190
 
8399
- - Added `todo` tool for creating and managing structured task lists during coding sessions
8191
+ - Added `todo_write` tool for creating and managing structured task lists during coding sessions
8400
8192
  - Added persistent todo panel above the editor that displays task progress
8401
8193
  - Added `Ctrl+T` keybinding to toggle todo list expansion
8402
8194
  - Added grouped display for consecutive Read tool calls, showing multiple file reads in a compact tree view
8403
- - Added `todo` tool and persistent todo panel above the editor
8195
+ - Added `todo_write` tool and persistent todo panel above the editor
8404
8196
 
8405
8197
  ### Changed
8406
8198
 
@@ -8510,8 +8302,6 @@
8510
8302
 
8511
8303
  - Fixed editor border rendering glitch after canceling slash command autocomplete
8512
8304
  - Fixed login/logout credential path message to reference agent.db
8513
- - Removed legacy auth.json file—credentials are stored exclusively in agent.db
8514
- - Removed legacy auth.json file—credentials are stored exclusively in agent.db
8515
8305
 
8516
8306
  ## [4.2.0] - 2026-01-10
8517
8307
 
@@ -8778,28 +8568,6 @@
8778
8568
  - Added auto-chdir to temp directories when starting in home unless `--allow-home` is set
8779
8569
  - Added upfront diff parsing and filtering for code review command to exclude lock files, generated code, and binary assets
8780
8570
 
8781
- ### Changed
8782
-
8783
- - Changed `Ctrl+P` to cycle through role models (slow → default → smol) instead of all available models
8784
- - Changed `Shift+Ctrl+P` to cycle role models temporarily (not persisted)
8785
- - Changed Extension Control Center to scale with terminal height instead of fixed 25-line limit
8786
- - Changed review command to parse git diff upfront and provide structured context to reviewer agents
8787
- - Changed session persistence to use structured logging instead of console.error for persistence failures
8788
- - Changed find tool to use fd command for .gitignore discovery instead of Bun.Glob for better abort handling
8789
- - Changed LSP config loading to only mark overrides when servers are actually defined
8790
- - Changed task tool to require explicit task `id` field instead of auto-generating names from agent type
8791
- - Changed grep and find tools to use native Bun file APIs instead of Node.js fs module for improved performance
8792
- - Changed YouTube scraper to use async command execution with proper stream handling
8793
- - Improved rust-analyzer diagnostic polling to use version-based stability detection instead of time-based delays
8794
- - Changed theme icons for extension types to use Unicode symbols (✧, ⚒) instead of text abbreviations (SK, TL, MCP)
8795
- - Changed task tool to use short CamelCase task IDs instead of agent-based naming (e.g., 'SessionStore' instead of 'explore_0')
8796
- - Changed task tool to accept single `agent` parameter at top level instead of per-task agent specification
8797
- - Changed reviewer agent to use `complete` tool instead of `submit_review` for finishing reviews
8798
- - Changed theme icons for extensions to use Unicode symbols instead of text abbreviations
8799
- - Changed LSP file type matching to support exact filename matches in addition to extensions
8800
- - Improved rust-analyzer diagnostic polling to use version-based stability detection
8801
- - Refactored web-fetch tool to use modular scraper architecture for improved maintainability
8802
-
8803
8571
  ### Fixed
8804
8572
 
8805
8573
  - Fixed auto-chdir to only use existing directories and fall back to `tmpdir()`
@@ -8832,6 +8600,28 @@
8832
8600
  - Fixed parallel task execution to fail fast on first error instead of waiting for all workers
8833
8601
  - Fixed byte counting in task output truncation to handle multi-byte Unicode characters correctly
8834
8602
 
8603
+ ### Changed
8604
+
8605
+ - Changed `Ctrl+P` to cycle through role models (slow → default → smol) instead of all available models
8606
+ - Changed `Shift+Ctrl+P` to cycle role models temporarily (not persisted)
8607
+ - Changed Extension Control Center to scale with terminal height instead of fixed 25-line limit
8608
+ - Changed review command to parse git diff upfront and provide structured context to reviewer agents
8609
+ - Changed session persistence to use structured logging instead of console.error for persistence failures
8610
+ - Changed find tool to use fd command for .gitignore discovery instead of Bun.Glob for better abort handling
8611
+ - Changed LSP config loading to only mark overrides when servers are actually defined
8612
+ - Changed task tool to require explicit task `id` field instead of auto-generating names from agent type
8613
+ - Changed grep and find tools to use native Bun file APIs instead of Node.js fs module for improved performance
8614
+ - Changed YouTube scraper to use async command execution with proper stream handling
8615
+ - Improved rust-analyzer diagnostic polling to use version-based stability detection instead of time-based delays
8616
+ - Changed theme icons for extension types to use Unicode symbols (✧, ⚒) instead of text abbreviations (SK, TL, MCP)
8617
+ - Changed task tool to use short CamelCase task IDs instead of agent-based naming (e.g., 'SessionStore' instead of 'explore_0')
8618
+ - Changed task tool to accept single `agent` parameter at top level instead of per-task agent specification
8619
+ - Changed reviewer agent to use `complete` tool instead of `submit_review` for finishing reviews
8620
+ - Changed theme icons for extensions to use Unicode symbols instead of text abbreviations
8621
+ - Changed LSP file type matching to support exact filename matches in addition to extensions
8622
+ - Improved rust-analyzer diagnostic polling to use version-based stability detection
8623
+ - Refactored web-fetch tool to use modular scraper architecture for improved maintainability
8624
+
8835
8625
  ### Removed
8836
8626
 
8837
8627
  - Removed `submit_review` tool - reviewers now finish via `complete` tool with structured output
@@ -8914,28 +8704,9 @@
8914
8704
 
8915
8705
  ## [3.21.0] - 2026-01-06
8916
8706
 
8917
- ### Added
8918
-
8919
- - Added `webSearchProvider` setting to override auto-detection priority (Exa > Perplexity > Anthropic)
8920
- - Added `imageProvider` setting to override auto-detection priority (OpenRouter > Gemini)
8921
- - Added `git.enabled` setting to enable/disable the structured git tool
8922
- - Added `offset` and `limit` parameters to Output tool for paginated reading of large outputs
8923
- - Added provider fallback chain for web search that tries all configured providers before failing
8924
- - Added `SearchProviderError` class with HTTP status for actionable provider error messages
8925
- - Added bash interceptor rule to block git commands when structured git tool is enabled
8926
- - Added validation requiring `message` parameter for git commit operations (prevents interactive editor)
8927
- - Added output ID hints in multi-agent Task results pointing to Output tool for full logs
8928
- - Added fuzzy matching support for `all: true` mode in edit tool, enabling replacement of similar text blocks with whitespace differences
8929
- - Added `all` parameter to edit tool for replacing all occurrences instead of requiring unique matches
8930
- - Added OpenRouter support for image generation when `OPENROUTER_API_KEY` is set
8931
- - Added ImageMagick fallback for image processing when sharp module is unavailable
8932
- - Added slash commands to the extensions inspector panel for visibility and management
8933
- - Added support for file-based slash commands from `commands/` directories
8934
- - Added `$ARGUMENTS` placeholder for slash command argument substitution, aligning with Claude and Codex conventions
8935
-
8936
8707
  ### Changed
8937
8708
 
8938
- - Switched from local `@oh-my-pi/pi-ai` to upstream `@oh-my-pi/pi-ai` package
8709
+ - Switched from local `@oh-my-pi/pi-ai` to upstream `@mariozechner/pi-ai` package
8939
8710
  - Refactored tool renderers to be co-located with their respective tool implementations for improved code organization
8940
8711
  - Changed web search to try all configured providers in sequence with fallback before reporting errors
8941
8712
  - Changed default Anthropic web search model from `claude-sonnet-4-5-20250514` to `claude-haiku-4-5`
@@ -8952,6 +8723,25 @@
8952
8723
  - Changed argument substitution order in slash commands to process positional args ($1, $2) before wildcards ($@, $ARGUMENTS) to prevent re-substitution issues
8953
8724
  - Changed image tool name from `gemini_image` to `generate_image` with label `GenerateImage`
8954
8725
 
8726
+ ### Added
8727
+
8728
+ - Added `webSearchProvider` setting to override auto-detection priority (Exa > Perplexity > Anthropic)
8729
+ - Added `imageProvider` setting to override auto-detection priority (OpenRouter > Gemini)
8730
+ - Added `git.enabled` setting to enable/disable the structured git tool
8731
+ - Added `offset` and `limit` parameters to Output tool for paginated reading of large outputs
8732
+ - Added provider fallback chain for web search that tries all configured providers before failing
8733
+ - Added `WebSearchProviderError` class with HTTP status for actionable provider error messages
8734
+ - Added bash interceptor rule to block git commands when structured git tool is enabled
8735
+ - Added validation requiring `message` parameter for git commit operations (prevents interactive editor)
8736
+ - Added output ID hints in multi-agent Task results pointing to Output tool for full logs
8737
+ - Added fuzzy matching support for `all: true` mode in edit tool, enabling replacement of similar text blocks with whitespace differences
8738
+ - Added `all` parameter to edit tool for replacing all occurrences instead of requiring unique matches
8739
+ - Added OpenRouter support for image generation when `OPENROUTER_API_KEY` is set
8740
+ - Added ImageMagick fallback for image processing when sharp module is unavailable
8741
+ - Added slash commands to the extensions inspector panel for visibility and management
8742
+ - Added support for file-based slash commands from `commands/` directories
8743
+ - Added `$ARGUMENTS` placeholder for slash command argument substitution, aligning with Claude and Codex conventions
8744
+
8955
8745
  ### Fixed
8956
8746
 
8957
8747
  - Fixed read tool markitdown truncation message using broken template string (missing `${` around format call)
@@ -9222,7 +9012,7 @@
9222
9012
  - Added Discovery settings tab in interactive mode to enable/disable individual configuration providers
9223
9013
  - Added provider source attribution showing which tool contributed each configuration item
9224
9014
  - Added support for Cursor MDC rule format with frontmatter (description, globs, alwaysApply)
9225
- - Added support for Windsurf rules from .windsurf/rules/\*.md and global_rules.md
9015
+ - Added support for Windsurf rules from .windsurf/rules/*.md and global_rules.md
9226
9016
  - Added support for Cline rules from .clinerules file or directory
9227
9017
  - Added support for GitHub Copilot instructions with applyTo glob patterns
9228
9018
  - Added support for Gemini extensions and system.md customization files
@@ -9245,7 +9035,7 @@
9245
9035
 
9246
9036
  ### Added
9247
9037
 
9248
- - Added `omp update` command to check for and install updates from GitHub releases or via bun
9038
+ - Added `pi update` command to check for and install updates from GitHub releases or via bun
9249
9039
 
9250
9040
  ### Changed
9251
9041
 
@@ -9259,7 +9049,7 @@
9259
9049
  ### Added
9260
9050
 
9261
9051
  - Added shell environment snapshot to preserve user aliases, functions, and shell options when executing bash commands
9262
- - Added support for `OMP_BASH_NO_CI`, `OMP_BASH_NO_LOGIN`, and `OMP_SHELL_PREFIX` environment variables for shell customization
9052
+ - Added support for `PI_BASH_NO_CI`, `PI_BASH_NO_LOGIN`, and `PI_SHELL_PREFIX` environment variables for shell customization
9263
9053
  - Added zsh support alongside bash for shell detection and configuration
9264
9054
 
9265
9055
  ### Changed
@@ -9274,7 +9064,7 @@
9274
9064
  - Added provider tabs to model selector with Tab/Arrow navigation for filtering models by provider
9275
9065
  - Added context menu to model selector for choosing model role (Default, Smol, Slow) instead of keyboard shortcuts
9276
9066
  - Added LSP diagnostics display in tool execution output showing errors and warnings after file edits
9277
- - Added centralized file logger with daily rotation to `~/.omp/logs/` for debugging production issues
9067
+ - Added centralized file logger with daily rotation to `~/.pi/logs/` for debugging production issues
9278
9068
  - Added `logger` property to hook and custom tool APIs for error/warning/debug logging
9279
9069
  - Added `output` tool to read full agent/task outputs by ID when truncated previews are insufficient
9280
9070
  - Added `task` tool to reviewer agent, enabling parallel exploration of large codebases during reviews
@@ -9285,8 +9075,8 @@
9285
9075
  - Added `explicitTools` option to `createAgentSession` for enabling hidden tools by name
9286
9076
  - Added example review tools (`report_finding`, `submit_review`) with structured findings accumulation and verdict rendering
9287
9077
  - Added `/review` example command for interactive code review with branch comparison, uncommitted changes, and commit review modes
9288
- - Custom TypeScript slash commands: Create programmable commands at `~/.omp/agent/commands/[name]/index.ts` or `.omp/commands/[name]/index.ts`. Commands export a factory returning `{ name, description, execute(args, ctx) }`. Return a string to send as LLM prompt, or void for fire-and-forget actions. Full access to `HookCommandContext` for UI dialogs, session control, and shell execution.
9289
- - Claude command directories: Markdown slash commands now also load from `~/.claude/commands/` and `.claude/commands/` (parallel to existing `.omp/commands/` support)
9078
+ - Custom TypeScript slash commands: Create programmable commands at `~/.pi/agent/commands/[name]/index.ts` or `.pi/commands/[name]/index.ts`. Commands export a factory returning `{ name, description, execute(args, ctx) }`. Return a string to send as LLM prompt, or void for fire-and-forget actions. Full access to `HookCommandContext` for UI dialogs, session control, and shell execution.
9079
+ - Claude command directories: Markdown slash commands now also load from `~/.claude/commands/` and `.claude/commands/` (parallel to existing `.pi/commands/` support)
9290
9080
  - `commands.enableClaudeUser` and `commands.enableClaudeProject` settings to disable Claude command directory loading
9291
9081
  - `/export --copy` option to copy entire session as formatted text to clipboard
9292
9082
 
@@ -9344,7 +9134,7 @@
9344
9134
  - Smol model auto-discovery using priority chain: haiku > flash > mini
9345
9135
  - Slow model auto-discovery using priority chain: gpt-5.2-codex > codex > gpt > opus > pro
9346
9136
  - CLI args for model roles: `--smol <model>` and `--slow <model>` (ephemeral, not persisted)
9347
- - Env var overrides: `OMP_SMOL_MODEL` and `OMP_SLOW_MODEL`
9137
+ - Env var overrides: `PI_SMOL_MODEL` and `PI_SLOW_MODEL`
9348
9138
  - Title generation now uses configured smol model from settings
9349
9139
  - LSP diagnostics on edit: Edit tool can now return LSP diagnostics after editing code files. Disabled by default to avoid noise during multi-edit sequences. Enable via `lsp.diagnosticsOnEdit` setting.
9350
9140
  - LSP workspace diagnostics: New `lsp action=workspace_diagnostics` command checks the entire project for errors. Auto-detects project type and uses appropriate checker (rust-analyzer/cargo for Rust, tsc for TypeScript, go build for Go, pyright for Python).
@@ -9356,7 +9146,7 @@
9356
9146
  - Edit fuzzy match setting: Added `edit.fuzzyMatch` setting (enabled by default) to control whether the edit tool accepts high-confidence fuzzy matches for whitespace/indentation differences. Toggle via `/settings`.
9357
9147
  - Multi-server LSP diagnostics: Diagnostics now query all applicable language servers for a file type. For TypeScript/JavaScript projects with Biome, this means both type errors (from tsserver) and lint errors (from Biome) are reported together.
9358
9148
  - Comprehensive LSP server configurations for 40+ languages including Rust, Go, Python, Java, Kotlin, Scala, Haskell, OCaml, Elixir, Ruby, PHP, C#, Lua, Nix, and many more. Each server includes sensible defaults for args, settings, and init options.
9359
- - Extended LSP config file search paths: Now searches for `lsp.json`, `.lsp.json` in project root and `.omp/` subdirectory, plus user-level configs in `~/.omp/` and home directory.
9149
+ - Extended LSP config file search paths: Now searches for `lsp.json`, `.lsp.json` in project root and `.pi/` subdirectory, plus user-level configs in `~/.pi/` and home directory.
9360
9150
 
9361
9151
  ### Changed
9362
9152
 
@@ -9432,64 +9222,1121 @@
9432
9222
 
9433
9223
  Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mono](https://github.com/badlogic/pi-mono).
9434
9224
 
9435
- ## [0.31.1] - 2026-01-02
9225
+ ## [1.5.1] - 2026-01-03
9436
9226
 
9437
- ### Fixed
9227
+ ### Added
9438
9228
 
9439
- - Model selector no longer allows negative index when pressing arrow keys before models finish loading ([#398](https://github.com/badlogic/pi-mono/pull/398) by [@mitsuhiko](https://github.com/mitsuhiko))
9440
- - Type guard functions (`isBashToolResult`, etc.) now exported at runtime, not just in type declarations ([#397](https://github.com/badlogic/pi-mono/issues/397))
9229
+ - Added shell environment snapshot to preserve user aliases, functions, and shell options when executing bash commands
9230
+ - Added support for `PI_BASH_NO_CI`, `PI_BASH_NO_LOGIN`, and `PI_SHELL_PREFIX` environment variables for shell customization
9231
+ - Added zsh support alongside bash for shell detection and configuration
9441
9232
 
9442
- ## [0.31.0] - 2026-01-02
9233
+ ### Changed
9443
9234
 
9444
- This release introduces session trees for in-place branching, major API changes to hooks and custom tools, and structured compaction with file tracking.
9235
+ - Changed shell detection to prefer user's `$SHELL` when it's bash or zsh, with improved fallback path resolution
9236
+ - Changed Edit tool to reject `.ipynb` files with guidance to use NotebookEdit tool instead
9445
9237
 
9446
- ### Session Tree
9238
+ ## [1.5.0] - 2026-01-03
9447
9239
 
9448
- Sessions now use a tree structure with `id`/`parentId` fields. This enables in-place branching: navigate to any previous point with `/tree`, continue from there, and switch between branches while preserving all history in a single file.
9240
+ ### Added
9449
9241
 
9450
- **Existing sessions are automatically migrated** (v1 v2) on first load. No manual action required.
9242
+ - Added provider tabs to model selector with Tab/Arrow navigation for filtering models by provider
9243
+ - Added context menu to model selector for choosing model role (Default, Smol, Slow) instead of keyboard shortcuts
9244
+ - Added LSP diagnostics display in tool execution output showing errors and warnings after file edits
9245
+ - Added centralized file logger with daily rotation to `~/.pi/logs/` for debugging production issues
9246
+ - Added `logger` property to hook and custom tool APIs for error/warning/debug logging
9247
+ - Added `output` tool to read full agent/task outputs by ID when truncated previews are insufficient
9248
+ - Added `task` tool to reviewer agent, enabling parallel exploration of large codebases during reviews
9249
+ - Added subprocess tool registry for extracting and rendering tool data from subprocess agents in real-time
9250
+ - Added combined review result rendering showing verdict and findings in a tree structure
9251
+ - Auto-read file mentions: Reference files with `@path/to/file.ext` syntax in prompts to automatically inject their contents, eliminating manual Read tool calls
9252
+ - Added `hidden` property for custom tools to exclude them from default tool list unless explicitly requested
9253
+ - Added `explicitTools` option to `createAgentSession` for enabling hidden tools by name
9254
+ - Added example review tools (`report_finding`, `submit_review`) with structured findings accumulation and verdict rendering
9255
+ - Added `/review` example command for interactive code review with branch comparison, uncommitted changes, and commit review modes
9256
+ - Custom TypeScript slash commands: Create programmable commands at `~/.pi/agent/commands/[name]/index.ts` or `.pi/commands/[name]/index.ts`. Commands export a factory returning `{ name, description, execute(args, ctx) }`. Return a string to send as LLM prompt, or void for fire-and-forget actions. Full access to `HookCommandContext` for UI dialogs, session control, and shell execution.
9257
+ - Claude command directories: Markdown slash commands now also load from `~/.claude/commands/` and `.claude/commands/` (parallel to existing `.pi/commands/` support)
9258
+ - `commands.enableClaudeUser` and `commands.enableClaudeProject` settings to disable Claude command directory loading
9259
+ - `/export --copy` option to copy entire session as formatted text to clipboard
9451
9260
 
9452
- New entry types: `BranchSummaryEntry` (context from abandoned branches), `CustomEntry` (hook state), `CustomMessageEntry` (hook-injected messages), `LabelEntry` (bookmarks).
9261
+ ### Changed
9453
9262
 
9454
- See [docs/session.md](docs/session.md) for the file format and `SessionManager` API.
9263
+ - Changed model selector keyboard shortcuts from S/L keys to a context menu opened with Enter
9264
+ - Changed model role indicators from symbols (✓ ⚡ 🧠) to labeled badges ([ DEFAULT ] [ SMOL ] [ SLOW ])
9265
+ - Changed model list sorting to include secondary sort by model ID within each provider
9266
+ - Changed silent error suppression to log warnings and debug info for tool errors, theme loading, and command loading failures
9267
+ - Changed Task tool progress display to show agent index (e.g., `reviewer(0)`) for easier Output tool ID derivation
9268
+ - Changed Task tool output to only include file paths when Output tool is unavailable, providing Read tool fallback
9269
+ - Changed Task tool output references to use simpler ID format (e.g., `reviewer_0`) with line/char counts for Output tool integration
9270
+ - Changed subagent recursion prevention from blanket blocking to same-agent blocking. Non-recursive agents can now spawn other agent types (e.g., reviewer can spawn explore agents) but cannot spawn themselves.
9271
+ - Changed `/review` command from markdown to interactive TypeScript with mode selection menu (branch comparison, uncommitted changes, commit review, custom)
9272
+ - Changed bundled commands to be overridable by user/project commands with same name
9273
+ - Changed subprocess termination to wait for message_end event to capture accurate token counts
9274
+ - Changed token counting in subprocess to accumulate across messages instead of overwriting
9275
+ - Updated bundled `reviewer` agent to use structured review tools with priority-based findings (P0-P3) and formal verdict submission
9276
+ - Task tool now streams artifacts in real-time: input written before spawn, session jsonl written by subprocess, output written at completion
9455
9277
 
9456
- ### Hooks Migration
9278
+ ### Removed
9457
9279
 
9458
- The hooks API has been restructured with more granular events and better session access.
9280
+ - Removed separate Exa error logger in favor of centralized logging system
9281
+ - Removed `findings_count` parameter from `submit_review` tool - findings are now counted automatically
9282
+ - Removed artifacts location display from task tool output
9459
9283
 
9460
- **Type renames:**
9284
+ ### Fixed
9461
9285
 
9462
- - `HookEventContext` `HookContext`
9463
- - `HookCommandContext` is now a new interface extending `HookContext` with session control methods
9286
+ - Fixed race condition in event listener iteration by copying array before iteration to prevent mutation during callbacks
9287
+ - Fixed potential memory leak from orphaned abort controllers by properly aborting existing controllers before replacement
9288
+ - Fixed stream reader resource leak by adding proper `releaseLock()` calls in finally blocks
9289
+ - Fixed hook API methods throwing clear errors when handlers are not initialized instead of silently failing
9290
+ - Fixed LSP client race conditions with concurrent client creation and file operations using proper locking
9291
+ - Fixed Task tool progress display showing stale data by cloning progress objects before passing to callbacks
9292
+ - Fixed Task tool missing final progress events by waiting for readline to close before resolving
9293
+ - Fixed RPC mode race condition with concurrent prompt commands by serializing execution
9294
+ - Fixed pre-commit hook race condition causing `index.lock` errors when GitKraken/IDE git integrations detect file changes during formatting
9295
+ - Fixed Task tool output artifacts (`out.md`) containing duplicated text from streaming updates
9296
+ - Fixed Task tool progress display showing repeated nearly-identical lines during streaming
9297
+ - Fixed Task tool subprocess model selection ignoring agent's configured model and falling back to settings default. The `--model` flag now accepts `provider/model` format directly.
9298
+ - Fixed Task tool showing "done + succeeded" when aborted; now correctly displays "⊘ aborted" status
9464
9299
 
9465
- **Event changes:**
9300
+ ## [0.50.1] - 2026-01-26
9466
9301
 
9467
- - The monolithic `session` event is now split into granular events: `session_start`, `session_before_switch`, `session_switch`, `session_before_branch`, `session_branch`, `session_before_compact`, `session_compact`, `session_shutdown`
9468
- - `session_before_switch` and `session_switch` events now include `reason: "new" | "resume"` to distinguish between `/new` and `/resume`
9469
- - New `session_before_tree` and `session_tree` events for `/tree` navigation (hook can provide custom branch summary)
9470
- - New `before_agent_start` event: inject messages before the agent loop starts
9471
- - New `context` event: modify messages non-destructively before each LLM call
9472
- - Session entries are no longer passed in events. Use `ctx.sessionManager.getEntries()` or `ctx.sessionManager.getBranch()` instead
9302
+ ### Fixed
9473
9303
 
9474
- **API changes:**
9304
+ - Git extension updates now handle force-pushed remotes gracefully instead of failing ([#961](https://github.com/badlogic/pi-mono/pull/961) by [@aliou](https://github.com/aliou))
9305
+ - Extension `ctx.newSession({ setup })` now properly syncs agent state and renders messages after setup callback runs ([#968](https://github.com/badlogic/pi-mono/issues/968))
9306
+ - Fixed extension UI bindings not initializing when starting with no extensions, which broke UI methods after `/reload`
9307
+ - Fixed `/hotkeys` output to title-case extension hotkeys ([#969](https://github.com/badlogic/pi-mono/pull/969) by [@Perlence](https://github.com/Perlence))
9308
+ - Fixed model catalog generation to exclude deprecated OpenCode Zen models ([#970](https://github.com/badlogic/pi-mono/pull/970) by [@DanielTatarkin](https://github.com/DanielTatarkin))
9309
+ - Fixed git extension removal to prune empty directories
9475
9310
 
9476
- - `pi.send(text, attachments?)` → `pi.sendMessage(message, triggerTurn?)` (creates `CustomMessageEntry`)
9477
- - New `pi.appendEntry(customType, data?)` for hook state persistence (not in LLM context)
9478
- - New `pi.registerCommand(name, options)` for custom slash commands (handler receives `HookCommandContext`)
9479
- - New `pi.registerMessageRenderer(customType, renderer)` for custom TUI rendering
9480
- - New `ctx.isIdle()`, `ctx.abort()`, `ctx.hasQueuedMessages()` for agent state (available in all events)
9481
- - New `ctx.ui.editor(title, prefill?)` for multi-line text editing with Ctrl+G external editor support
9482
- - New `ctx.ui.custom(component)` for full TUI component rendering with keyboard focus
9483
- - New `ctx.ui.setStatus(key, text)` for persistent status text in footer (multiple hooks can set their own)
9484
- - New `ctx.ui.theme` getter for styling text with theme colors
9485
- - `ctx.exec()` moved to `pi.exec()`
9486
- - `ctx.sessionFile` → `ctx.sessionManager.getSessionFile()`
9487
- - New `ctx.modelRegistry` and `ctx.model` for API key resolution
9311
+ ## [0.50.0] - 2026-01-26
9488
9312
 
9489
- **HookCommandContext (slash commands only):**
9313
+ ### New Features
9490
9314
 
9491
- - `ctx.waitForIdle()` - wait for agent to finish streaming
9492
- - `ctx.newSession(options?)` - create new sessions with optional setup callback
9315
+ - Pi packages for bundling and installing extensions, skills, prompts, and themes. See [docs/packages.md](docs/packages.md).
9316
+ - Hot reload (`/reload`) of resources including AGENTS.md, SYSTEM.md, APPEND_SYSTEM.md, prompt templates, skills, themes, and extensions. See [README.md#commands](README.md#commands) and [README.md#context-files](README.md#context-files).
9317
+ - Custom providers via `pi.registerProvider()` for proxies, custom endpoints, OAuth or SSO flows, and non-standard streaming APIs. See [docs/custom-provider.md](docs/custom-provider.md).
9318
+ - Azure OpenAI Responses provider support with deployment-aware model mapping. See [docs/providers.md#azure-openai](docs/providers.md#azure-openai).
9319
+ - OpenRouter routing support for custom models via `openRouterRouting`. See [docs/providers.md#api-keys](docs/providers.md#api-keys) and [docs/models.md](docs/models.md).
9320
+ - Skill invocation messages are now collapsible and skills can opt out of model invocation via `disable-model-invocation`. See [docs/skills.md#frontmatter](docs/skills.md#frontmatter).
9321
+ - Session selector renaming and configurable keybindings. See [README.md#commands](README.md#commands) and [docs/keybindings.md](docs/keybindings.md).
9322
+ - `models.json` headers can resolve environment variables and shell commands. See [docs/models.md#value-resolution](docs/models.md#value-resolution).
9323
+ - `--verbose` CLI flag to override quiet startup. See [README.md#cli-reference](README.md#cli-reference).
9324
+
9325
+ Read the fully revamped docs in `README.md`, or have your clanker read them for you.
9326
+
9327
+ ### SDK Migration Guide
9328
+
9329
+ There are multiple SDK breaking changes since v0.49.3. For the quickest migration, point your agent at `packages/coding-agent/docs/sdk.md`, the SDK examples in `packages/coding-agent/examples/sdk`, and the SDK source in `packages/coding-agent/src/core/sdk.ts` and related modules.
9330
+
9331
+ ### Breaking Changes
9332
+
9333
+ - Header values in `models.json` now resolve environment variables (if a header value matches an env var name, the env var value is used). This may change behavior if a literal header value accidentally matches an env var name. ([#909](https://github.com/badlogic/pi-mono/issues/909))
9334
+ - External packages (npm/git) are now configured via `packages` array in settings.json instead of `extensions`. Existing npm:/git: entries in `extensions` are auto-migrated. ([#645](https://github.com/badlogic/pi-mono/issues/645))
9335
+ - Resource loading now uses `ResourceLoader` only and settings.json uses arrays for extensions, skills, prompts, and themes ([#645](https://github.com/badlogic/pi-mono/issues/645))
9336
+ - Removed `discoverAuthStorage` and `discoverModels` from the SDK. `AuthStorage` and `ModelRegistry` now default to `~/.pi/agent` paths unless you pass an `agentDir` ([#645](https://github.com/badlogic/pi-mono/issues/645))
9337
+
9338
+ ### Added
9339
+
9340
+ - Session renaming in `/resume` picker via `Ctrl+R` without opening the session ([#863](https://github.com/badlogic/pi-mono/pull/863) by [@svkozak](https://github.com/svkozak))
9341
+ - Session selector keybindings are now configurable ([#948](https://github.com/badlogic/pi-mono/pull/948) by [@aos](https://github.com/aos))
9342
+ - `disable-model-invocation` frontmatter field for skills to prevent agentic invocation while still allowing explicit `/skill:name` commands ([#927](https://github.com/badlogic/pi-mono/issues/927))
9343
+ - Exposed `copyToClipboard` utility for extensions ([#926](https://github.com/badlogic/pi-mono/issues/926) by [@mitsuhiko](https://github.com/mitsuhiko))
9344
+ - Skill invocation messages are now collapsible in chat output, showing collapsed by default with skill name and expand hint ([#894](https://github.com/badlogic/pi-mono/issues/894))
9345
+ - Header values in `models.json` now support environment variables and shell commands, matching `apiKey` resolution ([#909](https://github.com/badlogic/pi-mono/issues/909))
9346
+ - Added HTTP proxy environment variable support for API requests ([#942](https://github.com/badlogic/pi-mono/pull/942) by [@haoqixu](https://github.com/haoqixu))
9347
+ - Added OpenRouter provider routing support for custom models via `openRouterRouting` compat field ([#859](https://github.com/badlogic/pi-mono/pull/859) by [@v01dpr1mr0s3](https://github.com/v01dpr1mr0s3))
9348
+ - Added `azure-openai-responses` provider support for Azure OpenAI Responses API. ([#890](https://github.com/badlogic/pi-mono/pull/890) by [@markusylisiurunen](https://github.com/markusylisiurunen))
9349
+ - Added changelog link to update notifications ([#925](https://github.com/badlogic/pi-mono/pull/925) by [@dannote](https://github.com/dannote))
9350
+ - Added `--verbose` CLI flag to override quietStartup setting ([#906](https://github.com/badlogic/pi-mono/pull/906) by [@Perlence](https://github.com/Perlence))
9351
+ - `markdown.codeBlockIndent` setting to customize code block indentation in rendered output
9352
+ - Extension package management with `pi install`, `pi remove`, `pi update`, and `pi list` commands ([#645](https://github.com/badlogic/pi-mono/issues/645))
9353
+ - Package filtering: selectively load resources from packages using object form in `packages` array ([#645](https://github.com/badlogic/pi-mono/issues/645))
9354
+ - Glob pattern support with minimatch in package filters, top-level settings arrays, and pi manifest (e.g., `"!funky.json"`, `"*.ts"`) ([#645](https://github.com/badlogic/pi-mono/issues/645))
9355
+ - `/reload` command to reload extensions, skills, prompts, and themes ([#645](https://github.com/badlogic/pi-mono/issues/645))
9356
+ - `pi config` command with TUI to enable/disable package and top-level resources via patterns ([#938](https://github.com/badlogic/pi-mono/issues/938))
9357
+ - CLI flags for `--skill`, `--prompt-template`, `--theme`, `--no-prompt-templates`, and `--no-themes` ([#645](https://github.com/badlogic/pi-mono/issues/645))
9358
+ - Package deduplication: if same package appears in global and project settings, project wins ([#645](https://github.com/badlogic/pi-mono/issues/645))
9359
+ - Unified collision reporting with `ResourceDiagnostic` type for all resource types ([#645](https://github.com/badlogic/pi-mono/issues/645))
9360
+ - Show provider alongside the model in the footer if multiple providers are available
9361
+ - Custom provider support via `pi.registerProvider()` with `streamSimple` for custom API implementations
9362
+ - Added `custom-provider.ts` example extension demonstrating custom Anthropic provider with OAuth
9363
+
9364
+ ### Changed
9365
+
9366
+ - `/resume` picker sort toggle moved to `Ctrl+S` to free `Ctrl+R` for rename ([#863](https://github.com/badlogic/pi-mono/pull/863) by [@svkozak](https://github.com/svkozak))
9367
+ - HTML export: clicking a sidebar message now navigates to its newest leaf and scrolls to it, instead of truncating the branch ([#853](https://github.com/badlogic/pi-mono/pull/853) by [@mitsuhiko](https://github.com/mitsuhiko))
9368
+ - HTML export: active path is now visually highlighted with dimmed off-path nodes ([#929](https://github.com/badlogic/pi-mono/pull/929) by [@hewliyang](https://github.com/hewliyang))
9369
+ - Azure OpenAI Responses provider now uses base URL configuration with deployment-aware model mapping and no longer includes service tier handling
9370
+ - `/reload` now re-renders the entire scrollback so updated extension components are visible immediately ([#928](https://github.com/badlogic/pi-mono/pull/928) by [@ferologics](https://github.com/ferologics))
9371
+ - Skill, prompt template, and theme discovery now use settings and CLI path arrays instead of legacy filters ([#645](https://github.com/badlogic/pi-mono/issues/645))
9372
+
9373
+ ### Fixed
9374
+
9375
+ - Extension `setWorkingMessage()` calls in `agent_start` handlers now work correctly; previously the message was silently ignored because the loading animation didn't exist yet ([#935](https://github.com/badlogic/pi-mono/issues/935))
9376
+ - Fixed package auto-discovery to respect loader rules, config overrides, and force-exclude patterns
9377
+ - Fixed /reload restoring the correct editor after reload ([#949](https://github.com/badlogic/pi-mono/pull/949) by [@Perlence](https://github.com/Perlence))
9378
+ - Fixed distributed themes breaking `/export` ([#946](https://github.com/badlogic/pi-mono/pull/946) by [@mitsuhiko](https://github.com/mitsuhiko))
9379
+ - Fixed startup hints to clarify thinking level selection and expanded thinking guidance
9380
+ - Fixed SDK initial model resolution to use `findInitialModel` and default to Claude Opus 4.5 for Anthropic models
9381
+ - Fixed no-models warning to include the `/model` instruction
9382
+ - Fixed authentication error messages to point to the authentication documentation
9383
+ - Fixed bash output hint lines to truncate to terminal width
9384
+ - Fixed custom editors to honor the `paddingX` setting ([#936](https://github.com/badlogic/pi-mono/pull/936) by [@Perlence](https://github.com/Perlence))
9385
+ - Fixed system prompt tool list to show only built-in tools
9386
+ - Fixed package manager to check npm package versions before using cached copies
9387
+ - Fixed package manager to run `npm install` after cloning git repositories with a package.json
9388
+ - Fixed extension provider registrations to apply before model resolution
9389
+ - Fixed editor multi-line insertion handling and lastAction tracking ([#945](https://github.com/badlogic/pi-mono/pull/945) by [@Perlence](https://github.com/Perlence))
9390
+ - Fixed editor word wrapping to reserve a cursor column ([#934](https://github.com/badlogic/pi-mono/pull/934) by [@Perlence](https://github.com/Perlence))
9391
+ - Fixed editor word wrapping to use single-pass backtracking for whitespace handling ([#924](https://github.com/badlogic/pi-mono/pull/924) by [@Perlence](https://github.com/Perlence))
9392
+ - Fixed Kitty image ID allocation and cleanup to prevent image ID collisions
9393
+ - Fixed overlays staying centered after terminal resizes ([#950](https://github.com/badlogic/pi-mono/pull/950) by [@nicobailon](https://github.com/nicobailon))
9394
+ - Fixed streaming dispatch to use the model api type instead of hardcoded API defaults
9395
+ - Fixed Google providers to default tool call arguments to an empty object when omitted
9396
+ - Fixed OpenAI Responses streaming to handle `arguments.done` events on OpenAI-compatible endpoints ([#917](https://github.com/badlogic/pi-mono/pull/917) by [@williballenthin](https://github.com/williballenthin))
9397
+ - Fixed OpenAI Codex Responses tool strictness handling after the shared responses refactor
9398
+ - Fixed Azure OpenAI Responses streaming to guard deltas before content parts and correct metadata and handoff gating
9399
+ - Fixed OpenAI completions tool-result image batching after consecutive tool results ([#902](https://github.com/badlogic/pi-mono/pull/902) by [@terrorobe](https://github.com/terrorobe))
9400
+ - Off-by-one error in bash output "earlier lines" count caused by counting spacing newline as hidden content ([#921](https://github.com/badlogic/pi-mono/issues/921))
9401
+ - User package filters now layer on top of manifest filters instead of replacing them ([#645](https://github.com/badlogic/pi-mono/issues/645))
9402
+ - Auto-retry now handles "terminated" errors from Codex API mid-stream failures
9403
+ - Follow-up queue (Alt+Enter) now sends full paste content instead of `[paste #N ...]` markers ([#912](https://github.com/badlogic/pi-mono/issues/912))
9404
+ - Fixed Alt-Up not restoring messages queued during compaction ([#923](https://github.com/badlogic/pi-mono/pull/923) by [@aliou](https://github.com/aliou))
9405
+ - Fixed session corruption when loading empty or invalid session files via `--session` flag ([#932](https://github.com/badlogic/pi-mono/issues/932) by [@armanddp](https://github.com/armanddp))
9406
+ - Fixed extension shortcuts not firing when extension also uses `setEditorComponent()` ([#947](https://github.com/badlogic/pi-mono/pull/947) by [@Perlence](https://github.com/Perlence))
9407
+ - Session "modified" time now uses last message timestamp instead of file mtime, so renaming doesn't reorder the recent list ([#863](https://github.com/badlogic/pi-mono/pull/863) by [@svkozak](https://github.com/svkozak))
9408
+
9409
+ ## [0.49.3] - 2026-01-22
9410
+
9411
+ ### Added
9412
+
9413
+ - `markdown.codeBlockIndent` setting to customize code block indentation in rendered output ([#855](https://github.com/badlogic/pi-mono/pull/855) by [@terrorobe](https://github.com/terrorobe))
9414
+ - Added `inline-bash.ts` example extension for expanding `!{command}` patterns in prompts ([#881](https://github.com/badlogic/pi-mono/pull/881) by [@scutifer](https://github.com/scutifer))
9415
+ - Added `antigravity-image-gen.ts` example extension for AI image generation via Google Antigravity ([#893](https://github.com/badlogic/pi-mono/pull/893) by [@benvargas](https://github.com/benvargas))
9416
+ - Added `PI_SHARE_VIEWER_URL` environment variable for custom share viewer URLs ([#889](https://github.com/badlogic/pi-mono/pull/889) by [@andresaraujo](https://github.com/andresaraujo))
9417
+ - Added Alt+Delete as hotkey for delete word forwards ([#878](https://github.com/badlogic/pi-mono/pull/878) by [@Perlence](https://github.com/Perlence))
9418
+
9419
+ ### Changed
9420
+
9421
+ - Tree selector: changed label filter shortcut from `l` to `Shift+L` so users can search for entries containing "l" ([#861](https://github.com/badlogic/pi-mono/pull/861) by [@mitsuhiko](https://github.com/mitsuhiko))
9422
+ - Fuzzy matching now scores consecutive matches higher for better search relevance ([#860](https://github.com/badlogic/pi-mono/pull/860) by [@mitsuhiko](https://github.com/mitsuhiko))
9423
+
9424
+ ### Fixed
9425
+
9426
+ - Fixed error messages showing hardcoded `~/.pi/agent/` paths instead of respecting `PI_CODING_AGENT_DIR` ([#887](https://github.com/badlogic/pi-mono/pull/887) by [@aliou](https://github.com/aliou))
9427
+ - Fixed `write` tool not displaying errors in the UI when execution fails ([#856](https://github.com/badlogic/pi-mono/issues/856))
9428
+ - Fixed HTML export using default theme instead of user's active theme ([#870](https://github.com/badlogic/pi-mono/pull/870) by [@scutifer](https://github.com/scutifer))
9429
+ - Show session name in the footer and terminal / tab title ([#876](https://github.com/badlogic/pi-mono/pull/876) by [@scutifer](https://github.com/scutifer))
9430
+ - Fixed 256color fallback in Terminal.app to prevent color rendering issues ([#869](https://github.com/badlogic/pi-mono/pull/869) by [@Perlence](https://github.com/Perlence))
9431
+ - Fixed viewport tracking and cursor positioning for overlays and content shrink scenarios
9432
+ - Fixed autocomplete to allow searches with `/` characters (e.g., `folder1/folder2`) ([#882](https://github.com/badlogic/pi-mono/pull/882) by [@richardgill](https://github.com/richardgill))
9433
+ - Fixed autolinked emails displaying redundant `(mailto:...)` suffix ([#888](https://github.com/badlogic/pi-mono/pull/888) by [@terrorobe](https://github.com/terrorobe))
9434
+ - Fixed `@` file autocomplete adding space after directories, breaking continued autocomplete into subdirectories
9435
+
9436
+ ## [0.49.2] - 2026-01-19
9437
+
9438
+ ### Added
9439
+
9440
+ - Added widget placement option for extension widgets via `widgetPlacement` in `pi.addWidget()` ([#850](https://github.com/badlogic/pi-mono/pull/850) by [@marckrenn](https://github.com/marckrenn))
9441
+ - Added AWS credential detection for ECS/Kubernetes environments: `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`, `AWS_CONTAINER_CREDENTIALS_FULL_URI`, `AWS_WEB_IDENTITY_TOKEN_FILE` ([#848](https://github.com/badlogic/pi-mono/issues/848))
9442
+ - Add "quiet startup" setting to `/settings` ([#847](https://github.com/badlogic/pi-mono/pull/847) by [@unexge](https://github.com/unexge))
9443
+
9444
+ ### Changed
9445
+
9446
+ - HTML export now includes JSONL download button, jump-to-last-message on click, and fixed missing labels ([#853](https://github.com/badlogic/pi-mono/pull/853) by [@mitsuhiko](https://github.com/mitsuhiko))
9447
+ - Improved error message for OAuth authentication failures (expired credentials, offline) instead of generic 'No API key found' ([#849](https://github.com/badlogic/pi-mono/pull/849) by [@zedrdave](https://github.com/zedrdave))
9448
+
9449
+ ### Fixed
9450
+
9451
+ - Fixed `/model` selector scope toggle so you can switch between all and scoped models when scoped models are saved ([#844](https://github.com/badlogic/pi-mono/issues/844))
9452
+ - Fixed OpenAI Responses 400 error "reasoning without following item" when replaying aborted turns ([#838](https://github.com/badlogic/pi-mono/pull/838))
9453
+ - Fixed pi exiting with code 0 when cancelling resume session selection
9454
+
9455
+ ### Removed
9456
+
9457
+ - Removed `strictResponsesPairing` compat option from models.json schema (no longer needed)
9458
+
9459
+ ## [0.49.1] - 2026-01-18
9460
+
9461
+ ### Added
9462
+
9463
+ - Added `strictResponsesPairing` compat option for custom OpenAI Responses models on Azure ([#768](https://github.com/badlogic/pi-mono/pull/768) by [@nicobako](https://github.com/nicobako))
9464
+ - Session selector (`/resume`) now supports path display toggle (`Ctrl+P`) and session deletion (`Ctrl+D`) with inline confirmation ([#816](https://github.com/badlogic/pi-mono/pull/816) by [@w-winter](https://github.com/w-winter))
9465
+ - Added undo support in interactive mode with Ctrl+- hotkey. ([#831](https://github.com/badlogic/pi-mono/pull/831) by [@Perlence](https://github.com/Perlence))
9466
+
9467
+ ### Changed
9468
+
9469
+ - Share URLs now use hash fragments (`#`) instead of query strings (`?`) to prevent session IDs from being sent to buildwithpi.ai ([#829](https://github.com/badlogic/pi-mono/pull/829) by [@terrorobe](https://github.com/terrorobe))
9470
+ - API keys in `models.json` can now be retrieved via shell command using `!` prefix (e.g., `"apiKey": "!security find-generic-password -ws 'anthropic'"` for macOS Keychain) ([#762](https://github.com/badlogic/pi-mono/pull/762) by [@cv](https://github.com/cv))
9471
+
9472
+ ### Fixed
9473
+
9474
+ - Fixed IME candidate window appearing in wrong position when filtering menus with Input Method Editor (e.g., Chinese IME). Components with search inputs now properly propagate focus state for cursor positioning. ([#827](https://github.com/badlogic/pi-mono/issues/827))
9475
+ - Fixed extension shortcut conflicts to respect user keybindings when built-in actions are remapped. ([#826](https://github.com/badlogic/pi-mono/pull/826) by [@richardgill](https://github.com/richardgill))
9476
+ - Fixed photon WASM loading in standalone compiled binaries.
9477
+ - Fixed tool call ID normalization for cross-provider handoffs (e.g., Codex to Antigravity Claude) ([#821](https://github.com/badlogic/pi-mono/issues/821))
9478
+
9479
+ ## [0.49.0] - 2026-01-17
9480
+
9481
+ ### Added
9482
+
9483
+ - `pi.setLabel(entryId, label)` in ExtensionAPI for setting per-entry labels from extensions ([#806](https://github.com/badlogic/pi-mono/issues/806))
9484
+ - Export `keyHint`, `appKeyHint`, `editorKey`, `appKey`, `rawKeyHint` for extensions to format keybinding hints consistently ([#802](https://github.com/badlogic/pi-mono/pull/802) by [@dannote](https://github.com/dannote))
9485
+ - Exported `VERSION` from the package index and updated the custom-header example. ([#798](https://github.com/badlogic/pi-mono/pull/798) by [@tallshort](https://github.com/tallshort))
9486
+ - Added `showHardwareCursor` setting to control cursor visibility while still positioning it for IME support. ([#800](https://github.com/badlogic/pi-mono/pull/800) by [@ghoulr](https://github.com/ghoulr))
9487
+ - Added Emacs-style kill ring editing with yank and yank-pop keybindings, plus legacy Alt+letter handling and Alt+D delete word forward support in the interactive editor. ([#810](https://github.com/badlogic/pi-mono/pull/810) by [@Perlence](https://github.com/Perlence))
9488
+ - Added `ctx.compact()` and `ctx.getContextUsage()` to extension contexts for programmatic compaction and context usage checks.
9489
+ - Added documentation for delete word forward and kill ring keybindings in interactive mode. ([#810](https://github.com/badlogic/pi-mono/pull/810) by [@Perlence](https://github.com/Perlence))
9490
+
9491
+ ### Changed
9492
+
9493
+ - Updated the default system prompt wording to clarify the pi harness and documentation scope.
9494
+ - Simplified Codex system prompt handling to use the default system prompt directly for Codex instructions.
9495
+
9496
+ ### Fixed
9497
+
9498
+ - Fixed photon module failing to load in ESM context with "require is not defined" error ([#795](https://github.com/badlogic/pi-mono/pull/795) by [@dannote](https://github.com/dannote))
9499
+ - Fixed compaction UI not showing when extensions trigger compaction.
9500
+ - Fixed orphaned tool results after errored assistant messages causing Codex API errors. When an assistant message has `stopReason: "error"`, its tool calls are now excluded from pending tool tracking, preventing synthetic tool results from being generated for calls that will be dropped by provider-specific converters. ([#812](https://github.com/badlogic/pi-mono/issues/812))
9501
+ - Fixed Bedrock Claude max_tokens handling to always exceed thinking budget tokens, preventing compaction failures. ([#797](https://github.com/badlogic/pi-mono/pull/797) by [@pjtf93](https://github.com/pjtf93))
9502
+ - Fixed Claude Code tool name normalization to match the Claude Code tool list case-insensitively and remove invalid mappings.
9503
+
9504
+ ### Removed
9505
+
9506
+ - Removed `pi-internal://` path resolution from the read tool.
9507
+
9508
+ ## [0.48.0] - 2026-01-16
9509
+
9510
+ ### Added
9511
+
9512
+ - Added `quietStartup` setting to silence startup output (version header, loaded context info, model scope line). Changelog notifications are still shown. ([#777](https://github.com/badlogic/pi-mono/pull/777) by [@ribelo](https://github.com/ribelo))
9513
+ - Added `editorPaddingX` setting for horizontal padding in input editor (0-3, default: 0)
9514
+ - Added `shellCommandPrefix` setting to prepend commands to every bash execution, enabling alias expansion in non-interactive shells (e.g., `"shellCommandPrefix": "shopt -s expand_aliases"`) ([#790](https://github.com/badlogic/pi-mono/pull/790) by [@richardgill](https://github.com/richardgill))
9515
+ - Added bash-style argument slicing for prompt templates ([#770](https://github.com/badlogic/pi-mono/pull/770) by [@airtonix](https://github.com/airtonix))
9516
+ - Extension commands can provide argument auto-completions via `getArgumentCompletions` in `pi.registerCommand()` ([#775](https://github.com/badlogic/pi-mono/pull/775) by [@ribelo](https://github.com/ribelo))
9517
+ - Bash tool now displays the timeout value in the UI when a timeout is set ([#780](https://github.com/badlogic/pi-mono/pull/780) by [@dannote](https://github.com/dannote))
9518
+ - Export `getShellConfig` for extensions to detect user's shell environment ([#766](https://github.com/badlogic/pi-mono/pull/766) by [@dannote](https://github.com/dannote))
9519
+ - Added `thinkingText` and `selectedBg` to theme schema ([#763](https://github.com/badlogic/pi-mono/pull/763) by [@scutifer](https://github.com/scutifer))
9520
+ - `navigateTree()` now supports `replaceInstructions` option to replace the default summarization prompt entirely, and `label` option to attach a label to the branch summary entry ([#787](https://github.com/badlogic/pi-mono/pull/787) by [@mitsuhiko](https://github.com/mitsuhiko))
9521
+
9522
+ ### Fixed
9523
+
9524
+ - Fixed crash during auto-compaction when summarization fails (e.g., quota exceeded). Now displays error message instead of crashing ([#792](https://github.com/badlogic/pi-mono/issues/792))
9525
+ - Fixed `--session <UUID>` to search globally across projects if not found locally, with option to fork sessions from other projects ([#785](https://github.com/badlogic/pi-mono/pull/785) by [@ribelo](https://github.com/ribelo))
9526
+ - Fixed standalone binary WASM loading on Linux ([#784](https://github.com/badlogic/pi-mono/issues/784))
9527
+ - Fixed string numbers in tool arguments not being coerced to numbers during validation ([#786](https://github.com/badlogic/pi-mono/pull/786) by [@dannote](https://github.com/dannote))
9528
+ - Fixed `--no-extensions` flag not preventing extension discovery ([#776](https://github.com/badlogic/pi-mono/issues/776))
9529
+ - Fixed extension messages rendering twice on startup when `pi.sendMessage({ display: true })` is called during `session_start` ([#765](https://github.com/badlogic/pi-mono/pull/765) by [@dannote](https://github.com/dannote))
9530
+ - Fixed `PI_CODING_AGENT_DIR` env var not expanding tilde (`~`) to home directory ([#778](https://github.com/badlogic/pi-mono/pull/778) by [@aliou](https://github.com/aliou))
9531
+ - Fixed session picker hint text overflow ([#764](https://github.com/badlogic/pi-mono/issues/764))
9532
+ - Fixed Kitty keyboard protocol shifted symbol keys (e.g., `@`, `?`) not working in editor ([#779](https://github.com/badlogic/pi-mono/pull/779) by [@iamd3vil](https://github.com/iamd3vil))
9533
+ - Fixed Bedrock tool call IDs causing API errors from invalid characters ([#781](https://github.com/badlogic/pi-mono/pull/781) by [@pjtf93](https://github.com/pjtf93))
9534
+
9535
+ ### Changed
9536
+
9537
+ - Hardware cursor is now disabled by default for better terminal compatibility. Set `PI_HARDWARE_CURSOR=1` to enable (replaces `PI_NO_HARDWARE_CURSOR=1` which disabled it).
9538
+
9539
+ ## [0.47.0] - 2026-01-16
9540
+
9541
+ ### Breaking Changes
9542
+
9543
+ - Extensions using `Editor` directly must now pass `TUI` as the first constructor argument: `new Editor(tui, theme)`. The `tui` parameter is available in extension factory functions. ([#732](https://github.com/badlogic/pi-mono/issues/732))
9544
+
9545
+ ### Added
9546
+
9547
+ - **OpenAI Codex official support**: Full compatibility with OpenAI's Codex CLI models (`gpt-5.1`, `gpt-5.2`, `gpt-5.1-codex-mini`, `gpt-5.2-codex`). Features include static system prompt for OpenAI allowlisting, prompt caching via session ID, and reasoning signature retention across turns. Set `OPENAI_API_KEY` and use `--provider openai-codex` or select a Codex model. ([#737](https://github.com/badlogic/pi-mono/pull/737))
9548
+ - `pi-internal://` URL scheme in read tool for accessing internal documentation. The model can read files from the coding-agent package (README, docs, examples) to learn about extending pi.
9549
+ - New `input` event in extension system for intercepting, transforming, or handling user input before the agent processes it. Supports three result types: `continue` (pass through), `transform` (modify text/images), `handled` (respond without LLM). Handlers chain transforms and short-circuit on handled. ([#761](https://github.com/badlogic/pi-mono/pull/761) by [@nicobailon](https://github.com/nicobailon))
9550
+ - Extension example: `input-transform.ts` demonstrating input interception patterns (quick mode, instant commands, source routing) ([#761](https://github.com/badlogic/pi-mono/pull/761) by [@nicobailon](https://github.com/nicobailon))
9551
+ - Custom tool HTML export: extensions with `renderCall`/`renderResult` now render in `/share` and `/export` output with ANSI-to-HTML color conversion ([#702](https://github.com/badlogic/pi-mono/pull/702) by [@aliou](https://github.com/aliou))
9552
+ - Direct filter shortcuts in Tree mode: Ctrl+D (default), Ctrl+T (no-tools), Ctrl+U (user-only), Ctrl+L (labeled-only), Ctrl+A (all) ([#747](https://github.com/badlogic/pi-mono/pull/747) by [@kaofelix](https://github.com/kaofelix))
9553
+
9554
+ ### Changed
9555
+
9556
+ - Skill commands (`/skill:name`) are now expanded in AgentSession instead of interactive mode. This enables skill commands in RPC and print modes, and allows the `input` event to intercept `/skill:name` before expansion.
9557
+
9558
+ ### Fixed
9559
+
9560
+ - Editor no longer corrupts terminal display when loading large prompts via `setEditorText`. Content now scrolls vertically with indicators showing lines above/below the viewport. ([#732](https://github.com/badlogic/pi-mono/issues/732))
9561
+ - Piped stdin now works correctly: `echo foo | pi` is equivalent to `pi -p foo`. When stdin is piped, print mode is automatically enabled since interactive mode requires a TTY ([#708](https://github.com/badlogic/pi-mono/issues/708))
9562
+ - Session tree now preserves branch connectors and indentation when filters hide intermediate entries so descendants attach to the nearest visible ancestor and sibling branches align. Fixed in both TUI and HTML export ([#739](https://github.com/badlogic/pi-mono/pull/739) by [@w-winter](https://github.com/w-winter))
9563
+ - Added `upstream connect`, `connection refused`, and `reset before headers` patterns to auto-retry error detection ([#733](https://github.com/badlogic/pi-mono/issues/733))
9564
+ - Multi-line YAML frontmatter in skills and prompt templates now parses correctly. Centralized frontmatter parsing using the `yaml` library. ([#728](https://github.com/badlogic/pi-mono/pull/728) by [@richardgill](https://github.com/richardgill))
9565
+ - `ctx.shutdown()` now waits for pending UI renders to complete before exiting, ensuring notifications and final output are visible ([#756](https://github.com/badlogic/pi-mono/issues/756))
9566
+ - OpenAI Codex provider now retries on transient errors (429, 5xx, connection failures) with exponential backoff ([#733](https://github.com/badlogic/pi-mono/issues/733))
9567
+
9568
+ ## [0.46.0] - 2026-01-15
9569
+
9570
+ ### Fixed
9571
+
9572
+ - Scoped models (`--models` or `enabledModels`) now remember the last selected model across sessions instead of always starting with the first model in the scope ([#736](https://github.com/badlogic/pi-mono/pull/736) by [@ogulcancelik](https://github.com/ogulcancelik))
9573
+ - Show `bun install` instead of `npm install` in update notification when running under Bun ([#714](https://github.com/badlogic/pi-mono/pull/714) by [@dannote](https://github.com/dannote))
9574
+ - `/skill` prompts now include the skill path ([#711](https://github.com/badlogic/pi-mono/pull/711) by [@jblwilliams](https://github.com/jblwilliams))
9575
+ - Use configurable `expandTools` keybinding instead of hardcoded Ctrl+O ([#717](https://github.com/badlogic/pi-mono/pull/717) by [@dannote](https://github.com/dannote))
9576
+ - Compaction turn prefix summaries now merge correctly ([#738](https://github.com/badlogic/pi-mono/pull/738) by [@vsabavat](https://github.com/vsabavat))
9577
+ - Avoid unsigned Gemini 3 tool calls ([#741](https://github.com/badlogic/pi-mono/pull/741) by [@roshanasingh4](https://github.com/roshanasingh4))
9578
+ - Fixed signature support for non-Anthropic models in Amazon Bedrock provider ([#727](https://github.com/badlogic/pi-mono/pull/727) by [@unexge](https://github.com/unexge))
9579
+ - Keyboard shortcuts (Ctrl+C, Ctrl+D, etc.) now work on non-Latin keyboard layouts (Russian, Ukrainian, Bulgarian, etc.) in terminals supporting Kitty keyboard protocol with alternate key reporting ([#718](https://github.com/badlogic/pi-mono/pull/718) by [@dannote](https://github.com/dannote))
9580
+
9581
+ ### Added
9582
+
9583
+ - Edit tool now uses fuzzy matching as fallback when exact match fails, tolerating trailing whitespace, smart quotes, Unicode dashes, and special spaces ([#713](https://github.com/badlogic/pi-mono/pull/713) by [@dannote](https://github.com/dannote))
9584
+ - Support `APPEND_SYSTEM.md` to append instructions to the system prompt ([#716](https://github.com/badlogic/pi-mono/pull/716) by [@tallshort](https://github.com/tallshort))
9585
+ - Session picker search: Ctrl+R toggles sorting between fuzzy match (default) and most recent; supports quoted phrase matching and `re:` regex mode ([#731](https://github.com/badlogic/pi-mono/pull/731) by [@ogulcancelik](https://github.com/ogulcancelik))
9586
+ - Export `getAgentDir` for extensions ([#749](https://github.com/badlogic/pi-mono/pull/749) by [@dannote](https://github.com/dannote))
9587
+ - Show loaded prompt templates on startup ([#743](https://github.com/badlogic/pi-mono/pull/743) by [@tallshort](https://github.com/tallshort))
9588
+ - MiniMax China (`minimax-cn`) provider support ([#725](https://github.com/badlogic/pi-mono/pull/725) by [@tallshort](https://github.com/tallshort))
9589
+ - `gpt-5.2-codex` models for GitHub Copilot and OpenCode Zen providers ([#734](https://github.com/badlogic/pi-mono/pull/734) by [@aadishv](https://github.com/aadishv))
9590
+
9591
+ ### Changed
9592
+
9593
+ - Replaced `wasm-vips` with `@silvia-odwyer/photon-node` for image processing ([#710](https://github.com/badlogic/pi-mono/pull/710) by [@can1357](https://github.com/can1357))
9594
+ - Extension example: `plan-mode/` shortcut changed from Shift+P to Ctrl+Alt+P to avoid conflict with typing capital P ([#746](https://github.com/badlogic/pi-mono/pull/746) by [@ferologics](https://github.com/ferologics))
9595
+ - UI keybinding hints now respect configured keybindings across components ([#724](https://github.com/badlogic/pi-mono/pull/724) by [@dannote](https://github.com/dannote))
9596
+ - CLI process title is now set to `pi` for easier process identification ([#742](https://github.com/badlogic/pi-mono/pull/742) by [@richardgill](https://github.com/richardgill))
9597
+
9598
+ ## [0.45.7] - 2026-01-13
9599
+
9600
+ ### Added
9601
+
9602
+ - Exported `highlightCode` and `getLanguageFromPath` for extensions ([#703](https://github.com/badlogic/pi-mono/pull/703) by [@dannote](https://github.com/dannote))
9603
+
9604
+ ## [0.45.6] - 2026-01-13
9605
+
9606
+ ### Added
9607
+
9608
+ - `ctx.ui.custom()` now accepts `overlayOptions` for overlay positioning and sizing (anchor, margins, offsets, percentages, absolute positioning) ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
9609
+ - `ctx.ui.custom()` now accepts `onHandle` callback to receive the `OverlayHandle` for controlling overlay visibility ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
9610
+ - Extension example: `overlay-qa-tests.ts` with 10 commands for testing overlay positioning, animation, and toggle scenarios ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
9611
+ - Extension example: `doom-overlay/` - DOOM game running as an overlay at 35 FPS (auto-downloads WAD on first run) ([#667](https://github.com/badlogic/pi-mono/pull/667) by [@nicobailon](https://github.com/nicobailon))
9612
+
9613
+ ## [0.45.5] - 2026-01-13
9614
+
9615
+ ### Fixed
9616
+
9617
+ - Skip changelog display on fresh install (only show on upgrades)
9618
+
9619
+ ## [0.45.4] - 2026-01-13
9620
+
9621
+ ### Changed
9622
+
9623
+ - Light theme colors adjusted for WCAG AA compliance (4.5:1 contrast ratio against white backgrounds)
9624
+ - Replaced `sharp` with `wasm-vips` for image processing (resize, PNG conversion). Eliminates native build requirements that caused installation failures on some systems. ([#696](https://github.com/badlogic/pi-mono/issues/696))
9625
+
9626
+ ### Added
9627
+
9628
+ - Extension example: `summarize.ts` for summarizing conversations using custom UI and an external model ([#684](https://github.com/badlogic/pi-mono/pull/684) by [@scutifer](https://github.com/scutifer))
9629
+ - Extension example: `question.ts` enhanced with custom UI for asking user questions ([#693](https://github.com/badlogic/pi-mono/pull/693) by [@ferologics](https://github.com/ferologics))
9630
+ - Extension example: `plan-mode/` enhanced with explicit step tracking and progress widget ([#694](https://github.com/badlogic/pi-mono/pull/694) by [@ferologics](https://github.com/ferologics))
9631
+ - Extension example: `questionnaire.ts` for multi-question input with tab bar navigation ([#695](https://github.com/badlogic/pi-mono/pull/695) by [@ferologics](https://github.com/ferologics))
9632
+ - Experimental Vercel AI Gateway provider support: set `AI_GATEWAY_API_KEY` and use `--provider vercel-ai-gateway`. Token usage is currently reported incorrectly by Anthropic Messages compatible endpoint. ([#689](https://github.com/badlogic/pi-mono/pull/689) by [@timolins](https://github.com/timolins))
9633
+
9634
+ ### Fixed
9635
+
9636
+ - Fix API key resolution after model switches by using provider argument ([#691](https://github.com/badlogic/pi-mono/pull/691) by [@joshp123](https://github.com/joshp123))
9637
+ - Fixed z.ai thinking/reasoning: thinking toggle now correctly enables/disables thinking for z.ai models ([#688](https://github.com/badlogic/pi-mono/issues/688))
9638
+ - Fixed extension loading in compiled Bun binary: extensions with local file imports now work correctly. Updated `@mariozechner/jiti` to v2.6.5 which bundles babel for Bun binary compatibility. ([#681](https://github.com/badlogic/pi-mono/issues/681))
9639
+ - Fixed theme loading when installed via mise: use wrapper directory in release tarballs for compatibility with mise's `strip_components=1` extraction. ([#681](https://github.com/badlogic/pi-mono/issues/681))
9640
+
9641
+ ## [0.45.2] - 2026-01-13
9642
+
9643
+ ### Fixed
9644
+
9645
+ - Extensions now load correctly in compiled Bun binary by using jiti for module resolution with proper alias handling
9646
+
9647
+ ## [0.45.1] - 2026-01-13
9648
+
9649
+ ### Changed
9650
+
9651
+ - `/share` now outputs `buildwithpi.ai` session preview URLs instead of `shittycodingagent.ai`
9652
+
9653
+ ## [0.45.0] - 2026-01-13
9654
+
9655
+ ### Added
9656
+
9657
+ - MiniMax provider support: set `MINIMAX_API_KEY` and use `minimax/MiniMax-M2.1` ([#656](https://github.com/badlogic/pi-mono/pull/656) by [@dannote](https://github.com/dannote))
9658
+ - `/scoped-models`: Alt+Up/Down to reorder enabled models. Order is preserved when saving with Ctrl+S and determines Ctrl+P cycling order. ([#676](https://github.com/badlogic/pi-mono/pull/676) by [@thomasmhr](https://github.com/thomasmhr))
9659
+ - Amazon Bedrock provider support (experimental, tested with Anthropic Claude models only) ([#494](https://github.com/badlogic/pi-mono/pull/494) by [@unexge](https://github.com/unexge))
9660
+ - Extension example: `sandbox/` for OS-level bash sandboxing using `@anthropic-ai/sandbox-runtime` with per-project config ([#673](https://github.com/badlogic/pi-mono/pull/673) by [@dannote](https://github.com/dannote))
9661
+
9662
+ ## [0.44.0] - 2026-01-12
9663
+
9664
+ ### Breaking Changes
9665
+
9666
+ - `pi.getAllTools()` now returns `ToolInfo[]` (with `name` and `description`) instead of `string[]`. Extensions that only need names can use `.map(t => t.name)`. ([#648](https://github.com/badlogic/pi-mono/pull/648) by [@carsonfarmer](https://github.com/carsonfarmer))
9667
+
9668
+ ### Added
9669
+
9670
+ - Session naming: `/name <name>` command sets a display name shown in the session selector instead of the first message. Useful for distinguishing forked sessions. Extensions can use `pi.setSessionName()` and `pi.getSessionName()`. ([#650](https://github.com/badlogic/pi-mono/pull/650) by [@scutifer](https://github.com/scutifer))
9671
+ - Extension example: `notify.ts` for desktop notifications via OSC 777 escape sequence ([#658](https://github.com/badlogic/pi-mono/pull/658) by [@ferologics](https://github.com/ferologics))
9672
+ - Inline hint for queued messages showing the `Alt+Up` restore shortcut ([#657](https://github.com/badlogic/pi-mono/pull/657) by [@tmustier](https://github.com/tmustier))
9673
+ - Page-up/down navigation in `/resume` session selector to jump by 5 items ([#662](https://github.com/badlogic/pi-mono/pull/662) by [@aliou](https://github.com/aliou))
9674
+ - Fuzzy search in `/settings` menu: type to filter settings by label ([#643](https://github.com/badlogic/pi-mono/pull/643) by [@ninlds](https://github.com/ninlds))
9675
+
9676
+ ### Fixed
9677
+
9678
+ - Session selector now stays open when current folder has no sessions, allowing Tab to switch to "all" scope ([#661](https://github.com/badlogic/pi-mono/pull/661) by [@aliou](https://github.com/aliou))
9679
+ - Extensions using theme utilities like `getSettingsListTheme()` now work in dev mode with tsx
9680
+
9681
+ ## [0.43.0] - 2026-01-11
9682
+
9683
+ ### Breaking Changes
9684
+
9685
+ - Extension editor (`ctx.ui.editor()`) now uses Enter to submit and Shift+Enter for newlines, matching the main editor. Previously used Ctrl+Enter to submit. Extensions with hardcoded "ctrl+enter" hints need updating. ([#642](https://github.com/badlogic/pi-mono/pull/642) by [@mitsuhiko](https://github.com/mitsuhiko))
9686
+ - Renamed `/branch` command to `/fork` ([#641](https://github.com/badlogic/pi-mono/issues/641))
9687
+ - RPC: `branch` → `fork`, `get_branch_messages` → `get_fork_messages`
9688
+ - SDK: `branch()` → `fork()`, `getBranchMessages()` → `getForkMessages()`
9689
+ - AgentSession: `branch()` → `fork()`, `getUserMessagesForBranching()` → `getUserMessagesForForking()`
9690
+ - Extension events: `session_before_branch` → `session_before_fork`, `session_branch` → `session_fork`
9691
+ - Settings: `doubleEscapeAction: "branch" | "tree"` → `"fork" | "tree"`
9692
+ - `SessionManager.list()` and `SessionManager.listAll()` are now async, returning `Promise<SessionInfo[]>`. Callers must await them. ([#620](https://github.com/badlogic/pi-mono/pull/620) by [@tmustier](https://github.com/tmustier))
9693
+
9694
+ ### Added
9695
+
9696
+ - `/resume` selector now toggles between current-folder and all sessions with Tab, showing the session cwd in the All view and loading progress. ([#620](https://github.com/badlogic/pi-mono/pull/620) by [@tmustier](https://github.com/tmustier))
9697
+ - `SessionManager.list()` and `SessionManager.listAll()` accept optional `onProgress` callback for progress updates
9698
+ - `SessionInfo.cwd` field containing the session's working directory (empty string for old sessions)
9699
+ - `SessionListProgress` type export for progress callbacks
9700
+ - `/scoped-models` command to enable/disable models for Ctrl+P cycling. Changes are session-only by default; press Ctrl+S to persist to settings.json. ([#626](https://github.com/badlogic/pi-mono/pull/626) by [@CarlosGtrz](https://github.com/CarlosGtrz))
9701
+ - `model_select` extension hook fires when model changes via `/model`, model cycling, or session restore with `source` field and `previousModel` ([#628](https://github.com/badlogic/pi-mono/pull/628) by [@marckrenn](https://github.com/marckrenn))
9702
+ - `ctx.ui.setWorkingMessage()` extension API to customize the "Working..." message during streaming ([#625](https://github.com/badlogic/pi-mono/pull/625) by [@nicobailon](https://github.com/nicobailon))
9703
+ - Skill slash commands: loaded skills are registered as `/skill:name` commands for quick access. Toggle via `/settings` or `skills.enableSkillCommands` in settings.json. ([#630](https://github.com/badlogic/pi-mono/pull/630) by [@Dwsy](https://github.com/Dwsy))
9704
+ - Slash command autocomplete now uses fuzzy matching (type `/skbra` to match `/skill:brave-search`)
9705
+ - `/tree` branch summarization now offers three options: "No summary", "Summarize", and "Summarize with custom prompt". Custom prompts are appended as additional focus to the default summarization instructions. ([#642](https://github.com/badlogic/pi-mono/pull/642) by [@mitsuhiko](https://github.com/mitsuhiko))
9706
+
9707
+ ### Fixed
9708
+
9709
+ - Session picker respects custom keybindings when using `--resume` ([#633](https://github.com/badlogic/pi-mono/pull/633) by [@aos](https://github.com/aos))
9710
+ - Custom footer extensions now see model changes: `ctx.model` is now a getter that returns the current model instead of a snapshot from when the context was created ([#634](https://github.com/badlogic/pi-mono/pull/634) by [@ogulcancelik](https://github.com/ogulcancelik))
9711
+ - Footer git branch not updating after external branch switches. Git uses atomic writes (temp file + rename), which changes the inode and breaks `fs.watch` on the file. Now watches the directory instead.
9712
+ - Extension loading errors are now displayed to the user instead of being silently ignored ([#639](https://github.com/badlogic/pi-mono/pull/639) by [@aliou](https://github.com/aliou))
9713
+
9714
+ ## [0.42.5] - 2026-01-11
9715
+
9716
+ ### Fixed
9717
+
9718
+ - Reduced flicker by only re-rendering changed lines ([#617](https://github.com/badlogic/pi-mono/pull/617) by [@ogulcancelik](https://github.com/ogulcancelik)). No worries tho, there's still a little flicker in the VS Code Terminal. Praise the flicker.
9719
+ - Cursor position tracking when content shrinks with unchanged remaining lines
9720
+ - TUI renders with wrong dimensions after suspend/resume if terminal was resized while suspended ([#599](https://github.com/badlogic/pi-mono/issues/599))
9721
+ - Pasted content containing Kitty key release patterns (e.g., `:3F` in MAC addresses) was incorrectly filtered out ([#623](https://github.com/badlogic/pi-mono/pull/623) by [@ogulcancelik](https://github.com/ogulcancelik))
9722
+
9723
+ ## [0.42.4] - 2026-01-10
9724
+
9725
+ ### Fixed
9726
+
9727
+ - Bash output expanded hint now says "(ctrl+o to collapse)" ([#610](https://github.com/badlogic/pi-mono/pull/610) by [@tallshort](https://github.com/tallshort))
9728
+ - Fixed UTF-8 text corruption in remote bash execution (SSH, containers) by using streaming TextDecoder ([#608](https://github.com/badlogic/pi-mono/issues/608))
9729
+
9730
+ ## [0.42.3] - 2026-01-10
9731
+
9732
+ ### Changed
9733
+
9734
+ - OpenAI Codex: updated to use bundled system prompt from upstream
9735
+
9736
+ ## [0.42.2] - 2026-01-10
9737
+
9738
+ ### Added
9739
+
9740
+ - `/model <search>` now pre-filters the model selector or auto-selects on exact match. Use `provider/model` syntax to disambiguate (e.g., `/model openai/gpt-4`). ([#587](https://github.com/badlogic/pi-mono/pull/587) by [@zedrdave](https://github.com/zedrdave))
9741
+ - `FooterDataProvider` for custom footers: `ctx.ui.setFooter()` now receives a third `footerData` parameter providing `getGitBranch()`, `getExtensionStatuses()`, and `onBranchChange()` for reactive updates ([#600](https://github.com/badlogic/pi-mono/pull/600) by [@nicobailon](https://github.com/nicobailon))
9742
+ - `Alt+Up` hotkey to restore queued steering/follow-up messages back into the editor without aborting the current run ([#604](https://github.com/badlogic/pi-mono/pull/604) by [@tmustier](https://github.com/tmustier))
9743
+
9744
+ ### Fixed
9745
+
9746
+ - Fixed LM Studio compatibility for OpenAI Responses tool strict mapping in the ai provider ([#598](https://github.com/badlogic/pi-mono/pull/598) by [@gnattu](https://github.com/gnattu))
9747
+
9748
+ ## [0.42.1] - 2026-01-09
9749
+
9750
+ ### Fixed
9751
+
9752
+ - Symlinked directories in `prompts/` folders are now followed when loading prompt templates ([#601](https://github.com/badlogic/pi-mono/pull/601) by [@aliou](https://github.com/aliou))
9753
+
9754
+ ## [0.42.0] - 2026-01-09
9755
+
9756
+ ### Added
9757
+
9758
+ - Added OpenCode Zen provider support. Set `OPENCODE_API_KEY` env var and use `opencode/<model-id>` (e.g., `opencode/claude-opus-4-5`).
9759
+
9760
+ ## [0.41.0] - 2026-01-09
9761
+
9762
+ ### Added
9763
+
9764
+ - Anthropic OAuth support is back! Use `/login` to authenticate with your Claude Pro/Max subscription.
9765
+
9766
+ ## [0.40.1] - 2026-01-09
9767
+
9768
+ ### Removed
9769
+
9770
+ - Anthropic OAuth support (`/login`). Use API keys instead.
9771
+
9772
+ ## [0.40.0] - 2026-01-08
9773
+
9774
+ ### Added
9775
+
9776
+ - Documentation on component invalidation and theme changes in `docs/tui.md`
9777
+
9778
+ ### Fixed
9779
+
9780
+ - Components now properly rebuild their content on theme change (tool executions, assistant messages, bash executions, custom messages, branch/compaction summaries)
9781
+
9782
+ ## [0.39.1] - 2026-01-08
9783
+
9784
+ ### Fixed
9785
+
9786
+ - `setTheme()` now triggers a full rerender so previously rendered components update with the new theme colors
9787
+ - `mac-system-theme.ts` example now polls every 2 seconds and uses `osascript` for real-time macOS appearance detection
9788
+
9789
+ ## [0.39.0] - 2026-01-08
9790
+
9791
+ ### Breaking Changes
9792
+
9793
+ - `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](https://github.com/badlogic/pi-mono/issues/575))
9794
+ - `discoverSkills()` now returns `{ skills: Skill[], warnings: SkillWarning[] }` instead of `Skill[]`. This allows callers to handle skill loading warnings. ([#577](https://github.com/badlogic/pi-mono/pull/577) by [@cv](https://github.com/cv))
9795
+
9796
+ ### Added
9797
+
9798
+ - `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](https://github.com/badlogic/pi-mono/pull/576))
9799
+ - `--no-tools` flag to disable all built-in tools, allowing extension-only tool setups ([#557](https://github.com/badlogic/pi-mono/pull/557) by [@cv](https://github.com/cv))
9800
+ - Pluggable operations for built-in tools enabling remote execution via SSH or other transports ([#564](https://github.com/badlogic/pi-mono/issues/564)). Interfaces: `ReadOperations`, `WriteOperations`, `EditOperations`, `BashOperations`, `LsOperations`, `GrepOperations`, `FindOperations`
9801
+ - `user_bash` event for intercepting user `!`/`!!` commands, allowing extensions to redirect to remote systems ([#528](https://github.com/badlogic/pi-mono/issues/528))
9802
+ - `setActiveTools()` in ExtensionAPI for dynamic tool management
9803
+ - Built-in renderers used automatically for tool overrides without custom `renderCall`/`renderResult`
9804
+ - `ssh.ts` example: remote tool execution via `--ssh user@host:/path`
9805
+ - `interactive-shell.ts` example: run interactive commands (vim, git rebase, htop) with full terminal access via `!i` prefix or auto-detection
9806
+ - Wayland clipboard support for `/copy` command using wl-copy with xclip/xsel fallback ([#570](https://github.com/badlogic/pi-mono/pull/570) by [@OgulcanCelik](https://github.com/OgulcanCelik))
9807
+ - **Experimental:** `ctx.ui.custom()` now accepts `{ overlay: true }` option for floating modal components that composite over existing content without clearing the screen ([#558](https://github.com/badlogic/pi-mono/pull/558) by [@nicobailon](https://github.com/nicobailon))
9808
+ - `AgentSession.skills` and `AgentSession.skillWarnings` properties to access loaded skills without rediscovery ([#577](https://github.com/badlogic/pi-mono/pull/577) by [@cv](https://github.com/cv))
9809
+
9810
+ ### Fixed
9811
+
9812
+ - String `systemPrompt` in `createAgentSession()` now works as a full replacement instead of having context files and skills appended, matching documented behavior ([#543](https://github.com/badlogic/pi-mono/issues/543))
9813
+ - Update notification for bun binary installs now shows release download URL instead of npm command ([#567](https://github.com/badlogic/pi-mono/pull/567) by [@ferologics](https://github.com/ferologics))
9814
+ - ESC key now works during "Working..." state after auto-retry ([#568](https://github.com/badlogic/pi-mono/pull/568) by [@tmustier](https://github.com/tmustier))
9815
+ - Abort messages now show correct retry attempt count (e.g., "Aborted after 2 retry attempts") ([#568](https://github.com/badlogic/pi-mono/pull/568) by [@tmustier](https://github.com/tmustier))
9816
+ - Fixed Antigravity provider returning 429 errors despite available quota ([#571](https://github.com/badlogic/pi-mono/pull/571) by [@ben-vargas](https://github.com/ben-vargas))
9817
+ - Fixed malformed thinking text in Gemini/Antigravity responses where thinking content appeared as regular text or vice versa. Cross-model conversations now properly convert thinking blocks to plain text. ([#561](https://github.com/badlogic/pi-mono/issues/561))
9818
+ - `--no-skills` flag now correctly prevents skills from loading in interactive mode ([#577](https://github.com/badlogic/pi-mono/pull/577) by [@cv](https://github.com/cv))
9819
+
9820
+ ## [0.38.0] - 2026-01-08
9821
+
9822
+ ### Breaking Changes
9823
+
9824
+ - `ctx.ui.custom()` factory signature changed from `(tui, theme, done)` to `(tui, theme, keybindings, done)` for keybinding access in custom components
9825
+ - `LoadedExtension` type renamed to `Extension`
9826
+ - `LoadExtensionsResult.setUIContext()` removed, replaced with `runtime: ExtensionRuntime`
9827
+ - `ExtensionRunner` constructor now requires `runtime: ExtensionRuntime` as second parameter
9828
+ - `ExtensionRunner.initialize()` signature changed from options object to positional params `(actions, contextActions, commandContextActions?, uiContext?)`
9829
+ - `ExtensionRunner.getHasUI()` renamed to `hasUI()`
9830
+ - 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](https://github.com/badlogic/pi-mono/pull/536) by [@ghoulr](https://github.com/ghoulr))
9831
+
9832
+ ### Added
9833
+
9834
+ - `--no-extensions` flag to disable extension discovery while still allowing explicit `-e` paths ([#524](https://github.com/badlogic/pi-mono/pull/524) by [@cv](https://github.com/cv))
9835
+ - SDK: `InteractiveMode`, `runPrintMode()`, `runRpcMode()` exported for building custom run modes. See `docs/sdk.md`.
9836
+ - `PI_SKIP_VERSION_CHECK` environment variable to disable new version notifications at startup ([#549](https://github.com/badlogic/pi-mono/pull/549) by [@aos](https://github.com/aos))
9837
+ - `thinkingBudgets` setting to customize token budgets per thinking level for token-based providers ([#529](https://github.com/badlogic/pi-mono/pull/529) by [@melihmucuk](https://github.com/melihmucuk))
9838
+ - Extension UI dialogs (`ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`) now support a `timeout` option with live countdown display ([#522](https://github.com/badlogic/pi-mono/pull/522) by [@nicobailon](https://github.com/nicobailon))
9839
+ - Extensions can now provide custom editor components via `ctx.ui.setEditorComponent()`. See `examples/extensions/modal-editor.ts` and `docs/tui.md` Pattern 7.
9840
+ - Extension factories can now be async, enabling dynamic imports and lazy-loaded dependencies ([#513](https://github.com/badlogic/pi-mono/pull/513) by [@austinm911](https://github.com/austinm911))
9841
+ - `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](https://github.com/badlogic/pi-mono/pull/542) by [@kaofelix](https://github.com/kaofelix))
9842
+
9843
+ ### Fixed
9844
+
9845
+ - Default thinking level from settings now applies correctly when `enabledModels` is configured ([#540](https://github.com/badlogic/pi-mono/pull/540) by [@ferologics](https://github.com/ferologics))
9846
+ - External edits to `settings.json` while pi is running are now preserved when pi saves settings ([#527](https://github.com/badlogic/pi-mono/pull/527) by [@ferologics](https://github.com/ferologics))
9847
+ - Overflow-based compaction now skips if error came from a different model or was already handled by a previous compaction ([#535](https://github.com/badlogic/pi-mono/pull/535) by [@mitsuhiko](https://github.com/mitsuhiko))
9848
+ - OpenAI Codex context window reduced from 400k to 272k tokens to match Codex CLI defaults and prevent 400 errors ([#536](https://github.com/badlogic/pi-mono/pull/536) by [@ghoulr](https://github.com/ghoulr))
9849
+ - Context overflow detection now recognizes `context_length_exceeded` errors.
9850
+ - Key presses no longer dropped when input is batched over SSH ([#538](https://github.com/badlogic/pi-mono/issues/538))
9851
+ - Clipboard image support now works on Alpine Linux and other musl-based distros ([#533](https://github.com/badlogic/pi-mono/issues/533))
9852
+
9853
+ ## [0.37.6] - 2026-01-06
9854
+
9855
+ ### Added
9856
+
9857
+ - 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](https://github.com/badlogic/pi-mono/issues/474))
9858
+ - HTML export now shows bridge prompts in model change messages for Codex sessions ([#510](https://github.com/badlogic/pi-mono/pull/510) by [@mitsuhiko](https://github.com/mitsuhiko))
9859
+
9860
+ ## [0.37.5] - 2026-01-06
9861
+
9862
+ ### Added
9863
+
9864
+ - ExtensionAPI: `setModel()`, `getThinkingLevel()`, `setThinkingLevel()` methods for extensions to change model and thinking level at runtime ([#509](https://github.com/badlogic/pi-mono/issues/509))
9865
+ - Exported truncation utilities for custom tools: `truncateHead`, `truncateTail`, `truncateLine`, `formatSize`, `DEFAULT_MAX_BYTES`, `DEFAULT_MAX_LINES`, `TruncationOptions`, `TruncationResult`
9866
+ - New example `truncated-tool.ts` demonstrating proper output truncation with custom rendering for extensions
9867
+ - New example `preset.ts` demonstrating preset configurations with model/thinking/tools switching ([#347](https://github.com/badlogic/pi-mono/issues/347))
9868
+ - Documentation for output truncation best practices in `docs/extensions.md`
9869
+ - 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`
9870
+ - `docs/tui.md`: Common Patterns section with copy-paste code for SelectList, BorderedLoader, SettingsList, setStatus, setWidget, setFooter
9871
+ - `docs/tui.md`: Key Rules section documenting critical patterns for extension UI development
9872
+ - `docs/extensions.md`: Exhaustive example links for all ExtensionAPI methods and events
9873
+ - System prompt now references `docs/tui.md` for TUI component development
9874
+
9875
+ ## [0.37.4] - 2026-01-06
9876
+
9877
+ ### Added
9878
+
9879
+ - Session picker (`pi -r`) and `--session` flag now support searching/resuming by session ID (UUID prefix) ([#495](https://github.com/badlogic/pi-mono/issues/495) by [@arunsathiya](https://github.com/arunsathiya))
9880
+ - Extensions can now replace the startup header with `ctx.ui.setHeader()`, see `examples/extensions/custom-header.ts` ([#500](https://github.com/badlogic/pi-mono/pull/500) by [@tudoroancea](https://github.com/tudoroancea))
9881
+
9882
+ ### Changed
9883
+
9884
+ - Startup help text: fixed misleading "ctrl+k to delete line" to "ctrl+k to delete to end"
9885
+ - Startup help text and `/hotkeys`: added `!!` shortcut for running bash without adding output to context
9886
+
9887
+ ### Fixed
9888
+
9889
+ - Queued steering/follow-up messages no longer wipe unsent editor input ([#503](https://github.com/badlogic/pi-mono/pull/503) by [@tmustier](https://github.com/tmustier))
9890
+ - OAuth token refresh failure no longer crashes app at startup, allowing user to `/login` to re-authenticate ([#498](https://github.com/badlogic/pi-mono/issues/498))
9891
+
9892
+ ## [0.37.3] - 2026-01-06
9893
+
9894
+ ### Added
9895
+
9896
+ - Extensions can now replace the footer with `ctx.ui.setFooter()`, see `examples/extensions/custom-footer.ts` ([#481](https://github.com/badlogic/pi-mono/issues/481))
9897
+ - Session ID is now forwarded to LLM providers for session-based caching (used by OpenAI Codex for prompt caching).
9898
+ - Added `blockImages` setting to prevent images from being sent to LLM providers ([#492](https://github.com/badlogic/pi-mono/pull/492) by [@jsinge97](https://github.com/jsinge97))
9899
+ - Extensions can now send user messages via `pi.sendUserMessage()` ([#483](https://github.com/badlogic/pi-mono/issues/483))
9900
+
9901
+ ### Fixed
9902
+
9903
+ - Add `minimatch` as a direct dependency for explicit imports.
9904
+ - Status bar now shows correct git branch when running in a git worktree ([#490](https://github.com/badlogic/pi-mono/pull/490) by [@kcosr](https://github.com/kcosr))
9905
+ - Interactive mode: Ctrl+V clipboard image paste now works on Wayland sessions by using `wl-paste` with `xclip` fallback ([#488](https://github.com/badlogic/pi-mono/pull/488) by [@ghoulr](https://github.com/ghoulr))
9906
+
9907
+ ## [0.37.2] - 2026-01-05
9908
+
9909
+ ### Fixed
9910
+
9911
+ - Extension directories in `settings.json` now respect `package.json` manifests, matching global extension behavior ([#480](https://github.com/badlogic/pi-mono/pull/480) by [@prateekmedia](https://github.com/prateekmedia))
9912
+ - Share viewer: deep links now scroll to the target message when opened via `/share`
9913
+ - Bash tool now handles spawn errors gracefully instead of crashing the agent (missing cwd, invalid shell path) ([#479](https://github.com/badlogic/pi-mono/pull/479) by [@robinwander](https://github.com/robinwander))
9914
+
9915
+ ## [0.37.1] - 2026-01-05
9916
+
9917
+ ### Fixed
9918
+
9919
+ - Share viewer: copy-link buttons now generate correct URLs when session is viewed via `/share` (iframe context)
9920
+
9921
+ ## [0.37.0] - 2026-01-05
9922
+
9923
+ ### Added
9924
+
9925
+ - Share viewer: copy-link button on messages to share URLs that navigate directly to a specific message ([#477](https://github.com/badlogic/pi-mono/pull/477) by [@lockmeister](https://github.com/lockmeister))
9926
+ - Extension example: add `claude-rules` to load `.claude/rules/` entries into the system prompt ([#461](https://github.com/badlogic/pi-mono/pull/461) by [@vaayne](https://github.com/vaayne))
9927
+ - Headless OAuth login: all providers now show paste input for manual URL/code entry, works over SSH without DISPLAY ([#428](https://github.com/badlogic/pi-mono/pull/428) by [@ben-vargas](https://github.com/ben-vargas), [#468](https://github.com/badlogic/pi-mono/pull/468) by [@crcatala](https://github.com/crcatala))
9928
+
9929
+ ### Changed
9930
+
9931
+ - OAuth login UI now uses dedicated dialog component with consistent borders
9932
+ - Assume truecolor support for all terminals except `dumb`, empty, or `linux` (fixes colors over SSH)
9933
+ - 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](https://github.com/badlogic/pi-mono/pull/472) by [@ben-vargas](https://github.com/ben-vargas))
9934
+
9935
+ ### Fixed
9936
+
9937
+ - Messages submitted during compaction are queued and delivered after compaction completes, preserving steering and follow-up behavior. Extension commands execute immediately during compaction. ([#476](https://github.com/badlogic/pi-mono/pull/476) by [@tmustier](https://github.com/tmustier))
9938
+ - Managed binaries (`fd`, `rg`) now stored in `~/.pi/agent/bin/` instead of `tools/`, eliminating false deprecation warnings ([#470](https://github.com/badlogic/pi-mono/pull/470) by [@mcinteerj](https://github.com/mcinteerj))
9939
+ - Extensions defined in `settings.json` were not loaded ([#463](https://github.com/badlogic/pi-mono/pull/463) by [@melihmucuk](https://github.com/melihmucuk))
9940
+ - OAuth refresh no longer logs users out when multiple pi instances are running ([#466](https://github.com/badlogic/pi-mono/pull/466) by [@Cursivez](https://github.com/Cursivez))
9941
+ - Migration warnings now ignore `fd.exe` and `rg.exe` in `tools/` on Windows ([#458](https://github.com/badlogic/pi-mono/pull/458) by [@carlosgtrz](https://github.com/carlosgtrz))
9942
+ - CI: add `examples/extensions/with-deps` to workspaces to fix typecheck ([#467](https://github.com/badlogic/pi-mono/pull/467) by [@aliou](https://github.com/aliou))
9943
+ - SDK: passing `extensions: []` now disables extension discovery as documented ([#465](https://github.com/badlogic/pi-mono/pull/465) by [@aliou](https://github.com/aliou))
9944
+
9945
+ ## [0.36.0] - 2026-01-05
9946
+
9947
+ ### Added
9948
+
9949
+ - Experimental: OpenAI Codex OAuth provider support: access Codex models via ChatGPT Plus/Pro subscription using `/login openai-codex` ([#451](https://github.com/badlogic/pi-mono/pull/451) by [@kim0](https://github.com/kim0))
9950
+
9951
+ ## [0.35.0] - 2026-01-05
9952
+
9953
+ This release unifies hooks and custom tools into a single "extensions" system and renames "slash commands" to "prompt templates". ([#454](https://github.com/badlogic/pi-mono/issues/454))
9954
+
9955
+ **Before migrating, read:**
9956
+ - [docs/extensions.md](docs/extensions.md) - Full API reference
9957
+ - [README.md](README.md) - Extensions section with examples
9958
+ - [examples/extensions/](examples/extensions/) - Working examples
9959
+
9960
+ ### Extensions Migration
9961
+
9962
+ 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.
9963
+
9964
+ **Automatic migration:**
9965
+ - `commands/` directories are automatically renamed to `prompts/` on startup (both `~/.pi/agent/commands/` and `.pi/commands/`)
9966
+
9967
+ **Manual migration required:**
9968
+ 1. Move files from `hooks/` and `tools/` directories to `extensions/` (deprecation warnings shown on startup)
9969
+ 2. Update imports and type names in your extension code
9970
+ 3. Update `settings.json` if you have explicit hook and custom tool paths configured
9971
+
9972
+ **Directory changes:**
9973
+ ```
9974
+ # Before
9975
+ ~/.pi/agent/hooks/*.ts → ~/.pi/agent/extensions/*.ts
9976
+ ~/.pi/agent/tools/*.ts → ~/.pi/agent/extensions/*.ts
9977
+ .pi/hooks/*.ts → .pi/extensions/*.ts
9978
+ .pi/tools/*.ts → .pi/extensions/*.ts
9979
+ ```
9980
+
9981
+ **Extension discovery rules** (in `extensions/` directories):
9982
+ 1. **Direct files:** `extensions/*.ts` or `*.js` → loaded directly
9983
+ 2. **Subdirectory with index:** `extensions/myext/index.ts` → loaded as single extension
9984
+ 3. **Subdirectory with package.json:** `extensions/myext/package.json` with `"pi"` field → loads declared paths
9985
+
9986
+ ```json
9987
+ // extensions/my-package/package.json
9988
+ {
9989
+ "name": "my-extension-package",
9990
+ "dependencies": { "zod": "^3.0.0" },
9991
+ "pi": {
9992
+ "extensions": ["./src/main.ts", "./src/tools.ts"]
9993
+ }
9994
+ }
9995
+ ```
9996
+
9997
+ 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.
9998
+
9999
+ **Type renames:**
10000
+ - `HookAPI` → `ExtensionAPI`
10001
+ - `HookContext` → `ExtensionContext`
10002
+ - `HookCommandContext` → `ExtensionCommandContext`
10003
+ - `HookUIContext` → `ExtensionUIContext`
10004
+ - `CustomToolAPI` → `ExtensionAPI` (merged)
10005
+ - `CustomToolContext` → `ExtensionContext` (merged)
10006
+ - `CustomToolUIContext` → `ExtensionUIContext`
10007
+ - `CustomTool` → `ToolDefinition`
10008
+ - `CustomToolFactory` → `ExtensionFactory`
10009
+ - `HookMessage` → `CustomMessage`
10010
+
10011
+ **Import changes:**
10012
+ ```typescript
10013
+ // Before (hook)
10014
+ import type { HookAPI, HookContext } from "@mariozechner/pi-coding-agent";
10015
+ export default function (pi: HookAPI) { ... }
10016
+
10017
+ // Before (custom tool)
10018
+ import type { CustomToolFactory } from "@mariozechner/pi-coding-agent";
10019
+ const factory: CustomToolFactory = (pi) => ({ name: "my_tool", ... });
10020
+ export default factory;
10021
+
10022
+ // After (both are now extensions)
10023
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
10024
+ export default function (pi: ExtensionAPI) {
10025
+ pi.on("tool_call", async (event, ctx) => { ... });
10026
+ pi.registerTool({ name: "my_tool", ... });
10027
+ }
10028
+ ```
10029
+
10030
+ **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:
10031
+
10032
+ - `pi.registerTool()` - Register tools the LLM can call
10033
+ - `pi.registerCommand()` - Register commands like `/mycommand`
10034
+ - `pi.registerShortcut()` - Register keyboard shortcuts (shown in `/hotkeys`)
10035
+ - `pi.registerFlag()` - Register CLI flags (shown in `--help`)
10036
+ - `pi.registerMessageRenderer()` - Custom TUI rendering for message types
10037
+ - `pi.on()` - Subscribe to lifecycle events (tool_call, session_start, etc.)
10038
+ - `pi.sendMessage()` - Inject messages into the conversation
10039
+ - `pi.appendEntry()` - Persist custom data in session (survives restart/branch)
10040
+ - `pi.exec()` - Run shell commands
10041
+ - `pi.getActiveTools()` / `pi.setActiveTools()` - Dynamic tool enable/disable
10042
+ - `pi.getAllTools()` - List all available tools
10043
+ - `pi.events` - Event bus for cross-extension communication
10044
+ - `ctx.ui.confirm()` / `select()` / `input()` - User prompts
10045
+ - `ctx.ui.notify()` - Toast notifications
10046
+ - `ctx.ui.setStatus()` - Persistent status in footer (multiple extensions can set their own)
10047
+ - `ctx.ui.setWidget()` - Widget display above editor
10048
+ - `ctx.ui.setTitle()` - Set terminal window title
10049
+ - `ctx.ui.custom()` - Full TUI component with keyboard handling
10050
+ - `ctx.ui.editor()` - Multi-line text editor with external editor support
10051
+ - `ctx.sessionManager` - Read session entries, get branch history
10052
+
10053
+ **Settings changes:**
10054
+ ```json
10055
+ // Before
10056
+ {
10057
+ "hooks": ["./my-hook.ts"],
10058
+ "customTools": ["./my-tool.ts"]
10059
+ }
10060
+
10061
+ // After
10062
+ {
10063
+ "extensions": ["./my-extension.ts"]
10064
+ }
10065
+ ```
10066
+
10067
+ **CLI changes:**
10068
+ ```bash
10069
+ # Before
10070
+ pi --hook ./safety.ts --tool ./todo.ts
10071
+
10072
+ # After
10073
+ pi --extension ./safety.ts -e ./todo.ts
10074
+ ```
10075
+
10076
+ ### Prompt Templates Migration
10077
+
10078
+ "Slash commands" (markdown files defining reusable prompts invoked via `/name`) are renamed to "prompt templates" to avoid confusion with extension-registered commands.
10079
+
10080
+ **Automatic migration:** The `commands/` directory is automatically renamed to `prompts/` on startup (if `prompts/` doesn't exist). Works for both regular directories and symlinks.
10081
+
10082
+ **Directory changes:**
10083
+ ```
10084
+ ~/.pi/agent/commands/*.md → ~/.pi/agent/prompts/*.md
10085
+ .pi/commands/*.md → .pi/prompts/*.md
10086
+ ```
10087
+
10088
+ **SDK type renames:**
10089
+ - `FileSlashCommand` → `PromptTemplate`
10090
+ - `LoadSlashCommandsOptions` → `LoadPromptTemplatesOptions`
10091
+
10092
+ **SDK function renames:**
10093
+ - `discoverSlashCommands()` → `discoverPromptTemplates()`
10094
+ - `loadSlashCommands()` → `loadPromptTemplates()`
10095
+ - `expandSlashCommand()` → `expandPromptTemplate()`
10096
+ - `getCommandsDir()` → `getPromptsDir()`
10097
+
10098
+ **SDK option renames:**
10099
+ - `CreateAgentSessionOptions.slashCommands` → `.promptTemplates`
10100
+ - `AgentSession.fileCommands` → `.promptTemplates`
10101
+ - `PromptOptions.expandSlashCommands` → `.expandPromptTemplates`
10102
+
10103
+ ### SDK Migration
10104
+
10105
+ **Discovery functions:**
10106
+ - `discoverAndLoadHooks()` → `discoverAndLoadExtensions()`
10107
+ - `discoverAndLoadCustomTools()` → merged into `discoverAndLoadExtensions()`
10108
+ - `loadHooks()` → `loadExtensions()`
10109
+ - `loadCustomTools()` → merged into `loadExtensions()`
10110
+
10111
+ **Runner and wrapper:**
10112
+ - `HookRunner` → `ExtensionRunner`
10113
+ - `wrapToolsWithHooks()` → `wrapToolsWithExtensions()`
10114
+ - `wrapToolWithHooks()` → `wrapToolWithExtensions()`
10115
+
10116
+ **CreateAgentSessionOptions:**
10117
+ - `.hooks` → removed (use `.additionalExtensionPaths` for paths)
10118
+ - `.additionalHookPaths` → `.additionalExtensionPaths`
10119
+ - `.preloadedHooks` → `.preloadedExtensions`
10120
+ - `.customTools` type changed: `Array<{ path?; tool: CustomTool }>` → `ToolDefinition[]`
10121
+ - `.additionalCustomToolPaths` → merged into `.additionalExtensionPaths`
10122
+ - `.slashCommands` → `.promptTemplates`
10123
+
10124
+ **AgentSession:**
10125
+ - `.hookRunner` → `.extensionRunner`
10126
+ - `.fileCommands` → `.promptTemplates`
10127
+ - `.sendHookMessage()` → `.sendCustomMessage()`
10128
+
10129
+ ### Session Migration
10130
+
10131
+ **Automatic.** Session version bumped from 2 to 3. Existing sessions are migrated on first load:
10132
+ - Message role `"hookMessage"` → `"custom"`
10133
+
10134
+ ### Breaking Changes
10135
+
10136
+ - **Settings:** `hooks` and `customTools` arrays replaced with single `extensions` array
10137
+ - **CLI:** `--hook` and `--tool` flags replaced with `--extension` / `-e`
10138
+ - **Directories:** `hooks/`, `tools/` → `extensions/`; `commands/` → `prompts/`
10139
+ - **Types:** See type renames above
10140
+ - **SDK:** See SDK migration above
10141
+
10142
+ ### Changed
10143
+
10144
+ - Extensions can have their own `package.json` with dependencies (resolved via jiti)
10145
+ - Documentation: `docs/hooks.md` and `docs/custom-tools.md` merged into `docs/extensions.md`
10146
+ - Examples: `examples/hooks/` and `examples/custom-tools/` merged into `examples/extensions/`
10147
+ - README: Extensions section expanded with custom tools, commands, events, state persistence, shortcuts, flags, and UI examples
10148
+ - SDK: `customTools` option now accepts `ToolDefinition[]` directly (simplified from `Array<{ path?, tool }>`)
10149
+ - SDK: `extensions` option accepts `ExtensionFactory[]` for inline extensions
10150
+ - SDK: `additionalExtensionPaths` replaces both `additionalHookPaths` and `additionalCustomToolPaths`
10151
+
10152
+ ## [0.34.1] - 2026-01-04
10153
+
10154
+ ### Added
10155
+
10156
+ - Hook API: `ctx.ui.setTitle(title)` allows hooks to set the terminal window/tab title ([#446](https://github.com/badlogic/pi-mono/pull/446) by [@aliou](https://github.com/aliou))
10157
+
10158
+ ### Changed
10159
+
10160
+ - Expanded keybinding documentation to list all 32 supported symbol keys with notes on ctrl+symbol behavior ([#450](https://github.com/badlogic/pi-mono/pull/450) by [@kaofelix](https://github.com/kaofelix))
10161
+
10162
+ ## [0.34.0] - 2026-01-04
10163
+
10164
+ ### Added
10165
+
10166
+ - 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.
10167
+ - Hook API: `before_agent_start` handlers can now return multiple messages (all are injected, not just the first)
10168
+ - New example hook: `tools.ts` - Interactive `/tools` command to enable/disable tools with session persistence
10169
+ - New example hook: `pirate.ts` - Demonstrates `systemPromptAppend` to make the agent speak like a pirate
10170
+ - 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()`.
10171
+ - System prompt now automatically rebuilds when tools change via `setActiveTools()`, updating tool descriptions and guidelines to match the new tool set
10172
+ - Hook errors now display full stack traces for easier debugging
10173
+
10174
+ ### Changed
10175
+
10176
+ - Removed image placeholders after copy & paste, replaced with inserting image file paths directly. ([#442](https://github.com/badlogic/pi-mono/pull/442) by [@mitsuhiko](https://github.com/mitsuhiko))
10177
+
10178
+ ### Fixed
10179
+
10180
+ - Fixed potential text decoding issues in bash executor by using streaming TextDecoder instead of Buffer.toString()
10181
+ - External editor (Ctrl-G) now shows full pasted content instead of `[paste #N ...]` placeholders ([#444](https://github.com/badlogic/pi-mono/pull/444) by [@aliou](https://github.com/aliou))
10182
+
10183
+ ## [0.33.0] - 2026-01-04
10184
+
10185
+ ### Breaking Changes
10186
+
10187
+ - **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](https://github.com/badlogic/pi-mono/pull/405))
10188
+
10189
+ ### Added
10190
+
10191
+ - 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](https://github.com/badlogic/pi-mono/issues/419))
10192
+ - 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](https://github.com/badlogic/pi-mono/pull/405) by [@hjanuschka](https://github.com/hjanuschka))
10193
+ - `/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](https://github.com/badlogic/pi-mono/pull/426) by [@ben-vargas](https://github.com/ben-vargas))
10194
+
10195
+ ### Fixed
10196
+
10197
+ - Subagent example README referenced incorrect filename `subagent.ts` instead of `index.ts` ([#427](https://github.com/badlogic/pi-mono/pull/427) by [@Whamp](https://github.com/Whamp))
10198
+
10199
+ ## [0.32.3] - 2026-01-03
10200
+
10201
+ ### Fixed
10202
+
10203
+ - `--list-models` no longer shows Google Vertex AI models without explicit authentication configured
10204
+ - JPEG/GIF/WebP images not displaying in terminals using Kitty graphics protocol (Kitty, Ghostty, WezTerm). The protocol requires PNG format, so non-PNG images are now converted before display.
10205
+ - Version check URL typo preventing update notifications from working ([#423](https://github.com/badlogic/pi-mono/pull/423) by [@skuridin](https://github.com/skuridin))
10206
+ - Large images exceeding Anthropic's 5MB limit now retry with progressive quality/size reduction ([#424](https://github.com/badlogic/pi-mono/pull/424) by [@mitsuhiko](https://github.com/mitsuhiko))
10207
+
10208
+ ## [0.32.2] - 2026-01-03
10209
+
10210
+ ### Added
10211
+
10212
+ - `$ARGUMENTS` syntax for custom slash commands as alternative to `$@` for all arguments joined. Aligns with patterns used by Claude, Codex, and OpenCode. Both syntaxes remain fully supported. ([#418](https://github.com/badlogic/pi-mono/pull/418) by [@skuridin](https://github.com/skuridin))
10213
+
10214
+ ### Changed
10215
+
10216
+ - **Slash commands and hook commands now work during streaming**: Previously, using a slash command or hook command while the agent was streaming would crash with "Agent is already processing". Now:
10217
+ - Hook commands execute immediately (they manage their own LLM interaction via `pi.sendMessage()`)
10218
+ - File-based slash commands are expanded and queued via steer/followUp
10219
+ - `steer()` and `followUp()` now expand file-based slash commands and error on hook commands (hook commands cannot be queued)
10220
+ - `prompt()` accepts new `streamingBehavior` option (`"steer"` or `"followUp"`) to specify queueing behavior during streaming
10221
+ - RPC `prompt` command now accepts optional `streamingBehavior` field
10222
+ ([#420](https://github.com/badlogic/pi-mono/issues/420))
10223
+
10224
+ ### Fixed
10225
+
10226
+ - Slash command argument substitution now processes positional arguments (`$1`, `$2`, etc.) before all-arguments (`$@`, `$ARGUMENTS`) to prevent recursive substitution when argument values contain dollar-digit patterns like `$100`. ([#418](https://github.com/badlogic/pi-mono/pull/418) by [@skuridin](https://github.com/skuridin))
10227
+
10228
+ ## [0.32.1] - 2026-01-03
10229
+
10230
+ ### Added
10231
+
10232
+ - Shell commands without context contribution: use `!!command` to execute a bash command that is shown in the TUI and saved to session history but excluded from LLM context. Useful for running commands you don't want the AI to see. ([#414](https://github.com/badlogic/pi-mono/issues/414))
10233
+
10234
+ ### Fixed
10235
+
10236
+ - Edit tool diff not displaying in TUI due to race condition between async preview computation and tool execution
10237
+
10238
+ ## [0.32.0] - 2026-01-03
10239
+
10240
+ ### Breaking Changes
10241
+
10242
+ - **Queue API replaced with steer/followUp**: The `queueMessage()` method has been split into two methods with different delivery semantics ([#403](https://github.com/badlogic/pi-mono/issues/403)):
10243
+ - `steer(text)`: Interrupts the agent mid-run (Enter while streaming). Delivered after current tool execution.
10244
+ - `followUp(text)`: Waits until the agent finishes (Alt+Enter while streaming). Delivered only when agent stops.
10245
+ - **Settings renamed**: `queueMode` setting renamed to `steeringMode`. Added new `followUpMode` setting. Old settings.json files are migrated automatically.
10246
+ - **AgentSession methods renamed**:
10247
+ - `queueMessage()` → `steer()` and `followUp()`
10248
+ - `queueMode` getter → `steeringMode` and `followUpMode` getters
10249
+ - `setQueueMode()` → `setSteeringMode()` and `setFollowUpMode()`
10250
+ - `queuedMessageCount` → `pendingMessageCount`
10251
+ - `getQueuedMessages()` → `getSteeringMessages()` and `getFollowUpMessages()`
10252
+ - `clearQueue()` now returns `{ steering: string[], followUp: string[] }`
10253
+ - `hasQueuedMessages()` → `hasPendingMessages()`
10254
+ - **Hook API signature changed**: `pi.sendMessage()` second parameter changed from `triggerTurn?: boolean` to `options?: { triggerTurn?, deliverAs? }`. Use `deliverAs: "followUp"` for follow-up delivery. Affects both hooks and internal `sendHookMessage()` method.
10255
+ - **RPC API changes**:
10256
+ - `queue_message` command → `steer` and `follow_up` commands
10257
+ - `set_queue_mode` command → `set_steering_mode` and `set_follow_up_mode` commands
10258
+ - `RpcSessionState.queueMode` → `steeringMode` and `followUpMode`
10259
+ - **Settings UI**: "Queue mode" setting split into "Steering mode" and "Follow-up mode"
10260
+
10261
+ ### Added
10262
+
10263
+ - Configurable double-escape action: choose whether double-escape with empty editor opens `/tree` (default) or `/branch`. Configure via `/settings` or `doubleEscapeAction` in settings.json ([#404](https://github.com/badlogic/pi-mono/issues/404))
10264
+ - Vertex AI provider (`google-vertex`): access Gemini models via Google Cloud Vertex AI using Application Default Credentials ([#300](https://github.com/badlogic/pi-mono/pull/300) by [@default-anton](https://github.com/default-anton))
10265
+ - Built-in provider overrides in `models.json`: override just `baseUrl` to route a built-in provider through a proxy while keeping all its models, or define `models` to fully replace the provider ([#406](https://github.com/badlogic/pi-mono/pull/406) by [@yevhen](https://github.com/yevhen))
10266
+ - Automatic image resizing: images larger than 2000x2000 are resized for better model compatibility. Original dimensions are injected into the prompt. Controlled via `/settings` or `images.autoResize` in settings.json. ([#402](https://github.com/badlogic/pi-mono/pull/402) by [@mitsuhiko](https://github.com/mitsuhiko))
10267
+ - Alt+Enter keybind to queue follow-up messages while agent is streaming
10268
+ - `Theme` and `ThemeColor` types now exported for hooks using `ctx.ui.custom()`
10269
+ - Terminal window title now displays "pi - dirname" to identify which project session you're in ([#407](https://github.com/badlogic/pi-mono/pull/407) by [@kaofelix](https://github.com/kaofelix))
10270
+
10271
+ ### Changed
10272
+
10273
+ - Editor component now uses word wrapping instead of character-level wrapping for better readability ([#382](https://github.com/badlogic/pi-mono/pull/382) by [@nickseelert](https://github.com/nickseelert))
10274
+
10275
+ ### Fixed
10276
+
10277
+ - `/model` selector now opens instantly instead of waiting for OAuth token refresh. Token refresh is deferred until a model is actually used.
10278
+ - Shift+Space, Shift+Backspace, and Shift+Delete now work correctly in Kitty-protocol terminals (Kitty, WezTerm, etc.) instead of being silently ignored ([#411](https://github.com/badlogic/pi-mono/pull/411) by [@nathyong](https://github.com/nathyong))
10279
+ - `AgentSession.prompt()` now throws if called while the agent is already streaming, preventing race conditions. Use `steer()` or `followUp()` to queue messages during streaming.
10280
+ - Ctrl+C now works like Escape in selector components, so mashing Ctrl+C will eventually close the program ([#400](https://github.com/badlogic/pi-mono/pull/400) by [@mitsuhiko](https://github.com/mitsuhiko))
10281
+
10282
+ ## [0.31.1] - 2026-01-02
10283
+
10284
+ ### Fixed
10285
+
10286
+ - Model selector no longer allows negative index when pressing arrow keys before models finish loading ([#398](https://github.com/badlogic/pi-mono/pull/398) by [@mitsuhiko](https://github.com/mitsuhiko))
10287
+ - Type guard functions (`isBashToolResult`, etc.) now exported at runtime, not just in type declarations ([#397](https://github.com/badlogic/pi-mono/issues/397))
10288
+
10289
+ ## [0.31.0] - 2026-01-02
10290
+
10291
+ This release introduces session trees for in-place branching, major API changes to hooks and custom tools, and structured compaction with file tracking.
10292
+
10293
+ ### Session Tree
10294
+
10295
+ Sessions now use a tree structure with `id`/`parentId` fields. This enables in-place branching: navigate to any previous point with `/tree`, continue from there, and switch between branches while preserving all history in a single file.
10296
+
10297
+ **Existing sessions are automatically migrated** (v1 → v2) on first load. No manual action required.
10298
+
10299
+ New entry types: `BranchSummaryEntry` (context from abandoned branches), `CustomEntry` (hook state), `CustomMessageEntry` (hook-injected messages), `LabelEntry` (bookmarks).
10300
+
10301
+ See [docs/session.md](docs/session.md) for the file format and `SessionManager` API.
10302
+
10303
+ ### Hooks Migration
10304
+
10305
+ The hooks API has been restructured with more granular events and better session access.
10306
+
10307
+ **Type renames:**
10308
+
10309
+ - `HookEventContext` → `HookContext`
10310
+ - `HookCommandContext` is now a new interface extending `HookContext` with session control methods
10311
+
10312
+ **Event changes:**
10313
+
10314
+ - The monolithic `session` event is now split into granular events: `session_start`, `session_before_switch`, `session_switch`, `session_before_branch`, `session_branch`, `session_before_compact`, `session_compact`, `session_shutdown`
10315
+ - `session_before_switch` and `session_switch` events now include `reason: "new" | "resume"` to distinguish between `/new` and `/resume`
10316
+ - New `session_before_tree` and `session_tree` events for `/tree` navigation (hook can provide custom branch summary)
10317
+ - New `before_agent_start` event: inject messages before the agent loop starts
10318
+ - New `context` event: modify messages non-destructively before each LLM call
10319
+ - Session entries are no longer passed in events. Use `ctx.sessionManager.getEntries()` or `ctx.sessionManager.getBranch()` instead
10320
+
10321
+ **API changes:**
10322
+
10323
+ - `pi.send(text, attachments?)` → `pi.sendMessage(message, triggerTurn?)` (creates `CustomMessageEntry`)
10324
+ - New `pi.appendEntry(customType, data?)` for hook state persistence (not in LLM context)
10325
+ - New `pi.registerCommand(name, options)` for custom slash commands (handler receives `HookCommandContext`)
10326
+ - New `pi.registerMessageRenderer(customType, renderer)` for custom TUI rendering
10327
+ - New `ctx.isIdle()`, `ctx.abort()`, `ctx.hasQueuedMessages()` for agent state (available in all events)
10328
+ - New `ctx.ui.editor(title, prefill?)` for multi-line text editing with Ctrl+G external editor support
10329
+ - New `ctx.ui.custom(component)` for full TUI component rendering with keyboard focus
10330
+ - New `ctx.ui.setStatus(key, text)` for persistent status text in footer (multiple hooks can set their own)
10331
+ - New `ctx.ui.theme` getter for styling text with theme colors
10332
+ - `ctx.exec()` moved to `pi.exec()`
10333
+ - `ctx.sessionFile` → `ctx.sessionManager.getSessionFile()`
10334
+ - New `ctx.modelRegistry` and `ctx.model` for API key resolution
10335
+
10336
+ **HookCommandContext (slash commands only):**
10337
+
10338
+ - `ctx.waitForIdle()` - wait for agent to finish streaming
10339
+ - `ctx.newSession(options?)` - create new sessions with optional setup callback
9493
10340
  - `ctx.branch(entryId)` - branch from a specific entry
9494
10341
  - `ctx.navigateTree(targetId, options?)` - navigate the session tree
9495
10342
 
@@ -9581,8 +10428,8 @@ See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](ex
9581
10428
  ```typescript
9582
10429
  import { discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
9583
10430
 
9584
- const authStorage = discoverAuthStorage(); // ~/.omp/agent/auth.json
9585
- const modelRegistry = discoverModels(authStorage); // + ~/.omp/agent/models.json
10431
+ const authStorage = discoverAuthStorage(); // ~/.pi/agent/auth.json
10432
+ const modelRegistry = discoverModels(authStorage); // + ~/.pi/agent/models.json
9586
10433
 
9587
10434
  // Get all models (built-in + custom)
9588
10435
  const allModels = modelRegistry.getAll();
@@ -9717,25 +10564,25 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9717
10564
 
9718
10565
  ### Fixed
9719
10566
 
9720
- - **Sessions saved to wrong directory**: In v0.30.0, sessions were being saved to `~/.omp/agent/` instead of `~/.omp/agent/sessions/<encoded-cwd>/`, breaking `--resume` and `/resume`. Misplaced sessions are automatically migrated on startup. ([#320](https://github.com/badlogic/pi-mono/issues/320) by [@aliou](https://github.com/aliou))
10567
+ - **Sessions saved to wrong directory**: In v0.30.0, sessions were being saved to `~/.pi/agent/` instead of `~/.pi/agent/sessions/<encoded-cwd>/`, breaking `--resume` and `/resume`. Misplaced sessions are automatically migrated on startup. ([#320](https://github.com/badlogic/pi-mono/issues/320) by [@aliou](https://github.com/aliou))
9721
10568
  - **Custom system prompts missing context**: When using a custom system prompt string, project context files (AGENTS.md), skills, date/time, and working directory were not appended. ([#321](https://github.com/badlogic/pi-mono/issues/321))
9722
10569
 
9723
10570
  ## [0.30.0] - 2025-12-25
9724
10571
 
9725
10572
  ### Breaking Changes
9726
10573
 
9727
- - **SessionManager API**: The second parameter of `create()`, `continueRecent()`, and `list()` changed from `agentDir` to `sessionDir`. When provided, it specifies the session directory directly (no cwd encoding). When omitted, uses default (`~/.omp/agent/sessions/<encoded-cwd>/`). `open()` no longer takes `agentDir`. ([#313](https://github.com/badlogic/pi-mono/pull/313))
10574
+ - **SessionManager API**: The second parameter of `create()`, `continueRecent()`, and `list()` changed from `agentDir` to `sessionDir`. When provided, it specifies the session directory directly (no cwd encoding). When omitted, uses default (`~/.pi/agent/sessions/<encoded-cwd>/`). `open()` no longer takes `agentDir`. ([#313](https://github.com/badlogic/pi-mono/pull/313))
9728
10575
 
9729
10576
  ### Added
9730
10577
 
9731
- - **`--session-dir` flag**: Use a custom directory for sessions instead of the default `~/.omp/agent/sessions/<encoded-cwd>/`. Works with `-c` (continue) and `-r` (resume) flags. ([#313](https://github.com/badlogic/pi-mono/pull/313) by [@scutifer](https://github.com/scutifer))
10578
+ - **`--session-dir` flag**: Use a custom directory for sessions instead of the default `~/.pi/agent/sessions/<encoded-cwd>/`. Works with `-c` (continue) and `-r` (resume) flags. ([#313](https://github.com/badlogic/pi-mono/pull/313) by [@scutifer](https://github.com/scutifer))
9732
10579
  - **Reverse model cycling and model selector**: Shift+Ctrl+P cycles models backward, Ctrl+L opens model selector (retaining text in editor). ([#315](https://github.com/badlogic/pi-mono/pull/315) by [@mitsuhiko](https://github.com/mitsuhiko))
9733
10580
 
9734
10581
  ## [0.29.1] - 2025-12-25
9735
10582
 
9736
10583
  ### Added
9737
10584
 
9738
- - **Automatic custom system prompt loading**: OMP now auto-loads `SYSTEM.md` files to replace the default system prompt. Project-local `.omp/SYSTEM.md` takes precedence over global `~/.omp/agent/SYSTEM.md`. CLI `--system-prompt` flag overrides both. ([#309](https://github.com/badlogic/pi-mono/issues/309))
10585
+ - **Automatic custom system prompt loading**: Pi now auto-loads `SYSTEM.md` files to replace the default system prompt. Project-local `.pi/SYSTEM.md` takes precedence over global `~/.pi/agent/SYSTEM.md`. CLI `--system-prompt` flag overrides both. ([#309](https://github.com/badlogic/pi-mono/issues/309))
9739
10586
  - **Unified `/settings` command**: New settings menu consolidating thinking level, theme, queue mode, auto-compact, show images, hide thinking, and collapse changelog. Replaces individual `/thinking`, `/queue`, `/theme`, `/autocompact`, and `/show-images` commands. ([#310](https://github.com/badlogic/pi-mono/issues/310))
9740
10587
 
9741
10588
  ### Fixed
@@ -9762,8 +10609,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9762
10609
 
9763
10610
  ### Changed
9764
10611
 
9765
- - **Credential storage refactored**: API keys and OAuth tokens are now stored in `~/.omp/agent/auth.json` instead of `oauth.json` and `settings.json`. Existing credentials are automatically migrated on first run. ([#296](https://github.com/badlogic/pi-mono/issues/296))
9766
-
10612
+ - **Credential storage refactored**: API keys and OAuth tokens are now stored in `~/.pi/agent/auth.json` instead of `oauth.json` and `settings.json`. Existing credentials are automatically migrated on first run. ([#296](https://github.com/badlogic/pi-mono/issues/296))
9767
10613
  - **SDK API changes** ([#296](https://github.com/badlogic/pi-mono/issues/296)):
9768
10614
  - Added `AuthStorage` class for credential management (API keys and OAuth tokens)
9769
10615
  - Added `ModelRegistry` class for model discovery and API key resolution
@@ -9773,7 +10619,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9773
10619
  - Removed `getApiKey` callback option (use `AuthStorage.setRuntimeApiKey()` for runtime overrides)
9774
10620
  - Use `getModel()` from `@oh-my-pi/pi-ai` for built-in models, `modelRegistry.find()` for custom models + built-in models
9775
10621
  - See updated [SDK documentation](docs/sdk.md) and [README](README.md)
9776
-
9777
10622
  - **Settings changes**: Removed `apiKeys` from `settings.json`. Use `auth.json` instead. ([#296](https://github.com/badlogic/pi-mono/issues/296))
9778
10623
 
9779
10624
  ### Fixed
@@ -9807,7 +10652,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9807
10652
  - `messagesToKeep`: Messages that will be kept after the summary (recent turns), in addition to `messagesToSummarize`
9808
10653
  - `resolveApiKey`: Function to resolve API keys for any model (checks settings, OAuth, env vars)
9809
10654
  - Removed `apiKey` string in favor of `resolveApiKey` for more flexibility
9810
-
9811
10655
  - **SessionManager API cleanup**:
9812
10656
  - Renamed `loadSessionFromEntries()` to `buildSessionContext()` (builds LLM context from entries, handling compaction)
9813
10657
  - Renamed `loadEntries()` to `getEntries()` (returns defensive copy of all session entries)
@@ -9828,13 +10672,13 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9828
10672
 
9829
10673
  ### Fixed
9830
10674
 
9831
- - **Symlinked skill directories**: Skills in symlinked directories (e.g., `~/.omp/agent/skills/my-skills -> /path/to/skills`) are now correctly discovered and loaded.
10675
+ - **Symlinked skill directories**: Skills in symlinked directories (e.g., `~/.pi/agent/skills/my-skills -> /path/to/skills`) are now correctly discovered and loaded.
9832
10676
 
9833
10677
  ## [0.27.3] - 2025-12-24
9834
10678
 
9835
10679
  ### Added
9836
10680
 
9837
- - **API keys in settings.json**: Store API keys in `~/.omp/agent/settings.json` under the `apiKeys` field (e.g., `{ "apiKeys": { "anthropic": "sk-..." } }`). Settings keys take priority over environment variables. ([#295](https://github.com/badlogic/pi-mono/issues/295))
10681
+ - **API keys in settings.json**: Store API keys in `~/.pi/agent/settings.json` under the `apiKeys` field (e.g., `{ "apiKeys": { "anthropic": "sk-..." } }`). Settings keys take priority over environment variables. ([#295](https://github.com/badlogic/pi-mono/issues/295))
9838
10682
 
9839
10683
  ### Fixed
9840
10684
 
@@ -9855,7 +10699,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9855
10699
 
9856
10700
  ### Added
9857
10701
 
9858
- - **Startup timing instrumentation**: Set `OMP_TIMING=1` to see startup performance breakdown (interactive mode only).
10702
+ - **Startup timing instrumentation**: Set `PI_TIMING=1` to see startup performance breakdown (interactive mode only).
9859
10703
 
9860
10704
  ## [0.27.0] - 2025-12-22
9861
10705
 
@@ -9870,7 +10714,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9870
10714
  ### Fixed
9871
10715
 
9872
10716
  - **File tab completion display**: File paths no longer get cut off early. Folders now show trailing `/` and removed redundant "directory"/"file" labels to maximize horizontal space. ([#280](https://github.com/badlogic/pi-mono/issues/280))
9873
-
9874
10717
  - **Bash tool visual line truncation**: Fixed bash tool output in collapsed mode to use visual line counting (accounting for line wrapping) instead of logical line counting. Now consistent with bash-execution.ts behavior. Extracted shared `truncateToVisualLines` utility. ([#275](https://github.com/badlogic/pi-mono/issues/275))
9875
10718
 
9876
10719
  ## [0.26.1] - 2025-12-22
@@ -9884,11 +10727,8 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9884
10727
  ### Added
9885
10728
 
9886
10729
  - **SDK for programmatic usage**: New `createAgentSession()` factory with full control over model, tools, hooks, skills, session persistence, and settings. Philosophy: "omit to discover, provide to override". Includes 12 examples and comprehensive documentation. ([#272](https://github.com/badlogic/pi-mono/issues/272))
9887
-
9888
- - **Project-specific settings**: Settings now load from both `~/.omp/agent/settings.json` (global) and `<cwd>/.omp/settings.json` (project). Project settings override global with deep merge for nested objects. Project settings are read-only (for version control). ([#276](https://github.com/badlogic/pi-mono/pull/276))
9889
-
10730
+ - **Project-specific settings**: Settings now load from both `~/.pi/agent/settings.json` (global) and `<cwd>/.pi/settings.json` (project). Project settings override global with deep merge for nested objects. Project settings are read-only (for version control). ([#276](https://github.com/badlogic/pi-mono/pull/276))
9890
10731
  - **SettingsManager static factories**: `SettingsManager.create(cwd?, agentDir?)` for file-based settings, `SettingsManager.inMemory(settings?)` for testing. Added `applyOverrides()` for programmatic overrides.
9891
-
9892
10732
  - **SessionManager static factories**: `SessionManager.create()`, `SessionManager.open()`, `SessionManager.continueRecent()`, `SessionManager.inMemory()`, `SessionManager.list()` for flexible session management.
9893
10733
 
9894
10734
  ## [0.25.4] - 2025-12-22
@@ -9902,13 +10742,9 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9902
10742
  ### Added
9903
10743
 
9904
10744
  - **Gemini 3 preview models**: Added `gemini-3-pro-preview` and `gemini-3-flash-preview` to the google-gemini-cli provider. ([#264](https://github.com/badlogic/pi-mono/pull/264) by [@LukeFost](https://github.com/LukeFost))
9905
-
9906
10745
  - **External editor support**: Press `Ctrl+G` to edit your message in an external editor. Uses `$VISUAL` or `$EDITOR` environment variable. On successful save, the message is replaced; on cancel, the original is kept. ([#266](https://github.com/badlogic/pi-mono/pull/266) by [@aliou](https://github.com/aliou))
9907
-
9908
- - **Process suspension**: Press `Ctrl+Z` to suspend omp and return to the shell. Resume with `fg` as usual. ([#267](https://github.com/badlogic/pi-mono/pull/267) by [@aliou](https://github.com/aliou))
9909
-
10746
+ - **Process suspension**: Press `Ctrl+Z` to suspend pi and return to the shell. Resume with `fg` as usual. ([#267](https://github.com/badlogic/pi-mono/pull/267) by [@aliou](https://github.com/aliou))
9910
10747
  - **Configurable skills directories**: Added granular control over skill sources with `enableCodexUser`, `enableClaudeUser`, `enableClaudeProject`, `enablePiUser`, `enablePiProject` toggles, plus `customDirectories` and `ignoredSkills` settings. ([#269](https://github.com/badlogic/pi-mono/pull/269) by [@nicobailon](https://github.com/nicobailon))
9911
-
9912
10748
  - **Skills CLI filtering**: Added `--skills <patterns>` flag for filtering skills with glob patterns. Also added `includeSkills` setting and glob pattern support for `ignoredSkills`. ([#268](https://github.com/badlogic/pi-mono/issues/268))
9913
10749
 
9914
10750
  ## [0.25.2] - 2025-12-21
@@ -9922,7 +10758,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9922
10758
  ### Fixed
9923
10759
 
9924
10760
  - **Gemini image reading broken**: Fixed the `read` tool returning images causing flaky/broken responses with Gemini models. Images in tool results are now properly formatted per the Gemini API spec.
9925
-
9926
10761
  - **Tab completion for absolute paths**: Fixed tab completion producing `//tmp` instead of `/tmp/`. Also fixed symlinks to directories (like `/tmp`) not getting a trailing slash, which prevented continuing to tab through subdirectories.
9927
10762
 
9928
10763
  ## [0.25.0] - 2025-12-20
@@ -9930,9 +10765,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9930
10765
  ### Added
9931
10766
 
9932
10767
  - **Interruptible tool execution**: Queuing a message while tools are executing now interrupts the current tool batch. Remaining tools are skipped with an error result, and your queued message is processed immediately. Useful for redirecting the agent mid-task. ([#259](https://github.com/badlogic/pi-mono/pull/259) by [@steipete](https://github.com/steipete))
9933
-
9934
10768
  - **Google Gemini CLI OAuth provider**: Access Gemini 2.0/2.5 models for free via Google Cloud Code Assist. Login with `/login` and select "Google Gemini CLI". Uses your Google account with rate limits.
9935
-
9936
10769
  - **Google Antigravity OAuth provider**: Access Gemini 3, Claude (sonnet/opus thinking models), and GPT-OSS models for free via Google's Antigravity sandbox. Login with `/login` and select "Antigravity". Uses your Google account with rate limits.
9937
10770
 
9938
10771
  ### Changed
@@ -9942,9 +10775,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9942
10775
  ### Fixed
9943
10776
 
9944
10777
  - **Connection errors not retried**: Added "connection error" to the list of retryable errors so Anthropic connection drops trigger auto-retry instead of silently failing. ([#252](https://github.com/badlogic/pi-mono/issues/252))
9945
-
9946
10778
  - **Thinking level not clamped on model switch**: Fixed TUI showing xhigh thinking level after switching to a model that doesn't support it. Thinking level is now automatically clamped to model capabilities. ([#253](https://github.com/badlogic/pi-mono/issues/253))
9947
-
9948
10779
  - **Cross-model thinking handoff**: Fixed error when switching between models with different thinking signature formats (e.g., GPT-OSS to Claude thinking models via Antigravity). Thinking blocks without signatures are now converted to text with `<thinking>` delimiters.
9949
10780
 
9950
10781
  ## [0.24.5] - 2025-12-20
@@ -9976,23 +10807,16 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
9976
10807
  ### Added
9977
10808
 
9978
10809
  - **OAuth and model config exports**: Scripts using `AgentSession` directly can now import `getAvailableModels`, `getApiKeyForModel`, `findModel`, `login`, `logout`, and `getOAuthProviders` from `@oh-my-pi/pi-coding-agent` to reuse OAuth token storage and model resolution. ([#245](https://github.com/badlogic/pi-mono/issues/245))
9979
-
9980
10810
  - **xhigh thinking level for gpt-5.2 models**: The thinking level selector and shift+tab cycling now show xhigh option for gpt-5.2 and gpt-5.2-codex models (in addition to gpt-5.1-codex-max). ([#236](https://github.com/badlogic/pi-mono/pull/236) by [@theBucky](https://github.com/theBucky))
9981
10811
 
9982
10812
  ### Fixed
9983
10813
 
9984
10814
  - **Hooks wrap custom tools**: Custom tools are now executed through the hook wrapper, so `tool_call`/`tool_result` hooks can observe, block, and modify custom tool executions (consistent with hook type docs). ([#248](https://github.com/badlogic/pi-mono/pull/248) by [@nicobailon](https://github.com/nicobailon))
9985
-
9986
10815
  - **Hook onUpdate callback forwarding**: The `onUpdate` callback is now correctly forwarded through the hook wrapper, fixing custom tool progress updates. ([#238](https://github.com/badlogic/pi-mono/pull/238) by [@nicobailon](https://github.com/nicobailon))
9987
-
9988
10816
  - **Terminal cleanup on Ctrl+C in session selector**: Fixed terminal not being properly restored when pressing Ctrl+C in the session selector. ([#247](https://github.com/badlogic/pi-mono/pull/247) by [@aliou](https://github.com/aliou))
9989
-
9990
10817
  - **OpenRouter models with colons in IDs**: Fixed parsing of OpenRouter model IDs that contain colons (e.g., `openrouter:meta-llama/llama-4-scout:free`). ([#242](https://github.com/badlogic/pi-mono/pull/242) by [@aliou](https://github.com/aliou))
9991
-
9992
- - **Global AGENTS.md loaded twice**: Fixed global AGENTS.md being loaded twice when present in both `~/.omp/agent/` and the current directory. ([#239](https://github.com/badlogic/pi-mono/pull/239) by [@aliou](https://github.com/aliou))
9993
-
10818
+ - **Global AGENTS.md loaded twice**: Fixed global AGENTS.md being loaded twice when present in both `~/.pi/agent/` and the current directory. ([#239](https://github.com/badlogic/pi-mono/pull/239) by [@aliou](https://github.com/aliou))
9994
10819
  - **Kitty keyboard protocol on Linux**: Fixed keyboard input not working in Ghostty on Linux when Num Lock is enabled. The Kitty protocol includes Caps Lock and Num Lock state in modifier values, which broke key detection. Now correctly masks out lock key bits when matching keyboard shortcuts. ([#243](https://github.com/badlogic/pi-mono/issues/243))
9995
-
9996
10820
  - **Emoji deletion and cursor movement**: Backspace, Delete, and arrow keys now correctly handle multi-codepoint characters like emojis. Previously, deleting an emoji would leave partial bytes, corrupting the editor state. ([#240](https://github.com/badlogic/pi-mono/issues/240))
9997
10821
 
9998
10822
  ## [0.24.0] - 2025-12-19
@@ -10000,35 +10824,26 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10000
10824
  ### Added
10001
10825
 
10002
10826
  - **Subagent orchestration example**: Added comprehensive custom tool example for spawning and orchestrating sub-agents with isolated context windows. Includes scout/planner/reviewer/worker agents and workflow commands for multi-agent pipelines. ([#215](https://github.com/badlogic/pi-mono/pull/215) by [@nicobailon](https://github.com/nicobailon))
10003
-
10004
10827
  - **`getMarkdownTheme()` export**: Custom tools can now import `getMarkdownTheme()` from `@oh-my-pi/pi-coding-agent` to use the same markdown styling as the main UI.
10005
-
10006
10828
  - **`pi.exec()` signal and timeout support**: Custom tools and hooks can now pass `{ signal, timeout }` options to `pi.exec()` for cancellation and timeout handling. The result includes a `killed` flag when the process was terminated.
10007
-
10008
10829
  - **Kitty keyboard protocol support**: Shift+Enter, Alt+Enter, Shift+Tab, Ctrl+D, and all Ctrl+key combinations now work in Ghostty, Kitty, WezTerm, and other modern terminals. ([#225](https://github.com/badlogic/pi-mono/pull/225) by [@kim0](https://github.com/kim0))
10009
-
10010
10830
  - **Dynamic API key refresh**: OAuth tokens (GitHub Copilot, Anthropic OAuth) are now refreshed before each LLM call, preventing failures in long-running agent loops where tokens expire mid-session. ([#223](https://github.com/badlogic/pi-mono/pull/223) by [@kim0](https://github.com/kim0))
10011
-
10012
10831
  - **`/hotkeys` command**: Shows all keyboard shortcuts in a formatted table.
10013
-
10014
10832
  - **Markdown table borders**: Tables now render with proper top and bottom borders.
10015
10833
 
10016
10834
  ### Changed
10017
10835
 
10018
10836
  - **Subagent example improvements**: Parallel mode now streams updates from all tasks. Chain mode shows all completed steps during streaming. Expanded view uses proper markdown rendering with syntax highlighting. Usage footer shows turn count.
10019
-
10020
10837
  - **Skills standard compliance**: Skills now adhere to the [Agent Skills standard](https://agentskills.io/specification). Validates name (must match parent directory, lowercase, max 64 chars), description (required, max 1024 chars), and frontmatter fields. Warns on violations but remains lenient. Prompt format changed to XML structure. Removed `{baseDir}` placeholder in favor of relative paths. ([#231](https://github.com/badlogic/pi-mono/issues/231))
10021
10838
 
10022
10839
  ### Fixed
10023
10840
 
10024
- - **JSON mode stdout flush**: Fixed race condition where `omp --mode json` could exit before all output was written to stdout, causing consumers to miss final events.
10025
-
10841
+ - **JSON mode stdout flush**: Fixed race condition where `pi --mode json` could exit before all output was written to stdout, causing consumers to miss final events.
10026
10842
  - **Symlinked tools, hooks, and slash commands**: Discovery now correctly follows symlinks when scanning for custom tools, hooks, and slash commands. ([#219](https://github.com/badlogic/pi-mono/pull/219), [#232](https://github.com/badlogic/pi-mono/pull/232) by [@aliou](https://github.com/aliou))
10027
10843
 
10028
10844
  ### Breaking Changes
10029
10845
 
10030
- - **Custom tools now require `index.ts` entry point**: Auto-discovered custom tools must be in a subdirectory with an `index.ts` file. The old pattern `~/.omp/agent/tools/mytool.ts` must become `~/.omp/agent/tools/mytool/index.ts`. This allows multi-file tools to import helper modules. Explicit paths via `--tool` or `settings.json` still work with any `.ts` file.
10031
-
10846
+ - **Custom tools now require `index.ts` entry point**: Auto-discovered custom tools must be in a subdirectory with an `index.ts` file. The old pattern `~/.pi/agent/tools/mytool.ts` must become `~/.pi/agent/tools/mytool/index.ts`. This allows multi-file tools to import helper modules. Explicit paths via `--tool` or `settings.json` still work with any `.ts` file.
10032
10847
  - **Hook `tool_result` event restructured**: The `ToolResultEvent` now exposes full tool result data instead of just text. ([#233](https://github.com/badlogic/pi-mono/pull/233))
10033
10848
  - Removed: `result: string` field
10034
10849
  - Added: `content: (TextContent | ImageContent)[]` - full content array
@@ -10043,15 +10858,12 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10043
10858
  ### Added
10044
10859
 
10045
10860
  - **Syntax highlighting**: Added syntax highlighting for markdown code blocks, read tool output, and write tool content. Uses cli-highlight with theme-aware color mapping and VS Code-style syntax colors. ([#214](https://github.com/badlogic/pi-mono/pull/214) by [@svkozak](https://github.com/svkozak))
10046
-
10047
10861
  - **Intra-line diff highlighting**: Edit tool now shows word-level changes with inverse highlighting when a single line is modified. Multi-line changes show all removed lines first, then all added lines.
10048
10862
 
10049
10863
  ### Fixed
10050
10864
 
10051
10865
  - **Gemini tool result format**: Fixed tool result format for Gemini 3 Flash Preview which strictly requires `{ output: value }` for success and `{ error: value }` for errors. Previous format using `{ result, isError }` was rejected by newer Gemini models. ([#213](https://github.com/badlogic/pi-mono/issues/213), [#220](https://github.com/badlogic/pi-mono/pull/220))
10052
-
10053
10866
  - **Google baseUrl configuration**: Google provider now respects `baseUrl` configuration for custom endpoints or API proxies. ([#216](https://github.com/badlogic/pi-mono/issues/216), [#221](https://github.com/badlogic/pi-mono/pull/221) by [@theBucky](https://github.com/theBucky))
10054
-
10055
10867
  - **Google provider FinishReason**: Added handling for new `IMAGE_RECITATION` and `IMAGE_OTHER` finish reasons. Upgraded @google/genai to 1.34.0.
10056
10868
 
10057
10869
  ## [0.23.3] - 2025-12-17
@@ -10063,7 +10875,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10063
10875
  ### Changed
10064
10876
 
10065
10877
  - Improved system prompt documentation section with clearer pointers to specific doc files for custom models, themes, skills, hooks, custom tools, and RPC.
10066
-
10067
10878
  - Cleaned up documentation:
10068
10879
  - `theme.md`: Added missing color tokens (`thinkingXhigh`, `bashMode`)
10069
10880
  - `skills.md`: Rewrote with better framing and examples
@@ -10071,7 +10882,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10071
10882
  - `custom-tools.md`: Added intro with use cases and comparison table
10072
10883
  - `rpc.md`: Added missing `hook_error` event documentation
10073
10884
  - `README.md`: Complete settings table, condensed philosophy section, standardized OAuth docs
10074
-
10075
10885
  - Hooks loader now supports same import aliases as custom tools (`@sinclair/typebox`, `@oh-my-pi/pi-ai`, `@oh-my-pi/pi-tui`, `@oh-my-pi/pi-coding-agent`).
10076
10886
 
10077
10887
  ### Breaking Changes
@@ -10083,9 +10893,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10083
10893
  ### Fixed
10084
10894
 
10085
10895
  - Fixed Claude models via GitHub Copilot re-answering all previous prompts in multi-turn conversations. The issue was that assistant message content was sent as an array instead of a string, which Copilot's Claude adapter misinterpreted. Also added missing `Openai-Intent: conversation-edits` header and fixed `X-Initiator` logic to check for any assistant/tool message in history. ([#209](https://github.com/badlogic/pi-mono/issues/209))
10086
-
10087
10896
  - Detect image MIME type via file magic (read tool and `@file` attachments), not filename extension.
10088
-
10089
10897
  - Fixed markdown tables overflowing terminal width. Tables now wrap cell contents to fit available width instead of breaking borders mid-row. ([#206](https://github.com/badlogic/pi-mono/pull/206) by [@kim0](https://github.com/kim0))
10090
10898
 
10091
10899
  ## [0.23.1] - 2025-12-17
@@ -10093,15 +10901,13 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10093
10901
  ### Fixed
10094
10902
 
10095
10903
  - Fixed TUI performance regression caused by Box component lacking render caching. Built-in tools now use Text directly (like v0.22.5), and Box has proper caching for custom tool rendering.
10096
-
10097
- - Fixed custom tools failing to load from `~/.omp/agent/tools/` when omp is installed globally. Module imports (`@sinclair/typebox`, `@oh-my-pi/pi-tui`, `@oh-my-pi/pi-ai`) are now resolved via aliases.
10904
+ - Fixed custom tools failing to load from `~/.pi/agent/tools/` when pi is installed globally. Module imports (`@sinclair/typebox`, `@oh-my-pi/pi-tui`, `@oh-my-pi/pi-ai`) are now resolved via aliases.
10098
10905
 
10099
10906
  ## [0.23.0] - 2025-12-17
10100
10907
 
10101
10908
  ### Added
10102
10909
 
10103
- - **Custom tools**: Extend omp with custom tools written in TypeScript. Tools can provide custom TUI rendering, interact with users via `omp.ui` (select, confirm, input, notify), and maintain state across sessions via `onSession` callback. See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](examples/custom-tools/). ([#190](https://github.com/badlogic/pi-mono/issues/190))
10104
-
10910
+ - **Custom tools**: Extend pi with custom tools written in TypeScript. Tools can provide custom TUI rendering, interact with users via `pi.ui` (select, confirm, input, notify), and maintain state across sessions via `onSession` callback. See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](examples/custom-tools/). ([#190](https://github.com/badlogic/pi-mono/issues/190))
10105
10911
  - **Hook and tool examples**: Added `examples/hooks/` and `examples/custom-tools/` with working examples. Examples are now bundled in npm and binary releases.
10106
10912
 
10107
10913
  ### Breaking Changes
@@ -10133,7 +10939,6 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
10133
10939
  ### Changed
10134
10940
 
10135
10941
  - **Tool output display**: When collapsed, tool output now shows the last N lines instead of the first N lines, making streaming output more useful.
10136
-
10137
10942
  - Updated `@oh-my-pi/pi-ai` with X-Initiator header support for GitHub Copilot, ensuring agent calls are not deducted from quota. ([#200](https://github.com/badlogic/pi-mono/pull/200) by [@kim0](https://github.com/kim0))
10138
10943
 
10139
10944
  ### Fixed
@@ -10171,13 +10976,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10171
10976
  ### Added
10172
10977
 
10173
10978
  - **Inline image rendering**: Terminals supporting Kitty graphics protocol (Kitty, Ghostty, WezTerm) or iTerm2 inline images now render images inline in tool output. Aspect ratio is preserved by querying terminal cell dimensions on startup. Toggle with `/show-images` command or `terminal.showImages` setting. Falls back to text placeholder on unsupported terminals or when disabled. ([#177](https://github.com/badlogic/pi-mono/pull/177) by [@nicobailon](https://github.com/nicobailon))
10174
-
10175
10979
  - **Gemini 3 Pro thinking levels**: Thinking level selector now works with Gemini 3 Pro models. Minimal/low map to Google's LOW, medium/high map to Google's HIGH. ([#176](https://github.com/badlogic/pi-mono/pull/176) by [@markusylisiurunen](https://github.com/markusylisiurunen))
10176
10980
 
10177
10981
  ### Fixed
10178
10982
 
10179
10983
  - Fixed read tool failing on macOS screenshot filenames due to Unicode Narrow No-Break Space (U+202F) in timestamp. Added fallback to try macOS variant paths and consolidated duplicate expandPath functions into shared path-utils.ts. ([#181](https://github.com/badlogic/pi-mono/pull/181) by [@nicobailon](https://github.com/nicobailon))
10180
-
10181
10984
  - Fixed double blank lines rendering after markdown code blocks ([#173](https://github.com/badlogic/pi-mono/pull/173) by [@markusylisiurunen](https://github.com/markusylisiurunen))
10182
10985
 
10183
10986
  ## [0.20.1] - 2025-12-13
@@ -10190,7 +10993,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10190
10993
 
10191
10994
  ### Breaking Changes
10192
10995
 
10193
- - **OMP skills now use `SKILL.md` convention**: OMP skills must now be named `SKILL.md` inside a directory, matching Codex CLI format. Previously any `*.md` file was treated as a skill. Migrate by renaming `~/.omp/agent/skills/foo.md` to `~/.omp/agent/skills/foo/SKILL.md`.
10996
+ - **Pi skills now use `SKILL.md` convention**: Pi skills must now be named `SKILL.md` inside a directory, matching Codex CLI format. Previously any `*.md` file was treated as a skill. Migrate by renaming `~/.pi/agent/skills/foo.md` to `~/.pi/agent/skills/foo/SKILL.md`.
10194
10997
 
10195
10998
  ### Added
10196
10999
 
@@ -10206,8 +11009,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10206
11009
 
10207
11010
  ### Added
10208
11011
 
10209
- - **Skills system**: Auto-discover and load instruction files on-demand. Supports Claude Code (`~/.claude/skills/*/SKILL.md`), Codex CLI (`~/.codex/skills/`), and OMP-native formats (`~/.omp/agent/skills/`, `.omp/skills/`). Skills are listed in system prompt with descriptions, agent loads them via read tool when needed. Supports `{baseDir}` placeholder. Disable with `--no-skills` or `skills.enabled: false` in settings. ([#169](https://github.com/badlogic/pi-mono/issues/169))
10210
-
11012
+ - **Skills system**: Auto-discover and load instruction files on-demand. Supports Claude Code (`~/.claude/skills/*/SKILL.md`), Codex CLI (`~/.codex/skills/`), and Pi-native formats (`~/.pi/agent/skills/`, `.pi/skills/`). Skills are listed in system prompt with descriptions, agent loads them via read tool when needed. Supports `{baseDir}` placeholder. Disable with `--no-skills` or `skills.enabled: false` in settings. ([#169](https://github.com/badlogic/pi-mono/issues/169))
10211
11013
  - **Version flag**: Added `--version` / `-v` flag to display the current version and exit. ([#170](https://github.com/badlogic/pi-mono/pull/170))
10212
11014
 
10213
11015
  ## [0.18.2] - 2025-12-11
@@ -10215,16 +11017,13 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10215
11017
  ### Added
10216
11018
 
10217
11019
  - **Auto-retry on transient errors**: Automatically retries requests when providers return overloaded, rate limit, or server errors (429, 500, 502, 503, 504). Uses exponential backoff (2s, 4s, 8s). Shows retry status in TUI with option to cancel via Escape. Configurable in `settings.json` via `retry.enabled`, `retry.maxRetries`, `retry.baseDelayMs`. RPC mode emits `auto_retry_start` and `auto_retry_end` events. ([#157](https://github.com/badlogic/pi-mono/issues/157))
10218
-
10219
11020
  - **HTML export line numbers**: Read tool calls in HTML exports now display line number ranges (e.g., `file.txt:10-20`) when offset/limit parameters are used, matching the TUI display format. Line numbers appear in yellow color for better visibility. ([#166](https://github.com/badlogic/pi-mono/issues/166))
10220
11021
 
10221
11022
  ### Fixed
10222
11023
 
10223
11024
  - **Branch selector now works with single message**: Previously the branch selector would not open when there was only one user message. Now it correctly allows branching from any message, including the first one. This is needed for checkpoint hooks to restore state from before the first message. ([#163](https://github.com/badlogic/pi-mono/issues/163))
10224
-
10225
11025
  - **In-memory branching for `--no-session` mode**: Branching now works correctly in `--no-session` mode without creating any session files. The conversation is truncated in memory.
10226
-
10227
- - **Git branch indicator now works in subdirectories**: The footer's git branch detection now walks up the directory hierarchy to find the git root, so it works when running omp from a subdirectory of a repository. ([#156](https://github.com/badlogic/pi-mono/issues/156))
11026
+ - **Git branch indicator now works in subdirectories**: The footer's git branch detection now walks up the directory hierarchy to find the git root, so it works when running pi from a subdirectory of a repository. ([#156](https://github.com/badlogic/pi-mono/issues/156))
10228
11027
 
10229
11028
  ## [0.18.1] - 2025-12-10
10230
11029
 
@@ -10240,16 +11039,11 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10240
11039
 
10241
11040
  ### Added
10242
11041
 
10243
- - **Hooks system**: TypeScript modules that extend agent behavior by subscribing to lifecycle events. Hooks can intercept tool calls, prompt for confirmation, modify results, and inject messages from external sources. Auto-discovered from `~/.omp/agent/hooks/*.ts` and `.omp/hooks/*.ts`. Thanks to [@nicobailon](https://github.com/nicobailon) for the collaboration on the design and implementation. ([#145](https://github.com/badlogic/pi-mono/issues/145), supersedes [#158](https://github.com/badlogic/pi-mono/pull/158))
10244
-
11042
+ - **Hooks system**: TypeScript modules that extend agent behavior by subscribing to lifecycle events. Hooks can intercept tool calls, prompt for confirmation, modify results, and inject messages from external sources. Auto-discovered from `~/.pi/agent/hooks/*.ts` and `.pi/hooks/*.ts`. Thanks to [@nicobailon](https://github.com/nicobailon) for the collaboration on the design and implementation. ([#145](https://github.com/badlogic/pi-mono/issues/145), supersedes [#158](https://github.com/badlogic/pi-mono/pull/158))
10245
11043
  - **`pi.send()` API**: Hooks can inject messages into the agent session from external sources (file watchers, webhooks, CI systems). If streaming, messages are queued; otherwise a new agent loop starts immediately.
10246
-
10247
11044
  - **`--hook <path>` CLI flag**: Load hook files directly for testing without modifying settings.
10248
-
10249
11045
  - **Hook events**: `session_start`, `session_switch`, `agent_start`, `agent_end`, `turn_start`, `turn_end`, `tool_call` (can block), `tool_result` (can modify), `branch`.
10250
-
10251
11046
  - **Hook UI primitives**: `ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`, `ctx.ui.notify()` for interactive prompts from hooks.
10252
-
10253
11047
  - **Hooks documentation**: Full API reference at `docs/hooks.md`, shipped with npm package.
10254
11048
 
10255
11049
  ## [0.17.0] - 2025-12-09
@@ -10257,21 +11051,17 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10257
11051
  ### Changed
10258
11052
 
10259
11053
  - **Simplified compaction flow**: Removed proactive compaction (aborting mid-turn when threshold approached). Compaction now triggers in two cases only: (1) overflow error from LLM, which compacts and auto-retries, or (2) threshold crossed after a successful turn, which compacts without retry.
10260
-
10261
11054
  - **Compaction retry uses `Agent.continue()`**: Auto-retry after overflow now uses the new `continue()` API instead of re-sending the user message, preserving exact context state.
10262
-
10263
11055
  - **Merged turn prefix summary**: When a turn is split during compaction, the turn prefix summary is now merged into the main history summary instead of being stored separately.
10264
11056
 
10265
11057
  ### Added
10266
11058
 
10267
11059
  - **`isCompacting` property on AgentSession**: Check if auto-compaction is currently running.
10268
-
10269
11060
  - **Session compaction indicator**: When resuming a compacted session, displays "Session compacted N times" status message.
10270
11061
 
10271
11062
  ### Fixed
10272
11063
 
10273
11064
  - **Block input during compaction**: User input is now blocked while auto-compaction is running to prevent race conditions.
10274
-
10275
11065
  - **Skip error messages in usage calculation**: Context size estimation now skips both aborted and error messages, as neither have valid usage data.
10276
11066
 
10277
11067
  ## [0.16.0] - 2025-12-09
@@ -10315,11 +11105,8 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10315
11105
  ### Added
10316
11106
 
10317
11107
  - **OpenAI compatibility overrides in models.json**: Custom models using `openai-completions` API can now specify a `compat` object to override provider quirks (`supportsStore`, `supportsDeveloperRole`, `supportsReasoningEffort`, `maxTokensField`). Useful for LiteLLM, custom proxies, and other non-standard endpoints. ([#133](https://github.com/badlogic/pi-mono/issues/133), thanks @fink-andreas for the initial idea and PR)
10318
-
10319
11108
  - **xhigh thinking level**: Added `xhigh` thinking level for OpenAI codex-max models. Cycle through thinking levels with Shift+Tab; `xhigh` appears only when using a codex-max model. ([#143](https://github.com/badlogic/pi-mono/issues/143))
10320
-
10321
- - **Collapse changelog setting**: Add `"collapseChangelog": true` to `~/.omp/agent/settings.json` to show a condensed "Updated to vX.Y.Z" message instead of the full changelog after updates. Use `/changelog` to view the full changelog. ([#148](https://github.com/badlogic/pi-mono/issues/148))
10322
-
11109
+ - **Collapse changelog setting**: Add `"collapseChangelog": true` to `~/.pi/agent/settings.json` to show a condensed "Updated to vX.Y.Z" message instead of the full changelog after updates. Use `/changelog` to view the full changelog. ([#148](https://github.com/badlogic/pi-mono/issues/148))
10323
11110
  - **Bash mode**: Execute shell commands directly from the editor by prefixing with `!` (e.g., `!ls -la`). Output streams in real-time, is added to the LLM context, and persists in session history. Supports multiline commands, cancellation (Escape), truncation for large outputs, and preview/expand toggle (Ctrl+O). Also available in RPC mode via `{"type":"bash","command":"..."}`. ([#112](https://github.com/badlogic/pi-mono/pull/112), original implementation by [@markusylisiurunen](https://github.com/markusylisiurunen))
10324
11111
 
10325
11112
  ## [0.13.2] - 2025-12-07
@@ -10338,7 +11125,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10338
11125
 
10339
11126
  ### Added
10340
11127
 
10341
- - **Flexible Windows shell configuration**: The bash tool now supports multiple shell sources beyond Git Bash. Resolution order: (1) custom `shellPath` in settings.json, (2) Git Bash in standard locations, (3) any bash.exe on PATH. This enables Cygwin, MSYS2, and other bash environments. Configure with `~/.omp/agent/settings.json`: `{"shellPath": "C:\\cygwin64\\bin\\bash.exe"}`.
11128
+ - **Flexible Windows shell configuration**: The bash tool now supports multiple shell sources beyond Git Bash. Resolution order: (1) custom `shellPath` in settings.json, (2) Git Bash in standard locations, (3) any bash.exe on PATH. This enables Cygwin, MSYS2, and other bash environments. Configure with `~/.pi/agent/settings.json`: `{"shellPath": "C:\\cygwin64\\bin\\bash.exe"}`.
10342
11129
 
10343
11130
  ### Fixed
10344
11131
 
@@ -10432,7 +11219,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10432
11219
 
10433
11220
  ### Added
10434
11221
 
10435
- - **Forking/Rebranding Support**: All branding (app name, config directory, environment variable names) is now configurable via `ompConfig` in `package.json`. Forks can change `ompConfig.name` and `ompConfig.configDir` to rebrand the CLI without code changes. Affects CLI banner, help text, config paths, and error messages. ([#95](https://github.com/badlogic/pi-mono/pull/95))
11222
+ - **Forking/Rebranding Support**: All branding (app name, config directory, environment variable names) is now configurable via `piConfig` in `package.json`. Forks can change `piConfig.name` and `piConfig.configDir` to rebrand the CLI without code changes. Affects CLI banner, help text, config paths, and error messages. ([#95](https://github.com/badlogic/pi-mono/pull/95))
10436
11223
 
10437
11224
  ### Fixed
10438
11225
 
@@ -10551,7 +11338,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10551
11338
 
10552
11339
  ### Added
10553
11340
 
10554
- - **File-based Slash Commands**: Create custom reusable prompts as `.txt` files in `~/.omp/slash-commands/`. Files become `/filename` commands with first-line descriptions. Supports `{{selection}}` placeholder for referencing selected/attached content.
11341
+ - **File-based Slash Commands**: Create custom reusable prompts as `.txt` files in `~/.pi/slash-commands/`. Files become `/filename` commands with first-line descriptions. Supports `{{selection}}` placeholder for referencing selected/attached content.
10555
11342
  - **`/branch` Command**: Create conversation branches from any previous user message. Opens a selector to pick a message, then creates a new session file starting from that point. Original message text is placed in the editor for modification.
10556
11343
  - **Unified Content References**: Both `@path` in messages and `--file path` CLI arguments now use the same attachment system with consistent MIME type detection.
10557
11344
  - **Drag & Drop Files**: Drop files onto the terminal to attach them to your message. Supports multiple files and both text and image content.
@@ -10613,7 +11400,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10613
11400
 
10614
11401
  ### Added
10615
11402
 
10616
- - Added thinking level persistence. Default level stored in `~/.omp/settings.json`, restored on startup. Per-session overrides saved in session files.
11403
+ - Added thinking level persistence. Default level stored in `~/.pi/settings.json`, restored on startup. Per-session overrides saved in session files.
10617
11404
  - Added model cycling shortcut: `Ctrl+I` cycles through available models (or scoped models with `-m` flag).
10618
11405
  - Added automatic retry with exponential backoff for transient API errors (network issues, 500s, overload).
10619
11406
  - Cumulative token usage now shown in footer (total tokens used across all messages in session).
@@ -10630,7 +11417,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
10630
11417
 
10631
11418
  ### Added
10632
11419
 
10633
- - Add custom model configuration via `~/.omp/models.json`
11420
+ - Add custom model configuration via `~/.pi/models.json`
10634
11421
 
10635
11422
  ## [0.10.0] - 2025-11-25
10636
11423
 
@@ -10653,3 +11440,259 @@ Initial public release.
10653
11440
  - Message queueing during streaming responses
10654
11441
  - OAuth integration for Gmail and Google Calendar access
10655
11442
  - HTML export with syntax highlighting and collapsible sections
11443
+
11444
+ ## [0.9.3] - 2025-11-24
11445
+
11446
+ ### Added
11447
+
11448
+ - Added Anthropic Claude Opus 4.5 support
11449
+
11450
+ ## [0.9.2] - 2025-11-24
11451
+
11452
+ ### Fixed
11453
+
11454
+ - **Edit Tool Dollar Sign Bug**: Fixed critical bug in the `edit` tool where `String.replace()` was interpreting `$` as a special replacement pattern (e.g., `$$`, `$&`, `$'`). When trying to insert `$` into code (like adding a dollar sign to a template literal), the replacement would silently fail and produce unchanged content, but the tool would incorrectly report success. Now uses `indexOf` + `substring` for raw string replacement without special character interpretation. Also added verification that content actually changed, rejecting with a clear error if the replacement produces identical content. ([#53](https://github.com/badlogic/pi-mono/issues/53))
11455
+
11456
+ ## [0.9.0] - 2025-11-21
11457
+
11458
+ ### Added
11459
+
11460
+ - **`/clear` Command**: New slash command to reset the conversation context and start a fresh session. Aborts any in-flight agent work, clears all messages, and creates a new session file. ([#48](https://github.com/badlogic/pi-mono/pull/48))
11461
+ - **Model Cycling with Thinking Levels**: The `--models` flag now supports thinking level syntax (e.g., `--models sonnet:high,haiku:low`). When cycling models with `Ctrl+P`, the associated thinking level is automatically applied. The first model in the scope is used as the initial model when starting a new session. Both model and thinking level changes are now saved to session and settings for persistence. ([#47](https://github.com/badlogic/pi-mono/pull/47))
11462
+ - **`--thinking` Flag**: New CLI flag to set thinking level directly (e.g., `--thinking high`). Valid values: `off`, `minimal`, `low`, `medium`, `high`. Takes highest priority over all other thinking level sources. ([#45](https://github.com/badlogic/pi-mono/issues/45))
11463
+
11464
+ ### Breaking
11465
+
11466
+ - **Interactive Mode with Initial Prompt**: Passing a prompt on the command line (e.g., `pi "List files"`) now starts interactive mode with the prompt pre-submitted, instead of exiting after completion. Use `--print` or `-p` to get the previous non-interactive behavior (e.g., `pi -p "List files"`). This matches Claude CLI (`-p`) and Codex (`exec`) behavior. ([#46](https://github.com/badlogic/pi-mono/issues/46))
11467
+
11468
+ ### Fixed
11469
+
11470
+ - **Slash Command Autocomplete**: Fixed issue where pressing Enter on a highlighted slash command suggestion (e.g., typing `/mod` with `/model` highlighted) would submit the partial text instead of executing the selected command. Now Enter applies the completion and submits in one action. ([#49](https://github.com/badlogic/pi-mono/issues/49))
11471
+ - **Model Matching Priority**: The `--models` flag now prioritizes exact matches over partial matches. Supports `provider/modelId` format (e.g., `openrouter/openai/gpt-5.1-codex`) for precise selection. Exact ID matches are tried before partial matching, so `--models gpt-5.1-codex` correctly selects `gpt-5.1-codex` instead of `openai/gpt-5.1-codex-mini`.
11472
+ - **Markdown Link Rendering**: Fixed links with identical text and href (e.g., `https://github.com/badlogic/pi-mono/pull/48/files`) being rendered twice. Now correctly compares raw text instead of styled text (which contains ANSI codes) when determining if link text matches href.
11473
+
11474
+ ## [0.8.5] - 2025-11-21
11475
+
11476
+ ### Fixed
11477
+
11478
+ - **Path Completion Hanging**: Fixed catastrophic regex backtracking in path completion that caused the terminal to hang when text contained many `/` characters (e.g., URLs). Replaced complex regex with simple string operations. ([#18](https://github.com/badlogic/pi-mono/issues/18))
11479
+ - **Autocomplete Arrow Keys**: Fixed issue where arrow keys would move both the autocomplete selection and the editor cursor simultaneously when the file selector list was shown.
11480
+
11481
+ ## [0.8.4] - 2025-11-21
11482
+
11483
+ ### Fixed
11484
+
11485
+ - **Read Tool Error Handling**: Fixed issue where the `read` tool would return errors as successful text content instead of throwing. Now properly throws errors for file not found and offset out of bounds conditions.
11486
+
11487
+ ## [0.8.3] - 2025-11-21
11488
+
11489
+ ### Improved
11490
+
11491
+ - **Export HTML**: Limited container width to 700px for better readability. Fixed message statistics to match `/session` command output with proper breakdown of User/Assistant/Tool Calls/Tool Results/Total messages.
11492
+ - **Dark Theme**: Increased visibility of editor border (darkGray from #303030 to #505050) and thinking minimal indicator (from #4e4e4e to #6e6e6e).
11493
+
11494
+ ## [0.8.0] - 2025-11-21
11495
+
11496
+ ### Added
11497
+
11498
+ - **Theme System**: Full theming support with 44 customizable color tokens. Two built-in themes (`dark`, `light`) with auto-detection based on terminal background. Use `/theme` command to select themes interactively. Custom themes in `~/.pi/agent/themes/*.json` support live editing - changes apply immediately when the file is saved. Themes use RGB hex values for consistent rendering across terminals. VS Code users: set `terminal.integrated.minimumContrastRatio` to `1` for proper color rendering. See [Theme Documentation](docs/theme.md) for details.
11499
+
11500
+ ## [0.7.29] - 2025-11-20
11501
+
11502
+ ### Improved
11503
+
11504
+ - **Read Tool Display**: When the `read` tool is called with offset/limit parameters, the tool execution now displays the line range in a compact format (e.g., `read src/main.ts:100-200` for offset=100, limit=100).
11505
+
11506
+ ## [0.7.28] - 2025-11-20
11507
+
11508
+ ### Added
11509
+
11510
+ - **Message Queuing**: You can now send multiple messages while the agent is processing without waiting for the previous response to complete. Messages submitted during streaming are queued and processed based on your queue mode setting. Queued messages are shown in a pending area below the chat. Press Escape to abort and restore all queued messages to the editor. Use `/queue` to select between "one-at-a-time" (process queued messages sequentially, recommended) or "all" (process all queued messages at once). The queue mode setting is saved and persists across sessions. ([#15](https://github.com/badlogic/pi-mono/issues/15))
11511
+
11512
+ ## [0.7.27] - 2025-11-20
11513
+
11514
+ ### Fixed
11515
+
11516
+ - **Slash Command Submission**: Fixed issue where slash commands required two Enter presses to execute. Now pressing Enter on a slash command autocomplete suggestion immediately submits the command, while Tab still applies the completion for adding arguments. ([#30](https://github.com/badlogic/pi-mono/issues/30))
11517
+ - **Slash Command Autocomplete**: Fixed issue where typing a typo then correcting it would not show autocomplete suggestions. Autocomplete now re-triggers when typing or backspacing in a slash command context. ([#29](https://github.com/badlogic/pi-mono/issues/29))
11518
+
11519
+ ## [0.7.26] - 2025-11-20
11520
+
11521
+ ### Added
11522
+
11523
+ - **Tool Output Expansion**: Press `Ctrl+O` to toggle between collapsed and expanded tool output display. Expands all tool call outputs (bash, read, write, etc.) to show full content instead of truncated previews. ([#31](https://github.com/badlogic/pi-mono/issues/31))
11524
+ - **Custom Headers**: Added support for custom HTTP headers in `models.json` configuration. Headers can be specified at both provider and model level, with model-level headers overriding provider-level ones. This enables bypassing Cloudflare bot detection and other proxy requirements. ([#39](https://github.com/badlogic/pi-mono/issues/39))
11525
+
11526
+ ### Fixed
11527
+
11528
+ - **Chutes AI Provider**: Fixed 400 errors when using Chutes AI provider. Added compatibility fixes for `store` field exclusion, `max_tokens` parameter usage, and system prompt role handling. ([#42](https://github.com/badlogic/pi-mono/pull/42) by [@butelo](https://github.com/butelo))
11529
+ - **Mistral/Chutes Syntax Error**: Fixed syntax error in merged PR that used `iif` instead of `if`.
11530
+ - **Anthropic OAuth Bug**: Fixed bug where `process.env.ANTHROPIC_API_KEY = undefined` set the env var to string "undefined" instead of deleting it. Now uses `delete` operator.
11531
+
11532
+ ## [0.7.25] - 2025-11-20
11533
+
11534
+ ### Added
11535
+
11536
+ - **Model Cycling**: Press `Ctrl+P` to quickly cycle through models. Use `--models` CLI argument to scope to specific models (e.g., `--models claude-sonnet,gpt-4o`). Supports pattern matching and smart version selection (prefers aliases over dated versions). ([#37](https://github.com/badlogic/pi-mono/pull/37) by [@fightbulc](https://github.com/fightbulc))
11537
+
11538
+ ## [0.7.24] - 2025-11-20
11539
+
11540
+ ### Added
11541
+
11542
+ - **Thinking Level Cycling**: Press `Shift+Tab` to cycle through thinking levels (off → minimal → low → medium → high) for reasoning-capable models. Editor border color changes to indicate current level (gray → blue → cyan → magenta).
11543
+
11544
+ ## [0.7.23] - 2025-11-20
11545
+
11546
+ ### Added
11547
+
11548
+ - **Update Notifications**: Interactive mode now checks for new versions on startup and displays a notification if an update is available.
11549
+
11550
+ ### Changed
11551
+
11552
+ - **System Prompt**: Updated system prompt to instruct agent to output plain text summaries directly instead of using cat or bash commands to display what it did.
11553
+
11554
+ ### Fixed
11555
+
11556
+ - **File Path Completion**: Removed 10-file limit in tab completion selector. All matching files and directories now appear in the completion list.
11557
+ - **Absolute Path Completion**: Fixed tab completion for absolute paths (e.g., `/Applications`). Absolute paths in the middle of text (like "hey /") now complete correctly. Also fixed crashes when trying to stat inaccessible files (like macOS `.VolumeIcon.icns`) during directory traversal.
11558
+
11559
+ ## [0.7.22] - 2025-11-19
11560
+
11561
+ ### Fixed
11562
+
11563
+ - **Long Line Wrapping**: Fixed crash when rendering long lines without spaces (e.g., file paths). Long words now break character-by-character to fit within terminal width.
11564
+
11565
+ ## [0.7.21] - 2025-11-19
11566
+
11567
+ ### Fixed
11568
+
11569
+ - **Terminal Flicker**: Fixed flicker at bottom of viewport (especially editor component) in xterm.js-based terminals (VS Code, etc.) by using per-line clear instead of clear-to-end sequence.
11570
+ - **Background Color Rendering**: Fixed black cells appearing at end of wrapped lines when using background colors. Completely rewrote text wrapping and background application to properly handle ANSI reset codes.
11571
+ - **Tool Output**: Strip ANSI codes from bash/tool output before rendering to prevent conflicts with TUI styling.
11572
+
11573
+ ## [0.7.20] - 2025-11-18
11574
+
11575
+ ### Fixed
11576
+
11577
+ - **Message Wrapping**: Fixed word-based text wrapping for long lines in chat messages. Text now properly wraps at word boundaries while preserving ANSI styling (colors, bold, italic, etc.) across wrapped lines. Background colors now extend to the full width of each line. Empty lines in messages now render correctly with full-width background.
11578
+
11579
+ ## [0.7.18] - 2025-11-18
11580
+
11581
+ ### Fixed
11582
+
11583
+ - **Bash Tool Error Handling**: Bash tool now properly throws errors for failed commands (non-zero exit codes), timeouts, and aborted executions. This ensures tool execution components display with red background when bash commands fail.
11584
+ - **Thinking Traces Styling**: Thinking traces now maintain gray italic styling throughout, even when containing inline code blocks, bold text, or other inline formatting
11585
+
11586
+ ## [0.7.17] - 2025-11-18
11587
+
11588
+ ### Added
11589
+
11590
+ - **New Model**: Added `gemini-3-pro-preview` to Google provider.
11591
+ - **OAuth Authentication**: Added `/login` and `/logout` commands for OAuth-based authentication with Claude Pro/Max subscriptions. Tokens are stored in `~/.pi/agent/oauth.json` with 0600 permissions and automatically refreshed when expired. OAuth tokens take priority over API keys for Anthropic models.
11592
+
11593
+ ### Fixed
11594
+
11595
+ - **Anthropic Aborted Thinking**: Fixed error when resubmitting assistant messages with incomplete thinking blocks (from aborted streams). Thinking blocks without valid signatures are now converted to text blocks with `<thinking>` delimiters, preventing API rejection.
11596
+ - **Model Selector Loading**: Fixed models not appearing in `/model` selector until user started typing. Models now load asynchronously and re-render when available.
11597
+ - **Input Paste Support**: Added bracketed paste mode support to `Input` component, enabling paste of long OAuth authorization codes.
11598
+
11599
+ ## [0.7.16] - 2025-11-17
11600
+
11601
+ ### Fixed
11602
+
11603
+ - **Tool Error Display**: Fixed edit tool (and all other tools) not showing error state correctly in TUI. Failed tool executions now properly display with red background and show the error message. Previously, the `isError` flag from tool execution events was not being passed to the UI component, causing all tool results to show with green (success) background regardless of whether they succeeded or failed.
11604
+
11605
+ ## [0.7.15] - 2025-11-17
11606
+
11607
+ ### Fixed
11608
+
11609
+ - **Anthropic OAuth Support**: Added support for `ANTHROPIC_OAUTH_TOKEN` environment variable. The agent now checks for OAuth tokens before falling back to API keys for Anthropic models, enabling OAuth-based authentication.
11610
+
11611
+ ## [0.7.14] - 2025-11-17
11612
+
11613
+ ### Fixed
11614
+
11615
+ - **Mistral API Compatibility**: Fixed compatibility with Mistral API by excluding the `store` field and using `max_tokens` instead of `max_completion_tokens`, and avoiding the `developer` role in system prompts.
11616
+ - **Error Display**: Fixed error message display in assistant messages to include proper spacing before the error text.
11617
+ - **Message Streaming**: Fixed missing `message_start` event when no partial message chunks were received during streaming.
11618
+
11619
+ ## [0.7.13] - 2025-11-16
11620
+
11621
+ ### Fixed
11622
+
11623
+ - **TUI Editor**: Fixed unicode input support for umlauts (äöü), emojis (😀), and other extended characters. Previously the editor only accepted ASCII characters (32-126). Now properly handles all printable unicode while still filtering out control characters. ([#20](https://github.com/badlogic/pi-mono/pull/20))
11624
+
11625
+ ## [0.7.12] - 2025-11-16
11626
+
11627
+ ### Added
11628
+
11629
+ - **Custom Models and Providers**: Support for custom models and providers via `~/.pi/agent/models.json` configuration file. Add local models (Ollama, vLLM, LM Studio) or any OpenAI-compatible, Anthropic-compatible, or Google-compatible API. File is reloaded on every `/model` selector open, allowing live updates without restart. ([#21](https://github.com/badlogic/pi-mono/issues/21))
11630
+ - Added `gpt-5.1-codex` model to OpenAI provider (400k context, 128k max output, reasoning-capable).
11631
+
11632
+ ### Changed
11633
+
11634
+ - **Breaking**: No longer hardcodes Anthropic/Claude as default provider/model. Now prefers sensible defaults per provider (e.g., `claude-sonnet-4-5` for Anthropic, `gpt-5.1-codex` for OpenAI), or requires explicit selection in interactive mode.
11635
+ - Interactive mode now allows starting without a model, showing helpful error on message submission instead of failing at startup.
11636
+ - Non-interactive mode (CLI messages, JSON, RPC) still fails early if no model or API key is available.
11637
+ - Model selector now saves selected model as default in settings.json.
11638
+ - `models.json` validation errors (syntax + schema) now surface with precise file/field info in both CLI and `/model` selector.
11639
+ - Agent system prompt now includes absolute path to its own README.md for self-documentation.
11640
+
11641
+ ### Fixed
11642
+
11643
+ - Fixed crash when restoring a session with a custom model that no longer exists or lost credentials. Now gracefully falls back to default model, logs the reason, and appends a warning message to the restored chat.
11644
+ - Footer no longer crashes when no model is selected.
11645
+
11646
+ ## [0.7.11] - 2025-11-16
11647
+
11648
+ ### Changed
11649
+
11650
+ - The `/model` selector now filters models based on available API keys. Only models for which API keys are configured in environment variables are shown. This prevents selecting models that would fail due to missing credentials. A yellow hint is displayed at the top of the selector explaining this behavior. ([#19](https://github.com/badlogic/pi-mono/pull/19))
11651
+
11652
+ ## [0.7.10] - 2025-11-14
11653
+
11654
+ ### Added
11655
+
11656
+ - `/branch` command for creating conversation branches. Opens a selector showing all user messages in chronological order. Selecting a message creates a new session with all messages before the selected one, and places the selected message in the editor for modification or resubmission. This allows exploring alternative conversation paths without losing the current session. (fixes [#16](https://github.com/badlogic/pi-mono/issues/16))
11657
+
11658
+ ## [0.7.9] - 2025-11-14
11659
+
11660
+ ### Changed
11661
+
11662
+ - Editor: updated keyboard shortcuts to follow Unix conventions:
11663
+ - **Ctrl+W** deletes the previous word (stopping at whitespace or punctuation)
11664
+ - **Ctrl+U** deletes from cursor to start of line (at line start, merges with previous line)
11665
+ - **Ctrl+K** deletes from cursor to end of line (at line end, merges with next line)
11666
+ - **Option+Backspace** in Ghostty now behaves like **Ctrl+W** (delete word backwards)
11667
+ - **Cmd+Backspace** in Ghostty now behaves like **Ctrl+U** (delete to start of line)
11668
+
11669
+ ## [0.7.8] - 2025-11-13
11670
+
11671
+ ### Changed
11672
+
11673
+ - Updated README.md with `/changelog` slash command documentation
11674
+
11675
+ ## [0.7.7] - 2025-11-13
11676
+
11677
+ ### Added
11678
+
11679
+ - Automatic changelog display on startup in interactive mode. When starting a new session (not continuing/resuming), the agent will display all changelog entries since the last version you used. The last shown version is tracked in `~/.pi/agent/settings.json`.
11680
+ - `/changelog` command to display the changelog in the TUI
11681
+ - OpenRouter Auto Router model support ([#5](https://github.com/badlogic/pi-mono/pull/5))
11682
+ - Windows Git Bash support with automatic detection and process tree termination ([#1](https://github.com/badlogic/pi-mono/pull/1))
11683
+
11684
+ ### Changed
11685
+
11686
+ - **BREAKING**: Renamed project context file from `AGENT.md` to `AGENTS.md`. The system now looks for `AGENTS.md` or `CLAUDE.md` (with `AGENTS.md` preferred). Existing `AGENT.md` files will need to be renamed to `AGENTS.md` to continue working. (fixes [#9](https://github.com/badlogic/pi-mono/pull/9))
11687
+ - **BREAKING**: Session file format changed to store provider and model ID separately instead of as a single `provider/modelId` string. Existing sessions will not restore the model correctly when resumed - you'll need to manually set the model again using `/model`. (fixes [#4](https://github.com/badlogic/pi-mono/pull/4))
11688
+ - Improved Windows Git Bash detection logic with better error messages showing actual paths searched ([#13](https://github.com/badlogic/pi-mono/pull/13))
11689
+
11690
+ ### Fixed
11691
+
11692
+ - Fixed markdown list rendering bug where bullets were not displayed when list items contained inline code with cyan color formatting
11693
+ - Fixed context percentage showing 0% in footer when last assistant message was aborted ([#12](https://github.com/badlogic/pi-mono/issues/12))
11694
+ - Fixed error message loss when `turn_end` event contains an error. Previously, errors in `turn_end` events (e.g., "Provider returned error" from OpenRouter Auto Router) were not captured in `agent.state.error`, making it appear as if the agent completed successfully. ([#6](https://github.com/badlogic/pi-mono/issues/6))
11695
+
11696
+ ## [0.7.6] - 2025-11-13
11697
+
11698
+ Previous releases did not maintain a changelog.