v0.13.0 · beta

An outliner that keeps your notes as plain markdown.

Write in bullets on a daily page. Link ideas with [[pages]] and see every place they come up. Your notes live in a folder of .md files you choose, and outl syncs them between the devices you pair.

~/notes — outl May 26, 2026
● journal · 🚀 launch-day ctrl-p ⌃k ?
● ▍
● synced 3 blocks 2 backlinks tree-crdt · op-log: 247
everywhere you write

your day starts on
today's page.

Type a bullet, indent it under another with Tab, mark a line TODO, DOING or DONE, and link to another page with [[brackets]], and that page then lists every place it got mentioned. Same workspace folder on the terminal with vim keys, the desktop app and your phone. click any screen to zoom, or see all 48 screens

desktop · macOS
macOS · linux · windows beta installers not signed yet
mobile · iOS
iOS beta android apk on every release
terminal · TUI
macOS · linux · windows vim-first, mouse-optional
on the phone
a reminder you can answer

A banner used to tell you what was due and offer nothing to do about it — you opened the app, found the page, found the block. It carries Snooze 1h and Done now, and snoozing is an operation like any other, so it silences every device rather than the one you tapped. A plain tap opens the page and scrolls the block into view — scrolls, not zooms, because zoom hides the rest of the page and nobody asked for that by tapping a notification.

on the desktop
Open With → outl

Right-click a .md or .txt anywhere in Finder, Explorer or your file manager and it lands as a page, linked from today's journal so you can find it again without remembering it exists. outl imports a copy and never writes back to the file, and opening the same one twice takes you to the page the first open made instead of duplicating it.

on all three
a key that does nothing says so

Three surfaces will never do all the same things — a file manager has no terminal to hand a file to, and a phone has no chords. What each one can and cannot do is declared in code as an exhaustive list, so a client cannot ship a gap by forgetting to mention it. Press something that is not there and outl tells you, instead of leaving you to wonder whether it broke.

one workspace folder, every surface reads it. outl syncs it between your devices, so a bullet you write on your phone shows up in the terminal too.

your files

the markdown you see
is the markdown you wrote.

No id:: lines. No UUIDs. No HTML comments smuggling metadata. The IDs outl needs live in a separate sidecar file (.foo.outl), version it or don't. Your .md is yours. Full spec at /format, and /import if you're bringing notes over from somewhere else.

logseq · pages/post.md
- ## ship outl 0.1.0 id:: 6624a82c-3b11-4d44-9d3f-d9c7e8f0a1b3 collapsed:: false - draft post #launch id:: 6624a82c-9a22-4e55-be40-eaf8d9015c2a - ship binaries id:: 6624a82c-7c33-4f66-cf51-f0a9eb126d3b - linux x86_64 id:: 6624a82c-5d44-4077-d062-01baf1237e4c - macos arm64 id:: 6624a82c-3e55-411a-e173-12cbf2348f5d - test sync id:: 6624a82c-1f66-422b-f284-23dcf3459a6e - <!-- logseq.order-list-type:: number -->
outl · post.md + .post.outl (sidecar)
title:: ship outl 0.1.0 icon:: 🚀 tags:: launch - draft post #launch - ship binaries - linux x86_64 - macos arm64 - test sync
diff-friendly
your git diff is what you changed — not 30 UUID lines that shifted parents.
tool-friendly
works with pandoc, hugo, mdbook, your editor, your scripts. plain commonmark.
future-friendly
delete outl tomorrow. your notes still read the same in any text editor.
sync

two devices edit
offline.
they sync to the
same tree.

outl's default transport is peer-to-peer over iroh: your devices talk straight to each other, end-to-end encrypted, with no account. On the same Wi-Fi they find each other and sync with no internet connection at all.

Edit two devices offline and when they reconnect, a tree-CRDT (Kleppmann et al. 2022) merges both edit streams into one tree without asking you to pick a winner. The proof behind that algorithm covers the merge, not every corner of the app: the full guarantees and the honest trade-offs are on /sync.

When two devices can't reach each other directly, a relay helps them connect and forwards the already-encrypted data. It can see device IDs, timing and how much traffic moves, but not your notes. If you'd rather skip it, point outl at a folder synced by iCloud Drive or Syncthing instead, or run your own always-on peer. More on what the relay sees at /docs/relay.

Pairing is between devices you own. It isn't a way to share a workspace with someone else.

laptop A offline
laptop B offline
● op-log step 0/5
extras

notes that run code, and that your LLM can read.

code blocks

Drop a ```python, ```js, ```lua or ```rust block and the result lands as a > result: line right under it. These four run in the terminal and desktop builds. On mobile, Rust isn't available. Plugins are JavaScript, in beta.

more on code execution
mcp server

outl mcp serve runs locally and lets a connected AI tool (Claude, Cursor, ChatGPT…) read and write your notes: look things up, append to today's page, update a block. outl itself uploads nothing, but whatever the tool reads it sends on to its own model provider, under that provider's terms.

set it up with your LLM
ship it

one binary.
your notes.

outl is beta, pre-1.0, MIT licensed. Press ▷ and you're typing in a journal.

homebrew recommended beta
$ brew tap outlmd/outl https://github.com/outlmd/outl
$ brew trust outlmd/outl
$ brew install outl-beta
windows beta
$ scoop bucket add outl https://github.com/outlmd/outl
$ scoop install outl/outl-beta
nix (linux)
$ nix profile add github:outlmd/outl
$ nix profile add github:outlmd/outl#outl-desktop
from source
$ git clone https://github.com/outlmd/outl && cd outl
$ cargo install --path crates/outl-cli
first run
$ outl init ~/notes && outl --workspace ~/notes

currently shipping outl-beta via the outlmd/outl tap. stable brew install outl arrives with 1.0. no brew? grab a binary for macOS, Linux, Windows, iOS or Android →

The macOS and Windows installers are unsigned for now: macOS asks you to right-click → Open on first launch, Windows SmartScreen needs "More info → Run anyway". Official release builds also send a crash report (Sentry) by default, with no note text, page names or filesystem paths in it, and self-compiled builds never report at all. Turn it off in Settings → Privacy, or run outl telemetry off. Full detail at /privacy.

frequently asked

questions people actually ask.

What is outl?

+ −

outl is an outliner for markdown notes, a bullet-point editor where every line is a block you can move, link and search. It stores plain markdown on disk, no UUIDs in the file, with the IDs it needs in a separate sidecar. It ships as a single binary with a vim-style TUI, plus a desktop app and mobile apps, all in beta.

Do I need an account to use outl, or to sync?

+ −

No. There's no account and no cloud sign-up. Sync is peer-to-peer and encrypted, directly between the devices you pair yourself, not a way to collaborate with someone else's workspace.

What leaves my device?

+ −

Nothing of your note content by default. Sync sends your notes, end-to-end encrypted, only to devices you've paired; when a direct connection isn't possible, a relay forwards that already-encrypted data and can see metadata like device IDs and timing, not your notes. If you connect an AI tool over MCP, whatever it reads gets sent on to that tool's own model provider. Official release builds also send a crash report by default, with no note text in it, and you can turn that off in Settings → Privacy. Full detail at /privacy.

Is outl free?

+ −

Yes. outl is MIT licensed, the code is on GitHub at github.com/outlmd/outl, and there's no paid tier. It's beta software, pre-1.0, so expect rough edges.

Can I import my notes from Logseq, Roam or Obsidian?

+ −

Yes. Run `outl import logseq <path-to-graph> <dst>` for Logseq, `outl import roam <backup.json> <dst>` for Roam, or `outl init <vault>` for an Obsidian vault, which is already plain markdown. The importer strips id:: lines, resolves ((uid)) block references, slugifies filenames and seeds the sidecars. Unresolved refs are kept as ((unresolved:UID)) for manual triage.

stuck on something? ask in github discussions.

questions and ideas go in discussions, bugs go in an issue. the maintainer reads both.