v0.7.0 — P2P sync, daily-driver-ready

notes that don't
corrupt when you
sync them.

outl is a local-first outliner. Plain markdown is the source of truth. The CRDT lives in a sidecar, not in your files.
Two devices sync peer-to-peer to the same tree — end-to-end encrypted, no account, no cloud, no server that holds your notes. And your LLM reads them as a second brain over MCP.

0
formal guarantees
0
id:: in your .md
0
files benched
~/notes — outl May 26, 2026
journal · 🚀 launch-day ctrl-p ⌃k ?
synced 3 blocks 2 backlinks tree-crdt · op-log: 247
01 · the bet

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

Roam keeps your notes on their servers — the later write silently wins. Logseq scatters id::abc123 UUIDs through your .md so rsync has something to match on; concurrent moves still lose data. git gives you conflict markers across nested bullets every time.

And every one of them round-trips your notes through a server you don't control — Roam's cloud, or the paid sync tier bolted onto the others. outl syncs peer-to-peer over iroh: your devices talk straight to each other, end-to-end encrypted. No account, no cloud, no server that holds — or reads — your notes.

outl uses the Kleppmann et al. 2022 tree CRDT — the algorithm that backs Automerge and Y.js, adapted for trees.

  • Strong eventual consistency. Same ops → same tree, any order.
  • Commutative after reordering. Late arrivals don't break the result.
  • Idempotent. Apply twice = apply once.
  • Tree invariant always holds. No node has two parents, no cycles.
  • No silent loss. Every op stays in the log — even ones turned into no-ops.
laptop A offline
laptop B offline
op-log step 0/5
private by default

your notes never touch
a server you don't own.

Roam and Notion keep everything on their servers. Logseq and Obsidian bolt on a paid cloud to move your files around. Either way, your notes ride through a company you don't control — one that can read them, leak them, or price you out.

outl syncs peer-to-peer over iroh. Your devices talk straight to each other, end-to-end encrypted — no account, no cloud, no third-party server in the middle. Privacy isn't a mode you switch on. It's the only way it works.

No server holds your notes.

Device-to-device over iroh, end-to-end encrypted with QUIC. Nothing we — or anyone — run ever stores your data. When your network blocks a direct path, a relay forwards bytes it can't decrypt; it never sees your notes.

Nothing to breach.

No account, no login, no paid cloud tier. There's no database of your notes sitting on someone's servers to leak — it doesn't exist. And the source is open, so you can audit the wire yourself instead of trusting us.

Zero UX tax.

Same TUI, desktop and iOS. Same clean markdown on disk. Offline-first — no spinner waiting on a server to answer. Pair two devices once with `outl peer pair` and they stay in lockstep. Privacy that isn't a downgrade.

02 · notes that compute

your code
your data
your notebook.

Markdown fences aren't just for syntax highlighting. Drop a ```python, ```lisp, ```js, ```lua or ```rust block. The result lands as a > result: subblock right underneath it. Re-runs are idempotent.

Set auto-run:: on a block and it re-runs every time you open the page — cache-aware by source hash. Adding a new language is an ~80-line adapter.

python
lisp
js
lua
rust
~/notes/algorithms.md ▷ run
title:: algorithms
fibonacci in 4 lines
```python
def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)
print([fib(i) for i in range(10)])
```
idle
› result:
cached · hash: auto-run:: on
the result block is just a markdown blockquote — your file stays diff-able.
03 · markdown stays markdown

the markdown you see
is the markdown you wrote.

No id:: lines. No UUIDs. No HTML comments smuggling metadata. The IDs the CRDT needs live in a separate sidecar file (.foo.outl) — version it, or don't. Your .md is yours.

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.
04 · second brain · new
just shipped · MCP server

outl is your
LLM's second brain.

The same notes you write in the TUI are the notes Claude, Cursor, Zed and ChatGPT read through the Model Context Protocol. One binary. One config block. No upload — your second brain stays on your disk.

  • read any page, search the graph, list backlinks, query by tag.
  • write new blocks, append to today's journal, toggle a TODO — from the chat.
  • pin outl://daily/today as a resource so the model has today's context every turn.
claude_desktop_config.json
{
  "mcpServers": {
    "outl": {
      "command": "outl",
      "args": ["--workspace", "~/notes", "mcp", "serve"]
    }
  }
}

MCP is an open standard. Any new host that adopts it picks outl up for free — the binary doesn't change.

04 · vs them

we like the ideas.
we don't like the trade-offs.

Roam, Logseq and Obsidian got a lot right — graph thinking, backlinks, daily journals, block addressability. outl picks those up and fixes the sync, the file format, and the runtime.

feature
outl MIT · rust
Roam closed · cloud
Logseq AGPL · electron
Obsidian closed · electron
markdown is the source of truth partial
no UUIDs in your .md n/a
block-level outliner plugin
[[wiki-links]] + backlinks
daily journal first-class
code blocks that execute 5 langs limited plugin
tree-CRDT algorithm (provably correct)
P2P device sync — no third-party server cloud paid paid
works offline, no account
open source MIT AGPL
ships as a native binary
TUI / terminal editor
vim-style keys built-in plugin setting
desktop GUI app macOS beta
mobile app iOS beta
graph view planned
plugin system JS · beta partial
shipped (outl) shipped (others) planned on the roadmap not supported
coming from logseq or roam?
$ outl import logseq ~/graph ~/notes
$ outl import roam ~/backup.json ~/notes

strips id::, resolves ((uid)) refs, slugifies filenames, seeds sidecars. unresolved refs stay as ((unresolved:UID)) for triage.

honest about what's not done

v0.7.0 ships the tree-CRDT algorithm + op-log infrastructure (validated by 10+ property tests), a daily-driver-ready TUI, and P2P sync via iroh as the default transport — your devices talk straight to each other, end-to-end encrypted, with no third-party server holding or reading your notes. Roam round-trips through their cloud; Logseq and Obsidian gate device sync behind a paid cloud tier. Code execution (5 langs) and a JavaScript plugin system both ship today. The pieces still marked planned above are graph view and the query DSL. macOS desktop is already shipping in beta via Homebrew cask (install here), iOS is on public TestFlight beta (join here); Android is planned. See the roadmap.

frequently asked

questions people actually ask.

What is outl?

+

outl is a local-first outliner — a bullet-point note-taking app where every line is a block you can move, reference and search. It stores plain markdown on disk (no UUIDs, no metadata pollution), has a tree-CRDT under the hood for sync that doesn't lose data, and ships as a single Rust binary with a vim-style TUI.

How is outl different from Logseq, Roam or Obsidian?

+

Three things. (1) Sync: outl syncs peer-to-peer over iroh — your devices talk straight to each other, end-to-end encrypted, with no third-party server holding or reading your notes. Roam round-trips through their cloud and loses data on offline conflicts, Logseq's built-in sync is rsync-flavored and overwrites, Obsidian's built-in sync is a paid cloud tier. Under the hood outl uses a Kleppmann tree-CRDT with five formal guarantees. (2) File format: Logseq writes UUIDs into your .md files. outl never does — IDs live in a sidecar. (3) Stack: outl is open source (MIT) and ships as a native binary; the others are Electron or proprietary.

Is outl open source and free?

+

Yes. outl is licensed under MIT and the entire codebase is on GitHub at github.com/avelino/outl. There is no paid tier, no account, no telemetry. Free forever.

Does outl work offline?

+

outl is local-first. Your notes live as .md files on your machine — you edit them with zero network. No account, no cloud requirement. You can use outl on a plane and lose nothing; when two devices reconnect, the tree-CRDT merges both edit streams without dropping a block.

Do I need an account or a cloud to sync?

+

No. outl syncs peer-to-peer over iroh: your own devices connect straight to each other and the notes are end-to-end encrypted in transit. There's no account to create and no third-party server that holds, stores or reads your notes — they live only on your devices. (iroh uses relay servers to punch through NATs, but a relay only forwards already-encrypted bytes; it never stores or decrypts anything.) Compare: Roam and Notion keep your notes in their cloud; Logseq and Obsidian gate their built-in sync behind a paid cloud tier. Self-hosting over a shared folder you control is an advanced opt-in, but P2P is the default and needs no setup.

What does "local-first outliner" mean?

+

Local-first means your data lives on your device as plain files you own. The app reads and writes them. If outl disappears tomorrow, you can open every note in VS Code, cat, or any markdown editor — nothing is trapped. Outliner means the editor is built around nested bullets (blocks) instead of long prose, so you can collapse, reorder and link individual thoughts.

Can I import my notes from Logseq or Roam Research?

+

Yes. Run `outl import logseq <path-to-graph> <dst>` for Logseq, or `outl import roam <backup.json> <dst>` for Roam. 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.

Does outl have backlinks and a graph view?

+

Backlinks are first-class — every page has a backlinks panel showing what references it. Wiki-style [[page name]] links and #tags work out of the box. A visual graph view is on the roadmap.

Can I run code inside my notes?

+

Yes — this is a core feature, not a plugin. Drop a fenced code block in Python, Lisp, JavaScript, Lua or Rust. The result lands as a markdown blockquote subblock right under the source. Re-runs are idempotent and cache-aware (SHA-256 of source). Set `auto-run:: on` and it re-runs every time you open the page.

Is there a mobile app or desktop GUI?

+

Yes — both in beta. macOS desktop ships as a Homebrew cask: `brew tap avelino/outl https://github.com/avelino/outl && brew trust avelino/outl && brew install --cask outl-desktop-beta` (universal dmg, Apple Silicon + Intel). iOS is on public TestFlight. Android is planned. All frontends share the same outl-core and outl-md Rust crates, so the algorithm and file format don't fork.

How do I install outl?

+

`brew install outl` (Homebrew formula coming soon) or `cargo install outl` (works today). Then `outl init ~/notes && outl --workspace ~/notes` opens the TUI on today's journal. First-run cost is ~30 seconds.

everywhere you write

desktop, mobile, terminal —
same notes.

One workspace folder on disk. Three surfaces reading the same plain markdown — no proprietary database, no upload. Open it where the moment finds you. · click any screen to zoom

desktop · macOS
native macOS windows & linux next
mobile · iOS
iOS beta android in progress
terminal · TUI
macOS · linux · windows vim-first, mouse-optional

one workspace folder. every surface reads it. P2P CRDT sync keeps your devices in lockstep — talking straight to each other, no third-party server in the middle — even when you go offline.

05 · ship it

one binary.
your notes.

No electron. No account. No cloud. Press ▷ and you're typing in a journal.

homebrew recommended beta
$ brew tap avelino/outl https://github.com/avelino/outl
$ brew trust avelino/outl
$ brew install outl-beta
cargo
$ cargo install outl
from source
$ git clone https://github.com/avelino/outl && cd outl && cargo build --release
first run
$ outl init ~/notes && outl --workspace ~/notes

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