Skip to content

Vect v0.3.0

Choose a tag to compare

@github-actions github-actions released this 06 Aug 00:03
· 6 commits to main since this release

Vect leaves the one window it used to live in. A worktree now opens as a
workspace whose panes you arrange yourself, any agent CLI can drive that
workspace over MCP, and a phone paired to your machine is a second screen onto
the same agents, on iOS and on Android.

If you are coming from 0.2.2, this also carries everything in 0.2.3, whose
build published binaries but never reached the downloads page: the data-loss
fixes in the context editor and memory saves, the session-lifecycle fixes that
stop orphaned agents and terminals, and the input-escaping and path-traversal
fixes. That section is below, unchanged.

Changed

  • Every workspace pane docks anywhere. Drag a pane by its header onto the left, right, top or bottom edge of any other pane and it splits there; drop it in the middle and the two trade places. The arrangement is a split tree rather than a fixed chat-left/panels-right frame, so it can express any layout, dividers move only the two panes they sit between, and closing a pane hands its room back to its neighbours. Escape abandons a drag in flight. A workspace still opens as the conversation alone, and pane headers appear only once there is somewhere to drag to
  • Tabs keep one rounded shape and fade where they run out of room. Each tab is its own rounded top, inset from the window edge, so the leftmost one is no longer a blunt slab flush against the sidebar; the strip scrolls instead of squeezing, and tabs past either end dissolve into the background rather than being sliced mid-shape into what looked like two overlapping tabs
  • The installer is ~384 MB lighter — voice models no longer ship inside it. Supertonic TTS (~398 MB) downloads on first play and Silero VAD (~630 KB) on first /voice use, into the app data dir with progress events, exactly the way SenseVoice STT already did; dev checkouts keep using scripts/fetch-supertonic.sh so tauri dev doesn't wait on a download
  • Installers look intentional — the Windows installer carries the Vect icon (it shipped with the stock NSIS one), installs per-user without an elevation prompt, hides the file-copy log and advances itself to the finish page; the macOS DMG opens onto a designed dark backdrop (wordmark, corner glows, drag-to-Applications arrow) instead of the bare white Finder window
  • Calm surface — Vect now opens as a near-empty frame and earns its density back. Workspaces are opt-in: discovery still walks every agent's session store, but the results are offered behind a .claude sync picker instead of filling the sidebar, so a fresh launch shows "Nothing here yet" and a count of what was found. The nav rail and status bar are summoned by approaching the screen edge rather than sitting there permanently, and borders drop to a single near-invisible hairline (one token, not 180 call sites). A full density setting restores the previous always-on posture. Existing installs will find the sidebar empty on first launch — nothing is deleted, and .claude sync restores any subset in one click.
  • Thinking text now glazes — a highlight travels across the glyphs themselves while a model is working, in place of a static label
  • Dragging selects text, not the interface — a drag across a conversation used to paint over role chips, timestamps and the full empty width of every row, so copying a reply came back with "User", "4h ago" and the layout wrapped around the sentence. Chrome is no longer selectable; message bodies, rendered markdown, code blocks and text fields are. A selection must now begin on text (starting a drag in a gutter selects nothing), which is how a desktop app behaves and how the copy stays clean

Added

  • Vect MCP server — vect mcp serve (stdio) hands any agent CLI Vect's whole surface as tools: run and read the workspace's embedded terminal (the visible one — "restart the dev server" stops being a copy-paste conversation), point the workspace browser pane at a URL, spawn and steer other agent sessions cross-provider, create/update tasks in the audit hierarchy, read and write project memory, and query the audit trail. Calls proxy to the desktop app's localhost IPC bridge (which now actually starts — it existed but was never wired into the module tree), and every mutating call lands in the audit log as a tool_called event. Register with claude mcp add vect -- vect mcp serve (docs/guide/vect-mcp.md)
  • Workspaces — a worktree opens as one tab holding its whole working set: the agent conversation on the left, a terminal cwd'd into the worktree and a browser pane on the right, all resizable. Switching workspace tabs switches everything together, ending the chat/terminal/browser alt-tab shuffle. Each workspace gets a stable suggested port (seeded as $PORT in its terminal, and the browser pane opens on it by itself once something serves there), the PTY survives tab switches, and a worktree with no session yet offers to start one. Open from the worktree list or the palette
  • Focus Mode — ⌘⇧Enter (or the palette) folds away everything except the active pane: nav rail, sidebar, right panel, tab bar and status bar all leave the frame until toggled back. Rebindable like every command
  • One-click GitHub context — a branch button in the composer gathers the current branch's PR reviews, recent comments, and the log tails of failing CI checks (via the gh CLI) into one markdown block appended to the message, so handing an agent "fix the review feedback and the red checks" no longer means copy-pasting from the PR page
  • A real diff viewer — single-file diffs now render through CodeMirror's merge view instead of a hand-rolled line parser, so they get language-aware syntax highlighting, line numbers, intra-line change marks (the exact characters that changed within a modified line), and collapsed runs of unchanged context. Split and Unified toggle as before. The backend hands over the full before (HEAD blob) and after (working tree) contents rather than a unified diff, which is what a two-pane view needs; binary and added/deleted files are handled, and the language + theme tables are now shared with the code editor instead of duplicated
  • Tool calls appear while they are still being written — Claude's CLI does emit token-level events, it just needs --include-partial-messages, which Vect never passed. With the flag the same stream carries text_delta, thinking_delta and input_json_delta, so a tool call now shows the instant the model names it and fills each argument in as that argument closes, instead of appearing only after the whole assistant message lands. The incremental JSON parser behind it is ported from getpaseo/paseo (MIT) and pinned to a captured real stream in tests
  • Ask the palette in plain English — Cmd+P now takes a natural-language instruction ("show me my token spend analytics") and a fast one-shot agent, handed this window's live commands and recent sessions, resolves it to a single action and runs it. A ghost cursor arcs from the palette to the element being acted on and pulses a ring there, so the cause is visible rather than the UI just jumping. The resolver runs in the invoking renderer, so with several windows open the one you asked is the one that acts; actions are a closed schema grounded against the live registry, so a hallucinated command or session id becomes a clarifying question instead of a wrong click
  • Hermes — NousResearch's hermes-agent joins the provider lineup (quiet chat -q -Q runs with the session id captured from its stderr line, --resume continuity, session browser + transcripts from ~/.hermes/state.db, YAML MCP config management, Analytics coverage, icon, and -z one-shot powering utilities when Hermes is the default agent)
  • Session rename for every agent — rename now lands in each agent's own store where one exists: Claude custom-title entries, opencode's session.title, hermes via hermes sessions rename (its title-uniqueness rules respected), codex via the app-server thread/name/set RPC (the name becomes a codex resume handle) — with a Vect-local overlay as the universal fallback so the browser always shows the chosen name
  • Skills — the shared ~/.agents/skills standard (loaded by codex and opencode) and project .agents/skills are now listed alongside the Claude dirs, so the Skills view reflects what every agent actually sees
  • Windows release signing is wired — the release workflow signs the exe and NSIS installer via Azure Trusted Signing as soon as the AZURE_TS_* secrets are set (one-time Azure setup in docs/guide/windows-signing.md), which is what removes SmartScreen's grey "unknown publisher" screen; until then builds stay unsigned exactly as before
  • Auto-update — Vect now keeps itself current like Claude Code: on launch it checks the public GitHub release feed, downloads the new version in the background, and applies it on the next restart; the macOS app menu gains "Check for Updates…" (under About) for on-demand checks with a restart prompt. Release artifacts are minisign-signed and the public repo publishes a latest.json updater manifest

Fixed (runtime-verified by driving the app)

  • Scanning the pairing QR code actually pairs the phone. Two things stopped it, and both only show up on the path that matters (app not already running): the deep-link plugin filters incoming URLs against its own config, and the config declared https://vect/pair app links rather than the vect scheme the code carries, so a scanned link launched the app and was then dropped; and the client only listened for links arriving while it was already open, which a QR scan never is. Driven on an Android emulator from a cold start: link to paired to reading the conversation with no typing and no taps
  • A workspace tab shows its own panes. WorkspaceTabView was rendered without a key, so React reused one instance for every workspace tab and the pane layout and PTY of the workspace you left stayed on screen under the next one's title
  • The Android app refuses nothing on your own network. Tauri disables cleartext traffic for release builds, which would have blocked every ws:// connection to the machine running your agents

Added

  • A map of your own turns down the right edge of every conversation. Each mark is one message you sent and its width is how much you wrote, on a log scale, so a session's shape reads at a glance: a row of dots where you were answering yes/no, a long dash where you pasted a stack trace. Hovering anywhere on the strip picks the nearest mark and shows what you wrote there; clicking scrolls to it and flashes the message. The you-are-here mark follows as you scroll
  • Vect runs on Android. Same client as iOS, built from apps/mobile, with the generated project committed so a build is one command — a command sent by an agent through vect_terminal_run goes in as a bracketed paste when the shell's line editor is active, so zsh no longer repaints the prompt on every injected keystroke, and vect_terminal_read now replays the PTY stream (carriage returns, backspaces, erase sequences, clear) into the text a human sees instead of handing agents escape-laden output where echo hi arrived as eecho hi. Raw bytes are still the fallback while a foreground program owns the tty, which is what that program expects
  • The workspace preview no longer opens on a blank white page — the browser pane only navigates to the workspace's local address once something is actually answering there, and adopts it on its own the moment a server appears. Until then it shows a neutral empty state, because coding is one of the things a workspace is for, not the only one
  • The desktop binary stopped overwriting the vect CLI — the crate was named Vect, which is the same path as vect on a case-insensitive filesystem, so cargo build --workspace left whichever linked last at target/debug/vect (running the CLI could launch the desktop app). The crate is now vect-desktop; the app name, window title and bundle identifier are unchanged
  • ~/.vect/ipc.port is removed when the app exits, so vect mcp serve stops pointing at a dead socket

Fixed (runtime-verified against the installed CLIs)

  • opencode streamed replies rendered empty — the parser read part.content, a field the JSON format never had; the text delta lives at part.text (caught by running opencode 1.18.3 live). Reasoning events fixed the same way, and step_finish now feeds its part.tokens usage into the live token chips
  • hermes Analytics now report real token totals — the sessions table carries session-level input/output/cache aggregates (the "no token usage recorded" assumption was wrong)

Fixed (source-verified against each CLI's actual implementation)

  • opencode transcripts showed every message as "assistant" (the role lives in the type column, not the data blob) and pre-v2 sessions rendered empty (text lives in the part table); subagent child sessions and archived sessions no longer clutter the browser; non-stable install channels (opencode-<channel>.db) are found
  • Global analytics now count opencode sessions with real token totals from its DB (the old "can't walk per-project DBs" exclusion predates the global store) and hermes sessions with message counts

Fixed (agent parity — every agent works like Claude Code where its CLI allows)

  • Conversations continue — follow-up messages to codex/opencode no longer start a fresh thread each time: the real session id is captured from each CLI's own stream (codex thread.started, opencode sessionID) and fed back through the provider's resume flag. Verified live round-trip on codex 0.141
  • OpenCode actually runs — the adapter targeted the archived Go CLI (v0.0.55); current opencode v1.x uses run <msg> --format json (-p means --password now) and --session for resume. MCP config corrected to project-root opencode.json
  • Session browser covers every agent — codex rollouts (already), opencode's global DB, and hermes' state.db now all merge into the tree with provider tags; opencode and hermes transcripts open in the conversation view
  • Token usage — codex tokens now stream into the live chips and aggregate into Analytics with real per-project attribution from rollout files (was: message counts only, credited to "(codex)"); conversation counting no longer inflates on -wal/-shm sidecars
  • Utilities honor the default agent — magic commit / commit-message generation run on hermes when it is the default agent (claude otherwise: only those two CLIs have a silent one-shot text mode); the auto-answer generator falls back to hermes when claude is not installed
  • Status bar no longer brands unknown providers as Claude; opencode and hermes get agent icons; dead gemini session readers removed (the CLI is sunset for individual accounts)

Changed

  • Provider lineup focused to the four with working native streaming — Claude Code, Codex, OpenCode and Hermes. OpenClaw and Antigravity are dropped: OpenClaw only ever emits one whole JSON envelope at exit (no token stream is possible) and Antigravity's transcripts are protobuf blobs that never rendered. Their session readers, analytics, icons, MCP config, rename paths and docs are removed, which also let the whole-JSON accumulation special-case come out of the streaming loop
  • Skills — one meaning now: the SKILL.md standard. Removed the legacy prompt-injection "skill recommender" (8 built-in tool-hint rules silently prepended to messages) — Vect no longer modifies what you send; agents load SKILL.md themselves at session start. The Skills sidebar, Skills tab, and Hub now all draw from the same on-disk SKILL.md source (the sidebar previously showed a different system than the tab, and Hub's "8 skills installed" counted phantom built-ins). @skill mentions expand to a SKILL.md path pointer instead of inlining prompt text

Fixed

  • Marketplace search works without a GitHub login — the Hub used GitHub's code-search API, which refuses anonymous callers, so every deployed install without a token or gh login got HTTP 401 on its first search. Code search is now the authenticated upgrade path; without a token the Hub lands on curated skill repos (anthropics/skills, obra/superpowers) and searches via the anonymous repository API, listing each repo's SKILL.md files from a single git-trees call. A stored token that turns out expired or revoked falls back to anonymous instead of failing outright
  • Display — no more raw machine identifiers in the UI: MCP tool chips show server · tool instead of registry keys (mcp__plugin_playwright_playwright__browser_navigate), collab participant panes and agent output views render stream-json as its text and ▸ tool markers instead of protocol frames, provider chips show agent names ("Claude Code") instead of ids, and task status chips read "in progress" instead of in_progress
  • Collab — starting a team session from the session modal or a template now spawns its agent roster; previously only the landing hero did, so the modal produced a session labelled "team" with no participants that behaved like solo
  • Agents — codex hung forever instead of running: its prompt goes in argv but it still drains stdin, and Vect held the pipe open because it only recognised claude's -p flag as non-interactive. A codex collaborator sat at "Reading additional input from stdin..." consuming no CPU and never taking a turn. The spawning caller now states whether the process is interactive
  • Auto-answer — the autonomous "keep going" loop now runs: it listened for (y/n) text on the wrong id and print mode emits stream-json with no prompt text to match, so it never fired once. Continuation is decided at the turn boundary, still gated by the halt policy (100 iterations / 5 no-progress turns)
  • Roadmap — Resume is no longer a dead click: it marks the task in progress (opening its CRDT room) and opens a session in the task's working directory; Add Task now enrols the new task in the roadmap instead of just opening the Tasks tab, which left the roadmap permanently empty
  • Agents — custom agent rows show a real running count instead of always 0
  • Tasks — tasks are persisted with their full schema (working directory, timestamps); previously the board wrote partial rows that later readers saw as undefined
  • Collab — an unnamed team room is labelled Collab - <dir> wherever it is started from, instead of the bare directory name (a room called "." when no workspace is open)
  • CRDT — an agent joining an existing room is caught up with everything that happened before it connected; the relay forwarded live traffic only, so a joining agent (Solo → Collab upgrade) started from an empty document