v0.39.3
v0.39.3: cleaner bash control, readable callgraph output, Quarto, and config you can trust
A patch with a broad set of UX and correctness improvements: bash.background: false now fully removes the background surface instead of half-disabling it, aft_callgraph returns readable text instead of raw JSON, Quarto/R-Markdown files outline, malformed config no longer fails silently, and pipeline commands ask for permission once.
Bash: background: false now means it
Setting bash.background: false used to only block explicit bash({ background: true }) — long foreground commands still auto-promoted to background, and the bash_status/bash_kill/bash_watch tools stayed registered (#124). Now it fully disables the background surface: those tools aren't registered, the background/pty parameters are removed from the bash tool, and long commands run to completion in the foreground (bounded by timeout, default 30 minutes). If you keep background on (the default), nothing changes.
Bash waiting guidance, rebuilt around interruptible waits
Sync bash_watch is now interruptible — sending a message while it's waiting disengages the wait and converts it to a background notification. The old guidance told agents not to sync-wait on long commands because it "locks the user out"; that's no longer true, and the advice pushed agents into polling bash_status in a loop instead. The tool descriptions and workflow hints now steer agents to block on bash_watch when the result is the next thing they need (it's safe — you can always interrupt), end the turn when there's parallel work, and never loop bash_status to wait. The sync bash_watch timeout cap was raised from 5 minutes to 30 minutes so it can actually wait out a real build.
One permission prompt per pipeline (#123)
A piped bash command (cat x | grep y | wc -l) used to fire a separate permission prompt for each stage. Those are now collapsed into a single prompt. Access to paths outside the project root is still prompted separately.
aft_callgraph returns readable text
aft_callgraph was the last tool still dumping a raw JSON envelope to the agent. It now returns compact, grouped text — caller files with their call sites, call trees, trace paths, and impact sites — matching the format of the other tools. Repeated callers of the same symbol within a file collapse onto one line. Unresolved callees in a call tree are marked [unresolved] so a callsite is never mistaken for a definition.
Lower-memory callgraph cold build (#122)
The callgraph store's cold build now parses files in batches and bounds the method-dispatch pass, reducing peak memory on large repositories. The resulting graph is identical to the unbatched build. Batch size is tunable via callgraph_chunk_size (default 100; set 0 to parse all at once).
Quarto and R-Markdown (#113)
.qmd and .Rmd files now outline and zoom through the Markdown path (ATX and Setext headings). The Markdown heading extractor was reworked along the way for more reliable section ranges.
Config that fails loudly (#120)
A syntax error in your aft.jsonc used to be swallowed — AFT silently fell back to defaults and you only found out via doctor. A config file that exists but can't be parsed now surfaces a visible warning telling you it was ignored and pointing you at doctor. (A missing config file is still silent, as before.) Also: the /status dialog now closes on Enter as well as Esc, matching its footer.
Wider Linux compatibility (#119)
The linux-x64 binary is now built with cross, lowering the glibc floor (older distributions like Ubuntu 18.04/20.04) and bringing it in line with how the arm64 binary is already built.
Thanks to @dragon-Elec for the low-memory callgraph cold-build work (#122/#121) and @RoninZc for the cross linux-x64 build (#119/#118).
Questions or feedback? Join us on Discord.