- The bash shim runs bun as a job and forwards SIGTERM/SIGINT/SIGHUP (bash
holds a signal until a foreground child exits); the .ts kills the in-flight
vendor's process group on the way out (runExternal exposes the group kill
through onSpawn), so a hook the host terminates cannot leave the vendor
running with the prompt on its stdin.
- The tolerant stdout parser tries every complete top-level object (bounded)
and takes the first carrying a string additionalContext, so a banner with
braces or quotes, or a progress object, no longer costs the answer.
- git runs with LC_ALL=C and the not-a-repository check is anchored to the
start of its message: a localized git or a repository path containing the
phrase can no longer flip the lookup.
- The rate limiter remembers up to 32 live keys, so alternating failures cost
two lines, not one per prompt.
- Unicode format characters (bidi overrides, zero-width spaces) are stripped
from vendor text at egress; the zero-width joiner stays for emoji.
- A killed child (timeout, ENOBUFS) resolves on exit without the stdout drain,
and the post-kill grace is 100 ms, so the timeout outcome fits the reserve.
- The ledger size warning, which the host discards from an exit-0 hook's
stderr, is logged where status looks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The PR's hook exec'd the vendor binary with the full environment and
passed its stdout to Claude verbatim. It is now the house pattern: a
fail-open bash shim over a .ts twin that (1) gates on the memorable_recall
consent key, (2) skips repos whose trust policy is deny or read-only,
(3) scans the prompt (raw bytes and decoded string leaves) and refuses to
hand over a HIGH-tier credential shape, (4) writes a fail-closed egress
receipt naming the local executable it ran, (5) spawns the vendor in its
own process group with an allowlisted environment and group-kills it on
timeout, (6) accepts only a string additionalContext back, caps it at
8 KiB on a UTF-8 boundary and wraps it in the trust envelope, and (7)
records an `output-written` outcome after the stdout write completes.
One deadline clock (4.5 s) undercuts Claude Code's 5 s kill and bounds
both ledger writes through the new lockBudgetMs option on
writeReceipt/writeOutcome (default unchanged).
spawn-bin gains runExternal for external executables (detached group,
stderr drained, stdin EPIPE handled, stdout capped, win32 refused).
The wiring test pins the sink fail-closed and sweeps hosts/.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>