Notes apps with a CLI: ten terminal note tools compared

A notes app with a CLI, compared: nb, zk, iwe, jrnl, dnote, Joplin, the Obsidian CLI, NotesMD, Basic Memory and Jotura, with platforms and JSON output.

The right notes app with a command line interface (CLI) depends on who else will touch your notes. For a terminal-only setup, nb keeps every notebook in git, and zk or iwe give Neovim and VS Code a language server over plain Markdown files. jrnl suits a dated journal, and dnote a stash of snippets in one SQLite file.

Jotura fits best for notes that a desktop app shares with your scripts or AI agents. Its jotura command edits the same Markdown folder as the desktop app, open or closed, and can refuse a write when the note changed since the script read it. Joplin’s terminal app works on the same synced notebooks as the Joplin apps, and the official Obsidian CLI drives a running copy of Obsidian. Basic Memory is an MCP server for AI assistants that also answers on the command line.

Every fact below was checked against each project’s documentation and release page on October 10, 2026. The nb, zk, iwe, jrnl, dnote, Joplin and Jotura commands were run that day on Windows 11 (nb under Git Bash), and the outputs shown are what they printed. The Obsidian CLI, NotesMD CLI and Basic Memory examples come from their official docs.

The comparison table

Tool Platforms Where notes live Search Sync Latest release
nb macOS, Linux; Windows through WSL, MSYS or Cygwin Plain text files, Markdown by default; each notebook is a git repository Full text with regex, tags, AND, OR, NOT Any git remote, automatic once set 7.25.5, Aug 12, 2026
zk macOS, Linux, Windows Markdown files plus a SQLite index in .zk/ Full text, tags, link filters None built in v0.15.6, Jul 26, 2026
iwe macOS, Linux, Windows Markdown files in a folder Full text, fuzzy, link graph None built in 0.26.1, Oct 8, 2026
jrnl macOS, Linux, Windows (Python 3.11 or later) One text file, or a folder of dated files Text, tag and date filters None built in v4.6, Aug 7, 2026
dnote macOS, Linux, FreeBSD, Windows One SQLite file Full text A Dnote server you host CLI 0.16.0, Nov 8, 2025
Joplin terminal app macOS, Linux; Windows through WSL Markdown notes inside a SQLite database In the terminal interface only Joplin Cloud, Joplin Server, Nextcloud, WebDAV, S3, Dropbox, OneDrive, a folder 3.7.1 on npm, Sep 7, 2026
Obsidian CLI Windows, macOS, Linux, with the app running Markdown files in a folder Through the running app Obsidian Sync or any file sync Obsidian 1.14.4, Oct 5, 2026
NotesMD CLI Windows, macOS, Linux An Obsidian vault’s Markdown files Full text None built in v0.3.7, Sep 1, 2026
Basic Memory Anywhere Python 3.12 runs, through uv Markdown files plus a local SQLite index Text, vector or hybrid Basic Memory Cloud, or git yourself v0.23.2, Aug 25, 2026
Jotura macOS, Windows, Linux; the Android app reaches notes only through Sync Markdown files in a folder Full text; meaning-based modes query the desktop’s index Jotura Sync, end-to-end encrypted, run by the desktop and Android apps 0.11.1, Oct 6, 2026
Tool Install JSON output Editor integration License and cost
nb brew install xwmx/taps/nb or npm install -g nb.sh None Opens notes in $EDITOR; nb browse AGPL-3.0, free
zk brew install zk or a release binary --format json and jsonl Language server; Neovim and VS Code plugins GPL-3.0, free
iwe brew install iwe-org/iwe/iwe or npm install -g @iwe-org/iwe -f json on find Language server for Neovim, Helix, VS Code, Zed Apache-2.0, free
jrnl pipx install jrnl --format json Opens entries in your editor GPL-3.0, free
dnote brew install dnote or the getdnote.com script None Opens $EDITOR when you omit -c Apache-2.0, free
Joplin terminal app npm install -g joplin ls --format json External editor setting AGPL-3.0-or-later; Joplin Cloud from €2.40 a month billed yearly
Obsidian CLI A toggle in Settings, General (installer 1.12.7 or later) format=json on most listing commands It is the Obsidian app, plugins included Proprietary, free; Sync from $4 a month billed annually
NotesMD CLI brew install yakitrak/yakitrak/notesmd-cli, or Scoop --format json on content search --editor opens $EDITOR MIT, free
Basic Memory uv tool install basic-memory --prerelease=allow --json on search, read and context commands Any MCP client; Obsidian reads the same files AGPL-3.0, free locally; Cloud $15 a month in beta
Jotura The desktop installer, or the script on the download page Global --json flag; errors always JSON The Jotura desktop app; any editor sees plain files Closed source, free; Sync £4 or $5 a month

nb

nb is a single Bash script for notes, bookmarks, to-dos and web archives. Each notebook is a git repository, and nb commits every add, edit and delete in the background. Once a notebook has a remote (nb remote set), commands in it sync automatically, at most once every NB_AUTO_SYNC_SECONDS (60 by default), and nb sync forces one. A line changed on two machines ends up with both versions between git conflict markers.

nb add --title "Printer quote" --content "Quote came in at 4,200. See [[Vendors]]. #invoice"
# Added: [1] printer_quote.md "Printer quote"

nb search "#invoice" --list
# [1] Printer quote

nb show 1 --print
nb remote set https://github.com/you/notes.git

After two adds, git log showed [nb] Add: vendors.md and [nb] Add: printer_quote.md with no commit typed by hand. nb reads wikilinks and #tags, and --encrypt protects a single note. It runs wherever Bash and git do, and Git Bash on Windows 11 worked for this guide. Scripts have to parse text, since nb has no JSON output.

zk

zk is a plain text note-taking assistant for a Zettelkasten or personal wiki, with no editor of its own. Notes are Markdown files with wikilinks, tags and YAML frontmatter, indexed in a SQLite file under .zk/.

zk init notes && cd notes
echo "Quote came in at 4,200. #invoice" | zk new --title "Printer quote" --interactive --print-path
zk list --match printer --format json
zk list --tag invoice --format "{{title}} {{path}}"

--interactive makes zk new read the body from standard input, and new files get a short random name such as 8798.md unless you set a pattern. Each JSON result carries title, path, lead, body, tags, dates and a checksum. zk list also filters by links, finding orphans, notes that link to a given note, and broken links. zk graph --format json exports the whole graph.

zk lsp runs a language server, giving Neovim, VS Code, Emacs and other LSP editors link completion and navigation. Sync is left to git or a file sync tool. On Windows, the README warns that Defender has flagged some prebuilt binaries and recommends building from source.

iwe

iwe describes itself as a Markdown knowledge graph: a language server for your editor, plus a CLI and an MCP server for agents, over a plain folder of notes. A native app, iWe for Mac, opens the same folder.

iwe init
iwe find --lexical "4,200" -f json
iwe rename vendors suppliers
# Renaming 'vendors' to 'suppliers'
# Updated 1 document(s)

find returned each matching note’s key and title with its outgoing and incoming references. rename rewrote the Markdown link in the note that pointed at the old name. The language server (iwes) covers Neovim, Helix, VS Code and Zed, iwec is the MCP server, and there is no sync.

jrnl

jrnl writes timestamped journal entries from the command line. It reads plain-English dates, so jrnl yesterday: files an entry under the previous day, and words starting with @ become tags.

jrnl yesterday: Finished the @proposal draft.
jrnl Call with the printer about @invoice 4471
jrnl -contains printer
jrnl --format json

The JSON export returned a tags count and an entries array, each entry with title, body, date, time, tags and starred. A journal is one text file or a folder of dated files. Single-file journals can be AES-encrypted, and the docs warn that nobody can recover a lost password; folder journals cannot be encrypted. Every record is a dated entry with no links between entries, and nothing syncs beyond whatever moves the file.

dnote

dnote is a single Go binary for short notes filed into books, handy for commands and how-tos. Everything lives in one SQLite file. The project dates from 2017 and is quiet now: the last CLI release, 0.16.0, shipped on November 8, 2025, and later commits are dependency updates.

dnote add linux -c "find . -name '*.log' -mtime +7 -delete"
dnote add git -c "git commit --fixup HEAD~2, then git rebase -i --autosquash"
dnote view
# git (1)
# linux (1)
dnote find "rebase"

Leave out -c and dnote opens your editor, or pipe text in on standard input. Sync needs a Dnote server you host yourself, a single binary or Docker image, and dnote login. There is no JSON output, though dnote view <book> <id> --content-only prints a note’s text for a script.

Joplin’s terminal app

Joplin is a full notes app with desktop, mobile and web clients, and its terminal app reads and writes the same notebooks. Run joplin alone for a three-pane interface inside the terminal, or pass a command for one-shot use. It syncs to more targets than anything else here, and joplin e2ee manages end-to-end encryption.

NPM_CONFIG_PREFIX=~/.joplin-bin npm install -g joplin
joplin mkbook "Work"
joplin use "Work"
joplin mknote "Printer quote"
joplin set "Printer quote" body "Quote came in at 4,200."
joplin ls --format json

ls --format json returns each note’s id, title, notebook id and timestamps, and batch runs a file of commands in order. In shell mode, joplin search replies that the command only works in GUI mode, meaning the terminal interface, so scripts cannot search. Notes are Markdown stored inside a SQLite database in the profile folder, and other tools see them as files only after joplin export with --format md.

Joplin fits anyone who needs one open-source app on every platform, iPhone included. The docs list macOS, Linux and Windows through WSL, and the commands above also ran in a native Windows terminal. Joplin desktop 3.7 added an MCP server for AI clients, and Joplin Cloud starts at €2.40 a month billed yearly after a 14-day trial. Jotura vs Joplin compares the two apps.

The official Obsidian CLI

Obsidian added a command line tool in version 1.12, and it needs the 1.12.7 or later installer. Turn on Command line interface under Settings, General, and Obsidian registers an obsidian command on your PATH. Parameters use name=value syntax, and obsidian alone opens an interactive prompt with autocomplete and history.

obsidian search query="printer quote" format=json
obsidian create name="Printer quote" content="Quote came in at 4,200." template=Vendor
obsidian daily:append content="- [ ] Call the printer"
obsidian vault=Work tasks todo format=json
obsidian rename file="Printer quote" name="Printer quote 2026"

Your plugins, templates and settings apply because the CLI acts through the app, and no other tool here has a plugin ecosystem to match. move and rename update internal links when Automatically update internal links is on. Most listing commands, including search, tags, tasks, backlinks and properties, take format=json.

The CLI requires Obsidian to be running, and the first command launches it if it is closed. A headless server, or a job that runs while you are logged out, needs something else.

Obsidian Headless, in open beta, fills part of that gap. Installed with npm install -g obsidian-headless (Node.js 22 or later), its ob command syncs a vault through Obsidian Sync without the app, with no note editing.

Obsidian is free for any use. Sync Standard costs $4 a month billed annually, or $5 monthly, for one vault and 1 GB. Sync Plus costs $8 or $10 for ten vaults and 10 GB to 100 GB.

NotesMD CLI for vaults without the app

NotesMD CLI, formerly the unofficial obsidian-cli, works on an Obsidian vault’s files directly, so Obsidian never needs to run. It took the new name when the official CLI arrived. On a server without Obsidian you register the vault yourself, and daily notes follow .obsidian/daily-notes.json when it exists.

notesmd-cli add-vault /home/me/vaults/work --set-default
notesmd-cli search-content "printer" --format json

Basic Memory

Basic Memory is an MCP server (Model Context Protocol, the standard AI assistants use to call tools) that stores what your assistant learns as Markdown files you can edit too. A local SQLite index handles text, vector and hybrid search. Its bm tool commands give the shell the same note operations, and search-notes, read-note, build-context and recent-activity take --json.

uv tool install basic-memory --prerelease=allow
bm tool write-note --title "Printer quote" --folder vendors --content "Quote came in at 4,200."
bm tool search-notes "printer" --json

Notes use a format of observations and relations that an assistant walks with bm tool build-context. bm tool edit-note supports append, find_replace and replace_section, and find_replace takes an --expected-replacements count that defaults to 1.

Local use is free under AGPL-3.0. Basic Memory Cloud adds sync, mobile access and backups at a beta price of $15 a month, locked in for life, against a regular $19, with a 7-day trial. By default the CLI checks for updates daily and applies them silently, and anonymous promotion telemetry runs until you set BASIC_MEMORY_NO_PROMOS=1.

Jotura

Jotura is a local-first Markdown notes app for macOS, Windows, Linux and Android. The Windows and .deb installers put its jotura command on your PATH, and on macOS and the AppImage one click in Settings does it. The vault is an ordinary folder of .md files, an Obsidian vault opens as it is, and the CLI works with the app closed. When the CLI writes, the open app’s file tree, search and tabs refresh within about a second.

In this run against a test note, TODO appears twice and the last edit reuses a hash from before the second edit:

jotura edit "Projects/Printer quote.md" --replace "TODO" --with "DONE"
# exit 4, on stderr:
# {"code":"Ambiguous","message":"ambiguous match for `TODO`: 2 occurrences","lineHits":[3,4],"needle":"TODO","occurrences":2}

HASH=$(jotura read "Projects/Printer quote.md" --json | jq -r .hash)   # assumes jq
jotura edit "Projects/Printer quote.md" --replace "Status: TODO" --with "Status: ordered" --if-hash "$HASH"
# exit 0

jotura edit "Projects/Printer quote.md" --replace "4,200" --with "4,350" --if-hash "$HASH"
# exit 2, on stderr:
# {"code":"HashConflict","message":"hash conflict: expected b76df3463af77a054dacb4884beb978c, actual 66875304ec316f6b6081d6fd10a005fd","actual":"66875304ec316f6b6081d6fd10a005fd","actualHash":"66875304ec316f6b6081d6fd10a005fd","expected":"b76df3463af77a054dacb4884beb978c","expectedHash":"b76df3463af77a054dacb4884beb978c","path":"Projects/Printer quote.md"}

A replace that matches more than once is refused with its line numbers, and --all or --nth 2 makes the choice explicit. With --if-hash, a write is refused when the file on disk changed after the script read it, and the CLI and desktop app share a per-vault write lock around that check. A script that skips --if-hash overwrites like any other tool, and text the app has not yet saved is not on disk to protect.

Edit commands leave frontmatter alone, and frontmatter set and tag add change it. Errors are single-line JSON on stderr with stable exit codes. The editing docs and the CLI reference cover the rest, including today --append, tasks --json, backlinks and watch.

There is no standalone CLI download, and the CLI never syncs on its own, since the desktop and Android apps run Jotura Sync. The Android app reaches your notes only through Sync. There is no editor plugin, meaning-based search needs an index only the desktop builds, and Jotura is closed source with no plugins and no iOS app. The app and CLI are free to download, and Sync costs £4 or $5 a month, or £40 or $50 a year, with no free trial, close to Obsidian Sync’s price.

Which one fits

You want Best fit
A desktop app and scripts editing the same Markdown, with stale writes refused Jotura
An AI coding agent reading and editing your notes from a shell Jotura, with its agent skills; iwe and the Obsidian CLI also work
JSON from every command, errors included Jotura; zk, iwe, jrnl, Joplin, the Obsidian CLI and Basic Memory on some commands
An Obsidian vault edited with Obsidian closed Jotura, with link-aware renames; NotesMD CLI without installing an app
Obsidian’s plugins, scripted while the app is open Obsidian CLI
Every change versioned in git, from one portable script nb
Linked notes with completion inside Neovim, VS Code or Emacs zk; Jotura has no editor plugin
A link-aware note graph shared by your editor and an agent iwe
A dated journal with tags jrnl
A quick stash of shell commands and snippets dnote
Open source, on every platform including iPhone Joplin; Jotura is closed source with no iOS app
Sync driven from the command line on a headless machine nb or Joplin; Jotura’s CLI never syncs
A memory server for MCP-based AI assistants Basic Memory; Jotura has no MCP server

Jotura has no iOS app. Joplin reaches an iPhone with open-source apps and the widest choice of sync targets, and Obsidian does with plain files and plugins. Jotura vs Obsidian covers that decision in detail.

AI agents reach notes in one of two ways. Jotura, iwe and the Obsidian CLI give the agent a shell command, and Basic Memory and iwe’s iwec serve notes as MCP tools. CLI tools vs MCP servers for agents compares the two on cost and safety.

Frequently asked questions

Which terminal notes apps store plain Markdown files?

nb, zk, iwe, NotesMD CLI, the Obsidian CLI, Basic Memory and Jotura all keep notes as Markdown files in a folder that any other tool can read. zk and Basic Memory add a SQLite index beside the files. jrnl uses plain text files. Joplin and dnote store notes inside a SQLite database.

Which command line note-taking apps have built-in sync?

nb syncs through any git remote, and dnote through a server you host. Joplin syncs to Joplin Cloud, Joplin Server, Nextcloud, WebDAV, S3, Dropbox, OneDrive or a folder. Obsidian, Basic Memory and Jotura sell hosted sync, and Jotura’s runs in its desktop and Android apps, never in the CLI. zk, iwe, jrnl and NotesMD CLI leave sync to you.

Which notes CLI works best with AI agents?

Jotura fits best for an agent editing notes you also edit in a desktop app. With --if-hash it refuses a write to a note that changed after the agent read it, and its skills teach the agent to read before every edit. Any tool with plain files and non-interactive commands works with a coding agent, and zk, iwe, jrnl, the Obsidian CLI, NotesMD CLI and Basic Memory print JSON too. Basic Memory and iwe also offer MCP servers for assistants that connect that way.

Can I use the Obsidian CLI without Obsidian running?

No. The official Obsidian CLI requires the app to be running, and the first command launches it if it is closed. Obsidian Headless, in open beta, syncs a vault without the app but does not edit notes. NotesMD CLI, an independent MIT-licensed tool, reads and writes vault files directly with Obsidian closed.

Are these terminal note tools free?

nb, zk, iwe, jrnl, dnote, NotesMD CLI, Basic Memory and Joplin’s terminal app are free and open source. Obsidian and its CLI are free but proprietary, with Sync from $4 a month billed annually. Jotura’s app and CLI are free and closed source, with Sync at £4 or $5 a month. Joplin Cloud starts at €2.40 a month billed yearly, and Basic Memory Cloud costs $15 a month in beta.

The best markdown note apps in 2026, and why we pick Jotura2026-10-10
The best markdown note apps in 2026 compared on files, phones, sync, encryption and price, why we pick Jotura, and where another app fits you better.

More in Comparisons.

Download free

Jotura is free, and your notes stay plain markdown files you keep forever.