the format,
all of it.
Standard CommonMark, plus
six conventions for properties, refs, tags and runnable code.
That's it. The .md you read is the .md outl wrote.
one file. two layers.
Every page is one .md + one .outl sidecar. The .md is what humans (and other tools) read. The sidecar holds CRDT IDs and metadata that doesn't belong inline.
Lose the sidecar? outl doctor regenerates it from the op log. Lose the .md? The op log still has every block.
key:: value.
Every property is a plain markdown line: key:: value. Two colons. Space. Value. That's the entire grammar.
Page-level properties sit at the top of the file before any bullet. Block-level properties sit on the line below their block. outl recognizes a handful of reserved keys; everything else is yours.
| key | scope | what it does | example |
|---|---|---|---|
title:: | page | Display name. Slug is the filename. | title:: My Launch Plan |
icon:: | page | Single emoji. Surfaces in header, switcher, backlinks, autocomplete, inline [[refs]]. | icon:: 🚀 |
tags:: | page | Comma-separated tag list applied to the whole page. | tags:: launch, q2-2026 |
alias:: | page | Alternate names for the page. [[Alternate Name]] resolves here. | alias:: launch, q2 launch |
auto-run:: | block | Code blocks under this property re-run on page open (cache-aware). | auto-run:: on |
source-hash:: | result | Written by outl onto > result: subblocks. SHA-256 of source. Don't edit by hand. | source-hash:: a91f2c3 |
priority:: | block | Custom property. Any key:: value pair works. Used by queries. | priority:: p1 |
Custom keys are first-class. Queries (phase 3) treat them as columns. Anything key:: value indexes.
[[pages]], ((blocks)), #tags.
Three reference primitives. All of them stay in the markdown — nothing is rewritten with internal IDs visible to you.
| syntax | what it does | in context |
|---|---|---|
[[Page Name]] | Wiki-link to another page. Resolved via slug. If page doesn't exist, the link is clickable and creates it. | [[Launch Plan]] is on track |
[[Alternate Name]] | Resolved via alias:: on the target page. | [[q2 launch]] (alias) |
((block-id)) | Block reference. Renders the referenced block inline. ID maps to sidecar entry. | ((6624a82c)) |
#tag | Inline tag. Indexed and queryable. No nesting today (#a/b is two tags). | shipped #launch |
[label](url) | Standard markdown link. Untouched. | [paper](https://...) |
fences run.
Standard markdown fenced code blocks. Five languages are recognized as runtime — the rest stay as syntax-highlighted prose. Full walkthrough at /code.
the result subblock
A blockquote starting with › result: immediately under a code fence is the output. outl owns this subblock — re-running rewrites it in place. Don't edit by hand; your edits get overwritten.
markdown stays
markdown.
- ✕ No
id::lines. Block IDs never appear in your markdown. They live in the sidecar. - ✕ No YAML frontmatter delimiters. No
---separators at the top. Properties are plainkey:: valuelines you can read in any markdown tool. - ✕ No HTML comments smuggling metadata. No
<!-- collapsed:: true -->. State lives in the sidecar. - ✕ No custom non-CommonMark syntax. If you copy a block out of outl into pandoc, hugo, or your editor's preview, it renders as you'd expect.
The test: delete outl tomorrow. Open every.mdincat. Nothing reads like an artifact.
edit in vim.
outl catches up.
When you save a .md externally, outl runs a 3-level matching algorithm to figure out which block in your file maps to which ID in the sidecar:
- 1. Exact text match.
If a block's text is unchanged, its ID stays. Most edits move blocks around, not text.
- 2. Structural match.
Parent + sibling position. If text changed but the block is in the same place, it's the same block — text is just an edit.
- 3. Fuzzy text similarity.
Levenshtein distance over candidates. If structure changed too, the most similar surviving block keeps the ID. Ambiguous matches surface in
outl reconcile.
Duplicating a block in VS Code gives the duplicate a fresh ID (no collision). Renaming a page updates the slug; title:: stays human. Full algorithm in docs/markdown-format.
one format,
no surprises.
The full reference is open source on github.