Rift roadmap
July 10, 2026 · View on GitHub
Where rift goes from v0.4.x. Ordered by phase; each phase is shippable on its own. Principles that don't change along the way:
- Local-first. Everything works offline against your own server. Cloud providers become an option, never a requirement.
- Zero tool-calling errors. Every new provider or feature keeps the hardening that made local models reliable (truncation detection, textual tool-call recovery, alias resolution, doom-loop guard).
- One small binary. No runtimes, no daemons. Watch the size budget (currently 9.5MB; tree-sitter grammars are the main pressure).
v0.4 — Agent plan view + trust
The agent should show its plan and ask before dangerous things.
-
Interactive pickers (shipped 0.4.0) —
/modeland/sessionsopen ↑↓/Enter list overlays; direct/model <name>still works -
Elicitation (shipped 0.4.0) —
ask_usertool: the model asks clarifying questions mid-turn; choices reuse the picker, free-text answers go through the input box; headless/swarm runs stay autonomous -
Plan tool + activity-pane checklist (the to-do list)
- New built-in
plantool the model calls to set/update its task list:plan(set=["fix parser", "add test", "run tests"]),plan(done=1) - Rendered pinned at the top of the activity pane:
☑ fix parser,◐ add test(in progress),☐ run tests - System prompt nudges the model to plan first on multi-step tasks and check items off as it goes — also measurably helps local models stay on track
/plancommand to view/clear it
- New built-in
-
Write/bash approval mode
- Today rift auto-executes everything. Add
--approvemode (and config default) wherewrite/edit/bashpause for y/n in the TUI, with a per-session "always allow" memory; deny list stays as the hard floor
- Today rift auto-executes everything. Add
-
Input editing basics — cursor movement (←/→, word jumps, Home/End), insert anywhere, bracketed paste. Today input is append/backspace only; this is the biggest day-one UX gap
-
Load RIFT.md automatically —
/initgenerates it, but the agent doesn't read it back yet. Inject it into the system prompt when present (that's the whole point of the file). Also loads AGENTS.md and CLAUDE.md (the cross-tool standards), concatenated and capped -
Skills (Agent Skills standard, pi/Claude-style) —
.rift/skills/~/.config/rift/skills/SKILL.md files with frontmatter; listed to the model by name+description, bodies loaded on demand via theskilltool; user-invocable as/skill:<name> [task]with palette completion; /skills
-
/config + /approve — view config, edit in $EDITOR with hot-reload of permissions, session-level approval toggle
v0.5 — Command + UX expansion
- More slash commands (shipped 0.5.0):
/retry— re-run the last prompt (after an interruption or bad answer)/stats— session totals: tokens, calls, tool counts, compactions/system [text]— view or override the system prompt/temp <t>·/ctx <n>— runtime knobs without restarting/worktrees— list swarm worktrees + patches with cleanup hints/save <name>·/sessionsnamed sessions (not just timestamps)/quit
- @-file mentions (shipped 0.6.x) —
@src/main.rsin a prompt auto-attaches an outline (not the raw file — stay token-stingy), with palette completion like the/popup; unsupported file types attach a capped head instead - Syntax highlighting (shipped 0.6.x) — syntect in fenced code
blocks, stateful per block; pushed the binary to ~12MB so it sits behind a
default-on
highlightfeature (--no-default-featuresbuilds lean) - Streaming diff pane (shipped 0.6.x) — Ctrl+D flips the activity pane to a live working-tree diff, refreshed after every write/edit tool result and at turn end
- Themes (shipped 0.6.x) — built-in
dark/light/monopalettes;"theme"in config,/theme <name>at runtime; syntect theme follows
v0.6 — Provider abstraction (beyond Ollama, part 1: local)
The architectural step: extract a Provider trait so OllamaClient becomes
one implementation, not the foundation.
-
Providertrait (shipped 0.6.0):chat_stream,show,tags— everything the agent loop and swarm already consume - OpenAI-compatible provider (shipped 0.6.0, hardened 0.6.1/0.6.2) — unlocks vLLM, LM Studio, llama.cpp server, LiteLLM, OpenRouter, and Ollama's own compat endpoint; 0.6.x added timeouts, transport retries, mid-stream error surfacing, SSE tail flushing, and tool-call id repair
- Config + model addressing (shipped 0.6.0):
openrouter/qwen3routes through per-provider base URLs and keys in config; project config merges over user config with tighten-only permissions (0.6.2) - Token accounting per provider (shipped 0.6.0; usage fields normalized
into the shared
ChatStats) - Per-provider hardening test suite (shipped 0.6.4) — two layers:
a deterministic mock-server suite in CI (SSE/NDJSON framing across split
reads, missing
[DONE], mid-stream error events, tool-call accumulation and id handling,stream_optionsrejection recovery, truncated-argument errors, front-truncation detection, proxy error statuses), plus an env-gated live suite (RIFT_LIVE_OLLAMA/RIFT_LIVE_OPENAI+RIFT_LIVE_MODEL) run against real servers before a provider is called supported. v1.0's "provider matrix green in CI" builds on the live layer
v0.7 — Cloud providers + cross-provider swarm
- Anthropic + OpenAI native providers (shipped 0.7 phase 1) —
rift-anthropic speaks the Messages API natively (SSE content-block events,
tool_use/tool_result blocks, thinking with signature round-trip via
Message::provider_data, adaptive thinking, /v1/models discovery), with its own mock + live hardening suites (RIFT_LIVE_ANTHROPIC). OpenAI rides the existing rift-openai protocol.anthropic/<model>andopenai/<model>work with just ANTHROPIC_API_KEY / OPENAI_API_KEY in the env — no config entry needed;kind: "anthropic"on a provider entry selects the protocol for custom endpoints. API keys via env/config; never required - Cross-provider WarpDrive (shipped 0.8.0) — race
gemma4:26b(free, local) vsanthropic/claude-sonnet-4-6(cloud) on the same task in isolated worktrees and merge whoever wins: each candidate's model string resolves through a provider factory, so one race spans providers. No other TUI does this - Cost display for metered providers (shipped 0.8.0) —
/statsand the headless summary show estimated $; billed input tracked as summed per-call prompt tokens (not last-of-turn); built-in Anthropic rates, configpricingmap for everything else - Swarm auto-judge (shipped 0.8.0) —
--judge <model>scores every candidate's diff and recommends a winner (TUI: verdict in the winner's log, tab auto-selected; headless: machine-parseableJUDGE: winner=line).bench/judge_bench.pymeasures judge accuracy against verify.sh ground truth — discriminative-case accuracy is the headline number - Turn traces + failure counters — the hardening layer already
detects the interesting failures (textual tool-call recovery, alias
resolution, doom-loop guard, truncation detection, fuzzy edit misses)
and then discards the signal. Count them per turn in
TurnStats, and add an opt-in JSONL trace export (--trace <path>/ config) recording model, tokens, tool calls, failure flags, and outcome per turn. Local files only, never on by default — this is the data source every optimization item below consumes - Bench model matrix —
bench.py --models a,b,cruns the suite across models and diffs pass rate / prompt tokens / wall time per model; bench runs always emit traces. Every model-specific optimization needs this as its fitness function
v0.8 — Context engine v2
Method for this phase: design offline, implement deterministically. Feed traces + compaction logs + bench results to a frontier model acting as performance engineer; implement its packing strategy as plain Rust; gate every change on the bench matrix. The frontier model is never in the inference path.
- Hydrate-on-demand (shipped 0.9.0) — an unbounded read of a 500+ line source file returns its line-numbered outline; the model fetches exact ranges. Measured on the hard tier: −18.4% prompt tokens suite-wide, −66% on the buried-bug big-module task, pass rate held (BENCHMARKS.md)
- Persistent repo-map cache (shipped 0.8.x) — outlines cached per repo root keyed by (mtime, size); a hit skips the read and the tree-sitter parse. Best-effort JSON under the user data dir, LRU-capped
- Smarter compaction triggers (shipped 0.8.x) — the budget check also runs right after each turn completes, so pruning/summarizing happens while the user reads the reply instead of mid-turn while they wait
- Benchmark suite v2 (shipped 0.9.0) — hard tier (
bench/tasks2/,--dir tasks2): multi-file symptom-not-location bugs, tamper-guarded fix-the-tests, long-session big-module tasks;--runs Nreports per-run pass counts + flaky tasks; numbers published per release in BENCHMARKS.md/CHANGELOG - Repo-map ranking heuristics v2 (shipped 0.9.0) — import-centrality primary, recency tiebreak (cheap textual import extraction, cached with outlines; no embeddings, no index); degrades to pure recency when no imports resolve. Traces now record tool-call targets for future tuning
v0.8.5 — Model targets
One hardcoded system prompt goes to every model today, but open models differ dramatically in what prompting and formatting they want. Treat each model family as a compiler target, with the bench matrix as the fitness function.
- Prompt-target machinery (landed early, alongside v0.7 phase 2) —
crates/rift-core/prompts/<family>.md(markdown + frontmatter, the SKILL.md idiom: multi-line-friendly, zero new deps) embedded at compile time (include_str!— keeps the one-binary promise);match:substrings select a target by model name;~/.config/rift/prompts/overrides for experimenting without recompiling (user-level only — a cloned repo must never be able to replace the system prompt). Swarm candidates each get their own family prompt, so cross-provider races compare tuned targets - Family targets (shipped 1.8.0 — see the v1.8 section below) —
qwen/deepseek/glm/mistral files embedded alongside the provisional
gemma.md; workflow incrates/rift-core/prompts/README.md. All await matrix validation: the first 3-model run (2026-07) showed gemma4:26b at 40/50 with 8 chat-only failures and 3× the tokens of ornith/qwen - Prompt evolution gate (shipped 1.8.0) —
scripts/prompt_gate.py; prompts are code: benchmark → review → revise → benchmark → merge - Tool-schema A/B on the matrix (shipped 1.8.0) —
bench.py --schema lean|rich; measure per family, don't assume
v0.9 — Distribution + community
- Homebrew tap (shipped 0.8.1) —
brew tap exYze/tap && brew install rift, formula auto-regenerated by the release workflow from published checksums; scoop manifest installable from its raw URL. Still open: winget submission; homebrew-core once the repo clears the notability bar - Demo GIF/VHS tape in the README (shipped 0.8.1) — a real recorded session (VHS tape committed for reproducibility)
- CHANGELOG.md, CONTRIBUTING.md, issue templates (shipped 0.8.1)
- CI test matrix on macOS/Linux/Windows (build + test on all three landed early, in 0.4.x — Linux-only CI had let a Windows bug ship)
- Publish crates to crates.io (
rift-ollamais useful standalone)
v1.0 — The promise
Ship when: config format stable for 6 months of releases, provider matrix
green in CI against live servers, benchmark numbers published per release,
and rift update has carried users through 10+ versions without a manual
reinstall. 1.0 means breaking changes now require a major version — trust,
codified.
Shipped 2026-07-06. The 1.x line since (highlights): concurrent
sub-agents (1.0), model roles (1.1), vision attachments (1.2), post-edit
hooks (1.3), remote MCP (1.4), web_search (1.5), VS Code sidebar chat on
--serve (1.6), granular permission rules + inline diff review (1.7), and
merge-to-release CI. Full detail in CHANGELOG.md.
v1.8 — Model targets, finished
Absorbs the open v0.8.5 items — each model family treated as a compiler target, the bench matrix as the fitness function.
- Family targets (shipped 1.8.0): qwen/deepseek/glm/mistral prompt
files embedded, each derived from its family's documented failure modes.
All provisional — first gate run against
default.mdpending hardware, same status asgemma.md - Prompt evolution gate (shipped 1.8.0):
scripts/prompt_gate.pyruns the matrix with the embedded incumbent then the candidate as a user override, diffs pass rate / tokens / time / failure counters, and prints a PR-ready verdict; a candidate merges only if it wins every model - Tool-schema A/B on the matrix (shipped 1.8.0):
RIFT_TOOL_SCHEMA=lean(bench:--schema lean) cuts tool descriptions to the first sentence and drops per-parameter docs; results tag which variant produced them — measure per family, don't assume - Per-family bench numbers published in BENCHMARKS.md — needs the DGX matrix run (methodology + planned matrix already recorded there)
v1.9 — Distribution, finished
Closes the v0.9 tail so every mainstream install path works.
- winget (shipped 1.9.0):
scripts/make_winget.shgenerates the manifest trio from a release's checksums; the release workflow submits version bumps automatically via wingetcreate once the WINGET_TOKEN secret exists. The package's FIRST submission to winget-pkgs is manual — packaging/winget/README.md has the two routes - crates.io (shipped 1.9.0): the five library crates carry full
publish metadata (internal deps versioned via workspace.dependencies);
the release workflow publishes them in dependency order once the
CARGO_REGISTRY_TOKEN secret exists.
rift-tuistays releases-only - homebrew-core PR once the repo clears the notability bar (external — the tap install works today)
- Quick-wins batch (shipped 1.9.0):
/copyargument completion in the palette, mouse-wheel scroll moves the palette selection,--versionprints a cache-only update nudge (headless runs nudge on stderr too), autosaved session files capped at 10MB (whole turns trimmed from the front; live context untouched)
v1.10 — Serve protocol v1
The bridge to the platform: the --serve surface becomes something third
parties can build on without fear.
- Versioned protocol (shipped 1.10.0):
protocol_versioninready, acapabilitiesevent ackshellowith the negotiated set — docs/SERVE.md is the contract, with the additive-vs-breaking rules spelled out (breaking = version bump = 2.0-class change) - Compatibility tests (shipped 1.10.0): the conformance suite in
serve.rs pins every event's exact wire shape; the VS Code extension
checks
protocol_versionand warns on a mismatch — it is the reference consumer - Integration guide + reference client (shipped 1.10.0): SERVE.md's
"writing an integration" section +
scripts/serve_client.py, an interactive minimal client for Neovim/JetBrains plugin authors
v1.11 — Platform preview
Everything 2.0 will stabilize ships here first, behind flags, so the breaking release is a promotion — not a surprise.
- Experimental plugin API (shipped 1.11.0, behind
"experimental": {"plugins": true}):plugin.jsonmanifests in.rift/plugins/(project) and~/.config/rift/plugins/(user). Commands (prompt templates with{args}) ride the skill machinery —/skill:<name>, listed to the model. Tools (subprocess: args JSON on stdin, stdout = result) register from USER plugins only in the preview — a cloned repo must not register commands to execute; project-tool trust and themes/prompt-target contributions land with 2.0's stabilization - Config schema v2 + migrator (shipped 1.11.0):
rift config migrate [--dry-run] [--project]rewrites deprecatedbash_allow/bash_denyglobs toBash(...)rules, stamps"version": 2, backs up the original; runs before config load so a broken config can't block it - Deprecation warnings (shipped 1.11.0): loading a config with
bash_allow/bash_denywarns that they stop loading in 2.0 and names the migrator as the way out
v2.0 — The agent platform
Breaking changes, bundled once, and only these:
- Plugin API stable (shipped 2.0.0, on by default): commands, tools
(project plugins behind a one-time manifest trust prompt, like hooks),
post_edit hooks, JSON themes (
themes/<name>.json, plus~/.config/rift/themes/), and prompt targets (prompts/<family>.md, user plugins only — a cloned repo never replaces the system prompt) - Config schema v2 with one-shot automatic migration (shipped 2.0.0):
a v1 user config is rewritten in place on first load, with a
.v1.bakbackup; if the file can't be written, the migrated form is used in memory — old configs keep working either way. Project.rift.jsonfiles are never rewritten; their legacybash_denykeeps loading (tighten-only) with a nudge towardrift config migrate --project - Serve protocol v1 frozen (shipped 2.0.0):
PROTOCOL_VERSION = 1, the conformance suite pins every wire shape, and 2.0's additions (skillsin ready,/skill:prompt expansion) are additive — editor integrations built on v1 keep working across every 2.x release - The 1.0 stability promise resets for 2.x: config + protocol stable, provider matrix green, benchmarks per release
Engineering process (ongoing, not versioned)
Frontier models (Fable/Opus-class) act as an offline performance engineer — they profile, recommend, and leave. Never in the inference path, never a runtime dependency, so the local-first promise holds.
- Per-release architectural review: source tree + bench deltas + PROJECT.md in; prioritized engineering tasks out
- Failure-cluster analysis as traces accumulate: cluster failure counters by model/task/tool, turn root causes into roadmap items — improving rift itself, not just prompts
- Offline design, deterministic implementation: prompt, packing, and ranking strategies are designed against trace data, land as plain Rust (or frozen prompt files), and must win on the bench matrix to merge
Quick wins (grab whenever)
/copypalette completion forall/logarguments- Mouse-wheel scroll on the palette popup
rift --versioncheck against the update cache (nudge in headless too)- Session file size cap (compact stored history past N MB)
RIFT.mdtemplate improvements as real-world usage accumulates
Known risks
| risk | mitigation |
|---|---|
| Provider shims reintroduce the bugs rift exists to fix | per-provider hardening tests against live servers; capability matrix gates "supported" status |
| Binary size creep (tree-sitter, syntect) | track size in CI; feature-flag heavy deps |
| Scope creep toward generic chat app | every feature must serve the coding-agent loop; say no to the rest |
| Solo-maintainer bus factor | CI is the reviewer: clippy -D warnings, tests, live PTY smoke tests |