Skip to content

v0.59.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 09:49
· 4790 commits to main since this release

v0.59.0

AFT 0.59.0 updates configuration files that still use the keys retired in 0.58: your user config is rewritten to the current keys automatically, and a project's config keeps working, translated in memory. It adds live pull-request diffs, a pattern argument for aft_search, per-category switches for aft_inspect, and opt-in remote builds for CortexKit daemon users. Issues reported against OpenCode 2, Pi and OMP are fixed (listed under Fixed), and AFT does less repeated work and far fewer forced disk writes.

Upgrading

  • Retired keys are never refused. AFT rewrites ~/.config/cortexkit/aft.jsonc to the current keys the first time it reads it, keeps the old file beside it as aft.jsonc.bak-<time>, and shows one notice; a read-only file is translated in memory instead (list).
  • A project's .cortexkit/aft.jsonc is never written: its retired keys are translated in memory under the usual project limits, with one notice naming the file. Run npx @cortexkit/aft doctor --fix in the project to update it.
  • Retired keys: tool_surface, hoist_builtin_tools, top-level enabled, search_index, semantic_search, callgraph_store, github.enabled, gh_read, gh_shim.enabled, and aft_-prefixed names in disabled_tools.
  • bash: false, bash.enabled: false, inspect.enabled: false and backup.enabled: false now only switch the behaviour off; list tools in disabled_tools to remove them.
  • idle.lsp_ttl_minutes is replaced by lsp.idle_minutes: minutes since the last AFT call, default 60, range 5–1440, or "never". Your value moves over (docs).
  • inspect.tier2_soft_deadline_ms and inspect.max_drill_down_items did nothing and are dropped the same way.
  • aft.db moves to schema 15 on first start (schema 14 adds remote-run settings, 15 a record of tool calls). AFT 0.58 and older refuse to open it afterwards.
  • Background bash task records move to format 7, which AFT 0.58 cannot read.
  • Every project rebuilds its call graph once after upgrading, because Rust paths, imports and trait calls are now resolved more precisely; call-graph tools report building until it finishes.
  • Semantic indexes are now built only for repositories open in an OpenCode or Pi session, their linked worktrees, and user index.roots entries that select semantic.
  • Other projects keep exact and identifier search, read a saved semantic index if one exists, and show semantic as off (not opened).
  • OpenCode 2: when the host's own patch or shell tool runs beside AFT's apply_patch or bash, the TUI shows a one-time notice that points at doctor --fix.
  • OpenCode 2: setup also offers to turn off the host's patch tool. With it off, GPT models (except IDs containing gpt-4 or oss) get apply_patch and other models get edit and write (#395, thanks @null-axiom).
  • Subagent sessions: a blocking bash call or a bash_watch without a timeout now returns after bash.worker_wait_max_ms (default 30 minutes); the command keeps running in the background.
  • A subagent's wait: true command now has the default 30-minute kill, pushed back each time the subagent waits on it again; an explicit timeout is never extended.
  • Finished background task output is deleted 24 hours after its completion is delivered. Copy anything you need into your report.
  • Index data for a deleted linked worktree is reclaimed after one day instead of seven; main checkouts keep seven days.

New

  • read on pr://N/diff returns a live unified diff, and pr://N/diff/<path> one changed file; needs github.read (docs).
  • aft_search takes a pattern regex beside or instead of query, for when you know a name the answer must contain (docs).
  • aft_search shows a definition at its declaration line, and suggests the nearest names when an identifier is not found.
  • aft_search with path accepts pattern and answers identifier queries with an exact sweep of that project's files on disk.
  • Optional reranking of aft_search prose results with search.rerank (off by default; local ONNX, a remote service, or Synapse) (docs).
  • inspect.categories turns individual aft_inspect categories off; an off category is not computed and shows ○ in the status bar (docs).
  • aft_inspect saves completed Rust cargo check results, so an unchanged checkout does not wait for a fresh check after a restart.
  • aft_import adds and removes names inside the existing import list, keeping its line layout and comments; organize still reformats.
  • Remote builds: with runon: "linux", bash runs the whole line on the remote Linux build server (ck-motor) that your CortexKit daemon is connected to (docs).
  • runon is offered only to sessions running under the CortexKit daemon on macOS or Linux, with remote_exec.enabled and bash.runon_enabled set in your user config.
  • Without those settings nothing runs remotely and the argument is not shown; standalone sessions never get it.
  • bash.db_schema_hints (on by default): after a SQLite "no such table" or "no such column" error, finished output ends with a short read-only schema hint.
  • Replies that hand back a background task state when AFT will kill it, and a task killed by the default limit says so.
  • Dockerfiles use Docker's docker-language-server when installed, with the npm server as fallback.
  • AFT's health report shows live indexing progress with file rates and estimated time left.
  • Views (opt-in, views.enabled): editing one function re-embeds only that function's chunk, not the whole file.
  • Views: a folder holding several Git repositories is served from each repository's own indexes.
  • Views: per-checkout disk limits with least-recently-used eviction, and npx @cortexkit/aft cache prune-legacy to delete old pre-views caches.

Changed

  • aft_inspect starts with one header: FRESH, PARTIAL, INTERRUPTED or PHASE-FAILED. PARTIAL names the analyzer and reason, so unknown diagnostics never read as clean (docs).
  • aft_inspect with scope narrows every count, finding and example to that scope.
  • Code-health counts cover product code only; findings in tests and fixtures are counted separately on each category line.
  • Dead code is more accurate: Rust re-exports, glob and aliased imports, serde attribute functions, trait impls, struct literals, and custom library roots are followed.
  • Go methods count as used when called through an interface, and symbols only tests reach are reported as test-only, not dead.
  • Exports used only inside their own file are now reported as unused exports.
  • aft_inspect starts fewer language servers, rooted where they serve the most files, and starts them together under one deadline.
  • Call-graph answers for a file the index does not cover say not_indexed and suggest grep or aft_search, instead of symbol_not_found.
  • In a linked worktree, call-graph answers also search files that differ from the shared graph, marked as name matches.
  • Calls through a known trait or interface resolve to its declaration, with implementations listed as candidates.
  • apply_patch and symbol moves with full validation type-check once after every write succeeds, and print one summary line.
  • Import edits keep the file's quote style and semicolon style.
  • grep matches are line-oriented; a named ignored folder is searched; while the index builds, the footer says whether every file was checked.
  • aft_outline nests methods under their types in multi-file views, collapses tests to summaries, honours the target's .gitignore, and explains empty results.
  • aft_zoom lists only calls inside the selected symbol that resolve to local or imported names.
  • URL reads stop downloading at 8 MiB with a size notice and preview within 50 KiB; asking for a missing JSON key lists the top-level keys.
  • Every tool reply has a 2 MiB last-resort cap, and a cut names the tool that overflowed.
  • Results say when the file watcher is behind, so they may miss the latest edits.
  • Capped bash output keeps the final lines, and cargo test and nextest failures, totals and rerun hints survive output caps.
  • A background launch at the 8-task limit lists your own tasks holding slots and how to free one.
  • An explicit runon the server refuses is reported as remote_unavailable and not run locally.
  • Language servers run with GIT_OPTIONAL_LOCKS=0, so their git status calls do not take Git's optional index lock.
  • rust-analyzer uses its own Cargo target directory and no longer blocks your cargo builds.
  • In Bun workspaces, Biome runs from each package's own install; TypeScript files that no installed TypeScript covers are named.
  • GitHub: read-only GraphQL queries pass through gh; refusals name the endpoint; issue close and reopen print what gh prints.
  • GitHub: a session whose agent does not match the repository's bound agent is told why.
  • Pi 0.86 and later: workflow hints are added as a prompt section instead of replacing the system prompt (#390, thanks @johnpwilkinson).
  • CortexKit daemon (Subconscious) clients can ask for a head, worker or reader tool set; worker sessions also get bash_watch.

Fixed

  • A language server that starts slowly is retried with backoff instead of being marked failed until restart (#392, thanks @OlegAndreych).
  • OpenCode 2: notices reach the chat, and a failed completion wake is retried (#394, thanks @null-axiom).
  • OpenCode 2: workflow guidance is injected (#395, thanks @null-axiom).
  • OMP: plugin install and plugin upgrade exit instead of hanging on an aft process (#389, thanks @FrancoStino).
  • OMP: internal URLs are handled by OMP's own tools instead of failing in AFT's (#396, thanks @jprofiz).
  • Pi: tool renderers no longer fail when the host passes incomplete arguments (#397, thanks @Zireael).
  • Pi: with views on, standalone sessions no longer time out while the first index publication runs (#399, thanks @aredridel).
  • A call cut off by a plugin reload is reported as outcome unknown, and bash never reruns it on the host (#401, thanks @adambarber).
  • A non-UTF-8 file no longer makes complexity and duplicate scans fail and retry forever (#402, thanks @ICEY16360).
  • .gitignore rules apply to every index, including in folders that are not Git repositories, where global excludes apply too (#403, thanks @ICEY16360).
  • A per-call timeout no longer cuts off other calls on the same connection.
  • bash answers within its deadline even when the shell is slow to start, and says whether the command started.
  • Killing a bash task no longer stalls other calls while its process exits.
  • A task that exits on its own while it is being killed still delivers its completion notice before the kill returns.
  • A hung language server no longer stalls edits or inspections, and its pending results are reported as unknown, not clean.
  • Edits made while the language-server manager was busy are no longer dropped, which left servers on old file contents.
  • Rust diagnostics are not reported as current before the owed cargo check finishes, including after edits made outside AFT.
  • URL code blocks keep their line breaks and stay in one fence.
  • Reads on network or removable volumes, and named pipes, can no longer hang a request.
  • A deleted or abandoned project no longer deadlocks the daemon module so that new sessions fail to bind.
  • A session bind no longer waits behind a long read, and a refused bind names what blocked it.
  • The daemon module exits after a 30-second stall instead of hanging; detached background tasks keep running.
  • Daemon logs recover after a write failure, and failed project database opens are retried.
  • Abandoned project caches and unused index generations are now reclaimed.
  • Git co-author hooks chain to repository hooks set by worktree-scoped and global core.hooksPath.
  • OpenCode session directory lookups give up after one second instead of hanging a call.
  • The bash rewriter no longer rewrites commands whose heredocs or words would expand.

Performance

  • Call-graph cold builds parse each file once, and refreshes re-resolve only references a changed file can affect.
  • Rebuildable caches (search, symbols, call graph, inspect) and bash task records no longer force disk flushes.
  • A slow language server no longer holds up unrelated reads.
  • aft_outline, aft_zoom, ast_search and ast_replace parse and compile less often.
  • grep bounds work on very long lines with many matches, and indexed grep has a deadline.
  • Search-index loading, glob ordering and file-watcher updates do less filesystem work.
  • Plugins start faster and do less per call: cached checksums, reused connections and configuration, and no idle background-task check after every tool.
  • Large replies are read in linear time, and edit diffs on large files use far less memory.
  • Formatters and checkers no longer add up to 50 ms per run, and standalone search replies no longer wait for a 100 ms poll.

Platform notes

  • Windows: npm-installed OpenCode 2 is detected correctly by setup and doctor (#391, thanks @NineLEL).
  • Windows: PTY tasks report complete only after their output is captured, kills finish promptly, and a capture error no longer marks a successful command failed.
  • Windows: finished background task folders are deleted reliably.
  • Windows: runon is refused by name; remote builds need AFT on macOS or Linux.
  • macOS: with bash.disclaim_privacy: true, agent shells stop using the privacy permissions, such as folder access, granted to the app running AFT (docs).
  • macOS: with it on, use read for files in protected folders such as ~/Downloads; a shell that cannot disclaim is refused, not run.
  • macOS: a file-watcher overflow no longer restarts the watch streams repeatedly.
  • Linux: files written into a new folder before AFT starts watching it are now picked up.

Security

  • On Unix, AFT storage is readable only by you (0700 folders, 0600 files), and existing storage folders are tightened when opened.
  • The native sandbox hides CortexKit data and state folders and the daemon connection file from commands, except the project and the task's temporary folder.
  • Remote runs strip secret-looking and AFT control environment variables before sending, and the reply lists the names removed.
  • The gh shim parses GraphQL documents fully before allowing a read, and refuses documents gh would change before sending.