Skip to content

0.2.0 — 2026-06-12

Choose a tag to compare

@github-actions github-actions released this 12 Jun 06:23

Release Notes

Performance

  • Typed SSE pipeline — per-token DOM allocation eliminated — the streaming hot loop no longer builds a serde_json::Value per event
    • New runtime/sse.rs::SseLineBuffer — zero-copy line buffering: lines borrowed as &str, memchr (SIMD) newline search, O(1) read-cursor advance with periodic compaction (was two copies + an O(n) drain per line); UTF-8 splits across chunk boundaries handled by construction, with an exhaustive every-offset re-chunking test suite
    • Typed AnthropicEvent wire model with Cow<'a, str> borrowing — text deltas borrow from the line buffer on the escape-free fast path, own only when JSON escapes force decoding
    • ParseState + process_event consolidate the three parse sites (main loop, tail-flush, end-of-stream finalize) into a single write path — duplicate-site drift now structurally impossible; 15 behavioral seam tests pin the contract
  • Dirty-flag render loop + streaming redraw coalescing — the TUI burned a full core during streaming (unconditional full-frame draw on every 16ms tick and every SSE delta); needs_redraw flag draws only on actual state change, idle costs zero draws
  • Streaming raised 30→60fps — redraw coalescing throttle tightened now that frames are cheap
  • Draw-path allocation elimination — viewport Paragraph moves the line Vec instead of deep-cloning every frame; ASCII-art rendering collapses same-style runs from one Span-per-char to one Span-per-line; per-frame version format!concat! const
  • mem::take at session resumerebuild_display_messages no longer deep-copies the entire message history (potentially MBs) to dodge the borrow checker
  • Cache strategy: sliding-4 → single-last — one stationary cache_control marker on the last message replaces ~57 lines of sliding-breakpoint logic
    • Bench evidence: equivalent hit rate (96–97% both strategies); live-verified 99% hit on warm turn
    • Prefix-invalidation bug class (mutating old markers) eliminated by construction; 5 new unit tests on a previously untested function

Fixed

  • SSE double-emit on partial final line — when the final content_block_stop arrived without a trailing newline, the tail-flush pushed the block but left in_thinking/in_tool_use set, so the end-of-stream flush pushed it again — duplicated content block sent to the model on the next turn
  • PTY zombie reapingPtyHandle::Drop killed the child but never wait()ed; every timed-out or dropped shell session left a zombie. Now reaped with bounded-retry try_wait() (all other child-process sites already used kill_on_drop)
  • Extension crash-loop health liedrestart_count reset on successful handshake, so an extension that initialized fine and died on the next request never hit the exhaustion limit and reported Running. Consecutive-failure counter now resets only when the restarted process actually serves a call; new total_restarts (never reset) feeds health so recovered extensions report Degraded
  • Integration test rot from env_clear — security-hardened extension spawns silently broke 20+ test fixtures parameterized via env vars; fixtures moved to argv parameters, plus poison-cascade and parallel-env-race cleanup — full suite green, 3 consecutive runs
  • Hardcoded Claude Code identity removed from API preamble — replaced with a configurable identity config key + proper SynapsCLI default
  • Dotted (namespaced) config keys exempt from unknown-key warnings

Added

  • claude-fable-5 support — known-models entry with adaptive thinking, pricing ($10/$50 per MTok), and 1M context opt-in
  • Telemetry module — structured per-request API records: TelemetryLevel (off/basic/full), usage with cache TTL breakdown, rate-limit headers, cache-diagnosis records; JSONL writer to ~/.cache/synaps/api-log.jsonl (0600 + O_NOFOLLOW), wired into config keys and the Anthropic SSE stream
  • Cache strategy benchmark suite (bench/) — 21 tool-heavy questions with deterministic outcomes across 4 swappable breakpoint strategies (none / single-last / last-3 / sliding-4); per-turn JSONL logging of tokens, cache read/write, hit %, cost, latency; compare.py for side-by-side runs
  • synaps completions <shell> — shell completions via clap_complete (bash, zsh, fish, elvish, powershell)
  • First-run banner — boot with no OAuth, no ANTHROPIC_API_KEY, and no provider keys shows a getting-started banner with the three setup paths instead of a silent TUI

Changed

  • reqwest 0.11 → 0.12 — duplicate HTTP stack collapsed — reqwest 0.11 was the sole consumer of hyper 0.14/http 0.2/h2 0.3 alongside axum's hyper 1.x; the old stack (plus native-tls/OpenSSL) is gone, TLS is now rustls with native root certs — explicit in the manifest, smaller binary, zero source changes
  • Humanized API + network errors — raw JSON dumps and reqwest debug strings replaced with actionable text (529 → "overloaded, wait", 401 → "run synaps login", context overflow → "run /compact"); retry notices ("⏳ API error, retrying…") are now display-only system lines instead of fake assistant content persisted into session history
  • Input recovery on stream error — when a stream dies after retries, the user's popped message is restored to the input box instead of silently destroyed
  • Config parse warnings with did-you-mean — unknown keys suggest corrections via levenshtein (modle → did you mean model?); unparseable values warn and fall back to defaults instead of silently misbehaving
  • Login/status polish — token-refresh errors now say synaps login (was a nonexistent command); synaps status refreshes the OAuth token before the request instead of 401ing on expired tokens; --help rewritten with real about text and --profile documented

Earlier in this cycle

  • Engine refactor + chat headless modedaemon, run, and client subcommands deleted; chat is now fully-featured headless mode with MCP, extensions, skills, sessions, compaction, and the event bus (same engine as the TUI, stdin/stdout rendering)
    • New engine/ module: setup.rs (boot), commands.rs (headless slash commands), stream.rs (StreamEvent consumer), session.rs (ConversationState)
    • chatui/ module deleted — tui/ is the sole frontend
    • New pricing.rs — centralized Anthropic pricing (Opus/Sonnet/Haiku) with cache billing support
    • New harbor/synaps_agent.py — Terminal-Bench integration agent
    • Clippy CI added (cargo clippy --all-targets gates PRs)
    • Published on crates.io as synaps (v0.1.x); available via cargo install synaps, AUR (yay -S synaps), Homebrew, and GitHub Releases
  • Path B Phase 6 — The Big Move (extension contracts) — synaps-cli core no longer contains whisper-specific code; the local-voice plugin owns it
    • Deleted src/voice/{models,download,rebuild}.rs (whisper.cpp catalog, HuggingFace downloader, cmake-rebuild orchestrator)
    • Slimmed src/voice/discovery.rs from ~400 LOC to ~190: only discover() / discover_in() / DiscoveredVoiceSidecar remain; read_build_info, detect_host_backend, probe_* are gone (callers use the Phase 5 info.get cache instead)
    • Deleted in-core /voice models|help|download|rebuild action arms and parsers — those subcommands now route through the plugin via the Phase 2 interactive command contract; missing-plugin case errors with a clear message
    • Deleted in-core whisper download UI: App.{download_progress, download_filename, download_rx, voice_download_in_flight, model_browser_selected, cached_voice_compiled_backend} plus start_download / on_download_progress / on_download_complete and the download_change event-loop arm; the sticky progress widget now exclusively renders generic extensions::active_tasks::ActiveTasks (Phase 3)
    • Deleted EditorKind::{ModelBrowser, WhisperModelPicker}, ActiveEditor::ModelBrowser, ModelBrowserRow, model_browser_rows, whisper_model_options, render_model_browser, render_download_progress_line, plus the voice_stt_model / voice_stt_backend / voice_language setting definitions — the plugin replaces them via the Phase 4 settings categories contract
    • Migration shim: on first launch, legacy global voice config keys (voice_stt_model_path, voice_stt_model, voice_stt_backend, voice_language) are copied into the plugin namespace ~/.synaps-cli/plugins/local-voice/config if the destination is empty; legacy keys remain in place for safety. Reads at runtime prefer the plugin namespace and fall back to the legacy global key with a deprecation warning.
    • Net change: ~−2,400 LOC removed from synaps-cli core; behaviour preserved when the local-voice plugin is installed
  • Phase 2 — Extensions Capability Platform — extensions are now first-class citizens
    • Slash command extension contract (commands in plugin manifest)
    • Settings panel extension contract (settings in plugin manifest)
    • Keybind extension contract (User-tier binds via plugin manifest)
    • Model-provider extension contract — extensions can register OpenAI-compatible providers as full agentic backends with tool-call support
    • Capability discovery + permission gating per extension
    • Slices P–W complete; 836 tests green (682 lib + 154 bin)
  • Voice dictation — toggle-driven mic capture wired to the input buffer
    • /voice slash command with subcommands: models, download <id>, help, rebuild [backend]
    • Configurable toggle key — defaults to F8; supported: F8, F2, F12, C-V, C-G (Ctrl+Shift and Ctrl+Alt are unreliable in terminals)
    • Toggle-only flow: press once → start listening (🎤 listening pill), press again → stop, transcribe, append to input
    • VAD-aware: final transcripts during an armed session insert text without disarming
    • Settings → Voice category: toggle key, language cycler (14 langs), STT model, STT backend
    • voice_language cycler: auto / en / es / fr / de / it / pt / nl / ja / zh / ko / ar / hi / ru
    • Hot-reload keybind on settings save — no restart required
    • Kitty keyboard protocol enabled for reliable F-key + modifier capture
    • Voice sidecar lives in the local-voice-plugin (synaps-skills repo) — synaps core stays voice-free
  • Whisper model manager — discover, download, switch models in-app
    • 10-entry catalog hard-coded in src/voice/models.rs: tiny / base / small / medium / large-v3 / large-v3-turbo + .en variants, with real SHA256s from HuggingFace
    • /voice models renders an installed/uninstalled table
    • /voice download <id> — streaming download with atomic .partial → rename install, SHA256 verification, cancellable, single-in-flight
    • EditorKind::ModelBrowser — Settings → Voice → STT model browses the catalog inline, Up/Down to nav, Enter installs-or-selects
    • Inline footer download progress while a model fetches
    • Models live under ~/.synaps-cli/models/whisper/
  • Whisper backend selection — pick CPU / CUDA / Metal / Vulkan / OpenBLAS or auto-detect
    • voice_stt_backend cycler in Settings → Voice
    • auto probes the host (nvcc, vulkaninfo, pkg-config, target-os) and picks the best available
    • "Current build: " annotation surfaces the sidecar's compiled feature set
    • ⚠ rebuild annotation when the selected backend differs from the compiled one
    • /voice rebuild [backend] invokes local-voice-plugin/scripts/setup.sh --features <backend> and streams build output as System rows
    • Sidecar reports its build via --print-build-info (JSON: {backend, features, version})
  • Chat UI rendering polish
    • System / Error messages now split on \n and word-wrap on each sub-line (same path as User / Text)
    • Tab-aware soft wrap: continuation rows indent under the last-tab anchor column (4-col tab stops); safety clamp falls back to leading-space indent if the anchor exceeds 60% of width
    • Fixes /voice help, /chain ls, /keybinds, plugin command output rendering
  • Extension System — process-based JSON-RPC hooks (before_message, before_tool_call, after_tool_call, on_session_start, on_session_end)
    • Tool-specific filtering: hooks can target specific tools
    • Context injection via HookResult::Inject
    • Permission-gated with 6 permission types
    • Drop-in plugin support
    • Silent loading (only show failures)
  • Watcher notify_inbox hook — event bus notification on agent completion
    • Config option: [hooks] notify_inbox = true in watcher agent config
    • Drops JSON events into ~/.synaps-cli/inbox/ when agents complete
    • Works in both 'once' and 'deploy' modes
    • Event payload includes agent name, session number, elapsed time, exit code, timestamp
  • Table rendering improvements
    • Cells wrap instead of truncating with ellipsis
    • Inline markdown (bold/italic/code) rendered in table cells
    • Smarter column shrinking — preserves narrow columns
  • Structural refactoring — improved code organization
    • catalog.rscatalog/ directory with per-provider modules
    • palettes.rspalettes/ directory with per-palette files
    • tools/subagent*.rstools/subagent/ directory
    • tools/tests.rs → distributed inline test modules per tool
    • runtime/api.rs split into api.rs + api_sync.rs + request.rs
    • chatui/mod.rs helpers extracted to helpers.rs + lifecycle.rs
  • UTF-8 char boundary panics — multiple fixes for multi-byte character handling
    • Hook output truncation now finds valid char boundaries
    • Bash output highlighter fixed for emoji/CJK characters
    • Additional edge cases found by PR review
  • Hook system improvements
    • Handle HookResult::Block in before_message hook
    • Set tool_runtime_name in all before_tool_call hook paths
    • Track truncation explicitly in bash tool instead of string matching

Added

  • Multi-Provider Runtime — OpenAI-compatible provider engine
    • 17 providers: Groq, Cerebras, NVIDIA NIM, OpenRouter, Google AI Studio, DeepInfra, HuggingFace, Fireworks, Hyperbolic, Scaleway, SiliconFlow, Together, Chutes, Codestral, Perplexity, OVHcloud, + Local (Ollama/LM Studio/vLLM)
    • 55+ models cataloged with tier ratings (S+/S/A+/A/B)
    • provider/model shorthand: /model groq/llama-3.3-70b-versatile
    • SSE streaming with tool calling across all providers
    • StreamDecoder with HashMap-based tool call accumulation
    • Anthropic↔OpenAI message/tool translation layer
    • Provider router in api.rs — model prefix routes automatically
    • Config: provider.<name> = <key> in ~/.synaps-cli/config
    • Env var fallback: GROQ_API_KEY, CEREBRAS_API_KEY, etc.
    • Local model support: provider.local.url = http://localhost:11434/v1
  • /ping command — health-check all configured provider models
    • Non-blocking, results stream in live as each model responds
    • Shows ✅/❌/⏳/🔒/⌛ with latency per model
    • Results cached for model picker display
  • Settings → Providers — TUI panel for API key management
    • View all 17 providers with key status (✅ set / ⬚ not set)
    • Enter to set/update key, d/Del to clear
    • Key masking (last 4 chars only)
    • Local endpoint URL editing
    • Press p to ping all models
    • Scrollable list with overflow indicators
  • Settings → Model Picker — expanded to show provider models
    • Models grouped by provider with headers (── Groq ──, etc.)
    • Only shows providers with keys configured
    • Header rows are unselectable (skip on navigation)
    • Health status shown when ping data available
  • App starts without Anthropic credentials — users with only provider keys can boot the TUI and use free models
  • Session Naming/saveas <name> aliases for sessions
    • Name format [a-z0-9-]{1,40}, validated and collision-checked
    • /saveas (no arg) clears the name
    • synaps --continue <name> resolves session names
    • /sessions shows [@name] tags on named sessions
  • Chain Naming/chain name/list/unname bookmarks for compaction lineages with auto-advance
    • /chain name <name> bookmarks the current session's lineage
    • /chain list shows all named chains (* marks active)
    • /chain unname <name> removes a bookmark
    • /chain (no args) shows lineage + "bookmarked by: @name" if present
    • Chain pointers stored at ~/.synaps-cli/chains/<name>.json
    • On /compact, chain pointers auto-advance to the new session
  • Unified Session Resolutionresolve_session(): chain name → session name → partial ID, used by --continue and /resume
    • Shared by synaps --continue, /resume, and server --continue
    • Resolution path surfaced as a system message (↳ resolved via chain 'foo' / ↳ resolved via name 'bar')
    • --continue value_name changed from SESSION_ID to NAME_OR_ID
  • Event Bus — universal message ingestion for agent sessions
    • synaps send CLI command with atomic file writes
    • inotify inbox watcher via notify crate (spawn_blocking, non-blocking)
    • Priority EventQueue with severity ordering (Critical→front, High→after)
    • tokio::sync::Notify for instant TUI wake on event push
    • Events auto-trigger model turns when agent is idle
    • Events buffer during streaming via pending_events, flush on completion
    • Styled TUI event cards with severity icons (🔴🟠🟡🔵)
    • XML-wrapped event format with prompt injection hardening
    • 256KB file size cap, symlink guard, 0700 permissions
  • Reactive Subagents — dispatch, poll, steer, collect
    • subagent_start — spawn and return handle_id immediately
    • subagent_status — non-blocking progress snapshot
    • subagent_steer — inject guidance mid-flight via steering channel
    • subagent_collect — non-blocking result check
    • subagent_resume — restart timed-out agents (stub)
    • SubagentHandle with shared RwLock<SubagentState>
    • SubagentRegistry with cleanup_finished on stream Done
    • Abort cancels all running reactive subagents
    • Thread handles stored for graceful shutdown
    • 13 unit tests for handle + registry
  • Chain Sessions/compact creates linked child session
    • Old session preserved on disk with compacted_into forward link
    • New session starts with parent_session back link
    • /chain command walks the session lineage
    • System prompt included in compaction summary
    • Configurable compaction model (defaults to Sonnet)
    • ModelPicker for compaction model in settings
    • Non-blocking compaction with spinner animation
    • Compacted summary hidden from TUI display
    • Message queuing during compaction
  • respond tool (stub — returns honest failure until wired)
  • send_channel tool (stub — returns honest failure until wired)
  • /status command + synaps status subcommand: check account usage (5-hour, 7-day, Sonnet) with progress bars and reset countdowns. Hits OAuth usage API.
  • /compact slash command: summarize & compact conversation history when context gets long
    • Structured checkpoint format (goals, progress, decisions, file ops, next steps)
    • Iterative compaction — re-compacting merges new work into existing summary
    • File operation tracking (read/write/edit paths preserved across compactions)
    • Custom focus instructions via /compact <focus>
    • Uses dedicated low-effort API call (no tools, summarization system prompt)
  • context_window setting wired to API: 200k (default) omits beta header; 1m sends context-1m-2025-08-07 on supported models (Opus 4.6+, Sonnet 4.x); previously was UI-only display cap
  • Claude Code marketplace compatibility: probe both .synaps-plugin and .claude-plugin layouts, ${CLAUDE_PLUGIN_ROOT} substitution in skill bodies
  • Plugins subdir sources and cascade uninstall: install from subdir-based plugin repos, cascade-remove plugins when their marketplace is deleted
  • Settings → Plugins marketplace overlay: "Open Plugin Marketplace" action row in Settings, opens plugins modal as nested overlay
  • Hidden binary: GamblersDen bundled as hidden binary alongside synaps
  • Single binary architecture: all binaries consolidated into synaps
    • synaps (no args) = TUI (was chatui)
    • synaps chat = fully-featured headless mode (MCP, extensions, skills, sessions)
    • synaps server = WebSocket API (was server)
    • synaps agent = headless worker (was synaps-agent)
    • synaps watcher = supervisor (was watcher)
    • synaps login = OAuth (was login)
    • synaps send = push events into a running session
    • synaps status = check account usage
    • (Removed: run, client, daemon)
  • Live theme preview in /settings: scroll themes to preview, Enter confirms, Esc reverts
  • Theme hot-reload: /theme <name> applies instantly without restart (ArcSwap)
  • Settings picker scroll: theme/model picker scrolls with cursor
  • Adaptive thinking for Opus 4.7+: {type: "adaptive", display: "summarized"} with effort mapping (xhigh/high/medium/low/adaptive)
  • Model-agnostic context window: bar denominator adapts per-model (1M Opus 4.7, 200K Sonnet/Haiku)
  • Per-turn context tracking: usage bar shows actual request size, not cumulative cost
  • Effort parameter: thinking depth on adaptive models controlled via output_config.effort
  • "adaptive" thinking option: new cycler value in /settings — lets model decide thinking depth
  • Tab-cycle for slash commands: /s + Tab cycles through sessions → settings → system
  • Streaming command guard: known slash commands no longer leak into model stream as steering
  • Usage log opt-in: SYNAPS_USAGE_LOG=1 writes to ~/.cache/synaps/usage.log (0600, O_NOFOLLOW)
  • Opus 4.6 in model picker: was missing from /settings model list
  • settings + plugins in tab-complete: were missing from BUILTIN_COMMANDS
  • Plugin Keybinds — plugins declare custom keyboard shortcuts in plugin.json
    • KeybindRegistry with parser, matching, and conflict resolution
    • Key notation: C-x (Ctrl), A-x (Alt), S-x (Shift), F1F12, special keys
    • 4 action types: slash_command, load_skill, inject_prompt, run_script
    • User overrides via keybind.* in config — override or disable plugin binds
    • Priority: core > user > plugin (core binds never overridable)
    • /keybinds command shows all registered binds with source attribution
    • 23 unit tests for parser, registry, conflicts, overrides
  • Plugin Agent Namespaced Resolutionsubagent(agent: "dev-tools:sage") resolves plugin agents via plugin:agent syntax
    • Searches plugins/<plugin>/skills/*/agents/<agent>.md
    • Input validation, path traversal protection, ambiguity detection
    • Updated error messages to mention plugin:agent syntax
  • Mouse Text Selection & Clipboard — left-click drag to select text in chat area
    • Right-click with selection → copy to system clipboard
    • Right-click without selection → paste from clipboard
    • Singleton clipboard thread (no thread-per-copy accumulation)
    • Paste suppression with 150ms TTL (prevents terminal double-paste)
    • Selection highlight via Block::inner() computed content rect
    • Theme-aware highlight color

Fixed

  • Empty thinking/text blocks rejected by API — fixed two related 400 errors that could permanently brick a session:
    • messages.N.content.M.thinking: each thinking block must contain thinking — streaming accumulator (runtime/api.rs) was pushing thinking content blocks even when no thinking_delta arrived (only a signature, or stream cut off). Now skipped at all three accumulation sites (mid-stream, tail buffer, post-loop fallthrough).
    • messages: text content blocks must be non-empty — defensive sanitizer (runtime/helpers.rs::sanitize_thinking_blocks) added; runs on every outbound API call from both call_api_stream_inner and call_api. Strips empty thinking, redacted_thinking.data, and text blocks; drops assistant messages whose entire content gets stripped; merges resulting consecutive same-role messages to preserve Anthropic's strict role-alternation rule. Auto-heals sessions persisted before the streaming fix landed.
    • 9 unit tests covering the drop-and-merge cases.
  • Config file permissions — now 0600 (was 0644, world-readable with API keys)
  • API key masking — shows last 4 chars only (was showing first 8 + last 4)
  • ProviderConfig Debug — custom impl redacts api_key as [REDACTED] in logs
  • Provider base URLs — corrected siliconflow (.com→.cn), chutes (→llm.chutes.ai)
  • Dead models removed — groq/llama-3.1-70b, groq/qwen-qwq-32b, groq/gemma2-9b (all decommissioned)
  • Google stream_options — skip include_usage for googleapis.com (rejects it)
  • Tool→user message ordering — insert space-content assistant between tool result and user message for strict providers
  • Finish-frame tool call dedup — NVIDIA sends final argument chunk with finish_reason; was being dropped as "resend"
  • Model ID extraction — health prefix (✅ 253ms) no longer embedded in model string sent to API
  • /status on non-Anthropic — shows friendly message instead of crashing
  • "Calling Claude..." — now shows actual model name in synaps run
  • Paste in settingsEvent::Paste now handled in API key, text, and custom model editors
  • Missing provider key/model sambanova/llama with no key shows clear error instead of silent Anthropic misroute
  • UTF-8 truncation panicbash and shell output truncation now finds valid char boundaries before truncating, preventing crash on multi-byte characters (emoji, CJK)
  • Zero-width terminal panic — markdown word-wrap chunks(0) crash on rapid tmux pane resize, clamped to .max(1)
  • Local model connection — friendly "is Ollama running?" instead of raw TCP error
  • /help updated — mentions provider/model syntax and /settings for key management
  • ping_print lifecycle — resets after all results arrive via pending counter
  • MCP tool name causes 400 errors — Anthropic rejects mcp_ prefixed tool names (rate limit pool misrouting). Renamed mcp_connectconnect_mcp_server, tool prefix mcp__server__toolext__server__tool.
  • /saveas on empty sessionssave_session() bailed on empty api_messages, so the name never persisted. Now calls session.save() directly.
  • Compaction no longer overwrites original session (loads from disk)
  • Event content sanitized against prompt injection (XML tags, case-insensitive)
  • Atomic inbox writes (.json.tmp → .json rename)
  • inotify watcher runs on spawn_blocking (no longer starves tokio runtime)
  • Events during streaming buffered and flushed after MessageHistory
  • Spurious auto-triggers prevented by event_received guard
  • push() calls notify_one() (was missing — events silently queued)
  • Session save ordering: new session saved before old session updated
  • chars().count() moved outside lock scope
  • High-priority event FIFO ordering (was LIFO among Highs)
  • Queue-full events left in inbox for retry (not silently dropped)
  • push_priority logs evicted event ID
  • Session file corruption: atomic writes via write-to-tmp then rename
  • Tool input parse errors surfaced to model: malformed tool_use JSON no longer silently falls through to empty input; model sees invalid tool input JSON: ... and can self-correct
  • Custom theme crash: unreachable!() in draw replaced with graceful fallback colors for non-Rgb themes
  • ASCII logo alignment: use unicode display width for consistent centering
  • 'default' theme missing from settings picker
  • Context bar pinned at 100% after 2-3 turns (was using cumulative tokens / hardcoded 200K)
  • Thinking blocks invisible on Opus 4.7 (display defaulted to "omitted")
  • budget_tokens: 0 sentinel leaked to non-adaptive models → 400 error
  • /settings cycling capped at xhigh (apply_setting silently rejected "adaptive")
  • Stale test asserting thinking_level_for_budget(0) == "low" (production returns "adaptive")
  • Usage log world-readable at /tmp/ → moved to ~/.cache/ with 0600

Changed

  • Compaction logic moved from chatui to core/compaction.rs
  • SubagentHandle/Registry/Status moved to runtime/subagent.rs
  • ApiOptions struct replaces use_1m_context: bool threading
  • build_auth_header + build_beta_header extracted as helpers
  • clone_repo helper deduplicates plugin installer
  • All compaction prompts colocated in core/compaction.rs
  • Tool descriptions guide model choice (subagent vs subagent_start)
  • Stub tools unregistered from tool registry (model doesn't see unimplemented tools)
  • SubagentState uses RwLock instead of Mutex
  • define_settings! macro: settings schema + apply handler defined once in settings/defs.rs via declarative macro — zero drift possible (replaced manual sync + parity tests)
  • Single source of truth for commands: removed duplicate ALL_COMMANDS array; commands.rs now sources from skills::BUILTIN_COMMANDS
  • src/cmd_*.rssrc/cmd/ module: subcommand handlers moved to dedicated directory, cmd_ prefix stripped
  • Binary name: chatui/synaps-cli/synaps-agentsynaps (single binary with subcommands)
  • src/chatui/main.rssrc/chatui/mod.rs (module, not binary)
  • watcher spawns synaps agent instead of standalone synaps-agent
  • thinking_level_for_budget() consolidated from 4 copies into single source of truth in core/models.rs
  • DEFAULT_LEGACY_ADAPTIVE_FALLBACK constant replaces magic 16384 in clamp sites
  • Dead-code warnings suppressed with explanatory comments (reaper handles, settings help field)
  • Auto-cache toggle removed (manual breakpoints won: 90% vs 53%)
  • README rewritten from internal documentation to product landing page

Removed

  • SPEC-WATCHER.md — internal spec, not needed in repo
  • Auto-cache config toggle (auto_cache = true/false)

Install synaps 0.2.0

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/HaseebKhalid1507/SynapsCLI/releases/download/v0.2.0/synaps-installer.sh | sh

Download synaps 0.2.0

File Platform Checksum
synaps-aarch64-apple-darwin.tar.xz Apple Silicon macOS checksum
synaps-x86_64-apple-darwin.tar.xz Intel macOS checksum
synaps-aarch64-unknown-linux-gnu.tar.xz ARM64 Linux checksum
synaps-x86_64-unknown-linux-gnu.tar.xz x64 Linux checksum