# v0.24.0

Focused improvements to how AFT runs alongside parallel work, how it talks to its plugins, and how it reports its own state. Every change in this release applies to both `@cortexkit/aft-opencode` and `@cortexkit/aft-pi`. Matters most for users running Alfonso subagents, multiple worktrees, the TUI sidebar, or Pi v0.74+.

## Cross-worktree cache reuse

When you spawn a new git worktree (e.g. for an Alfonso subagent task) and AFT starts there, it now reuses the main project's on-disk search, semantic, and symbol caches via content-hash freshness checks instead of rebuilding. The 30-50 second CPU spike per worktree start is gone for typical projects.

Worktree bridges are now ephemeral readers: they load the base cache, refresh anything that has changed via Blake3 content hash, and never write back. The main project bridge stays the sole owner of cache state, so concurrent worktrees can't clobber each other.

One-time forced rebuild of all three caches happens the first time you launch v0.24 against an existing project. Expect ~30-60s on first launch as the new format is populated; every launch after that is fast.

## Push-driven status updates

`/aft-status` and the TUI sidebar used to round-trip through the AFT bridge on every poll (~every 1.5s). On a busy bridge — running `grep`, semantic builds, or watcher invalidation — that poll would queue behind real work and sometimes hit a 5-second timeout, producing misleading "retrying after port refresh" warnings.

AFT now pushes status changes directly to the plugin when configure completes, index builds finish, or LSP servers attach. The plugin caches the snapshot in memory; status calls hit that cache in microseconds without touching the bridge. Updates are debounced by 1 second to coalesce bursts.

Net effect: status is essentially free now, and the spurious RPC timeout warnings stop. Status push frames are also drained on idle (every 250ms), so the TUI sidebar transitions `loading → ready` automatically as soon as a background index build completes — no more sitting on "loading" until you fire a tool call.

## Redesigned `/aft-status` dialog

Both harnesses get a redesigned dialog inspired by `@cortexkit/opencode-magic-context`'s `/ctx-status`:

- **OpenCode (TUI)** — a themed two-column JSX dialog with flex layout, color-coded status tones, and a `cache_role` accent (main / worktree / not_initialized). Fits cleanly in the standard TUI viewport without scrolling.
- **OpenCode (Desktop)** — unchanged plain-text snapshot via `sendIgnoredMessage`.
- **Pi** — a custom overlay component (`ctx.ui.custom(...)`) with bordered two-column layout, themed colors, and 1.5s auto-refresh so loading → ready transitions surface live. Replaces the prior single-line input-prompt rendering that was effectively unreadable.

## ONNX Runtime race on Pi launch

When Pi launched with semantic search enabled, the eager bridge warm-up spawned ~4ms BEFORE the ONNX Runtime download path was patched onto the pool's configure overrides. The bridge that served the agent therefore had no `_ort_dylib_dir`, so Rust fell through to a system-path `dlopen("libonnxruntime.dylib")` that fails on managed installs. Symptom: `/aft-status` showed `semantic_index: failed` with `ONNX Runtime not found` even though the runtime had finished downloading seconds earlier.

OpenCode already awaited the ONNX promise (capped at 60s) before its eager spawn; Pi now mirrors that exact path. Semantic indexes now build cleanly on first launch instead of staying `failed` until manual restart.

## Background bash completion reliability

Fixed a regression where background bash completion notifications could be silently dropped, leaving the agent waiting indefinitely. The wake path bailed early if the bridge was busy with any in-flight call — but that included unrelated status RPC polls and configure work, not just agent tool calls. When a completion arrived during one of those windows, no follow-up trigger fired and the completion sat in a pending queue forever.

The early-return was wrong; the downstream debounce, timer cancellation, and retry mechanisms already handle the original concern correctly. Wakes are now always scheduled when a completion arrives, regardless of bridge activity. The 200-1000ms debounce window and in-turn drain cancellation guard still prevent duplicate or empty notifications.

Symmetric fix in OpenCode (`promptAsync` wake path) and Pi (`sendUserMessage` with `deliverAs: "steer"`). If you experienced "main agent stuck waiting for background bash" symptoms in v0.23.x, this fixes the root cause for both harnesses.

## Pi v0.74 doctor parity ([#37](https://github.com/cortexkit/aft/issues/37))

Pi v0.74 changed where it stores installed extensions and how `pi --version` writes output, breaking `bunx --bun @cortexkit/aft doctor` for Pi v0.74+ users. The visible symptom was `Plugin registered: false` reported even when AFT was correctly installed, plus `+0/-0` edit counts in diagnostics. Three fixes:

- **Plugin detection** now reads `~/.pi/agent/settings.json` (new v0.74 location) and falls back to the legacy `extensions.json` for older Pi installs. Handles all four package-source forms — `npm:<spec>`, `file:<path>`, absolute paths, and relative paths against the agent directory. Path entries verify against `package.json` name instead of substring-matching, so look-alikes like `awesome-aft-pi-thief` don't trigger a false positive.
- **Host version detection** now reads from both stdout and stderr (Pi v0.74 redirects stdout in non-interactive mode) and tolerates startup banners pre-empting the version line.
- **Doctor output labels** renamed `CLI` / `Binary` to `AFT CLI` / `AFT binary` to remove ambiguity with Pi's own versions. `Host version` is now on its own line so "unknown" is explicit instead of silently omitted.
