A terminal IDE you can use in five minutes: no tutorial, no muscle-memory tax.
Cove is a GUI-native terminal editor written in Go. If you come from VS Code, Zed, or JetBrains, everything works the way you expect: visible menus and tabs, a command palette, familiar shortcuts (Ctrl+S saves, Ctrl+P opens the palette), and first-class mouse support. The differentiator is discoverability, not a feature list.
- Fast on big files: rope buffer + virtualized viewport; keystroke-to-render under one frame on a 50k-line file (enforced by CI perf gates).
- Tree-sitter syntax highlighting for fifteen languages plus the config files around them (
.env,.gitignore,go.mod, lockfiles, shell dotfiles, …), with structural selection (Ctrl+Eexpands the selection to the enclosing syntax node) and embedded-language support:<script>/<style>in HTML and fenced code blocks in Markdown highlight as the real thing. - Code folding: every foldable region shows a
▾chevron in the gutter — click it (orAlt+-) to fold, click the▸to unfold; Fold: Fold All / Unfold All live in the palette. Fold an unfamiliar file to see its skeleton. Folds follow your edits, and anything that lands the cursor in a hidden line unfolds it. - LSP built in: diagnostics, go-to-definition (
F12), references (Shift+F12), hover docs (Ctrl+K), rename (F2), completion (Ctrl+Space), signature help (parameter hints appear as you type(and,), formatting, quick fixes and refactors (Alt+Enter— including server commands that create files, like gopls's add test and extract to new file), a symbol outline (Ctrl+T), project-wide symbol search (F3), a problems list (F8), and next/previous-diagnostic jumps (Alt+N/Alt+P). Go, Python, TypeScript/JavaScript, Rust, C/C++, HTML, CSS, and Terraform work out of the box — including TypeScript 7's native language server (both the push and pull diagnostics models are supported). - AI inline completion, bring your own model (opt-in): ghost-text suggestions appear when you pause typing —
Tabaccepts,Escdismisses. Works with any OpenAI-compatible endpoint (Ollama, LM Studio, OpenRouter, Groq, …) or Anthropic's native API; point the[ai]config block at your model and keep the API key in an env var. Prefer suggestions only on demand? Setmanual = trueand trigger them withAlt+\. - Search across the project (
F7): .gitignore-aware, smart-case, sees unsaved buffer content, and results land in a sidebar panel grouped by file — click a hit to preview, Enter to jump. Narrow with include/exclude glob filters (i/xin the panel). Replace in Project… (palette) previews the count and applies undoably to open files. - Markdown preview: Markdown: Preview (palette) renders the current
.mdfile into a styled read-only tab — headings, emphasis, links, lists, code blocks. Rerun to refresh after editing. - A jump list:
Alt+Leftwalks back through go-to-definition, symbol, and search jumps;Alt+Rightwalks forward. Navigation is never a one-way door. - Sessions restore themselves: quit and reopen the same directory — tabs, cursors, the split, and sidebar width come back. Opening an explicit file skips it (
cove main.gomeans exactly that). - Crash recovery: unsaved changes are snapshotted in the background every couple of seconds. If Cove (or your machine) dies, reopening the file restores them — undoably, and never over a file that changed on disk in the meantime. Saving or quitting normally leaves nothing behind.
- Command palette (
Ctrl+P): every action is discoverable and shows its keybinding and rebindable ID. - File tree, tabs, fuzzy file finder (
Ctrl+O): the chrome you expect from a GUI editor. Two open files with the same name show their parent folder in the tab. The tree shows git status at a glance — new, modified, and conflicted files are tinted, folders containing changes get a dot — and can create, rename, and delete files in place. - Split panes (
Ctrl+\): one vertical split with a draggable divider; both panes share the tab list,F6/Shift+F6cycles through panels. - Mouse support that actually works: click to place the cursor, click tabs and tree entries, drag to select, drag the split divider and panel heights.
- Integrated terminal (
Ctrl+J): your shell in a panel under the editor, with scrollback (mouse wheel orShift+PgUp/PgDn), multiple instances (the+button), and a draggable height. Register your favorite TUI apps (lazygit,redis-tui,btop, …) in the config and they get their own palette entry and optional keybinding, running as a named panel instance — invoking again refocuses the running app instead of starting a second one. - Your coding agent is a first-class panel instance: flag one app as
agent = true(Claude Code, aider, codex, opencode, … anything that runs in a terminal) and Agent: Send Selection (Alt+A) pastes the selection into it as apath:line-linereference plus a fenced code block, launching the agent first if it isn't running. Send File Reference and Send Diagnostic Under Cursor do the same for the cursor position and the error under it. Cove never presses Enter for you: the text lands in the agent's prompt, you read it and send it. The format is plain text every agent understands, not one tool's@-mention syntax. - The agent can ask the editor (MCP bridge): Cove serves its warm language servers and editor state to the agent over MCP, so Claude Code (or any MCP client) gets
diagnostics,definition,references,hover,document_symbols,workspace_symbols,rename, andopen_filesstraight from gopls, pyright, tsc, rust-analyzer or clangd instead of re-running builds and grepping. One-time setup: Agent: Register Cove's MCP Server with Claude Code in the palette (it runsclaude mcp add --scope user cove -- cove mcp). Every agent started in Cove's terminal panel finds its editor throughCOVE_SOCKET; outside Cove the server simply has no tools.renameedits open buffers in place (undoable) and writes closed files. Three tools go the other way:searchruns Cove's project search (gitignore-aware, sees unsaved buffers),open_fileshows you a file at a line without taking focus from the terminal, andnotifyputs a short message in the status bar. The other tools only read. - Review the agent's edits hunk by hunk (
Alt+R): launching the agent takes a checkpoint of the worktree (untracked files included,.gitignorehonored, your index untouched), and the Review panel in the sidebar lists everything that changed since, grouped by file.Enteropens the file on the hunk with gutter signs against the checkpoint,rreverts the hunk (an undoable edit on an open buffer, a disk write otherwise),aaccepts it by staging it (agit add -pyes),Astages everything and takes a new checkpoint,xpastes the hunk into the agent's prompt to ask about it,dshows checkpoint │ now side by side. Each prompt you submit is a turn: with nothing pending the baseline moves, so a review is always "what this prompt did", and the git panel is ready to commit what you accepted. The list re-diffs whenever the terminal panel produces output. Follow mode (f) opens whatever the agent just touched in a single reusable tab, without stealing focus from the terminal. - Git built in (
Ctrl+G): a Zed-style panel with staged/unstaged files, per-file diffs in a read-only tab, commit, amend (keeps a multi-line message intact when you only add files), undo last commit (keeps changes staged), push/pull/fetch (a branch with no upstream is published automatically; a push rejected because you rebased or amended offers--force-with-leasebehind a confirm), stash (everything, or just the selected file — pop brings it back), sync your branch (fetch + rebase onto any branch from a picker, carrying uncommitted work across), and per-file discard/restore. Multi-repo folders just work: open a directory containing several checkouts and the panel shows one section per repo, with every action targeting the repo under the cursor (or the active file's). Commit history opens in a fuzzy picker; Enter on any commit opens its full diff. Gutter signs mark added/modified/deleted lines as you type, inline blame (Git: Toggle Inline Blame in the palette) shows who last touched the cursor line, and the current branch and ahead/behind counts live in the status bar. - A commit graph you can actually read: one row per commit, box-drawing lanes colored per branch, and each branch's name written vertically above its own column — with a line running down to its tip, even when that tip sits deep in history. Enter on a row opens the commit's diff.
- Branch switching that knows your remote: the picker (
b) fetches first and lists remote branches alongside local ones — selectingorigin/foochecks it out as a local tracking branch. Creating a branch whose name already exists on the remote checks that one out instead of forking an unrelated copy. - Merge conflicts resolved in the editor: a conflicting pull highlights each
<<<<<<<block — ours green, theirs blue — and the palette's Merge: Accept Ours / Theirs / Both resolves the block under the cursor as an undoable edit. Whole-fileo/tshortcuts live in the panel's Conflicts section, a "Merging" banner tracks the in-progress merge, andcconcludes it with git's prepared message prefilled. - Multi-cursor editing, find & replace, undo/redo — plus the line-editing staples: toggle comment (
Ctrl+_), move line up/down (Alt+Shift+Up/Down), duplicate/delete line, indent/outdent, select all occurrences, and go to line (Ctrl+L). - Plays nice with the outside world: files edited outside Cove reload in place (undoable); a buffer with unsaved changes warns instead. The file tree and git status re-sync whenever the terminal regains focus, so changes from another shell or editor show up on their own.
- No terminal traps:
Ctrl+Ccopies,Ctrl+Zundoes. An opt-in Vim keymap exists; it is never the default.
brew install GurYN/tap/coveThe formula builds from source on your machine (tree-sitter uses CGo, so there are no prebuilt bottles yet); Homebrew pulls in the Go toolchain as a build dependency automatically.
Use WSL and install with Homebrew (or a Linux release binary) inside it. There is no native Windows build — the integrated terminal relies on Unix PTYs.
Download a binary from the releases page, or build from source (Go 1.26+ and a C compiler required; tree-sitter uses CGo):
git clone https://github.com/GurYN/cove-editor.git
cd cove-editor
go build -o cove ./cmd/coveThen open a file or a directory:
cove main.go
cove .Syntax highlighting ships in the binary for Go (including go.mod), Python, TypeScript/JavaScript (including JSX/TSX), Rust, C/C++, HTML (also .svg/.xml), CSS, Bash, JSON, TOML, YAML (including Docker Compose files), HCL/Terraform (.tf, .tfvars, .hcl), Dockerfile (Dockerfile, Dockerfile.*, Containerfile, *.dockerfile), and Markdown (also .mdx). HTML highlights embedded <script> and <style> blocks; Markdown highlights bold/italic/links/code spans and fenced code blocks in their own language (```go, ```js, …).
Everyday config files color too, reusing those grammars: .env (and .env.*), .gitignore/.dockerignore/.gitattributes, shell dotfiles (.bashrc, .zshrc, …), INI-style files (.ini, .cfg, .properties, .editorconfig, .gitconfig, .npmrc), lockfiles and manifests (Cargo.lock, Pipfile, uv.lock, poetry.lock, Procfile), and Makefile/Justfile.
Language intelligence needs the language's server on your PATH:
| Language | Server | Install |
|---|---|---|
| Go | gopls |
go install golang.org/x/tools/gopls@latest |
| Python | pyright-langserver |
npm i -g pyright |
| TypeScript / JavaScript | tsc --lsp (TypeScript 7+) |
npm i -g typescript |
| Rust | rust-analyzer |
rustup component add rust-analyzer |
| C / C++ | clangd |
ships with Xcode's command line tools; else your distro's clangd package |
| HTML / CSS | vscode-html-language-server / vscode-css-language-server |
npm i -g vscode-langservers-extracted |
| Terraform | terraform-ls |
brew install hashicorp/tap/terraform-ls |
Still on TypeScript 5? Nothing to configure: Cove probes your tsc version once and falls back to typescript-language-server (npm i -g typescript-language-server typescript@5) when tsc predates the native server. A [lsp.typescript] entry in the config file overrides the probe entirely.
Language intelligence also reaches the coding agent in the terminal panel: cove mcp is a stdio MCP server that proxies to the running editor, so an agent registered once with claude mcp add --scope user cove -- cove mcp (or the palette's Agent: Register Cove's MCP Server with Claude Code) queries the same servers Cove runs. Other MCP clients register the same command; they need COVE_SOCKET in their environment, which every panel terminal has.
Any other language server speaking stdio registers in the config file:
[lsp.zig]
command = ["zls"]
extensions = ["zig"]No server installed? Cove still works as a fast editor with syntax highlighting.
Everything below is also in the command palette (Ctrl+P), which shows the current binding next to each action.
| Key | Action |
|---|---|
Ctrl+P |
Command palette |
Ctrl+O |
Go to file (fuzzy finder) |
Ctrl+S |
Save |
Ctrl+F / Ctrl+R |
Find / find & replace |
F7 |
Search in project |
Ctrl+Z / Ctrl+Y |
Undo / redo |
Ctrl+C / Ctrl+X / Ctrl+V |
Copy / cut / paste |
Ctrl+B |
Toggle sidebar |
Ctrl+G |
Toggle git panel |
Ctrl+J |
Toggle terminal panel |
Ctrl+W |
Close tab |
Ctrl+PgUp / Ctrl+PgDn |
Previous / next tab |
Ctrl+\ |
Split pane |
F6 / Shift+F6 |
Next / previous panel |
Ctrl+E |
Expand selection to syntax node |
Alt+- |
Fold / unfold at cursor (or click the gutter chevron) |
Ctrl+D |
Add next occurrence to selection |
Alt+Up / Alt+Down |
Add cursor above / below |
Alt+Shift+Up / Alt+Shift+Down |
Move line up / down |
Ctrl+_ |
Toggle line comment |
Ctrl+L |
Go to line |
F12 / Shift+F12 |
Go to definition / references |
Ctrl+K |
Hover documentation |
Ctrl+Space |
Trigger completion |
Ctrl+T |
Go to symbol (outline) |
F3 |
Go to symbol in project |
Alt+Enter |
Quick fix / code action |
F2 |
Rename symbol |
Alt+\ |
Trigger AI suggestion (when [ai] is configured) |
Alt+A |
Send selection (or cursor line) to the agent (when an [apps.*] entry has agent = true) |
Alt+R |
Agent review panel: the agent's changes since the checkpoint, hunk by hunk |
F8 |
Problems list |
Alt+N / Alt+P |
Next / previous diagnostic |
Alt+Left / Alt+Right |
Jump back / forward |
Ctrl+Q |
Quit (asks for confirmation; warns about unsaved files) |
Every action has a stable ID (shown in the palette footer) and can be rebound in the config file. File: Save All, Edit: Duplicate Line, Edit: Delete Line, and more live in the palette without a default binding.
When the terminal panel has focus, every key goes to your shell except the ones that keep Cove reachable: Ctrl+J (hide panel), Ctrl+P/F1 (palette), Ctrl+B (sidebar), Ctrl+G (git panel), F6/Shift+F6 (cycle panels), Ctrl+Q (quit), and Shift+PgUp/PgDn (scrollback). Rebinding any of these moves the exception with it. (tmux inside Cove: rebind sidebar.toggle to free up Ctrl+B for the tmux prefix.)
Shift+Enter in the terminal panel (Claude Code and other TUI apps): if your terminal is configured to send a newline (
\n) forShift+Enter, that byte is indistinguishable fromCtrl+J— so it toggles the panel instead of reaching your app. Configure it to send\x1b\r(ESC + CR) instead, which TUI apps read as the same "insert newline" chord. In Ghostty:keybind = shift+enter=text:\x1b\r. The same applies to any terminal with a customShift+Enter→\nmapping (iTerm2, WezTerm, Alacritty, …).
Ctrl+B and Ctrl+G are tri-state: they open and focus their panel, refocus it if it's open but unfocused, and close it when it already has focus.
In the file tree: n new file, N new folder, r rename, x delete (with confirm). Right-click any row for the same actions as a menu.
Inside the panel (Alt+R; also in the palette as Agent: Review Changes):
| Key | Action |
|---|---|
Enter |
Open the file on the hunk (gutter signs diff against the checkpoint) and move into the editor |
Space |
Preview the hunk: same, but the panel keeps focus, so r/a still apply |
r |
Revert the hunk — undoable in an open buffer; a new file asks before deletion |
a / A |
Accept the hunk: it is staged, like a yes in git add -p / stage everything and take a new checkpoint |
x / X |
Paste the hunk into the agent's prompt as a diff to ask about it / revert it first and say so |
d |
Side-by-side diff: checkpoint │ now |
f |
Toggle follow mode |
R |
Refresh |
Esc |
Back to the editor |
Every prompt you submit to the agent is a turn (an Enter after typed or pasted text; a bare Enter answering a menu is not). The header shows the current turn and each file header the turn during which it changed. Once nothing is left to review, the next prompt moves the baseline so the review starts clean, and the git panel holds what you staged, ready to commit. While hunks are still pending, later prompts snapshot instead, so earlier turns keep their labels. The boundary is your Enter: anything the agent writes after you submit the next prompt counts toward that prompt. A file header also shows +N err when the language server reports more errors in that file than when the turn began (known for files a server has looked at: open tabs, or a whole package with gopls). The status bar carries the same signal, agent 3 hunks (turn 2) +1 err, so you notice changes without opening the panel. From the editor, Alt+R brings focus back to the panel (F6 cycles panels too). Opening the panel with no checkpoint takes one. Agent: Checkpoint (palette) resets the baseline by hand; [agent] checkpoint_on_launch = false stops the automatic one when the agent starts.
Inside the panel (all of this is also in the palette):
| Key | Action |
|---|---|
Space |
Stage / unstage the selected file |
Enter |
Open the file's diff (read-only tab; [git] diff_style = "side" makes it side-by-side) |
d |
Open the diff side-by-side (old │ new columns) |
o |
Open the file itself (on a conflict row: keep ours) |
c |
Commit staged files |
m |
Amend last commit (Enter keeps the message; typing rewords) |
z |
Undo last commit (keeps changes staged, with confirm) |
l |
Commit history (fuzzy picker; Enter opens the commit's diff) |
g |
Commit graph (read-only tab; Enter on a line opens that commit's diff) |
b |
Switch branch (fetches first; remote branches check out as tracking) |
s |
Sync branch: fetch, then rebase onto a picked branch (uncommitted work rides along via autostash) |
h / p |
Stash the selected file / pop the latest stash |
a / u |
Stage all / unstage all |
o / t |
Resolve the selected conflict: keep ours / keep theirs (whole file) |
x |
Discard the file's changes (with confirm) |
f |
Fetch |
r |
Refresh status |
Esc |
Back to the editor |
Mouse: clicking a file's status letter toggles staging; clicking its name opens the diff. Right-click opens a context menu — file actions on a file row (stage, diff, open, stash, discard), resolve on a conflict row, repo actions (commit, push, pull…) anywhere else. Push, pull, fetch, New Branch…, Stash All Changes, and Push — Force With Lease are in the palette.
Syncing a branch before the PR. On a feature branch, s fetches and lists every other branch — pick origin/main and Cove rebases your branch onto it, autostashing uncommitted work across the rebase. If the branch was already pushed, the next push detects the rewritten history and offers a --force-with-lease push (never a blind force: it refuses if the remote gained commits you haven't seen). A conflicted rebase points you to the terminal to resolve and git rebase --continue.
With several repos in the opened folder, each renders as its own bold name · branch section and every panel action applies to the section under the cursor — the commit prompt names its target (Commit to sources (main):), and toasts are prefixed with the repo name. Actions run from the palette follow the active file's repo; for a file outside every repo, a one-shot picker asks. The status bar shows the current repo as ⎇ name:branch.
Outside the panel, gutter signs next to the line numbers mark added, modified, and deleted lines as you type. Git: Toggle Inline Blame (palette) shows the last commit for the cursor line in the status bar: author, age, and summary; lines you have edited show uncommitted changes.
Merge conflicts. A pull that conflicts stops mid-merge (Cove pulls with merge semantics when you haven't configured pull.rebase): conflicted files appear in a Conflicts section, the status bar shows (merging), and Enter on a conflicted file opens it at the first block with both sides highlighted (ours green, theirs blue — merge.ours/merge.theirs in [colors] to retheme). Resolve per block from the palette — Merge: Accept Ours / Theirs / Both, Merge: Next Conflict — or edit the markers by hand; every accept is a normal undoable edit. Stage the file (Space) when done, then c commits and concludes the merge (the message is prefilled from git). o/t in the panel take one side for the whole file.
TOML at ~/.config/cove/config.toml (or point COVE_CONFIG elsewhere). Open it from inside Cove via the palette: Open Settings.
theme = "cove-dark" # or "cove-light"
keymap = "default" # or "vim" (opt-in)
[editor]
confirm_quit = true # false: Ctrl+Q quits without asking
[files]
hidden = [".DS_Store", "*.pyc"] # hide from the file tree (git panel still shows them)
[git]
view = "flat" # or "tree": changed files under collapsible directories (Enter/Space/click folds)
diff_style = "unified" # or "side": Enter opens diffs as two aligned columns ('d' always does)
[keys]
"file.save" = "ctrl+shift+s" # rebind any action by its ID
[lsp.go]
command = ["gopls"] # override or add language servers
[colors]
"git.added" = "#98c379" # override any theme color, incl. git states
"diff.bg.added" = "#29392b" # side-by-side diff line bands: also .deleted / .modified
[apps.lazygit] # favorite TUI apps: palette entry "App: lazygit",
command = ["lazygit"] # runs as a named terminal-panel instance
key = "ctrl+alt+g" # optional
[apps.claude] # your coding agent: "Agent: Send Selection" (Alt+A),
command = ["claude"] # "Send File Reference", "Send Diagnostic" paste into it
agent = true # (one entry only; launched on first send if not running)
[mcp]
enabled = true # serve diagnostics/definitions/references/rename to the agent
[agent]
checkpoint_on_launch = true # review baseline when the agent starts
follow = false # open files as the agent touches them
[ai] # AI inline completion (ghost text; Tab accepts, Esc dismisses)
enabled = true
protocol = "openai" # or "anthropic"
base_url = "http://localhost:11434/v1" # Ollama; any OpenAI-compatible host
model = "qwen2.5-coder:7b"
api_key_env = "OPENROUTER_API_KEY" # env var NAME — keys stay out of this file (local runtimes need none)
manual = false # true: suggest only on Alt+\, never on a typing pauseConfig mistakes don't fail silently: a binding that collides with an existing shortcut, a key terminals can't deliver (ctrl+i arrives as Tab), or an unknown action ID shows up in a toast at startup.
In active development, pre-1.0. The v1 scope is deliberately tight: editing, code folding, chrome, LSP for four languages (with signature help and diagnostic navigation), an integrated terminal, git integration (panel, staging, diffs, commit, amend, undo-commit, history & visual graph, push/pull with a safe force-with-lease path, branch sync via rebase, stash, remote-aware branch switching, in-editor conflict resolution, restore, gutter signs, inline blame, file-tree markers, multi-repo folders), split panes, project-wide search & replace (results panel with include/exclude filters), a Markdown preview, code actions, a jump list, per-workspace session restore, crash recovery, user-defined TUI app launchers, and provider-agnostic AI inline completion — all built and recently hardened by a full bug-hunt pass (UTF-8-safe cursor movement, LSP process lifecycle, tree-sitter memory management, non-ASCII git filenames). Plugins and debugging are deferred to v2.
go test ./... # full suite
go test ./internal/... -bench . # benchmarksThe performance gates (TestKeystrokeLatency50k, TestKeystrokeLatencyWithSyntax) are hard limits (p99 keystroke→frame < 16ms) and run in CI.
