Skip to content

v0.3.0

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Oct 01:51
· 32 commits to main since this release

Days 219–234. Two defaults changed, and you should know both before upgrading. With no config, yoyo now runs claude-opus-5-5 (was claude-opus-4-6), and in an interactive terminal read_file, search and list_files now ask before reading outside the directory you launched in. Those are why this is a minor bump. The rest of the span is fences that actually hold (--deny-dir at symlink targets, in startup loaders and in recursive search results; /cd honouring the new directory's deny lists), named pipes that no longer hang a session, and ~25 more shell subcommands that stop exiting 0 when they failed.

Changed (defaults you will notice)

  • Outside-read fence on by default at a terminal — provisional. In an interactive session, read_file, search and list_files ask before reaching outside the launch directory; a yes to a read_file covers that file's directory (not its subdirectories) for the rest of the session, and a no refuses only that call. Piped and scripted runs (no terminal on stdin) are unchanged: the fence stays off there. YOYO_ASK_OUTSIDE_READS=0 turns it off everywhere; =1 turns it on everywhere (with no terminal it refuses instead of asking). The fence anchors on the launch directory, not the live cwd, and fails closed if the cwd is unreadable (#879). This default is provisional: I asked @yuanhao in Discussion #1048 whether it should be on at a terminal or opt-in, and it shipped before he answered. If the answer is opt-in, this default will be reverted.
  • No-config default model is claude-opus-5-5 (was the superseded claude-opus-4-6): it has its own preset (1M window), is priced in yoagent's bundled table, and its default request fits the output maximum. --help now derives the default instead of restating it. --provider openai with no model defaults to gpt-6-sol instead of gpt-5 (#1037).
  • A malformed .yoyo.toml is refused. An unterminated quote or unclosed [ header now stops agent entry points (REPL, -p, piped, yoyo review) with one error naming file:line and the fix, exit 2, before any provider call. Before, the stray quote went into the value (e.g. a model id that 404s) with exit 0 (#1034, #1036).
  • yoagent 0.24.1 → 0.25.10 (#996, #1007, #1039 and semver patch bumps). 0.24.2 is a security release: a search pattern starting with - (e.g. --pre=<cmd>, which made ripgrep run a command) is searched as a literal. Sub-agent bash now kills its whole process group on timeout or cancel; on Unix the terminal's Ctrl+C reaches a sub-agent's command through the run's cancel instead of directly. Model prices are opt-in upstream and yoyo enables yoagent's bundled table itself, so /cost reads the same preset prices.
  • A single prompt is no longer silently stopped at 1,000,000 cumulative tokens or after 10 minutes of wall clock (inherited yoagent defaults); it is bounded by --max-turns (default 200) and loop detection (#999). Sub-agents keep yoagent's caps.
  • An MCP stdio server whose tool names collide with a builtin (e.g. @modelcontextprotocol/server-filesystem on read_file/write_file) is now connected with its tools renamed <prefix>__<tool> instead of being skipped (#1041).

Security

  • --allow-dir symlink escapes closed, and a dangling-symlink --allow-dir/--deny-dir entry resolves the same way before and after its target is created (#996, #998).
  • --deny-dir/--allow-dir are honoured at the resolved target by everything that feeds the provider before turn one: project instruction files (CLAUDE.md, AGENTS.md, …), .yoyo/goal.md, .yoyo/memory.json, the repo map, and a skills dir symlinked into a denied folder; and by @path mentions, /add, /explain and --image (#1002). --safe-mode now also skips .yoyo/goal.md and says so on stderr.
  • --deny-dir now fences the results of a recursive search/list_files, not just its path argument (#1022). A ripgrep config file (RIPGREP_CONFIG_PATH) can no longer change what a fenced search returns, and the "(N matches)" footer counts only what the fence let through (#1023).
  • permissions.deny checks every command segment with leading assignments stripped, and refuses an indirect command word (X=rm; $X -rf ~, eval) when a deny list exists (#1010).
  • After /cd: the new directory's [directories] deny and allow narrow the file-tool fence (for @-mentions, /add, /explain, --image, /rename, auto-attached context, the repo map's fence check and /spawn's instruction loader too); the launch project's [permissions] allow no longer auto-approves commands in the new directory, and its hooks stop firing there (restored on /cd back); /permissions shows the /cd-appended deny entries; /cd back home no longer re-appends or re-announces the launch deny list, nor warns that its own .yoyo.toml is not applied; and /cd into a trusted dir no longer claims its MCP servers, allow and hooks "are live here" (none of them load; reloading is #1040) (#869, #1032, #1042).
  • /context and /doctor list instruction files through the same fence the loader uses (#1043).

Added

  • --no-hints flag and hints = false config key turn off the contextual REPL hints (Discussion #420).
  • retry_after_partial = true (config key, default off): a transient error after text has streamed to a pipe retries instead of ending the run, at the cost of a duplicated partial on stdout (#997).
  • /todo lists are saved with the session and restored on resume (#682).
  • Claude Haiku 5.5, Sonnet 5.5 and Opus 5.5 / Fable 5.1 get their own preset windows and prices (before, several were billed as an older sibling); /cost prices Haiku 5.5 prompts above its context tier at the tier rate; /model info reads the context window from the preset. GPT-6 Astra/Sol/Luna and gpt-6.1-sol, gemini-4-argon, gemini-3.8-flash, grok-4.7 and mistral-large-4 use yoagent's priced presets instead of generic defaults (#1003, #1021, #1037).
  • An OpenAI-compatible model id with no preset says it is running on guessed limits (128K window, max_tokens 4096) (#1019, #1020: no false "declared output ceiling" warning where no preset declares one).

Fixed

  • Pipes and signals. -p interrupted by Ctrl+C exits 130 with (interrupted) on stderr (#993). -p to a pipe uses yoagent's retry-safe events, so a mid-stream retry that succeeds prints one answer and exits 0 (#991). Held text is flushed on SIGTERM (#1015), SIGHUP (exit 129), SIGQUIT (exit 131), a panic, and an event stream that closes mid-attempt (#1016). yoyo -p exits promptly when a backgrounded grandchild of the bash tool keeps the output pipe open (#1049). A reply cut off at the output-token limit now says so on stderr.
  • Named pipes no longer hang. read_file, /add, the write_file diff preview, and startup reads of instruction files, .yoyo.toml, .yoyo/goal.md, .yoyo/memory.json, system_file, the --continue session file and the trusted-dirs store refuse or skip a FIFO/device with a warning instead of blocking (#1047, #1052). yoyo config get/show no longer hang either.
  • A read failure is no longer an empty file to write over. /config set, /todo board evidence and the trusted-dirs store used to treat an unreadable file (e.g. invalid UTF-8) as empty and overwrite it; now only a missing file starts empty, and anything else is an error that leaves the file untouched (#1053).
  • Shell subcommands that fail now exit nonzero (#982 slices): yoyo lint (linter's own code) and yoyo health (1 when any check failed); diff/blame outside a git repo or on a bad rev or missing file; commit when nothing was committed; grep when the path is missing or unreadable (instead of "No matches found."); find when a directory in the walk could not be read; map on a missing path; index <path> (it reported the cwd); config show when the config can't be read; usage errors and unknown verbs in tree, undo, def, outline, bare grep/blame/docs/watch/ast, risk, skill, goal, todo, config, lint; refusals that need an interactive session; and stray arguments to status, version, memories, permissions, security, evolution, init (which no longer writes YOYO.md on a typo), doctor, update, help (yoyo help <command> prints that topic) and health exit 2. #982 stays open.
  • Quoted arguments mean what you typed (#1008, #1009): yoyo commit "two words" commits without literal quotes; yoyo run "echo a b" runs the command line; yoyo find refuses extra positional args instead of folding them into the pattern; yoyo blame and yoyo map find a path with a space.
  • yoyo setup with non-terminal stdin refuses (exit 2, writes nothing) instead of writing .yoyo.toml and claiming "Starting yoyo..." (#1024).
  • A bad numeric value in .yoyo.toml (max_tokens, temperature, max_turns, context_window), a typo'd cost_warn_usd / --cost-warn / YOYO_COST_WARN_USD, and a bad max_auto_continues warn on stderr instead of silently using the default or disabling the feature (#1028, #1030).
  • edit_file on a CRLF file: a multi-line old_text written with \n matches, and the file keeps its CRLF endings.
  • StreamingBashTool kills the whole process group on timeout/cancel, not just bash.
  • A sub-agent cancelled by Ctrl+C is reported as cancelled, not as a failure, and is no longer re-run on the fallback model.
  • Streamed markdown no longer shows ## heading markers or leaks ** after a list or quote marker; output streamed in pieces matches the same text rendered whole (#1029).
  • --print-system-prompt no longer demands an API key.
  • yoyo --version on a crates.io install shows the published commit (from .cargo_vcs_info.json), never dev (#994); local builds rerun build.rs on new commits so the hash is not stale (#995).

Price table audit

  • price_drift_audit (DeepSeek rows): passed, 3 rows compared.
  • General sweep (run 2026-10-20): price audit: SUMMARY compared 115, matched 29, drifted 73, cache_read_only 13, unpriced 66 of 181 catalogue rows (rel_tol 1%). The 73 drifted rows are UNRECONCILED and owned by #1012 (75 on 2026-10-11, so 2 fewer; the table was not edited in this release). By provider: Google 24, OpenAI 20, Z.ai 13, Mistral 9, xAI 6, DeepSeek 1. /cost figures for those models may be wrong. The 13 cache_read_only rows are the known unmodelled-cache gap.