github yologdev/yoyo-evolve v0.1.17

latest releases: day184-00-08, day183-22-18, day183-20-44...
7 hours ago

Days 155–183. If you run cargo with colour enabled, this release is required: watch mode's compiler-error parser was anchored to the start of a line, so a single ANSI escape in front of error[E0308] made it find zero errors — silently, with no warning, for anyone whose terminal or CARGO_TERM_COLOR turns colour on. The same class was fixed for TypeScript. Around that: yoyo learned to sit out a rate limit instead of burning five retries against it, sub-agents survive a dead model instead of dying with it, and a project-config trust boundary means a repository you just cloned can no longer silently grant itself MCP servers, auto-approved shell commands, or hooks. Plus yoagent 0.16.6 → 0.18.1, a pile of correctness fixes in commit-message generation and syntax highlighting, and four commands that worked in the REPL and silently became billed LLM prompts at the shell.

Added

  • --wait-for-reset — opt-in permission to wait out a provider rate limit (up to 6h) instead of giving up, reading the provider's own reset time rather than guessing; also settable as wait_for_reset = true in your config. Default off, because a process that can silently sleep for hours is not a safe default (Day 178)
  • Rate-limit-aware retry — when a provider reports when it will accept work again, yoyo honours that number instead of five capped backoffs against the same refusal, and says when the door reopens instead of failing silently (Day 177)
  • Sub-agent model fallback — if the session's model is unavailable, a dispatched sub_agent retries once against your configured fallback model instead of dying. Announces the switch; never fires on auth failures, rate limits, or a deliberate refusal (Day 180)
  • Sub-agent failure diagnostics — the parent now receives the error's class, HTTP status and model configuration instead of an opaque summary string, so it can tell "model unavailable" from "the delegated work failed" (Day 180)
  • Partial sub-agent results are labelled — a sub-agent stopped by its turn budget returns Ok with a truncated answer; that result is now annotated as partial rather than reading as finished work (Day 182)
  • Project-config trust boundary — a project-local .yoyo.toml can no longer silently start MCP servers, grant permissions.allow, or run shell hooks, and .yoyo/goal_verify.md no longer executes on /goal check. yoyo asks once per folder, remembers your answer with --trust-project-always, and names every grant before you answer. A non-interactive run always takes the safe answer (Days 166, 167, 175, 178)
  • Wildcards in [directories]deny = ["*/secrets"] and allow = ["src/*"] now match; previously a wildcard entry matched nothing at all, so a deny pattern silently fenced nothing and an allow pattern locked you out of every file (Day 178)
  • Failed MCP/OpenAPI servers are reported to the model — previously a server that failed to connect left the model with a shorter tool list and no error, so it concluded the capability did not exist and silently worked around it (Day 181)
  • Runaway-loop notice — when yoyo stops a run for repeating an identical tool call, it now says so and states that this was deliberate, rather than stopping with no stated reason (Day 181)
  • Malformed tool calls get one resample — a turn whose tool arguments never assembled is retried once instead of ending the run, bounded and announced (Day 183)
  • CLI doors for /ast and /defyoyo ast '$X.unwrap()' --in src/ and yoyo def <symbol> now reach the real handlers; they used to fall through and run as billed LLM prompts (Day 169)
  • /test forwards its argumentsyoyo test --lib and /test --lib reach your test runner instead of silently running the whole suite (Day 166)
  • A mistyped subcommand is caught, not billedyoyo statsu now suggests the real command and exits, instead of being sent to the model as a prompt with write-capable tools attached (Day 165)
  • /config show names the config files it skipped — first match wins and config files are not merged, so a shadowed ~/.yoyo.toml is no longer invisible in the one command you would check (Day 179)

Improved

  • yoagent 0.16.6 → 0.18.1 — two minor versions of the agent core, including loop detection and context-compaction events yoyo now handles explicitly (Day 181)
  • Syntax highlighting carries state across lines — block comments, multi-line strings, raw strings (r#"…"#) and JS/Go backtick literals no longer mis-colour every line after the first (Days 171, 173)
  • Commit messages generated by /commit describe the diff — the type is chosen by which files carry the most changed lines rather than by whichever file matched first, whole-file deletions are counted at all, and commits over three files name the largest change instead of collapsing to "update code" (Days 174, 178)
  • Hook stderr is bounded before it enters the conversation — a shell hook printing megabytes could previously overflow the context and wedge the session; now capped head-and-tail with the cut marked in band (Day 180)
  • Long diff lines are bounded — a diff touching a base64 blob, a minified bundle or a lockfile hash is one line, so it passed the existing line-count cap and rendered whole into your terminal (Day 179)

Fixed

  • Coloured compiler output parsed to zero errors — watch mode's Rust error parser anchored on error[ at column 0, so any ANSI escape made it find nothing; auto-fix then ran with no errors to fix (#859, Day 182)
  • TypeScript errors missed under --pretty or colour — the same anchoring bug, plus tsc's pretty format (file:line:col - error TSxxxx) never matched any pattern (#861, Day 182)
  • Rate limits classified as fatal client errors — status codes were matched as bare substrings, so retry after Some(14454000)ms contained 400 and read as a terminal error. This disabled backoff and --wait-for-reset for the exact shape they exist for (#852, Day 181)
  • A token-count overflow diagnosed as exhausted creditsprompt is too long: 402134 tokens contains 402, so yoyo confidently told you retrying would not help when the fix was /compact (Day 174)
  • /read and /plan mode did not block git commitgit was in neither the write-verb list nor the destructive-pattern list, so the single most consequential write in your repository passed straight through a mode whose whole promise is mechanical enforcement (#838, Day 179)
  • --allowed-tools and --output-format swallowed the next flagyoyo --allowed-tools --model gpt-5 consumed --model as a value, so it never fired and no warning was possible (#862, Day 182)
  • deny = ["~/.ssh"] never matched anything — a leading ~ was treated as a relative path and joined onto the working directory, so the documented way to fence off your SSH keys resolved to a directory that cannot exist (Day 177)
  • A narrow-looking permissions.allow pattern auto-approved arbitrary commandsgit * main also matched git -c core.sshCommand=<anything> push main, for the whole session (Day 178)
  • Auto-context ignored your directory restrictions — a file yoyo refused to read when the model asked for it was silently pasted into the same API request by automatic context injection (#817, Day 175)
  • Non-ASCII filenames came back as escaped byte strings — every git-derived file list (project context, /tree, /rename, risk scoring) received "src/n\303\244me.rs" instead of a usable path (#863, Days 182, 183)
  • /rename reported no changes — a multi-file rename wrote files and recorded nothing, so the per-turn summary, --output-format json, and the post-prompt watch gate all read it as "nothing happened" (#778/#783/#786, Day 170)
  • /extract could cut a symbol at the wrong line — the brace scanner counted braces inside strings, char literals and comments, so println!("}") ended a block early and left the code in neither file (#770/#771, Days 169, 171)
  • Rust lifetimes broke syntax highlighting&'a str opened a string literal that never closed, so the rest of every such line rendered in string colour (#759, Day 169)
  • /update could not succeed on Windows — a hardcoded /tmp path, a shared extract directory that could read a half-extracted tree from a crashed run, and unzip (which Windows does not ship) invoked for the Windows archive (#756, Day 169)
  • /bg list showed elapsed-since-start as runtime — a job that took 0.2 seconds read ✓ done 1h3m an hour later (#736, Day 165)
  • /revisit add destroyed the candidate list — an unreadable or truncated file read as empty, and the next add overwrote every surviving entry under a green success line; it now refuses. Entries also store the real issue title instead of a permanent (issue #N) placeholder (#740, #741, Days 165, 170)
  • /goal check ran the project's verify command before refusing — the refusal printed after the side effect it appeared to be declining (#754, Day 166)
  • /remember [category:typo] silently stored the malformed prefix inside the note — under a category you did not ask for, with a success line; it now refuses and lists the real categories (#769, Day 168)
  • /ast '$X.unwrap()' src/' searched for the path as part of the pattern — a bare path argument is now refused with the working form named, instead of silently reporting no matches (#767, Day 168)
  • A failed MCP connect reported a wrong server count — the rebuilt agent carries zero external connections, so with three servers and one failure you lost all three and were told you had two. A transient pre-flight failure also disabled the tool-name collision guard entirely, killing the session on turn one (#841, #842, Days 180, 181)
  • The setup wizard silently demoted or shadowed your existing config — saving to a project file demotes a working ~/.yoyo.toml; saving to the user file is shadowed by any ./.yoyo.toml. Both now say so (#816, Day 175)
  • The post-prompt watch cycle ran on turns that changed nothing — after any earlier edit in the session, a zero-change /extended turn ran the full lint→fix→test cycle and told the model "your changes caused failures" about a pre-existing failure (#818, Day 175)
  • The audit log double-counted every tool call — and recorded failed calls as successes with a fabricated zero duration (#751, Day 166)

Don't miss a new yoyo-evolve release

NewReleases is sending notifications on new releases.