Dev.to AI πŸ€– Ai πŸ‘ 0 πŸ“– 8 min read

Caret: an open-source Cursor class AI code editor

I wanted the Cursor experience without shipping a second copy of Chromium and without a monthly fee for routing my own API keys through somebody else's server. So I built Caret: an AI code editor with a Rust core, a Reac

Caret: an open-source Cursor class AI code editor

I wanted the Cursor experience without shipping a second copy of Chromium and without a monthly fee for routing my own API keys through somebody else's server. So I built Caret: an AI code editor with a Rust core, a React and Monaco front end running in the operating system's WebView, and every model call going straight from your machine to the provider you picked.

Version 0.2.0 shipped this week. This post is the tour: what Caret does, how it is built, what it still cannot do, and how to install it. Everything below is in the public repository under the MIT license: github.com/Fast-Editor/Caret.

Why not fork VS Code

Every serious AI editor today is a VS Code fork, which means an Electron app: a bundled Chromium, a Node runtime, and a baseline of a few hundred megabytes before you open a file. That is a reasonable trade for a company with a cloud backend to sell. It is a poor one for a tool whose whole pitch is "your keys, your machine".

Caret is a Tauri 2 application. The core is one Rust process with tokio and mimalloc. The UI is React 19, Monaco and xterm, rendered by WKWebView on macOS, WebView2 on Windows and WebKitGTK on Linux. There is no Node at run time and no extension host process.

Measured on a release build (the method is in docs/PERFORMANCE.md):

Measurement Value
Rust core, idle with a workspace open about 110 MB
First paint about 330 ms
Quick Open 8 ms
Project-wide search 33 ms
Hybrid codebase search (BM25 plus embeddings) 82 ms

One honest caveat: the whole process family, including the WebKit content process, is about 490 MB with a TypeScript file and a terminal open, against about 393 MB for Cursor idle on the same machine. The Rust side is small; the system WebView is not free. The plan for closing that gap is in the same document.

The editor you expect

Caret with a file open and the agent pane

Caret is a real editor first. Monaco with split groups, a diff editor, breadcrumbs and an outline. A lean Language Server Protocol client for TypeScript, Rust, Python, Go, C and C++, Java and others. A Debug Adapter Protocol client with breakpoints, stepping, variables, a watch list and a debug console for Node, TypeScript and Python, reading your existing launch.json. Source control with a commit UI, branches, stashes, worktrees, blame and a Bugbot-style review of the working tree, a branch or a commit.

The terminal is the piece I ended up enjoying most. It understands command boundaries, so output is grouped into blocks with exit status. File paths in output are clickable and open at the right line. Ghost-text suggestions come from your history and the model. A failed command gets a fix-it chip. History persists across sessions and you can search it in plain English.

Tab and inline edit

Tab gives multi-line ghost-text completions from any configured model, with partial accept and next-edit prediction. It reads your recent edits, open files and diagnostics for context, and it extends the language server's own suggestion instead of fighting it, so the LSP popup and the ghost text agree.

Cmd+K is inline edit: describe the change, watch a streaming diff appear in place, accept or reject. The same gesture in the terminal turns plain English into a shell command.

The agent, and what keeps it honest

The agent pane has Agent, Ask, Plan and Debug modes with streaming tool calls, checkpoints per turn, per-file review, queued messages, context summarisation and a live cost readout. Rules come from .caret files, .cursorrules, AGENTS.md and CLAUDE.md; there are memories, hooks, slash commands, skills and subagents. MCP servers connect over stdio or streamable HTTP from .caret/mcp.json or Cursor's own config.

Two things make it different from the agents I had used before.

Verified diffs. After a turn, Caret runs the project's checks before you accept: build, tests, lint, type-check, whatever it detects. The result shows up as a risk tier next to the change set with the evidence attached. You stop reading "I ran the tests" in a chat bubble and start seeing the exit code.

A shell classifier in front of every command. Every command an agent wants to run is parsed into segments and classified before anything executes. Blocked and denylisted commands never run. Destructive ones, like a recursive delete or a git clean, always ask, and the approval card shows which segment is the dangerous one and why. Everything else runs inside the macOS Seatbelt or Linux bubblewrap sandbox with the workspace writable and the rest of your home read-only. This applies to external agents too: a command that Claude Code or Codex runs through a Caret terminal goes through the same gate.

Permission modes in the composer

Permission modes sit on top of the classifier. Supervised asks for everything. Auto-accept edits applies edits inside the workspace. Auto lets the classifier decide and still stops on destructive commands. Full access runs everything except what is blocked. You pick a mode per thread from the composer, set a default in settings, and a project can cap the mode in its own .caret/settings.json.

Bring your own keys, or your own subscription

Caret talks directly to Anthropic, OpenAI, Google, OpenRouter, Ollama, LM Studio, vLLM and any OpenAI-compatible endpoint. Keys live in a local JSON file and never leave your machine except in the request to the provider you chose. Local models work fully offline for chat, Tab and embeddings.

Settings, Agents: Cursor and Grok Build with their sign-in state

If you already pay for Claude Code, a ChatGPT plan with Codex, Cursor or Grok, you can drive those agents from inside Caret through the Agent Client Protocol. Claude Code, Codex, Cursor, Grok Build, Gemini CLI, OpenCode and Pi each run as a local process with their own login. Their text, tool calls, permission prompts, diffs and terminals flow through Caret's UI. Settings shows the signed-in state read from each vendor's CLI, a Sign in button that runs the vendor's login in a Caret terminal, and Add account for a second Codex, Claude or Grok account with its own config home.

The rule that does not change: Caret drives the vendor's own CLI. It never replays a subscription token against a vendor API.

Auto routing

Pick "Auto" as the model and a managed Lynkr sidecar scores each request and routes it to one of your own models per tier, with session pins and fallback. Every reply shows which model answered. It is routing among the keys you configured, not a hosted proxy.

Threads for long agent sessions

The thread list with Pinned, Snoozed and Settled sections and the Snooze menu

Agent sessions are not chats; they are work items that run for a while. 0.2.0 treats them that way. Pin, snooze with a wake time, settle finished work, archive with a five-second Undo. The list folds into Working, Pinned, day buckets, Snoozed and Settled, and can group by project across every workspace. Message search covers every session on disk.

While a turn runs you can queue a follow-up, or steer the running turn with Alt+Enter so the message lands before the agent's next step. Cmd+Shift+Enter sends the draft to a new thread in the background. Queued messages are editable.

Three models answering the same prompt side by side

You can fork from any message, hand a thread to another agent or model with a budgeted context transfer, or send one prompt to several models at once and read the answers side by side, each in its own thread and, if you like, its own git worktree. Worktrees have branch templates and cleanup policies. Scratch threads start in a throwaway repository and can become a project later. Desktop notifications fire when a thread finishes, fails, needs an approval or asks a question.

Usage, across everything

Settings, Usage

A local ledger records tokens and cost for every request Caret makes: agent turns, inline edits, Tab, review, commit messages. The Usage page adds the histories your other agents keep on disk, Claude Code, Codex (including its rate-limit windows) and OpenCode, read-only, so you see what a week actually cost across all of them. Unknown models get a price editor.

Driving Caret from the outside

Settings, MCP: Caret as an MCP server

Caret can act as an MCP server on loopback with a bearer token. Any connected agent, Claude Code in a terminal for example, gets tools to create threads, send work, wait for the reply, read transcripts, and resolve approvals, with each thread running on whichever provider or external agent you configured. Settings prints the one-line configs for Claude Code, Codex and Cursor.

Settings, Remote

caret serve puts the whole editor in a browser on your LAN or over Tailscale. The Mac keeps running everything; the browser loads the same bundle with a shim that relays every command through the desktop webview over an authenticated WebSocket, so nothing is reimplemented. Browsers pair once with a six-digit code and hold a revocable token.

How it is built

The repository is a single Tauri 2 app. The Rust side is organised by domain: ai (providers, the agent runner, tools, the router), acp (the Agent Client Protocol client and bridge), sandbox (the classifier and the Seatbelt and bubblewrap wrappers), verify (the diff verification engine), index (a tantivy index plus optional embeddings), core (filesystem, git through libgit2, pty, settings, sessions), mcp, debug, orchestrator and remote.

The contract between the two halves is deliberately boring. Every Tauri command is domain_action in snake_case with a TypeScript wrapper in one file, every struct that crosses the boundary is a serde type mirrored one to one in src/types.ts, streams use Tauri channels, and low-frequency broadcasts are named events. UI modules talk to each other only through a command registry and a small bus. That discipline is what made it possible to build the remote mode as a transport shim rather than a second client.

There are close to six hundred automated tests across cargo and vitest, and the agent core runs headless, which is how the orchestrator and remote servers are tested end to end over real HTTP and WebSockets.

What is not there yet

  • No VS Code extension marketplace. Language support is the built-in LSP client, debugging is DAP, tools come from MCP and ACP. An extension host without Chromium is planned, not built.
  • Builds are ad-hoc signed until a Developer ID is configured, so a browser-downloaded DMG needs xattr -dr com.apple.quarantine once. The install script and the Homebrew cask handle it.
  • Windows and Linux installers are built by the same workflow as macOS and have had far less runtime testing.
  • No voice input, no computer use, no hosted cloud agents, no phone app. Remote access is a browser over your own network.

Install

macOS one-liner:

curl -fsSL https://caret-ochre.vercel.app/install.sh | sh

Homebrew (Homebrew 7 asks you to trust a third-party tap once):

brew tap fast-editor/caret
brew trust fast-editor/caret
brew install --cask caret

Windows and Linux installers, plus winget, scoop, AUR and Nix manifests, are on the download page. The app updates itself in place after that.

If you are weighing it against the editors you know, there is a feature-by-feature comparison with T3 Code and Cursor, and the docs are rendered from the same Markdown that ships in the repository.

Issues, ideas and pull requests: github.com/Fast-Editor/Caret. I read all of them.

πŸ“° Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.