scoot 0.11.0
- One-shot
--jsonis exactly one JSON object (R18). The JSON path used the interactive UI, so plan updates and approval prompts printed to stdout before the final object, and a hook-blocked prompt produced no JSON at all. A quiet one-shot UI now sends every diagnostic to stderr and declines an approval it cannot ask, and stdout carries the single result object on every exit path. - Untrusted terminal control sequences are stripped (R21). File diffs, tool output, replayed transcript, and model output (streamed or buffered) had ANSI and control bytes passed through, so a malicious file or reply could recolour the screen or hide an approval preview. Such text is now sanitised before display, keeping tabs and newlines, with split escapes handled across stream chunks.
- The router cannot loop between two dead models (R16). Rules and the classifier ignored the failed-model set, so fallback could alternate A to B to A while each attempt burned a step. Model selection now skips every model that already failed this turn, and fallback is bounded independently of the step count.
- "Allow this path" lasts one call (R20). The one-shot scope choice permanently added the path to the session grants, so "this path" behaved like "this session". It now lasts a single tool call and is asked again next time; the directory and anywhere choices still last the session.
- ripgrep errors are not "no matches". An invalid regex or an I/O failure (ripgrep exit 2 or more) is now surfaced as a search error instead of an empty result.
- Numeric settings are validated.
SCOOT_TIMEOUT,SCOOT_MAX_STEPS,SCOOT_COMPACT_AT, andSCOOT_IMAGE_MAX_BYTESnow give a clear config error with sensible bounds instead of a raw traceback on a bad value, andAGENTS.mdis read with a size cap. - One atomic JSON writer. Credentials, preferences, and sessions share a single writer that writes through a uniquely named temp file and an atomic rename with owner-only permissions; credential updates are no longer truncated in place, and temp names no longer collide between processes.
- Subprocess output is bounded (R15).
run_shell, ripgrep, and hook output were buffered in full bycommunicate()before truncation, so a runaway command could exhaust memory. Each stream is now drained by a reader thread into a buffer capped at 512 KB, with the process-group cancellation and timeout unchanged; a command that never stops printing is killed at the timeout instead of buffering without end.
Install: pipx install scootcli && pipx ensurepath, or curl -fsSL https://raw.githubusercontent.com/sergenes/scootcli/main/install.sh | bash, or download scoot.pyz below. Upgrade: pipx upgrade scootcli.