needs_review is true for any non-empty stack so end-of-turn inject
keeps firing under synthetic_tool. Message history keeps only the last
todo-nag tool pair (dedupe by todo-nag- tool_call_id).
Merge release into ci.yml: tag pushes run check then publish (needs:
check). Remove standalone python-publish so PyPI never ships on red CI.
Retag (delete+push v*) still retriggers the pipeline.
Remove system strategy (legacy maps to developer). synthetic_tool still
forges the call but uses real stack text as the tool result, and now
yields ToolCall/Result events so the CLI flushes and does not glue nag
text to the next assistant stream.
Split tags: [TODO OPEN WORK] for pending/in_progress (undone work) vs
[TODO HYGIENE] for all-terminal leftover groups. End-of-turn review lists
open titles; tool docs stress open items as unfinished work.
After setsid(), ioctl(TIOCSCTTY) (or reopen slave) so the session leader
has a real controlling terminal. Live-tested: open_pty([sudo,echo,test])
shows a password prompt; ask_into_pty + read_pty yields test with exit 0.
Denylist hits ask the user (default deny, timeout) instead of only hard
rejecting when a policy hook is installed. Independent of YOLO soft-confirm;
session grants skip re-prompt for the same basename. CLI installs the hook
via install_cli_limit_hooks.
Prompt the human (optional no-echo secret) and write only to the PTY.
Tool results never include the answer so secrets stay off external APIs.
Empty/Ctrl-C cancel without writing; submit defaults to trailing newline.
Map CancelledError and TimeoutError from models() to RuntimeError so
merged_model_choices falls back to config/cache. Stub remote fetch in
/provider unit tests so they never hit the network.
Prefer $VISUAL then $EDITOR (blocking). Without either, fall back to
xdg-open / open / startfile (non-blocking) for config paths only.
/edit stays blocking-only so the temp buffer can be re-read.
Default still replaces first match only. Report how many matches were
found, how many replaced, and remaining hits so agents can raise
max_replaces or narrow old_string.
Unset/empty url still maps to durable user-data chat.db.
Explicit :memory: is not rewritten; CLI warns when not quiet.
DatabaseConfig.url default is None; engine treats None as memory.
Inject turn-start [TODO REMINDER] for non-empty stacks; rewrite end-of-turn
[TODO OPEN] copy so open items read as unfinished work. needs_review now
always true while open items remain (even if todo_* ran this turn); terminal-only
stacks still need review if untouched. Update tool docs and tests.
Only fetch remote catalog when interactive model pick needs it; otherwise
use config/--model/session and warm Tab cache in the background. Cap list
fetch at 5s so a dead API cannot hang startup.
asyncio signal handlers freeze ContextVars at install time; reinstalling
while allow_task_cancel was still False left cancel permanently disabled.
Use a process-level prompt depth counter and reinstall only after depth=0.
Complete /todos actions and todo ids, session ids for /resume|/delete
(from cache after /sessions), /rounds hints, and --flags. Pass prior
tokens so multi-arg completion works.