github yologdev/yoyo-evolve v0.4.0

latest release: day249-01-55
6 hours ago

Days 234–249. Three defaults changed, and one of them can break a setup that worked. MCP stdio servers and shell hooks now start with your provider API keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, …) unset, so a server or hook that silently relied on an inherited key will fail its own calls until you give it the key explicitly or set YOYO_SUBPROCESS_ENV_SCRUB=0. With no --model, --provider openrouter now runs anthropic/claude-sonnet-5.5 (was anthropic/claude-sonnet-4-6) and --provider google runs gemini-3.8-flash (was gemini-2.5-flash). And yoyo now refuses what it used to ignore: an unknown flag, a mistyped --provider, or a numeric flag whose value doesn't parse exits 2 before anything is sent. Those are why this is a minor bump. The rest of the span is a data-loss guard on write_file, the GPT-6 openai default finally able to call tools, MCP servers that die (or survive Ctrl+C) honestly, and network errors that fail fast instead of retrying for a minute.

Changed (defaults you will notice)

  • Provider keys are unset for MCP stdio servers and shell hooks. A server from --mcp or [mcp_servers.*] (yours or a repo's .yoyo.toml), and every [hooks] command, starts without the provider credential variables; GITHUB_TOKEN/GH_TOKEN are kept. To give a server a key on purpose, put it in [mcp_servers.<name>] env = { KEY = "..." }; to turn the scrub off, YOYO_SUBPROCESS_ENV_SCRUB=0 (or false; any other value, including a typo, keeps it on). The model's bash tool keeps the scrub opt-in (YOYO_SUBPROCESS_ENV_SCRUB=1); /run, /bg and /watch are not scrubbed. @yuanhao decided the MCP half on #1064 (#1064, hooks Day 238, MCP Day 248).
  • openrouter default: anthropic/claude-sonnet-5.5, a dotted id OpenRouter actually lists (it has no dashed Anthropic ids). Every anthropic/… id on openrouter now gets the Anthropic preset's window, output limit and price instead of 128K / 4096 tokens (#1037). If you relied on the old default, pass --model anthropic/claude-sonnet-4.6, which also resolves to its preset now.
  • google default: gemini-3.8-flash (was gemini-2.5-flash, which had no preset and ran on guessed limits); gemini-3.0-pro/flash, absent from Google's model page, left the known list (#1021). GEMINI_API_KEY alone now starts yoyo on google.
  • Unknown or malformed flags are refused, exit 2, nothing sent. An unknown top-level flag names the nearest real one (yoyo --modle claude-haiku-4-5 -p hi → unknown flag '--modle' (did you mean --model?)); before, it printed a warning, ignored the flag and sent the request on the default model, and yoyo log --bogus sent "log" as a prompt and exited 0. Subcommand flags (yoyo diff --stat), anything after --, and a quoted prompt that starts with - are unchanged (#1109). A top-level -- now ends flag parsing and every word after it reaches the prompt verbatim (#1110, #1112, #1113, #1114). Also refused: a mistyped --provider (did-you-mean; before, it sent the fallback key to localhost:8080 for 80 s, #1103), --max-tokens abc / --temperature hot / --max-turns x / --context-window big, and a global flag placed before a subcommand (which used to turn the subcommand into a paid prompt).
  • On --provider openai, the GPT-6 preset ids (gpt-6-sol — the openai default — gpt-6-luna, gpt-6-astra, gpt-6.1-sol) now go over OpenAI's Responses API (/v1/responses) instead of Chat Completions, so tool calling works on yoyo's default openai model. OpenAI documents that Chat Completions does not support function calling with GPT-6 Astra or GPT-6.1 Sol, and allows it for Sol and Luna only at reasoning_effort: none, which yoyo never sent. Every other openai id (gpt-4o, gpt-5, …) still uses Chat Completions. If you point --provider openai with a GPT-6 id at a third-party --base-url, that endpoint now needs /responses. Checked against a local stub server, not against a real OpenAI call. The GPT-6 sub-agent, /side and architect doors use the same wire.

Added

  • write_file refuses to overwrite an existing file the session has only partly read (read_file pages at 500 lines; writing "the whole file" back after page 1 silently deleted the rest). The refusal names the lines read and the two moves: read the rest with offset/limit, or edit_file in place. A page that output truncation cut in the middle no longer counts as read (#1094).
  • Opt-in write fence: YOYO_BLOCK_OUTSIDE_WRITES=1 refuses write_file/edit_file outside the launch directory, in every mode including --yes.
  • An instruction file (CLAUDE.md, YOYO.md, …) over 150,000 bytes gets a loud stderr warning naming the file, its size and its token estimate (#1070).
  • When a stdio MCP server dies mid-session its tools are withdrawn at the next turn, and the model (once) and you are told which server went away, instead of the model calling dead tools (#1041).
  • /cost, /tokens, --output-format json and the --cost-warn tally count delegated sub-agent spend, on its own line beside the per-turn breakdown (#1073, #1108).

Fixed

  • Argv. The shell verbs refuse an unknown dash-led word instead of using it as an operand or ignoring it (exit 2, did-you-mean, nothing runs): changelog, memories, docs, def, find, outline, grep (#1111), commit (--ammend no longer goes into the commit message), review (a mistyped flag is no longer read as a file path or PR number, #1129; yoyo review -- --quick reviews the path --quick, #1130), and the verbs that take no flags.
  • yoyo diff and /diff refuse a flag they do not know (yoyo diff --cahced) with the usage line and unknown flag: --cahced, exit 2, instead of dropping it and showing the unstaged + staged diff with exit 0. -- is accepted as a path separator (#1107).
  • Shell wording. yoyo grep, yoyo def, yoyo outline (#1127, partial), yoyo goal, yoyo todo and yoyo watch print their shell form, not the REPL's /verb; bare yoyo run now prints usage: yoyo run <command> instead of the REPL-only usage: /run <command> or !<command> (neither /run nor ! works at a shell prompt). The same goes for yoyo find, yoyo tree (its usage line and its not-a-git-repository message) and yoyo undo. The REPL's /run, /find, /tree and /undo text is unchanged. Part of #1086; other shell verbs still print their slash form. yoyo doctor's rows and footer give advice that works on the surface they are printed on (#1074, #1075, #1083), and its project-context row names instruction files the fence refused (#1045).
  • Network. A DNS failure on an RFC 6761 reserved name (.invalid, .test, .example, .localhost) stops retrying (#1120); a refused connection to a loopback server fails in seconds and names the URL instead of 70 s of retries; -p network errors print a one-line summary without the REPL-only /retry advice (#1115). The 401 hint names where the key actually came from (--api-key, config, alias env var) (#1062), and a key passed with --api-key skips the first-run setup wizard.
  • Processes. /bg kill and /quit stop a job's whole process group with SIGTERM, a 10 s grace (docker stop's default), then SIGKILL, and report what actually happened (#1077, #1080, #1081). /run, !, /bg run, /watch and the auto-check edit hook stop waiting on a backgrounded grandchild that holds the output pipe (#1063). Stdio MCP servers start in their own process group, so Ctrl+C no longer kills them (#1098), and every live server is closed on exit, bounded so a hung one can't block it (#1099). A bash command that times out returns the output it printed so far. /spawn no longer force-removes a worktree holding uncommitted work and its stale sweep skips worktrees whose worker still runs (#1057, #1097).
  • Deny list and bash guard. With a deny list set, eval "$(...)" of a runtime-assembled command is refused (#1011), except eval "$(<known env emitter> …)" such as ssh-agent when the inner command passes the deny check (#1066). The rm-root guard tracks quotes across lines, so a quoted newline no longer splits a mention into a command (#1068, #1101); guard refusals no longer get a "try a simpler version" hint or a whole-prompt auto-retry.
  • yoyo ast and yoyo map detect ast-grep only when the binary really is ast-grep; on Debian/Ubuntu /usr/bin/sg is util-linux's set-group command, which passed the old --version check (#1131). Shell yoyo ast exits nonzero when ast-grep is missing or the search errors.
  • --output-format json/stream-json escape bidi, zero-width, C1 and DEL characters as \uXXXX (#1092).
  • Auto-memory keeps the newest entries instead of freezing at its cap, stops saving content-free panic headers, and stored content-free entries no longer reach the system prompt (#1106).
  • A Ctrl-C'd tool call reaches the model as "cancelled", with no failure hint (#1061). yoyo undo --last-commit/--all exit 1 when git refuses or outside a repository, and --all names what it could not revert (#1058, #1059, #1065). /pr create on a detached HEAD says so (#1072). /grep finds matches in a single file outside a git repo and searches each of several paths (#1087, #1091). Bare yoyo run, tree/undo usage errors exit 2 (#982).
  • The no-config bedrock default anthropic.claude-sonnet-4-6 runs on Anthropic's published limits, now from yoagent 0.26 presets (#1116, #1123).
  • Images you attach yourself (--image, /add, @path) are now refused before reading if they are over 20 MB, the same limit (and the same "exactly 20 MB is allowed") as the agent's own read_file. Before, the whole file was loaded and base64-encoded: a 300 MB --image used 4.7 GB of memory, then the provider rejected the request anyway.
  • Price table: exact rows for Google (gemini 3.x flash/pro, introductory rates billed by date, the >200K-prompt tier for gemini-3.1-pro-preview), xAI (by the endpoint yoyo calls), Mistral and Z.ai GLM, each checked against the vendor's pricing page (#1012, still open).
  • yoagent 0.25.10 → 0.26.8.

Price table audit

  • price_drift_audit (DeepSeek rows): passed (deepseek-v4-pro is a registered divergence; deepseek-r1/deepseek-v3 are not listed by models.dev, so nothing audits them).
  • General sweep (run 2026-11-04): price audit: SUMMARY compared 114, matched 78, drifted 23, cache_read_only 13, unpriced 61 of 175 catalogue rows (rel_tol 1%). The 23 drifted rows are UNRECONCILED and owned by #1012 (73 at v0.3.0). By provider: OpenAI 16 (gpt-4o-2024-05-13 and the gpt-5.x family billed at a shared 1.25/10 arm), Z.ai 5, DeepSeek 1, Mistral 1. /cost figures for those models may be wrong. The 13 cache_read_only rows are the known unmodelled-cache gap.

Don't miss a new yoyo-evolve release

NewReleases is sending notifications on new releases.