Repository navigation
v0.60.0
v0.60.0
AFT 0.60.0 makes call graphs much cheaper to keep current: a one-file edit now updates a project's graph in seconds rather than minutes, and linked git worktrees reuse their main checkout's graph until they change. aft_inspect dead-code and unused-export results are more accurate on Rust, Go and TypeScript, and inspect uses far less memory on large projects. OpenCode 2 users get native shell and patch tools, and stopped subagents are no longer woken by their own background commands. CortexKit daemon users get approval modes, permission asks for sandboxed workers, Windows remote builds and many reliability fixes.
Upgrading
- Every project rebuilds its call graph once after upgrading, including the call-graph data stored for each checkout view. Call-graph tools and
aft_inspect's dead-code categories report building until it finishes. aft_inspect's cached analysis is in a new format and is rebuilt once on the next run.aft.dbmoves from schema 15 to 18 on first start (permission grants, open permission asks, approval modes and macOS fix-it cards), and its reader floor rises to 18, so AFT 0.59 and older refuse to open it afterwards. To go back to 0.59, stop AFT, then in one transaction drop the tables each step added and setschema_versionto the previous number:- schema 18 → 17: drop
access_modes,access_scope_agentsandmacos_permission_cards. Approval modes fall back to the default and open macOS fix-it cards are forgotten locally. - schema 17 → 16: drop
access_asks. Open permission asks are discarded; a worker that retries its call asks again. - schema 16 → 15: drop
access_scopes,access_grants,access_launch_paramsandaccess_materialized. Saved permission grants and launch-time folder grants are discarded. - Before starting the older binary, also lower only the
aft.dbentry in the storage root'sreader-floor.jsonto 15, and leave every other entry unchanged. Lowering the database alone does not lower that floor.
- schema 18 → 17: drop
- OpenCode 2: AFT's
bashandapply_patchnow register asshellandpatch, so OpenCode 2 renders them natively and each session rebuilds its prompt cache once (#406, thanks @null-axiom). - With remote runs enabled, the
bashtool'srunondescription changed (it now mentionswindows), so those sessions also rebuild their prompt cache once, on every host. - CortexKit daemon: sessions now have approval modes. Primary agents default to full access for now;
askandread-onlyremain available. Inaskmode a primary agent asks the user before touching files outside its project, and a macOS permission denial raises a fix-it card with steps for System Settings. - CortexKit daemon: GitHub bot writes from an agent session are sent only under that session's agent scope. A session that isn't bound under its agent's scope is refused with
bot_write_requires_scopebefore anything is sent; restarting the host session binds it. - CortexKit daemon: index data for a deleted linked worktree is removed 10 minutes after its last session, not after a day. Other checkouts keep seven days.
New
runon: "windows"runs a command on a remote Windows runner when the daemon's build service offers one.runonalso takes a vCPU count (linux,4c) and,netfor outbound internet.bash_statusandbash_watchshow a queuedrunontask's wait time and queue position, and after it starts, when the runner will stop it.- A bash command that finishes within its call ends its reply with a
[task …]line naming its task, and its remote job forrunon. - CortexKit daemon: call modes.
flowserves only the read and navigation tools, andcodemodeserves the primary agent's tool set with bounded, run-scoped bash. Anything a mode does not serve is refused ascall_mode_unsupported. - CortexKit daemon: sandboxed worker shells. A worker's reads and writes outside its checkout become permission asks to its primary agent, and the worker resumes with the answer. Git commits, hooks, builds and its own temp folder keep working, and shared build-cache servers are out of reach (enforced on macOS, reported as unenforced on Linux).
- Primary agents can read their own workers' bash task records and status, including revived workers, without gaining control of the task; a worker's launch environment stays private. Sessions can also grep and glob their own task output folders.
Changed
- Call graphs update incrementally: a one-file change takes about 13 s instead of about 3 minutes on a large repository, and switching branches across 50 commits about 28 s instead of 5 minutes, with results identical to a full build.
- A linked worktree no longer builds its own call graph until something asks for it. Until its files differ from the main checkout,
aft_callgraph, zoom's call-graph annotations andaft_inspect's dead-code categories answer from the main checkout's graph, with the worktree's own paths. aft_inspectdead code and unused exports are more accurate: Go package initializers, Rust static values, macros, aliases and private trait methods called through their type, TypeScript namespaces, test imports with a query suffix, and public roots. Rust code compiled only for tests is left out of production findings.aft_inspectpeak memory on large Go projects dropped by about two thirds (hugo: about 1.4 GB to about 420 MB), and duplicate-code results take about half the memory to load. Output is unchanged.- Scoped
aft_inspectreports only what it actually checked for that scope, and pages its results. - Rust: automatic
cargo checkruns are off in checkouts with daemon worker sessions, whereaft_inspectskips its owncargo checkand says so; the daemon runs at most two rust-analyzers at once. - Edits are faster: diff previews compute each diff once, batch edits build their output once, and a hashline edit needs two round trips instead of three.
- Single-file
aft_outlinecalls reuse already-parsed symbols instead of parsing the file again. - Bash replies arrive sooner after the command ends (median about 100 ms instead of 230 ms).
aft_searchranks better for sentences that name an identifier, and keeps its semantic lane for every non-regex query.- The CortexKit daemon does less idle work: a cheaper health pass that re-reads each repository's status only when it changes, a lighter idle tick, and helper processes started without copying the daemon's memory.
bash_statuson a session's own task no longer searches for worker records, and looking up a worker task's owner uses memory or the database instead of walking session folders.
Fixed
- A search run right after an AFT edit now sees the edit. It no longer depends on when the operating system reports the change, and no longer answers "complete" from the old index.
- OpenCode 2: a stopped subagent is no longer woken by its own background commands, and its commands are stopped with it. Shutdowns and failures stop nothing (#409, thanks @null-axiom).
- OpenCode 2: completion notices arrive as synthetic messages, and one that arrives during a long
wait: truecommand or abash_watchhands control back to the agent (#407, thanks @null-axiom). - An idle AFT bridge now lets one-shot hosts exit (#389, thanks @FrancoStino).
aft_zoomambiguity menus keep their context, and the selectors they show can be passed back as they are.aft_importand other tools now resolve a relative path against the project, not the filesystem root.- Plugins no longer move or create project config files while loading; a project's legacy
.opencode/aft.jsonor.pi/aft.jsonis read where it is. - Bash: spawn failures name the reason, a cancelled call's still-running command is named once on the next call and keeps its completion notice, and a command that could not be confirmed started never runs after a crash.
- Bash: a background task's output files and finished status survive a daemon restart, and a remote job's exit status is kept.
- Configure no longer walks the whole project on the bind path; on large new checkouts that walk had delayed session start by 11 to 21 seconds.
aft_inspectwaits briefly for it and marks diagnostics as pending if it is still running. - Views: disk-limit checks run one at a time instead of all at once, and a check that ran out of time no longer records unmeasured views as empty.
- Views: storage retention clears the backlog of deleted checkouts instead of a few per pass, and removes orphan view folders after an hour.
- File access checks no longer blame the operating system for time spent waiting in AFT's own queue: a check that never started is refused as
read_io_queue_timeout, and the macOS Privacy & Security hint is shown only on macOS. Checking a path no longer lists its parent folder. - Call graph: a refresh blocked by another checkout's writer waits for it instead of replaying itself, and recovers if that writer dies (#411, thanks @chpock).
aft_inspect: waiting for another process's cache writer is reported as waiting, not as failed input, and is retried within 30 seconds (#412, thanks @chpock).- OpenCode and Pi: an idle session that never started a background task no longer warns about undelivered completions (#413, thanks @chpock).
- Swift: valid code using
try/try?/try!withawaitin conditions, or casts followed by??, is no longer rolled back as invalid syntax, and an edit that only tree-sitter rejects is kept whenswiftc -parseaccepts it. - With views on, searching a parent folder whose child checkouts are not indexed yet scans them on disk and says so, instead of finding nothing (#405, thanks @TreedsSlop).
aft_searchresult trailers say(cap)when a complete list was cut to one page, and(walk)only when part of the project went unsearched.- CortexKit daemon: the health report keeps its last measured figures, marked stale, when it is too busy to refresh them, instead of reporting zeros.
- CortexKit daemon: primary agents keep their scope across AFT restarts and reconnects, temporary refusals no longer downgrade a session to unscoped, and a
bot_write_requires_scoperefusal explains what the session is missing. - CortexKit daemon: revived workers keep their remote runner and launch settings.
- CortexKit daemon: worker bash refuses synthetic CPU load, including load hidden behind
exec,nohup,setsid,stdbuf,timeorcaffeinate, and asks for a deterministic proof instead. - Many reliability fixes from an external audit, across the bash task lifecycle, the daemon protocol, GitHub reads and writes, index publication and the file watcher.
aft_inspect's file scan now stops at its time limit even inside large ignored or hidden folders, and reports an unfinished scan instead of presenting it as fresh.