● local & offlineCLI + Flask web reader·GPLv3

Markdown notes that tag themselves.

NoteFlow is a local Markdown notes system with two interfaces: a fast CLI for writing from the terminal, and a Flask web server for reading notes as clean, syntax-highlighted HTML. Basically a personal Notion — local, offline, and yours.

DSAWeb-DevDevOpsDatabaseTools
The X factor

You never touch a tag.

Most notes apps make tagging a chore, so it never happens. NoteFlow reads what you wrote and figures out where it belongs.

◎

Auto-tagging

No manual tagging. config.json defines a keyword → tag map — things like "binary search": "DSA", "flask": "Web-Dev", "docker": "DevOps". Every time you run noteflow.py new, the note's content is scanned case-insensitively against every keyword, and matching tags are attached automatically into the note's frontmatter.

▤

Tag filtering

The web UI sidebar lists every tag currently in use across your notes. Click one — say DSA — and the note list is filtered server-side to only notes carrying that tag, via a plain GET /?tag=DSA. No client-side state, no JS framework.

◐

Highlighted search

Search from the CLI with search, or from the web search box. On the web, the matching term is wrapped in <mark> and highlighted inline inside the rendered note — the highlighter walks rendered HTML and only touches text nodes, so a search hit that happens to sit inside a syntax-highlighted code block still highlights cleanly instead of breaking the markup.

Preview

What it looks like

Write from the terminal, read in the browser. Search once and the match is filtered in the list and highlighted inline on the note itself.

localhost:5000/?q=join
⌕join1 match
  • SQL Joins ExplainedMay 18

    A SQL JOIN combines rows from two or more tables based on a related column. INNER JOIN returns only matching rows...

    Database
  • Binary Search NotesMay 14

    Binary search runs in O(log n) time by repeatedly halving the search interval over a sorted array...

    DSA
  • Flask Routing BasicsMay 11

    Routes map a URL path to a view function via @app.route(). Dynamic segments like <slug> are passed as arguments...

    Web-Dev
  • Docker BasicsMay 9

    A Dockerfile describes an image layer by layer. docker build tags an image; docker run starts a container from it...

    DevOps
  • Git CheatsheetMay 6

    git commit -m records staged changes. git rebase -i rewrites history interactively. Use git stash to shelve work...

    Tools
binary-search-notes.mdcodehilite
# Binary Search

# O(log n) search over a sorted array
def binary_search(arr, target):
    lo, hi = 0, len(arr) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
Rendered via markdown (fenced_code + codehilite) → served with a Pygments-generated /pygments.css
zsh
$ python noteflow.py new "Binary Search Notes" \
    --content "Binary search runs in O(log n)..."
Saved note: Binary Search Notes
  file: notes/binary-search-notes.md
  auto-tags: DSA

$ python noteflow.py search "binary search"
- Binary Search Notes  [DSA]
    ...runs in O(log n) time by repeatedly halving the search interval...
Under the hood

Key concepts & stack

Python 3argparseFlaskJinja2markdownPygmentsRegexFilesystem I/OFrontmatter parsingGPLv3

CLI subcommands

argparse wires new / list / search / serve into one entry point, noteflow.py.

Frontmatter storage

Every note is a plain .md file with a lightweight header: title, slug, created, tags.

Markdown → HTML

The markdown library renders bodies with fenced_code, codehilite, tables, and toc extensions.

Pygments highlighting

Fenced code blocks are syntax-highlighted and styled via a generated /pygments.css route.

Auto-tag engine

auto_tag() scans content against config.json's keyword map so the taxonomy grows without code changes.

Safe inline highlighting

highlight_text() splits rendered HTML into tag/text segments so only text nodes get wrapped in <mark>.

Run it

Two interfaces, one notes folder

Install once, then write from the terminal and read in the browser — both point at the same notes/ directory.

Setup

python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

CLI — write

  1. 1
    Create a note (content via flag, file, or piped stdin):
    python noteflow.py new "My Note" \
      --content "..."
  2. 2
    List every note with its auto-extracted tags:
    python noteflow.py list
  3. 3
    Full-text search from the terminal:
    python noteflow.py search "binary search"

Web — read

  1. 1
    Start the Flask server:
    python noteflow.py serve
  2. 2
    Open it in your browser:
    http://localhost:5000
  3. 3
    Browse rendered notes, filter by tag, or search — matches highlight inline on the note page.
    python noteflow.py serve \
      --port 5050 --debug