Vectrum
Sign In
201 lines · 12.6 KB
# Vectrum Code

A native [T3 Code](https://github.com/pingdotgg/t3code)-style desktop client for coding
agents, built with [GPUI](https://gpui.rs) and [GPUI Kit](https://github.com/longbridge/gpui-kit).
It drives [Claude Code](https://docs.claude.com/en/docs/claude-code),
[Pi](https://github.com/earendil-works/pi) and [jcode](https://github.com/1jehuang/jcode).

Every thread runs its own agent process in the background. Claude Code threads talk to the
`claude` CLI over the stream-json protocol the Claude Agent SDKs use
(`--input-format/--output-format stream-json` plus the stdio control channel). Pi threads
talk to `pi --mode rpc` over its JSONL RPC protocol. jcode threads talk to
`jcode api --stdio`, a bridge to jcode's versioned harness API that starts jcode's shared
daemon if it isn't running, so jcode threads also show up in jcode's own session list.

The layout and workflow follow T3 Code. The look follows [MetalUI](https://metalui.dev/), the
"soft hardware" design system [vectrum.cc](https://vectrum.cc/) is built on: the
conversation sits on a raised sheet, buttons are caps that sink when pressed, code and tool
output sit in inset wells, and labels are engraved in mono caps. It comes in MetalUI's two colorways, Bone and Graphite,
plus popular color schemes rebuilt in the same style: Tokyo Night, Catppuccin, GitHub, One, Nord,
Gruvbox, Rosé Pine, Solarized and Dracula.

![Vectrum Code in Bone](docs/screenshot.png)

![Vectrum Code in Graphite](docs/screenshot-graphite.png)

## Features

- A searchable thread list across all projects, newest activity first. Each card shows the
  project, its git branch, how long ago it was active, the agent, and a status light.
- Settle a thread to stop its process and file it under **Settled**. Its transcript stays,
  and the next message resumes the conversation.
- A new thread opens on a start screen, "What should we build in *project*?", with the
  project as a switcher, a way to start without a project, and the branch it starts from.
- A model picker across providers: Claude's models (current ones, plus legacy models
  folded away), every model Pi's configured providers offer, and every model route jcode's
  logins and provider profiles make available. Star models to keep them under **Favorites**,
  search across all of them, and pick the first nine with Ctrl+1–9. Picking another
  provider's model starts a thread of that kind in its place.
- A reasoning picker: Low to Max (as the model supports), Claude's Ultracode and
  Ultrathink, and Fast mode on models that have it. Pi threads list Pi's thinking levels;
  jcode threads offer effort levels on its Anthropic, OpenAI and OpenRouter routes.
  All of it switches live.
- An access picker: Supervised, Auto-accept edits, Auto, Plan or Full access. Pi and jcode
  have no approval prompts, so their threads always run with full access.
- Finished turns fold their tool calls and interim messages into one **Worked for 12s** row
  above the answer. Click it to unfold.
- Under each turn that touched files, **N changed files +a −r** with a folder tree and
  per-file counts. Click a file, or **Open diff**, to read the diff in the app. The app
  snapshots the working tree through a private git index, so your staging area is never
  touched.
- Streaming Markdown with a copy button on every code block, and tool calls as
  collapsible cards with their input and output.
- Inline permission prompts (Allow, Deny, "Always allow" / "Accept all edits"), and Pi
  extensions' confirm and choice dialogs as one-click questions.
- Claude's questions (AskUserQuestion) open as a form on top of the composer, one question
  at a time with tabs between them. Pick an option by click or with 1–9, tick several on
  multi-select questions, type your own answer in the composer, or skip. What you answered
  stays in the transcript.
- Attachments: images are sent inline, other files by path. A ring shows how full the
  context window is.
- A project panel: the machine, **Open in** your editor (Zed, VS Code, Cursor, VSCodium,
  Sublime Text, Kate or the file manager, whichever are installed), the branch with a
  switcher, **Commit** (asks the agent to commit, or commit and push), the size of the
  uncommitted changes, and the thread's cost.
- Background tasks: commands, monitors and subagents Claude leaves running show in a strip
  above the composer with their age and a stop button. When one finishes, the transcript
  says so and Claude picks the work back up and reports back on its own. A long-running
  command can be sent to the background from its tool card, like Ctrl+B in Claude Code.
- A browser the agent and you share (Ctrl+Shift+E, or the globe in the top bar), on
  Vercel's [agent-browser](https://github.com/vercel-labs/agent-browser): each thread has
  its own headless Chrome session, which its agent drives with the `agent-browser` CLI
  while the panel shows it live. Click, scroll and type in the page yourself, or go to a
  URL. When the agent opens a page while the panel is closed, a light on the globe says so.
- Interrupt with Esc or the stop button. Messages sent while the agent works are queued.
- Crash recovery: if a process dies, the next message restarts it and resumes the session.
- Threads are saved as you go and come back after a restart, settled ones included; the next
  message resumes the conversation. Optionally, threads a crash or restart interrupted
  continue on their own.
- New threads can start in a git worktree of their own: a fresh `vectrum/<title>` branch
  checked out under `~/.local/share/vectrum-code/worktrees`, optionally from the branch as
  origin has it, with submodules filled in. Pick Local or New worktree per thread on the
  start screen.
- Thread titles written by a small model from the first message (Settings → Text generation).
- Pin threads to the top, snooze them until later, rename them (right-click a thread card).
  The sidebar can group threads by project, fold working threads into a Working section, and
  order projects by last message, name or date added.
- When a usage limit stops a thread, it can snooze until the limit resets and continue then.
  Idle threads, and worktree threads whose pull request merged, can settle on their own.
- Send while the agent works to steer it, or queue the message for after the turn (and
  Ctrl+Enter for the other one). Queued messages wait above the composer.
- A `/` menu with Claude's commands and skills (`$` for skills alone).
- Diffs with hidden whitespace changes, foldable files, line numbers, and a stacked or
  side-by-side layout.
- Remote connections, like T3 Code's environments: turn on **Allow remote connections** on
  one device, and paste its pairing code (address and key) under Settings → Connections on
  another. The host's projects and threads appear in the sidebar tagged with its name; open,
  continue or start threads there and they run on the host. The connection is a WebSocket
  guarded by the key but not encrypted, so use it on trusted networks or over a VPN.
- A settings view (Ctrl+, or **Settings** in the sidebar), laid out like T3 Code's:
  - **General**: what new threads start with (model, reasoning, permissions, workspace,
    submodules), the text generation model, projects and threads, organization of the
    sidebar, and confirmations (unpin, settle, delete, and the quit shortcut).
  - **Behavior**: notifications (desktop, with sound, in-app), time format, response
    streaming, turn folding and costs, proactive diffs, diff defaults, the composer (skills in
    the `/` menu, collapsing on scroll, send key, follow-up behavior), update checks,
    continuing after restarts, background activity, and the editor "Open in" uses.
  - **Appearance**: comfortable or compact thread cards.
  - **Themes**: Light, Dark or System mode (System follows the desktop), and a light and a
    dark theme picked from live previews: Bone and Graphite; Tokyo Night (Night, Storm, Day);
    Catppuccin (Mocha, Macchiato, Frappé, Latte); GitHub (Dark, Dark Dimmed, Light); One Dark
    and One Light; Nord; Gruvbox Dark and Light; Rosé Pine (Main, Moon, Dawn); Solarized Dark
    and Light; and Dracula.
  - **Providers**: every agent instance (several Claude, Pi or jcode instances side by side,
    say two accounts), each with a switch, its version, login and plan, display name, binary, config
    folder, launch arguments and environment variables, plus updates and the health check
    interval, and usage hubs (CLIProxyAPI servers, with their management key).
  - **Usage**: cost, tokens and plan limits over the past day, week, month or quarter, read
    from Claude Code's and Pi's local logs and any usage hubs, by provider, model and day.
  - **Connections**, **Keybindings**, an **Archive** of settled threads, and **About**.

## Requirements

- Rust (edition 2024)
- The `claude` CLI, logged in (`claude` once interactively)
- Optional: [Pi](https://github.com/earendil-works/pi) for Pi threads
  (`npm install -g @earendil-works/pi-coding-agent`, then log in to a provider with `pi`)
- Optional: [jcode](https://github.com/1jehuang/jcode) for jcode threads
  (`curl -fsSL https://jcode.sh/install | bash`, then `jcode login`)
- Optional: agent-browser for the browser panel
  (`npm install -g agent-browser && agent-browser install`)
- GPUI's Linux system libraries: Vulkan, Wayland/X11, xkbcommon, fontconfig, freetype
  (on Arch/CachyOS: `vulkan-icd-loader` plus your GPU's Vulkan driver, `wayland`,
  `libxkbcommon-x11`, `libxcb`, `fontconfig`, `freetype2`)

## Run

```sh
cargo run --release -- /path/to/project   # defaults to the current directory
```

| Shortcut | Action |
| --- | --- |
| Enter / Shift+Enter | Send / new line |
| Esc | Interrupt Claude |
| Ctrl+N | New thread in the current project |
| Ctrl+O | Add a project folder |
| Ctrl+K | Search threads |
| Ctrl+, | Open or close settings |
| Ctrl+B | Show or hide the sidebar |
| Ctrl+Shift+B | Show or hide the project panel |
| Ctrl+Q | Quit |

### Environment

- `VECTRUM_CODE_CLAUDE_BIN`: path to the `claude` binary. Otherwise it's looked up on `PATH`,
  then `~/.local/bin` and `~/.claude/local`.
- `VECTRUM_CODE_PI_BIN`: path to the `pi` binary. Otherwise it's looked up on `PATH`, then in
  `~/.local/bin`, `~/.npm-global/bin`, `~/.bun/bin`, `~/.volta/bin` and nvm's Node versions.
- `VECTRUM_CODE_JCODE_BIN`: path to the `jcode` binary. Otherwise it's looked up on `PATH`,
  then in `~/.local/bin` and `~/.cargo/bin`.

Favorite models and everything in the settings view are saved in
`~/.config/vectrum-code/settings.json`. The environment variables above win over the binary
paths set there for each agent's first instance. Threads and the project list live in
`~/.local/share/vectrum-code` (`threads/`, `state.json`); threads started without a project run
in its `scratch` folder.

## Layout

- `src/claude.rs`: spawns and owns the agent process, `claude`, `pi` or `jcode api --stdio`
  (stdin writer and stdout/stderr reader threads).
- `src/session.rs`: per-thread state. Folds Claude's stream-json, Pi's RPC and jcode's
  harness API events into chat items, handles permission requests, control requests and
  extension dialogs, and snapshots each turn's changes.
- `src/models.rs`: the model catalog across providers, and favorites.
- `src/git.rs`: branch and change stats, working-tree snapshots, and diffs.
- `src/settings.rs`: the saved settings file, cached in memory.
- `src/ui/chat.rs`: start screen, transcript (with turn folding), tool cards, permission bar
  and composer.
- `src/ui/pickers.rs`: the model, reasoning and access pickers.
- `src/ui/settings.rs`: the settings view and its pages.
- `src/ui/changes.rs`: the per-turn change overview and the diff view.
- `src/ui/workspace.rs`: window root: thread sidebar, top bar and project panel, plus the
  git and editor helpers behind it.
- `src/ui/icons.rs`: the extra Lucide icons the app embeds.
- `src/ui/metal.rs`: the MetalUI layer. Colorway tokens and shadow recipes copied from
  MetalUI's CSS, the theme mapping for the stock widgets, and the primitives (caps, wells,
  keycaps, status LEDs, segmented switch).
- `src/ui/themes.rs`: the color schemes, the palette builder that turns each into a full
  MetalUI palette, the light/dark/system selection, and the Themes page.
- `assets/fonts/`: Geist, Geist Mono and Geist Pixel, embedded in the binary
  (SIL Open Font License, see `assets/fonts/OFL.txt`).

## Not yet supported

There is no UI for Claude's
`AskUserQuestion` (the tool is disabled, so Claude asks in plain text) or for Pi extensions
that ask for free text, code blocks have no syntax highlighting, and T3 Code's project
scripts and terminal drawer aren't here yet. jcode models can't write thread titles (every
jcode run is saved as a session), and jcode's side panel, applets and background-task
progress aren't shown.