# v0.35.0 — Leaner semantic indexing, agent status bar, sharper `aft_inspect`

This release substantially cuts the CPU and memory that local semantic indexing uses, adds an IDE-style status bar that surfaces codebase health on tool results without the agent asking, makes `aft_inspect` substantially more accurate (dead code, duplicates) and keeps its background scans fresh during long sessions, and makes the TUI sidebar collapsible. It also adds `npx @cortexkit/aft --version`, session-scoped `doctor --issue`, and an actionable hint when a rust-analyzer-style toolchain component is missing.

## Leaner semantic indexing

Local semantic indexing now uses roughly half the CPU and a fraction of the peak memory, with no change to search results and no re-index required.

- **CPU is bounded.** Embedding previously ran on every core, which pegged the machine and competed with the agent for the duration of a build. It now caps its worker threads at half the available cores. In our measurements that is about 40% less CPU *and* about 24% faster, because oversubscribing the cores was hurting throughput as well — on an 18-core machine the indexer now uses ~9 cores instead of all 18.
- **Memory is bounded.** A token budget now bounds each embedding pass so a batch that happens to contain very long symbols can no longer spike memory. On a 20,000-file repository the worst-case peak dropped from ~4.9 GB to ~1.3 GB, which keeps large-repo indexing safe on 8–16 GB machines.
- **Existing indexes keep working.** The reworked embedder produces vectors that match the previous backend, so your current semantic index continues to serve queries unchanged — no rebuild and no quality change.

## Faster startup on large repositories

Files that contain no top-level symbols were being re-parsed on every bridge startup — visible in logs as a recurring "N new files" churn on large repositories. They are now cached like any other file and skipped on subsequent starts, reducing repeated startup work.

## Agent status bar

Tool results now end with a compact one-line health bar — an IDE status-bar analog the agent sees as it works, instead of having to call a tool to check:

```
[AFT E0 W0 | D333 U221 C1160 | T8]
```

`E`/`W` are live LSP errors and warnings for files touched this session — a universal compile-error signal across every language with a language server, not just `tsc`/`cargo`. `D`/`U`/`C` are the `aft_inspect` Tier-2 counts (dead code, unused exports, clone/duplicate groups) and `T` is the TODO count. A `~` before `D` marks the Tier-2 counts as predating the latest edit, with current numbers a single `aft_inspect` call away.

The bar is emitted on change rather than on every call, so the transcript doesn't accumulate identical lines, and the latest bar always reflects current health. The legend is taught once in the system prompt, so each appearance costs only the compact values. Available on both OpenCode and Pi.

## `aft_inspect` is more accurate and stays fresh

**Dead-code accuracy.** Reachability now propagates liveness through methods reached only by dispatch and through type references, recognizes real entry points from `Cargo.toml` and `package.json` (binaries, `main`/`module`/`exports`, script targets) instead of a filename heuristic, and resolves `dist/` public-API entries and NodeNext `.js` import specifiers back to their `src/` TypeScript sources. Together these remove large clusters of false positives — command handlers, barrel re-exports, and dispatch-live helpers that earlier versions flagged as dead.

**Duplicate collapse.** Overlapping and nested duplicate fragments now collapse to their maximal outer span instead of each sub-fragment counting as its own group, so the duplicate count reflects distinct duplicated regions rather than every nested slice.

**Ranked drill-down.** Findings are ranked by signal tier — product code before tests and tooling — and the summary now carries a cost-ranked top-N preview so the highest-value items surface first.

**Background freshness.** A watcher-driven refresh scheduler now keeps the Tier-2 scans current during a working session — debounced after edits, with a maximum-staleness ceiling so continuous activity still triggers a refresh — rather than waiting for an idle window that a busy session never reaches. This runs in the binary, so it works the same on OpenCode and Pi.

## Collapsible sidebar (OpenCode TUI)

The AFT sidebar panel is now collapsible. Click the `▼ AFT` header to collapse it to a condensed view — Search Index and Semantic Index status dots plus a compact compression line (`7.7M / 64%`) — and click `▶ AFT` to expand it again.

## Languages

- **SCSS** (`.scss`) is now a recognized language for outline, symbol zoom, and AST search.
- **`.inc`** files are treated as PHP, so the common PHP include extension gets full parsing, outline, and import support.

## CLI

- **`npx @cortexkit/aft --version`** reports the CLI, binary, and per-harness host and plugin versions in one command.
- **`doctor --issue`** can scope a report to a specific session. It lists your recent OpenCode/Pi sessions; choosing one filters the bundled logs to that session, while "General" keeps everything. Secret and path redaction still apply.
- **`doctor --fix`** adds the config `$schema` URL when it is missing, so editor validation and autocomplete light up.
- The harness picker for `doctor` is now single-select; `setup` stays multi-select.

## Fixes

- **Deleted files no longer leave phantom diagnostics.** When a file is removed (`aft_delete`, `rm`, a branch switch, a failed rebase), its cached LSP errors and warnings are cleared instead of lingering in the warm set and inflating the status bar and `aft_inspect` counts.
- **Missing toolchain language servers now get an actionable hint.** When a server on `PATH` is a toolchain proxy whose component is not installed — most commonly `rust-analyzer` — AFT reports `rustup component add rust-analyzer` instead of the raw `Unknown binary` error.
- **Sidebar no longer flickers blank.** A transient pre-initialized status snapshot during a binary swap or session-directory change no longer overwrites a good one and blanks the panel; the last good snapshot is kept until real data returns.
- **Oversized YAML/Kubernetes manifests no longer break semantic indexing.** A manifest packing a large inline script (a CronJob/Job `command:` body) into one symbol could exceed the embedding backend's per-request token limit and abort the entire index build, silently degrading every search to lexical-only. Embedding text is now clamped so a single oversized symbol can't take down the build.
- **`edit` no longer drops a trailing newline on a fuzzy match.** When a whitespace-tolerant match landed on the last lines of a file and the replacement text had no trailing newline, the final replaced line could be joined to the following line. The trailing newline is now preserved.
- **Partial overrides of a built-in LSP server work again.** Setting `lsp.servers.<id>` to tweak a single field of a built-in server (for example pointing `rust` at a custom binary) no longer requires re-specifying `extensions` and `binary`; the built-in's values are inherited, and the whole `lsp` config section is no longer silently dropped when they are omitted.
- **Call-graph queries are now timed in the logs.** `aft_callgraph callers` on a large repository logs how long parsing and edge resolution took, so a slow first call (or a `project_too_large` rejection) is attributable instead of appearing as an opaque stall.

## Pi

- The `aft_conflicts` and `grep` bash-output hints — which nudge toward `aft_conflicts` after a failed merge and toward the indexed `grep` tool — now fire on Pi as well as OpenCode.

Thanks to @M0Rf30 (#79, semantic-indexing fix for oversized YAML/Kubernetes manifests) for the contribution to this release.

Join us on Discord: https://discord.gg/DSa65w8wuf
