Repository navigation
v0.59.0
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.jsoncto the current keys the first time it reads it, keeps the old file beside it asaft.jsonc.bak-<time>, and shows one notice; a read-only file is translated in memory instead (list). - A project's
.cortexkit/aft.jsoncis never written: its retired keys are translated in memory under the usual project limits, with one notice naming the file. Runnpx @cortexkit/aft doctor --fixin the project to update it. - Retired keys:
tool_surface,hoist_builtin_tools, top-levelenabled,search_index,semantic_search,callgraph_store,github.enabled,gh_read,gh_shim.enabled, andaft_-prefixed names indisabled_tools. bash: false,bash.enabled: false,inspect.enabled: falseandbackup.enabled: falsenow only switch the behaviour off; list tools indisabled_toolsto remove them.idle.lsp_ttl_minutesis replaced bylsp.idle_minutes: minutes since the last AFT call, default 60, range 5–1440, or"never". Your value moves over (docs).inspect.tier2_soft_deadline_msandinspect.max_drill_down_itemsdid nothing and are dropped the same way.aft.dbmoves 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.rootsentries that selectsemantic. - 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
patchorshelltool runs beside AFT'sapply_patchorbash, the TUI shows a one-time notice that points atdoctor --fix. - OpenCode 2:
setupalso offers to turn off the host's patch tool. With it off, GPT models (except IDs containinggpt-4oross) getapply_patchand other models geteditandwrite(#395, thanks @null-axiom). - Subagent sessions: a blocking
bashcall or abash_watchwithout a timeout now returns afterbash.worker_wait_max_ms(default 30 minutes); the command keeps running in the background. - A subagent's
wait: truecommand now has the default 30-minute kill, pushed back each time the subagent waits on it again; an explicittimeoutis 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
readonpr://N/diffreturns a live unified diff, andpr://N/diff/<path>one changed file; needsgithub.read(docs).aft_searchtakes apatternregex beside or instead ofquery, for when you know a name the answer must contain (docs).aft_searchshows a definition at its declaration line, and suggests the nearest names when an identifier is not found.aft_searchwithpathacceptspatternand answers identifier queries with an exact sweep of that project's files on disk.- Optional reranking of
aft_searchprose results withsearch.rerank(off by default; local ONNX, a remote service, or Synapse) (docs). inspect.categoriesturns individualaft_inspectcategories off; an off category is not computed and shows○in the status bar (docs).aft_inspectsaves completed Rustcargo checkresults, so an unchanged checkout does not wait for a fresh check after a restart.aft_importadds and removes names inside the existing import list, keeping its line layout and comments;organizestill reformats.- Remote builds: with
runon: "linux",bashruns the whole line on the remote Linux build server (ck-motor) that your CortexKit daemon is connected to (docs). runonis offered only to sessions running under the CortexKit daemon on macOS or Linux, withremote_exec.enabledandbash.runon_enabledset 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-serverwhen 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-legacyto delete old pre-views caches.
Changed
aft_inspectstarts with one header: FRESH, PARTIAL, INTERRUPTED or PHASE-FAILED. PARTIAL names the analyzer and reason, so unknown diagnostics never read as clean (docs).aft_inspectwithscopenarrows 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_inspectstarts 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_indexedand suggestgreporaft_search, instead ofsymbol_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_patchand 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.
grepmatches are line-oriented; a named ignored folder is searched; while the index builds, the footer says whether every file was checked.aft_outlinenests methods under their types in multi-file views, collapses tests to summaries, honours the target's.gitignore, and explains empty results.aft_zoomlists 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
bashoutput keeps the final lines, andcargo testand 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
runonthe server refuses is reported asremote_unavailableand not run locally. - Language servers run with
GIT_OPTIONAL_LOCKS=0, so theirgit statuscalls do not take Git's optional index lock. - rust-analyzer uses its own Cargo target directory and no longer blocks your
cargobuilds. - 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 closeandreopenprint whatghprints. - 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 installandplugin upgradeexit instead of hanging on anaftprocess (#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
bashnever 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).
.gitignorerules 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.
bashanswers 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 checkfinishes, 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_searchandast_replaceparse and compile less often.grepbounds work on very long lines with many matches, and indexedgrephas a deadline.- Search-index loading,
globordering 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
setupanddoctor(#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:
runonis 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
readfor 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
ghwould change before sending.