The whole notebook from any terminal — a single Node.js script, zero dependencies, same files as the desktop app.
pi@homelab: ~
~ $ noteflow --helpNoteFlow CLI — quick notes from your terminalusage: noteflow <command> [options] add · new · list · get · read · set sections · section · move · groups · folders login · push · pull · migrate · self-update · status~ $ noteflow add "It works." --section Ideas✓ Added to "07-07-2026" · Ideas
01 / install
One script, zero dependencies
The NoteFlow CLI is a single standalone Node.js script — cli/noteflow.js, no npm packages. It reads and writes the same files as the desktop app: same notes directory, same format, no daemon in between. That makes it perfect for servers, Raspberry Pis and any box without a screen.
Nothing to do — the CLI installs automatically with NoteFlow’s .deb and .exe desktop installers.
Only requirement: Node.js ≥ 18. To update a standalone install later, run noteflow self-update.
02 / notes dir
Where your notes live
The CLI operates directly on the NoteFlow notes directory — plain files on your disk, no database:
Platform
Path
Linux
~/.local/share/noteflow-notes/
Windows / macOS
~/noteflow-notes/
The NOTEFLOW_NOTES_DIR environment variable points the CLI at a different directory — useful for scripting and testing against a sandbox.
03 / format
Note format (v2 — folder per note)
Every note is a directory named <slug>-<id>/ holding a note.md (frontmatter only: metadata + section index) and one .md file per section (pure markdown):
noteflow-notes/
project-alpha-abc12345/ note.md ← metadata anchor + section index sec001.md ← body of section "Note" sec002.md ← body of section "Tasks"
Each section’s content lives in its own <sectionId>.md — no frontmatter, just markdown.
The updated: field in note.md is the canonical sync timestamp for the whole note.
isRawMode: true means raw/markdown mode; false means rich text (TipTap HTML).
Notes with an encryption: block in note.md are encrypted (the folder only contains note.md) — the CLI ignores them.
A .noteflow-format marker file (containing 2) at the root of the notes directory flags the v2 format.
Coming from the old flat v1 layout? A single noteflow migrate converts everything — see the commands table.
04 / commands
Command reference
Everything is addressed by name: note titles plus section names — you never touch ids. Titles can be partial (on multiple matches the CLI lists them and asks for precision), and duplicate section names are targeted with a 1-based suffix like "Tasks#2". Quote names containing spaces.
Notes
Command
What it does
noteflow add <text> [options]
Append text to today’s daily note (title DD-MM-YYYY) — or to any note via --title. Creates the note if it doesn’t exist; the text is appended to the end of the section, separated by a newline.
--title <title>
Write into the note with that title instead of today’s.
--section <name>
Target section/tab. Created if missing. Default: Note.
--tag <tag>
Add this tag to the note (if it doesn’t have it yet).
--group <name>
Assign the note to a group.
--folder <name>
Place the note in a folder of that group (requires --group).
--raw / --rich
New section in raw/markdown mode (default) or rich text.
$ noteflow add "Fix: CORS on /api/notes"$ noteflow add "Check server logs" --section Tasks --tag urgent
noteflow new <title> [options]
Create an empty note.
--section <name>
Name of the first section. Default: Note.
--group <name>
Assign to a group.
--folder <name>
Place in a folder of that group (requires --group).
--json
Print { id, title, dirname } as JSON.
$ noteflow new "Sprint 14" --group backend --section Planning
noteflow list [options]
List notes sorted by updated desc. Archived notes are excluded by default.
--tag <tag>
Filter by tag.
--group <name>
Filter by group.
--folder <name>
Filter by folder (disambiguate with --group if the name repeats).
--archived
Include archived notes.
--json
JSON array with full metadata per note (id, title, tags, group, folder, dates, sections…).
$ noteflow list --tag urgent --json
noteflow get <title> [options]
Pretty-print a note for humans (indented, decorated). The title can be partial — on multiple matches it lists them and asks for more precision. For piping or agents, use read instead.
--section <name>
Show only that section.
--json
Full JSON with every section and its content.
noteflow read <title> [section]
Print content verbatim to stdout — no indentation, no decoration. The recommended way to read a section for pipes and agents. Duplicate section names are addressed with a 1-based suffix, e.g. "Tasks#2".
--section <name>
Flag form of the positional section (handy with multi-word titles).
--json
JSON with every section (or just one if targeted).
Replace a section’s content (creating it if missing) — the complement of add, which only appends. The recommended way to edit a section. On ambiguous duplicate names without a #n suffix, it fails instead of guessing.
--text "<content>"
Inline text (first source present wins).
--file <path>
Read the content from a file — the most reliable route on Windows/PowerShell.
--stdin
Read from stdin (also used automatically when piped).
--rich
If the section is created, create it in rich-text mode (default: raw).
$ noteflow set "Project Alpha" Tasks --text "- [ ] deploy"$ cat todo.md | noteflow set "Project Alpha" Tasks --stdin
noteflow delete <title> [--yes]
Delete a note (alias: rm). Asks for confirmation unless --yes. With sync active it also removes it from the GitHub repo.
noteflow rename <current-title> <new-title>
Update the note’s title field. The folder name on disk doesn’t change (it contains the id).
noteflow favorite <title>
Toggle the favorited flag (alias: pin). The desktop app shows favorites at the top of the list.
noteflow archive <title>
Toggle the archived state. Archived notes don’t show in list unless --archived.
Sections
Command
What it does
noteflow sections <title>
List a note’s sections with name, line count and mode (raw/rich). section list is an alias.
noteflow section add <title> <name> [--rich]
Create an empty section (raw by default; --rich for rich text). Sections are managed by name — no ids needed.
Rename a section (the file on disk doesn’t change — it’s addressed by id).
noteflow section delete <title> <name> [--yes]
Delete a section (confirmation unless --yes). Refuses to delete the last one. Disambiguate duplicates with "Tasks#2".
Organization
Command
What it does
noteflow move <title> --group <g> [--folder <f>]
Move a note between groups and folders — the CLI equivalent of the app’s drag-and-drop. --group alone moves it to the group root (clearing the folder); --ungroup takes it out of both.
Delete a folder. Its notes fall to the group root (they keep the group, lose the folder) — nothing is deleted.
GitHub sync
Command
What it does
noteflow login [repo-name]
Connect to GitHub via Device Flow OAuth — it prints a code and a URL to authorize from any browser (perfect for headless boxes). Default repo: noteflow-notes. The CLI keeps its own token, separate from the desktop app’s.
noteflow logout
Disconnect from GitHub.
noteflow push
Upload every note to the repo.
noteflow pull
Download notes from the repo (alias: update). Only overwrites a local note when the remote updated timestamp is newer.
Maintenance
Command
What it does
noteflow migrate
One-time migration from the flat v1 layout (<slug>-<id>.md) to the v2 folder-per-note format. Writes the .noteflow-format marker and, with an accessible sync token, pushes the new layout and removes the flat files from the remote. Idempotent — the desktop app runs the same local migration on startup.
noteflow self-update
Download the latest cli/noteflow.js from GitHub and replace the current script. Uses the public repo API — no sync login needed. Handy on a headless RPi with no installer.
noteflow status [--json]
Show note count, notes directory, groups, GitHub state and last sync. JSON shape: { notesDir, noteCount, github: { owner, repo, lastSync, tokenAccessible }, groups }.
noteflow help [command]
General help, or detailed help for one command (help new, help folder…).
05 / flags
Global flags, colors & env vars
A few flags repeat across commands with the same meaning everywhere:
Flag
Applies to
Description
--json
list · get · read · new · groups · folders · status
Machine-readable JSON output.
--yes
delete · group delete · folder delete · section delete
Skip the interactive confirmation.
--archived
list
Include archived notes.
--section <name>
read · get · add · set
Target a section by name.
--group <name>
add · new · move · list · folders · folder *
Target / filter by a group.
--folder <name>
add · new · move · list
Target / filter by a folder (requires a group).
--ungroup
move
Take the note out of its group and folder.
--text / --file / --stdin
set
Source of the content to write (first one present wins).
--rich
add · set · section add
Create the new section in rich-text mode (default: raw).
Group colors
The palette accepted by group create --color — the same color tokens the desktop app uses for group dots and note accents:
accentaccent-2redcyanpurpletextorangepink
Environment variables
Variable
Effect
NOTEFLOW_NOTES_DIR
Redirect the notes directory (scripting / testing).
NOTEFLOW_NO_APP_CHECK
Set to 1 to silence the stderr warning when mutating groups/folders while the desktop app is running.
06 / agents
A tool built for AI agents
The CLI is deliberately agent-friendly: every read command takes --json for machine-readable output, results go to stdout and errors to stderr, and the exit code is 0 on success, 1 on error. Since everything is addressed by note title and section name, an agent never needs to track ids.
Two conventions matter: read vs get — get is for humans (indented, decorated) while read emits content verbatim, so agents should always use read. And set vs add — setreplaces a section, addappends to it.
Typical agent flow
agent session
# 1 · discover notes and section names$ noteflow list --json# 2 · read one section, raw (pipe-safe)$ noteflow read "Project Alpha" "Tasks"# 3 · overwrite it — or append with `add`$ noteflow set "Project Alpha" "Tasks" --text "- [x] deploy"# 4 · sync$ noteflow push
Install the skill
Running Claude Code or another skills-compatible agent? Install the NoteFlow CLI skill and your agent gets the full command reference, gotchas included:
skills
$ npx skills add yagoid/noteflow/cli/noteflow-cli
07 / caveats
Caveats worth knowing
Desktop app open ⇒ group/folder changes can be lost
The app keeps groups.json / folders.json in memory and rewrites them on its own cycles (saves and the 5-minute auto-sync), overwriting groups and folders created from the CLI while it runs. Note-level changes — content, sections, favorite, archive — do survive: they live in per-note folders. The CLI warns on stderr when it detects NoteFlow running while you mutate groups/folders (silence it with NOTEFLOW_NO_APP_CHECK=1). For reliable structural changes, close the app first — or make them in the app.
PowerShell: multiline --text can truncate silently
On Windows/PowerShell, passing --text with newlines may be truncated to the first line without warning. For anything beyond a single line use --file <path> (the most reliable route) or --stdin. Rule of thumb: non-trivial content → --file.
BOM on --stdin
PowerShell prepends a BOM to pipes and here-strings; the CLI strips it automatically, so piped content arrives clean.
08 / troubleshooting
Troubleshooting
“noteflow: command not found”
The headless install script places the CLI at /usr/local/bin/noteflow — make sure that’s on your PATH. On desktop it ships with the .deb / .exe installers; open a fresh terminal after installing.
I’m logged in in the app, but the CLI asks me to log in
Expected: the CLI can’t decrypt tokens the desktop app stores with Electron’s safeStorage. It keeps its own token — run noteflow login once.
A note doesn’t show up in list / read
Encrypted notes (an encryption: block in note.md) are ignored by every read command, by design. Decrypt the note in the desktop app if you need CLI access to it.
My CLI-made groups or folders vanished / pull didn’t change anything
Two sync rules: the desktop app’s auto-sync rewrites groups.json / folders.json while it runs (see caveats), and pull only overwrites a local note when the remote updated: timestamp is newer. Close the app for structural changes, and check noteflow status for the last sync.
Cookies
We use analytics cookies (Google Analytics) to understand how the site is used. Nothing loads until you accept. Cookie policy