# Patchloom 0.32.0
YAML merge-key edits keep shared mappings, sibling anchors, and
comments instead of rewriting the whole file. Patch deletes report
a change and apply hunks before unlink, so leftover lines stay on
disk.
## Highlights
`doc set` on a YAML merge (`<<: *shared`) now keeps the merge key
when you grow an inherited array, delete an inherited field, or
write an empty object. Sibling `&anchor` lines stay. Empty `{}`
and `[]` keep comments and spacing instead of rewriting the
whole file.
`apply_patch` on a git delete reports `changed: true` and empty
`new_content`. A hunked `+++ /dev/null` applies the minus lines
first. Leftover text is written back. A stale minus is
`error_kind: ambiguous` (exit 5) and the file is left unchanged.
## New features
- **Library `doc_keys` and `doc_len`.** Hosts can list object keys
and count array or object length without going through CLI or
MCP. Empty / `"."` is the document root. An array on `doc_keys`
is `type_error`. A wildcard or predicate (`items[*]`) is
`ambiguous` and names `items[0]` / `items[1]`. A missing file
is `not_found`.
```rust
let keys = patchloom::api::doc_keys(path, "database")?;
let n = patchloom::api::doc_len(path, "items")?;
```
CLI `doc keys` / `doc len` and MCP `doc_query` use the same
rules ([#2282](https://github.com/patchloom/patchloom/pull/2282), [#2284](https://github.com/patchloom/patchloom/pull/2284)).
- **Blank YAML is an empty object on read.** `doc keys`, `doc
len`, and `doc get .` treat an empty, whitespace-only, or
BOM/ZWSP-only YAML file as `{}`. Comment-only YAML, `null`,
and a bare `---` still return `type_error` on keys and len ([#2285](https://github.com/patchloom/patchloom/pull/2285), [#2286](https://github.com/patchloom/patchloom/pull/2286)).
- **Protobuf AST kinds.** `ast list` and `ast rename` on `.proto`
files include Status and enum symbols. Kind filters accept
`message`, `service`, and `rpc` as well as the tree-sitter
names ([#2264](https://github.com/patchloom/patchloom/pull/2264), [#2265](https://github.com/patchloom/patchloom/pull/2265)).
## Bug fixes
- **YAML merge edits dumped the file or dropped `<<:`.** Growing
an inherited array, deleting an inherited key, or expanding a
merge-only site now keeps the merge key, sibling anchors, and
comments. A merge-only site that becomes empty writes `{}` ([#2270](https://github.com/patchloom/patchloom/pull/2270), [#2271](https://github.com/patchloom/patchloom/pull/2271), [#2272](https://github.com/patchloom/patchloom/pull/2272), [#2273](https://github.com/patchloom/patchloom/pull/2273)).
- **Emptying a YAML sequence item glued the next line.** Setting
a non-last item to `{}` or `[]` used to drop the item newline
(`- {} - name: B`) and dump the file. The item stays on its
own line and comments remain ([#2277](https://github.com/patchloom/patchloom/pull/2277), [#2281](https://github.com/patchloom/patchloom/pull/2281)).
- **Mixed flow and block aliases dumped the file.** A flow
`[*shared]` next to a later `- *shared` no longer rewrites the
whole document. Merge-key walks stop at depth 128 ([#2267](https://github.com/patchloom/patchloom/pull/2267), [#2265](https://github.com/patchloom/patchloom/pull/2265)).
- **`apply_patch` delete looked unchanged.** An empty-hunk git
delete (`deleted file mode`, no hunks) now reports
`changed: true` and empty `new_content`. Regular files are
snapshotted for undo. Symlink, FIFO, and socket snapshots stay
empty so target bytes are not copied into the result ([#2287](https://github.com/patchloom/patchloom/pull/2287), [#2289](https://github.com/patchloom/patchloom/pull/2289)).
- **Hunked delete unlinked first and dropped leftover lines.** A
`+++ /dev/null` patch with minus hunks now applies those hunks
before unlink. Leftover text is written back. A stale minus is
`ambiguous` (exit 5) and the file stays ([#2294](https://github.com/patchloom/patchloom/pull/2294)).
- **Add-only hunks wiped a symlink target.** Content patches load
the symlink target instead of treating every special path as
empty. Empty-hunk delete snapshots stay empty ([#2293](https://github.com/patchloom/patchloom/pull/2293)).
## Numbers
| Version | 0.31.0 -> 0.32.0 |
| Focus | YAML merge edits, apply_patch delete, `doc_keys` / `doc_len` |
| Tests | 4800+ (3268 unit + 1553 integration + 10 PTY) |
## Upgrading
- **Agents:** `doc keys` / `doc len` on a wildcard or predicate
(`items[*]`) is `ambiguous`, even when there is one match. A
missing file is `not_found`. Blank YAML keys/len/get treat the
document as `{}`.
- **Library hosts:** `api::doc_keys` and `api::doc_len` are new.
`apply_patch` empty-hunk delete now sets `changed: true` and
empty `new_content`. Hunked `+++ /dev/null` applies minus lines
first; leftover text is a write, not an unlink. Content patches
follow symlink targets. Empty-hunk delete snapshots of symlink,
FIFO, and socket stay empty.
- **MCP / `--contain`:** a leftover rewrite through a workspace
symlink that points outside the workspace is rejected. CLI
without `--contain` still follows the path the user passed.
- Install from crates.io, npm, Homebrew, or Scoop after the tag
ships. On Windows, Scoop is recommended; winget may need
`winget source update` after Microsoft publishes; Chocolatey can
lag while moderation runs.
## Full changelog
https://github.com/patchloom/patchloom/compare/patchloom-v0.31.0...patchloom-v0.32.0