CLI tool
eugenioenko/ttt avatar
eugenioenko/ttt

ttt: a terminal text editor with a file tree, LSP and git built in

TTT Editor (Terminal Text Tool): A real alternative to VS Code, Zed, and Sublime that runs in your terminal. A TUI that feels like GUI. Single binary, zero config.

786 stars92 forksGoMIT

At a glance

What is it?
TTT, the Terminal Text Tool, is a Go program that puts a real editor in your terminal, with syntax highlighting for 124 languages, LSP completion and diagnostics, a file explorer, multi-folder workspaces, diff views and git integration in one binary. It suits a developer who works over SSH or on a remote box, and it will not satisfy someone who needs a full desktop IDE.
Who is it for?
ttt fits a developer working over SSH, on a headless box, or in a terminal-only environment who needs more than a text editor but does not want to run a graphical IDE. It is the wrong choice for a desktop-only workflow with heavy extension needs, and the wrong choice if the terminal is your only place to see the code and the file is long.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A terminal editor that stopped being a text editor

The README positions TTT as the IDE that lives in your terminal, a TUI that feels like GUI, and as a real alternative to VS Code, Zed and Sublime that happens to run in your terminal. The selling point in the tagline is single Go binary, zero config.

The feature list is what separates it from a terminal text editor, and it is worth reading in order because the scope is wider than the description suggests.

The editor basics are there: syntax highlighting, bracket matching with highlighted pairs, find and replace with an inline find bar on Ctrl+F and a replace bar on Ctrl+R, go to line on Ctrl+G, selection with system clipboard support, undo and redo through a command-pattern undo stack, and code folding with a toggle, fold all, and fold-aware search.

Then there is a layer that has no equivalent in a classic terminal editor. Multi-cursor editing with Ctrl+D to select the next occurrence, Ctrl+K L to select all occurrences and Alt+Click to add cursors, with typing, backspace, delete and enter working at all positions simultaneously. Line operations that toggle a line comment, move, duplicate and delete a line, join lines, sort lines and split a selection into lines. Mouse support for positioning the cursor, clicking tabs, dragging sidebar and panel dividers, and right-click context menus. And automatic indentation picked up per file from.editorconfig, with a manual override in the status bar.

The language support comes from textmate-go, described as a pure Go port of VS Code's TextMate engine, covering 124 languages with multi-line constructs handled correctly. That choice is what makes the highlighting match what a desktop editor would show.

The audience is a developer whose work happens in a terminal, whether because they are on a remote machine, because they live in a multiplexer, or because they simply prefer it. The homepage is tttedit.dev, the licence is MIT, and the last push was on 2026-10-20 with the repository not archived.

LSP, diagnostics and formatting, which is the actual IDE part

The features that separate TTT from a plain terminal editor are the ones that come from the Language Server Protocol.

Auto-completion is LSP-powered with live filtering, debounce and auto-import support, so a completion comes from the language server rather than from a keyword list. Signature help shows parameter hints automatically on the opening parenthesis and on the comma. Diagnostics give inline curly underline squiggles, a problems panel, a hover popup and status bar counts.

Document formatting is also LSP-driven where possible, with format document, format selection and format-on-save available, and the README notes the formatting works via LSP or external formatters.

There is one more feature here that no other entry in the list prepares you for, and it is a good sign about the project's priorities. Git blame shows inline blame information for the current line in the status bar, giving the author, the relative time and the summary.

The repository dependencies show how this is wired. There is no separate LSP client dependency, so the protocol handling is built in, while the syntax highlighting uses eugenioenko/textmate-go, the terminal layer uses eugenioenko/xterm-go, and the terminal UI itself is gdamore/tcell/v3. There is also fsnotify for filesystem change notification, go-pty for pseudo-terminal handling, and gopher-lua, which is the scripting language embedded in the editor.

One rendering detail is worth noting because it explains why the project can feel like a GUI. The README describes a diff-based renderer for efficient terminal updates, using a double-buffered cell grid, so the editor repaints only the cells that changed rather than the whole screen. That is the difference between a TUI that flickers and one that feels immediate.

Workspaces, file arguments and the ways you can open a thing

TTT can be pointed at a lot of different things, and the list of invocations in the README is a good map of what the tool is for.

bash
ttt                             # opens the current directory
ttt .                           # also opens the current directory
ttt /path/to/dir                # opens that directory as the workspace
ttt /path/to/file.go:42:5       # opens the file at line 42, column 5
ttt dir1 dir2                   # opens multiple folders as a multi-root workspace
ttt --workspace project.ttt     # loads a saved workspace file
ttt https://github.com/owner/repo/pull/123 # opens pull request review
git diff | ttt                  # opens piped output in an unsaved tab (or: ttt -)

Several of those are unusual. Opening a GitHub pull request URL for review, and reading piped output into an unsaved tab, are the kind of thing that suggests the author works the way the tool is built around rather than the other way round. There is also a variant that opens a subdirectory while keeping the git features pointed at the enclosing repository root.

Saved workspaces use the .ttt extension and store a list of folders as relative paths:

json
{
  "folders": [
    { "path": "." },
    { "path": "../other-project" }
  ]
}

You create one from Save Workspace As in the File menu, and you add or remove folders through the command palette. The detail that matters in practice is that the git branch shown in the status bar switches automatically depending on which workspace folder the active file belongs to, so a multi-root session over two repositories does not confuse the branch indicator.

The file explorer in the sidebar is opened with Ctrl+K E and shows directories before files, both alphabetically, with each root as a collapsible group in a multi-root session. The right-click menu offers New File, New Folder, Rename and Delete, and there is a Reveal Active File action that expands the tree to the file you are in, configurable with explorer.autoReveal to happen on every tab switch.

Installing it: a package manager for every platform, and two prerequisites

Before anything else there are two prerequisites, and the README is direct about them. Git is required for the source control features, and ripgrep, the rg binary, is required for workspace search. Neither is optional.

After that there is an install path for every platform.

On macOS through Homebrew:

bash
brew tap eugenioenko/ttt
brew trust eugenioenko/ttt
brew install ttt

On Linux, the install script downloads the latest release binary for your OS and architecture and installs it to /usr/local/bin, and you can point it elsewhere with an environment variable:

bash
INSTALL_DIR=~/.local/bin curl -sSfL https://raw.githubusercontent.com/eugenioenko/ttt/main/install.sh | sh

Arch users have an AUR package, and the README gives the command as yay -S ttt. For NixOS, the flake tracks main and the README warns that a future tagged release will ship a pinned flake, with nix run github:eugenioenko/ttt offered as a way to try it without installing, and the flake input to add to your own configuration.

Windows users have scoop, with scoop install ttt. Developers with Go 1.18 or newer can install the command directly with go install github.com/eugenioenko/ttt/cmd/ttt@latest, which puts the ttt binary in your GOPATH bin or your HOME/go bin by default, and the README reminds you to make sure that directory is in your PATH.

There are also prebuilt binaries for Linux, macOS and Windows on the Releases page, and building from source is a clone plus make build, which produces an optimized binary at bin/ttt that you copy somewhere on your PATH.

The source build carries a warning worth reading: building from source compiles the latest development code, which may include work-in-progress features and could be less stable than official releases. For a single Go binary with a small dependency list, that is a reasonable trade, but it means the release binaries are the ones to trust for daily work.

The repository as a Go project, benchmarks included

The repository layout is that of a serious Go project rather than a script collection. There is an internal directory for the implementation, a cmd directory for the entry point, a tests directory with an e2e subdirectory and a bench subdirectory, a docs-web directory holding the documentation source, a config directory, a scripts directory, a community-plugins.json file, a herdr-plugin directory, and a flake.nix with a flake.lock for Nix users.

The go.mod requires Go 1.25.0 and lists a short dependency set. The components that stand out are eugenioenko/textmate-go for the TextMate port, eugenioenko/xterm-go for terminal emulation, gdamore/tcell/v3 for the terminal UI, and yuin/gopher-lua for embedding a scripting language, which is what makes community plugins possible.

The Makefile shows the engineering habits. There are build, test, run, fmt, fmt-check and lint targets, and the build target embeds a version string taken from git describe, so a binary knows which tag it came from. The formatting target pins a specific Go toolchain version for gofmt, which keeps formatting stable across machines.

Then there are the benchmarks, and they are the most telling part of the file. There is a target for editor benchmarks through the full application, with a language variable so the same benchmark can be run against go, ts, cpp or python, and a note that comparisons against another checkout are done the way CI does on pull requests, through a script called bench-compare.mjs. There is a diff view benchmark covering split, unified, wrap, open changes and commit detail, and a log benchmark that opens real logs in the built binary with word wrap off and on, and that edits a committed 128 MiB log, reporting time and peak memory. A code benchmark opens, types and presses enter in a 64 MiB Go file in the built binary, again reporting time and peak RSS.

Those three benchmarks, editor, diff and log, tell you what the author thinks is hard about running an editor in a terminal. A large log and a large source file are where a TUI has to be careful, and the fact that peak RSS is measured says the concern is memory as much as speed.

Where ttt is the wrong tool

The first wrong-tool case is a desktop-only workflow with a large extension ecosystem. TTT has a plugin mechanism, since there is a community-plugins.json and gopher-lua is embedded for scripting, but the ecosystem is young and small compared with what a desktop editor offers. If your work depends on a specific language server plugin, a specific debugger integration or a specific formatter, the honest question is whether TTT has it yet.

The second is a workflow that needs to see a lot of code at once. A terminal editor works in a grid of cells, and the size of that grid is bounded by your terminal window. An IDE with a file tree, a minimap, multiple panes and a preview pane shows more of a project at a time, and for a code review or a refactor across many files the difference matters.

The third is a project that is not in a terminal. If you are on a desktop with a large monitor, a graphical editor gives you more pixels, hardware acceleration, and the operating system's own input handling, and the cost of TTT is that you are drawing your own UI in cells.

The fourth is a team that needs a shared editing environment. TTT is a local single binary. There is no collaboration layer, no server component and no review workflow in the repository, and the pull request review support is a convenience for opening a URL rather than a review client.

The fifth is a machine where you cannot install ripgrep or Git. Those are stated prerequisites rather than optional extras, and a locked-down environment without them leaves you with the editing features and none of the search or source control ones.

The alternative to weigh is a well-supported terminal editor, which will have a smaller feature set but a much larger user base and more predictable behaviour on an unusual terminal. The trade is that TTT is aiming at a different point on the curve, closer to a desktop editor in behaviour, and the question for an adopter is whether the terminal constraint or the feature set dominates your day.

Editorial conclusion

ttt fits a developer working over SSH, on a headless box, or in a terminal-only environment who needs more than a text editor but does not want to run a graphical IDE. It is the wrong choice for a desktop-only workflow with heavy extension needs, and the wrong choice if the terminal is your only place to see the code and the file is long. Before adopting it, install ripgrep and Git, since both are prerequisites for workspace search and the source control features, and try a large file first, because the diff-based renderer and the log benchmark targets in the Makefile suggest large inputs are the interesting case.

Frequently asked questions

What is TTT Editor and what does it give you over a plain terminal editor?

It is a Go terminal editor that adds LSP-powered completion, signature help, diagnostics and formatting, a multi-root file explorer, multi-cursor editing, code folding, git blame and diff views, all in a single binary with no configuration.

What does TTT require before I can use it?

Git for the source control features and ripgrep for workspace search are both required, plus the editor itself installed via Homebrew, the install script, the AUR, Nix, scoop, go install or a release binary.

How does TTT handle multiple project folders?

You can open several directories in one session as a multi-root workspace, each root appearing as a collapsible group in the explorer, search and changes panels, and the git branch in the status bar switches based on which folder the active file belongs to.

How does TTT do syntax highlighting?

It uses textmate-go, a pure Go port of VS Code's TextMate engine, covering 124 languages with multi-line constructs handled correctly.

Official sources

  1. eugenioenko/ttt on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/eugenioenko-ttt.svg)](https://hysenlabs.com/projects/eugenioenko-ttt)

Was this useful?