Plain Markdown on disk
Atomic saves, a name (conflict <time>).md copy instead of an overwrite, and live reload when a file changes outside the app.
Fast, minimal note-taking that never leaves your terminal. Plain .md on disk, live Markdown highlighting while you type, emacs or vim keys, and a headless JSON CLI so scripts and AI agents work the same vault.
1 tnotes roadmap 2 Weekly plan × # Weekly plan #work #planning - [x] Review pull requests - [x] Write release notes - [ ] Ship tnotes 1.1 #tnotes — see [[tnotes roadmap]] - [ ] Book flights for **Berlin** #travel - [ ] Prep [[Meeting notes]] > Keep the list short.
Left: folders, tags and the note list. Right: tabs and the editor. Everything is clickable; everything has a key.
One .md per note, folders are directories, tags live in the text. Atomic saves, conflict copies instead of silent overwrites, live reload. Sync with anything.
Live highlighting, list continuation, checkbox toggling, word wrap, link and tag completion, backlinks. Emacs or vim keys. Mouse works everywhere.
tnotes ls --json gives every note with tags, links, backlinks and timestamps. Agents and cron jobs write; your open TUI updates live.
Atomic saves, a name (conflict <time>).md copy instead of an overwrite, and live reload when a file changes outside the app.
Folders are real directories. Tags are parsed from the text, nested ones like #work/project included. Click a tag to filter.
Completion popup after [[, alt+enter or ctrl+click to follow (missing targets are created), a backlinks overlay, and links rewritten on rename.
Selecting a note previews it; typing or enter pins it. Jump with 1–9, cycle with alt+. / alt+,.
Headings, lists, checkboxes, code, links, emphasis, quotes and tags styled as you type. Colour or monochrome.
enter continues a list, an empty item ends it, tab / shift+tab nest, alt+x or a click toggles a checkbox.
Powered by edtui. Emacs by default; vim with normal/insert modes, . repeat, / search. Switch in settings.
Click to select, double-click to pin, right-click context menus, wheel scrolling, drag to select text (copied on release).
/ searches titles and bodies with a fuzzy matcher (nucleo), combined with tag and folder filters.
Open tabs, filter, sort, focus and folded tree sections come back exactly as you left them.
F2 or , opens a settings page that writes config.toml for you. Theme follows your terminal palette.
ls · search · cat · new · append · write · trash · restore. Same ids everywhere. A running TUI picks changes up live.
A single-panel layout kicks in on narrow windows; ctrl+b toggles the sidebar.
Every root has its own .Trash/ mirroring the folder layout, so u undoes and r restores to where a note came from.
If a save fails (disk full, permissions) the text is written under the state dir and the path is shown instead of losing it.
ctrl+t, type a title, keep typing. Autosave after 500 ms of idle.
# Groceries#home- [ ] milk- [ ] coffee⏎- [ ] ▌Type [[, pick from the popup, alt+enter to jump. Rename a note and every link follows.
- [ ] Prep [[Meet▌ ┌────────────────┐ │ Meeting notes │ │ Meetup ideas │ └────────────────┘Pipe text in from anywhere. The open TUI shows it the moment the file lands.
$ echo "- [ ] call Ann" \ | tnotes append weekly-plan --stdin$ tnotes search "berlin" --json \ | jq '.[0].path'"vault/weekly-plan.md"The CLI is the agent interface: no daemon, no API keys, no plugin — just files and JSON. Point an agent at your vault and let it read, search and write notes while you keep the TUI open. Edits show up live in both directions; a note with unsaved edits in the TUI is never overwritten.
links and backlinks in the JSON let an agent walk the note graph. Ids (root/sub/stem) are the same in every command.
$ tnotes ls --json | jq '.[0]'{ "id": "vault/weekly-plan", "path": "/home/me/notes/vault/weekly-plan.md", "title": "Weekly plan", "folder": "vault", "tags": ["work", "planning"], "links": ["tnotes roadmap", "Meeting notes"], "backlinks": ["tnotes roadmap"], "created": "2026-09-21T09:12:04Z", "modified": "2026-09-22T08:40:11Z", "preview": "#work #planning - [x] Review pull requests …"}Current version: v1.3.0. Binaries are not signed; on macOS, Homebrew and curl downloads run as-is.
$ brew install 0x1ocean/tnotes/tnotesmacOS (Apple Silicon, Intel) and Linux (x86_64, aarch64). Prebuilt — no Rust toolchain needed. Upgrade with brew upgrade tnotes.
$ tnotes # open your configured roots (asks where notes live on first launch)$ tnotes ~/notes # add a folder to your roots and open it$ tnotes --dir ~/tmp # use only this folder for the sessionPut a root inside Syncthing, iCloud Drive, Dropbox or a git repo. Changes from another device show up live; saves are atomic so a syncer never sees a half-written note; concurrent edits become a conflict copy, never a lost one.
Encrypt the folder, not the notes: FileVault, an encrypted .dmg, gocryptfs or fscrypt. Point roots at the mounted path and everything keeps working.
~/.config/tnotes/config.tomlroots = ["~/Sync/notes", "~/work/wiki"][editor]keys = "vim"autosave_ms = 500width = 72[theme]accent = "cyan"tag = "green"