Releases: dsaad68/ripple
Release list
0.7.0
Added
-
/config→ Lazy Tools: choose which tools are worth prefilling. A new tab with the feature
switch, the retriever, how many matches a search returns, and a core / auxiliary tier per toolset
and per configured MCP server. Core tools are in the model's prompt from the first token and are paid
for on every query; auxiliary tools are not in the prompt at all - the agent finds them with
search_toolsand then calls them normally, so they cost nothing until they are needed, at the price
of one extra round the first time. The tab carries a short explanation of that trade, and every row
below the switch is visibly locked (and says why) until the feature is on.Off by default, and stored in
settings.jsonundertoolPolicy(toolSearch,
auxiliaryMiddleware,auxiliaryTools,coreMCPServers,toolSearchModel,toolSearchLimit), so
an existing project is unaffected until you open the tab. The MCP tier lives there rather than in
mcp.json, which may be a shared.mcp.jsonthat other tools read. -
Retriever choice, with its download state. Space cycles
lexical (no model)→ColBERT 350M (8-bit)→ColBERT 350M (bf16), each showingreadyornot downloaded, 410 MB. The ColBERT
encoders score every query token against every tool token (late interaction), which reads intent
considerably better than term overlap; lexical needs no model at all. Both models appear in/model→
Local like any other, so they can be pulled ahead of time (ripple model pull mlx-community/LFM2.5-ColBERT-350M-8bit) and deleted. They can never be selected as a planner. -
The launch banner reports lazy tools with a
tool searchrow next tomain agent/vision,
naming the retriever and how many tools are held back (ColBERT 350M (8-bit) · 18 tools on demand).
The count comes from the live agent, so a toolset tiered auxiliary but also disabled is not counted as
available. No row when the feature is off. -
/toolsand/mcpshow each tool's tier. A filled●for a core tool, a hollow○plus an
[auxiliary]tag for one the agent has to search for, and a note on a toolset that is entirely
auxiliary;/mcpshowstier: core|auxiliarybeside each server's approval mode. Without this an
auxiliary tool looked identical to a core one, which made a configured tier indistinguishable from a
setting that had been lost.
Changed
-
Every
/configtab says what it is for. Each one now opens with a blue ⓘ box naming what that
tab governs and the trade-off you are making there - what a capability costs in prompt tokens, why
a container is slower than the local shell, why the compaction threshold rather than the model's
window is what keeps a session inside your memory, that the prefill cache is pure disk-for-speed.
Only Lazy Tools had one before, as plain grey text; the rows' own summaries are unchanged. -
/model→ Local and Remote are the same view now. Local was a flat twenty-one-row list with the
family repeated on every row, the repo id printed for all of them, no search, and nothing about the
two numbers that decide whether a model fits. It has the Remote tab's two levels instead: model
families first - split into LLM and Embedding, because a retrieval encoder has no LM head
and picking one as a planner only fails at load - then that family's models when you press enter,
under a heading per role (Text, Vision, Text + Vision for a unified VLM like Ornith
that plans and sees images). A family is the model line, so LFM2.5's vision conversions sit
inside it under the Vision heading rather than in a family of their own.Each model row is one line of aligned columns: ✓ on disk / ○ not yet, the weight format, the
download size, the context window, and the tokens one turn may generate. The Hugging Face
id, what the model is for, and the "default" note move to a subtitle under the highlighted row,
which halves the list's height. Above it, the same context line the Remote tab carries. -
Remote model rows carry what Local's do. The same ✓/○ marker, context window and output budget,
in the same cells, grouped by the same role headings - so comparing a free remote model with one
you could download is reading across rather than translating. Where a local row prices itself in
gigabytes a remote one is simplyfree; the output budget comes from the catalog's
max_completion_tokens, newly decoded. -
Every list overlay says what it is.
/model's three tabs,/toolsand/mcpopen with the
same blue ⓘ box the/configtabs carry - what the list is, and what enter does to a row (which on
Local and Remote changes as you drill in). -
The Sandbox tab says it needs Apple Containers. A second amber ⚠ box under the explanation,
titledneeds apple containers: the sandbox runs on Apple'scontainertool, which is not part of
macOS, and nothing on the tab hinted that its one switch depends on something you have to install.
It names the install andcontainer system start, and spells out what happens without it -
failoverfalls back to the local shell, so commands still run, just unsandboxed. The README and
docs carry the same prerequisite. -
Lazy tools is flagged experimental. Its
/configtab opens with an amber ⚠ box titled
lazy tools - EXPERIMENTAL!rather than the blue ⓘ the settled tabs carry, and the text leads with
why: a tool the model cannot see is a tool it may not think to look for, so a tiering that suits
one project can quietly change how the agent behaves in another. The docs and README say so too. -
The Local tab is searchable, like the Remote one. It carries the same bordered input: type to
narrow the list, backspace to edit, ctrl-u to clear. The query matches a model's name, family, id,
weight format and role, sothinking,gemma,4-bit,visionandembeddingall work, and the
highlighted model stays highlighted as the query is refined. esc clears the query before it
closes the overlay. Because printable keys are now the search, removing a model is ctrl-x, not
x. -
The banner wraps instead of clipping. In a narrow terminal the left pane cut its values off at
an ellipsis -tool search ColBERT 350M (8-bit) · 35 tools o…,available mcps: deepwiki, …-
which is exactly the text the banner exists to show. Values now wrap onto continuation lines
indented under the label, and when the label leaves under ~18 columns beside it (a 58-column
terminal) the value takes the whole pane on its own lines rather than being broken mid-word. -
The banner and status line name the model family-first.
LFM2.5 · 1.2B Instructrather than a
bare1.2B Instruct, which said nothing about which 1.2B once several families were downloaded.
Same in the vision row and the model-switch notes. -
The Select tab's model picker and
ripple model listcarry the same facts. Picking a main agent
or vision model shows each local option's purpose, weight format, size and context window;ripple model listis grouped by family and lists the context window and output budget alongside the size. -
Lazy tools says what it costs on a small planner, and which toolset to move first. The
/config
tab and the docs now warn that the feature wants a capable planner - the smallest models search less
reliably and one was seen answering from a tool's description instead of calling it, inventing a note
it had never read (fixed upstream in DeepAgents, which now tells the model after every search that it
received definitions rather than results). Both also namefilesystemas the toolset worth making
auxiliary first: a small planner surface-matches the request against the schema in front of it, so
"list my apple notes" reaches forlsand "read my clipboard" forread_file, and taking those out of
the prompt removes the wrong answer instead of arguing with it - 3/8 to 4/5 on a 2.6B, after three
rewrites of the prompt had barely moved it. SeeSTEPS/ISSUES/tool-search-small-planners.md. -
--modelno longer accepts a retrieval encoder. Planner ids are validated against the language
catalog rather than the whole model catalog, so a ColBERT id is rejected up front instead of booting
into a model that cannot load.
Fixed
- The context meter read far below the truth. The status line's percentage was a running tally of
what the UI watched stream past - the user's prompt, plus one per generated token - so it counted
neither the tool schemas (paid on every request, and never streamed) nor any tool result (a file
read, shell output, a search), which is most of a real context. An empty session showed 0% when the
prompt already cost thousands of tokens, a turn that read a large file barely moved the needle, and
automatic compaction fired at what looked like a fraction of the window./freshdidn't reset it
either. The meter is now measured from the agent - the newReactAgent.contextTokens(threadId:),
the same number the compaction trigger tests itself against - after every turn, compaction, model
switch,/configrebuild and/fresh, and seeded at launch (so a resumed session opens with its
real size). Per-token nudges still move it mid-turn; the measurement settles it at the end. This is
the behaviour the compaction docs already described.
0.6.0
Added
- A
/configContext tab sets when the conversation is compacted, cycling 20-90% with
space and showing what the threshold costs on the loaded model (20% - 52k tokens). Persisted as
compactionPercentinsettings.json(default 80, accepted range 10-99, project settings then
~/.ripple). Each model now reports the context window its own card documents instead of a
pre-shrunk one - 131,072 on LFM2.5-2.6B, 128,000 on 8B-A1B and Gemma 4, 262,144 on Ornith and
Qwen3.6 - so this threshold, not a smaller declared window, is what decides how large a
conversation may get. It matters most on those large-window models: 80% of 262k is past what a
laptop will carry, so lower it there and on any memory-tight machine. - Tools that ran at the same time are marked
∥Non their cards. A round's read-only tools
(grep,ls,tree, reads,git_*) now execute concurrently in DeepAgents, but three cards
each reading 0.1s are indistinguishable from three sequential calls - the round costs one wait
instead of three and nothing said so. The marker rides the card's top border next to the
duration, in the accent color, and shows the size of the group. A call that ran on its own shows
nothing, so ordinary rounds are unchanged. stream-jsonlines carrycallID, andtool_startedlines abatchID. A round's parallel
calls interleave - threetool_startedforread_file, then theirtool_completedlines in
whatever order the reads finish - so a consumer must pair oncallIDrather than onname.
batchIDis shared by the calls that ran together and absent from those that ran alone.
Changed
- Vision is off by default; turn it on in
/model's Select tab. Thevisionsubagent is a
second model to download, load and keep resident, and most sessions never delegate a screenshot
to it - so a fresh project now starts without one and fetches no VLM. A preset still suggests the
VLM that pairs with it; the Select tab offers that suggestion rather than enabling it unasked.
Projects that already setvisionModelinsettings.jsonare unaffected. The banner reports
vision noneuntil a model is picked, andripple model download defaultfetches the planner
only. - deepagents-swift 0.5.0 -> 0.6.0. Brings the round's parallel tool calls, the search tools no
longer reporting a truncated walk as "no matches", the agent being told which folder it works in,
a run never ending on an empty answer, and each model reporting the context window and output
budget its card documents.
Fixed
- A failed tool call is drawn as failed. Tool cards showed a green success tick on calls that
had done nothing -read_filegiven a URL rendered as ✓ besideError: no file at "https://…"-
because most built-in tools return their errors rather than throwing, and the runtime reported
those as completions. Ripple's rendering was already right; it was being told the wrong thing.
Fixed in DeepAgents (ToolOutput.failure), so the card, the∥Ngrouping and thestream-json
tool_failedlines now agree with what happened. - A tool's result reaches the card it belongs to. The transcript matched a result to "the last
unfinished step", which was unambiguous only while a round's tools ran one at a time. With
several open at once it attached results, streamed progress and failures to whichever card
happened to be last. Steps now route on the tool call's id, falling back to the old rule for a
step restored from a saved session, which has no call to name.
0.5.0
Added
- A Cache tab in
/config, for the on-disk prefill cache. The Prefill cache toggle moves here
from Capabilities, and joins two limits and a listing of what the store is actually holding:
Snapshots per model (2/4/6/8/12) and a total Size limit (1/2/4/8/16 GB, or no limit),
both cycled withspace, plus a row per model showing its size -xdeletes that model's saved
prefixes, or all of them on the "All models" row. Lowering a limit prunes immediately rather than
at the next save. Persisted asprefixKVSnapshotsPerModelandprefixKVMaxGigabytesin
settings.json, and honored by headless runs.
Fixed
/mcpgrouped tools by name prefix, so two similarly named servers showed each other's
tools. The dispatch prefix is normalized, soparallel-searchandparallel_searchboth yield
parallel_search__and matching on it cannot tell their tools apart. Grouping now asks the tool
which server contributed it (deepagents-swift'sServerScopedTool).
Changed
- deepagents-swift 0.4.0 -> 0.5.0. MCP tool names are now normalized in both directions, so a
hyphenated server is reachable: aparallel-searchserver's tools dispatch as
parallel_search__*, and a call the model spells differently still finds its tool./mcpand
/toolsshow the normalized names.
0.4.0
Added
- LFM2.5 2.6B in the catalog, the
/modelpicker, and--model- a general-purpose 2.69B
instruct planner in four precisions:LiquidAI/LFM2.5-2.6B-MLX/mxfp4(~1.6 GB),/mxfp8
(~2.8 GB),/8bit(~2.9 GB) and/bf16(~5.4 GB). It runs at its full 128k context window and
the card'srepetition_penalty 1.1. It reasons before answering, and that reasoning is surfaced
on Ripple's separate reasoning channel rather than mixed into the reply. No new DeepAgent preset -
select it with--model <id>or the/modelLocal tab. - Model ids can now name a precision subfolder. LiquidAI publishes all four 2.6B precisions in
one repo, so those ids carry a third component (LiquidAI/LFM2.5-2.6B-MLX/mxfp4). Each precision
pulls, lists, and removes independently;ripple model pullon the bare repo is rejected, since
it names eight precisions rather than a model.
Changed
ripple model pull <precision>downloads only that precision (previously the glob would have
matched every precision in a shared repo), andripple model rm <precision>removes only that
one - reclaiming its disk space while leaving any sibling precisions installed and loadable.
0.3.0
Added
- New on-device reasoning models in the catalog, the
/modelpicker, and--model:- Ornith-1.0-9B (
mlx-community/Ornith-1.0-9B-4bit/-8bit) - plans with<think>
reasoning and native tool calls, and sees images, so it appears in both the planner and
vision pickers plus a new DeepAgent (Ornith) preset that uses it for both roles. - Qwen3.6 (
mlx-community/Qwen3.6-27B-OptiQ-4bit~20 GB,Qwen3.6-35B-A3B-OptiQ-4bit
MoE ~24.7 GB) - the strongest local planners in the catalog; text-only. - Gemma 4 E4B (
mlx-community/gemma-4-e4b-it-8bit~9 GB,gemma-4-e4b-it-OptiQ-4bit
~7.5 GB) - reasons in Gemma's thought channel with native tool calls; a new
DeepAgent (Gemma 4) preset pairs it with the LFM2.5 VLM for vision.
All run with their model cards' recommended sampling and a 40k on-device context window.
- Ornith-1.0-9B (
- Prefill cache. The agent prompt's computed state is reused across rounds, queries, and now
processes - the base snapshot persists to disk, so a freshripplelaunch resumes it instead
of re-prefilling the ~10k-token system+tools prompt (cold prompt processing ~14 s → ~0.2 s
measured on Ornith 9B). Toggleable in/config▸ Capabilities as Prefill cache
(prefixKVCacheinsettings.json), honored by the REPL and headless runs. - Apple Notes tools. The agent can list, read, create, and update Apple Notes
(apple_notestoolset; writes are approval-gated, reads are not). /toolsbrowser - a two-level browser of the agent's tools grouped by toolset, with each
tool's description, parameters, and a[needs approval]badge.rippleworks in its launch directory. Filesystem tools and the@picker root at the
directory ripple was started in, and each session's transcript is written to
.ripple/sessions/inside it (--log <dir>overrides).- Bordered three-choice approval prompt (Approve / Reject / Always allow, arrow keys or
a/r/A) and a gradient ASCII-art launch wordmark.
Fixed
- Failures are never silent. A turn that dies mid-generation ends with a red
✗ turn failed - <reason>line under whatever streamed (the loader's real reason included),
instead of an empty answer. A broken planner no longer keepsripple chatfrom starting:
launch falls back to the default model when it's on disk, or opens on the chosen model anyway
and retries on the first message - either way a transcript note says what happened. A failed
/modelswitch notes the failure and keeps the current planner. Headless runs print the
loader's recorded reason and exit non-zero. - Download progress is real. Multi-GB pulls no longer sit at 0% (the hub's Xet transport
reports no incremental progress; the bar now blends live in-flight bytes), the/modelLocal
tab draws its progress bar inside the panel (it was hidden behind the menu) withescto
cancel, and a cold (re)load names its phase -loading <model> into memory…,
prefilling the prompt…- instead of a bare "working…". - The tokens/sec readout measures real decode speed - every generated token (reasoning +
answer) over active decoding time, excluding prefill, tool runs, and round transitions. - A turn renders in the order it happened. Reasoning / tool / plan / answer blocks keep
their streamed sequence instead of being grouped by type. ask_user(and every tool with nested array/object parameters) works on the Ornith,
Qwen3.6, and Gemma 4 planners - tool schemas are now passed into generation so nested
values arrive typed.
0.2.5
Added
- AWS Bedrock API keys (bearer-token auth). A
bedrockmodel can now authenticate with an Amazon
Bedrock API key instead of AWS SigV4 credentials. Put the token in the model'sapiKeyfield (e.g.
"$AWS_BEARER_TOKEN_BEDROCK") and set abaseURL; requests are then sent with
Authorization: Bearer <token>. Resolution order isapiKey-> theAWS_BEARER_TOKEN_BEDROCK
environment variable -> SigV4 access-key credentials, so existing SigV4 setups keep working
unchanged. See the Bedrock section of the remote-models docs for both configurations.
0.2.4
Fixed
- Up/Down arrows move between the lines of a multi-line prompt. In the
ripple chatinput box the
arrow keys now move the caret one visual row up or down -- across hard newlines and soft-wrapped rows
alike -- and fall back to prompt-history recall only at the top/bottom edge (the familiar shell
behavior). The column is preserved per press. Single-line and empty input keep history recall, and
the ask_user card's choice navigation is unchanged.
Packaging
- Homebrew tap.
rippleis now installable as a prebuilt Apple Silicon binary -- no Xcode
required:Each release is built on a self-hosted runner, attached to the GitHub Release as abrew install dsaad68/tap/ripple
macos-arm64
artifact, and the tap formula is bumped automatically. Building from source via
brew install --HEAD ./Formula/ripple.rbstill works.