Skip to content

Repository files navigation

notnote logo

notnote is a minimal, private, markdown outliner. It supports standalone documents, filesystem-backed graphs, daily journals, references, tasks, attachments, offline use, and an optional server for sharing one graph across trusted devices.

Important

Disclaimer — notnote is deliberately and strongly opinionated.
For years, I’ve used Logseq to keep track of all my ideas, tasks, activities, works, clients, and any other information worth being able to search and revisit even years later. Over time, I refined my workflow to handle a large volume of data while relying on as few plugins or extra features as possible. Recently, Logseq decided to change direction with its database version, so I figured it was time to make use of all the Markdown files I’ve accumulated over the years with a simpler tool that works exactly the way I need it to.
No, I'm not kidding — you probably shouldn't use this software, unless, unfortunately for you, you happen to share the exact same mindset as me.

Screenshot

notnote journal on Towel Day

Principles

  • Markdown files remain the source of truth.
  • Files are stored on a local server, so you can access them from any device without managing sync.
  • The interface stays quiet and exposes controls only when needed.
  • Features are added for a concrete workflow rather than broad configurability.
  • The application remains understandable and deployable without a JavaScript toolchain.

Features

  • Visual Markdown editing with an optional full source view.
  • Standalone file opening, saving, downloading, search, outline, and HTML export.
  • File-based graphs with pages, journals, nested blocks, zoom, collapse, and block selection.
  • [[page references]], ((block references)), linked references, unlinked references, and page hierarchy.
  • Task states, scheduled dates, task overview, and calendar navigation.
  • Reusable Markdown block templates with dynamic date, journal, page, and cursor placeholders.
  • Journal history, previous entries, and an expandable “on this day” view.
  • Local attachments, images, audio, video, code blocks, quotes, tables, and common Markdown formatting.
  • Command palette, customizable keyboard shortcuts, and optional Vim navigation.
  • Light, dark, and system themes with a configurable accent color.
  • Offline PWA support and recovery drafts.
  • Optional graph server with atomic writes, conflict detection, offline queues, live updates, and configurable Git snapshots.

The complete user guide is available in docs/user-guide.md and inside the application.

Requirements and quick start

The browser application ships as a prebuilt, dependency-free bundle. You need a current browser and any local static web server; no installation or build is required to run a checkout. The example below uses Python 3:

python3 -m http.server 4173

Open http://localhost:4173.

Python 3.10 or newer is required only for server.py. Node.js 22 or newer is required when changing browser code or running the complete JavaScript test suite. The browser smoke test uses Chrome when it is installed and skips cleanly when it is unavailable. Git is not installed or managed by notnote: install it separately only if you want page history, automatic commits, or repository-based review. Editing, saving, synchronization, offline use, and backups all continue to work without Git.

The single-document editor works in current browsers. Direct graph access uses the File System Access API.

Working with a local graph

Open the command palette and select Open local graph, then choose a directory. notnote reads Markdown files at the graph root and in pages/ and journals/.

Typical outliner controls include:

  • Enter to create a sibling block;
  • Shift+Enter to insert a line break;
  • Tab and Shift+Tab to change depth;
  • Alt+Up and Alt+Down to reorder blocks;
  • Cmd/Ctrl+Enter to cycle task states;
  • a bullet click to zoom into a block;
  • the arrow beside a bullet to collapse or expand its children.

See the user guide for graph navigation, commands, tasks, attachments, settings, and keyboard shortcuts.

Sharing a graph

The included Python server can expose the application and one writable graph:

python3 server.py \
  --host 127.0.0.1 \
  --port 4176 \
  --graph /absolute/path/to/graph

Open http://localhost:4176. To use another device on a trusted LAN, bind to 0.0.0.0 and connect through the host's private address.

The graph API does not provide application-level authentication. Do not expose it directly to the public internet. For remote use, provide authentication and access control through a separate VPN, access gateway, authenticated proxy, tunnel, or similar tool. See docs/deployment.md for provider-neutral guidance. Treat every admitted user as having full read/write access to the configured graph.

Privacy and storage

In standalone mode, document copies and preferences are stored in browser storage. In local graph mode, recovery drafts and the selected directory handle are stored in IndexedDB. Graph preferences are written to .notnote/settings.json inside the graph.

When the optional server is used, content is exchanged only with that server. Remote graph replicas and pending offline operations may remain in IndexedDB on each client. Markdown files always remain authoritative.

No analytics, trackers, hosted fonts, or third-party content services are included. Embedded external media may contact its original host when opened.

Offline support

notnote installs as a Progressive Web App when served from HTTPS or localhost. The application shell is cached by the Service Worker. Server-backed graphs also keep a local replica and queue supported edits while offline, then synchronize after reconnection.

After deploying an update, close and reopen the installed application so the latest Service Worker can take control.

Development

The project intentionally uses browser JavaScript, CSS, HTML, and the Python standard library. Feature code remains in native ES modules and editable stylesheets, while esbuild produces one minified script and one minified stylesheet for browsers. See docs/architecture.md for data flow, trust boundaries, and file ownership.

Install the pinned development tool and rebuild after changing JavaScript, CSS, or critical shell files:

npm ci
npm run build

Run the JavaScript tests and verify that the committed bundle is current with:

npm test
npm run build:check

The suite covers the graph model, module boundaries, browser startup and interactions, offline runtime registration, and large-graph performance regressions.

Run the server tests and syntax check with:

python3 -m unittest discover -s tests -p 'test_*.py'
python3 -m py_compile server.py

For a server-backed development session:

python3 server.py --port 4176 --graph /absolute/path/to/graph

Project structure

assets/icons/       Browser and PWA icons
assets/screenshots/ README screenshot
docker/             Container image, Compose stack, and environment template
docs/               User, architecture, and deployment documentation
tests/              Graph, server, browser, architecture, and performance tests
app/                Browser feature source modules
app.js              Application startup source
app.bundle.js       Minified browser JavaScript bundle
app.bundle.css      Minified browser stylesheet bundle
graph.js            Graph model source and Node-test entry point
scripts/             Deterministic browser build entry and build script
index.html           Application markup
styles.css           Core interface styles
theme-config.css     Theme variables and editorial overrides
server.py            Optional writable graph server
sw.js                Offline application cache
manifest.webmanifest PWA metadata

The browser loads one JavaScript bundle and one stylesheet bundle. Generated artifacts are committed for build-free deployment; CI rejects source drift, and the build derives the offline cache revision from the bundles and critical shell files.

Deployment

The static editor can be hosted on any HTTPS-capable static host. The writable graph server can run directly with Python or through the included Docker Compose configuration.

For internet access, provide authentication, access control, and TLS through a suitable external tool, keep the Python service private, and back up the graph independently of the application. Docker, remote-access, update, and maintenance guidance is available in docs/deployment.md.

Scope

notnote is maintained as a focused personal tool rather than a general-purpose knowledge platform. Features that add persistent interface complexity, broad configuration surfaces, plugin systems, or hosted dependencies may be outside its intended scope.

About

A minimal, private, markdown outliner and task manager

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages