# 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](https://discord.gg/DSa65w8wuf).
