olai
A git-native outliner: memory for the AI era.
Outlines are .jsonl files, one line per node.
Longer content is Markdown files referenced from the outline. Everything
is tracked in git, and agents edit through the same operations layer as
the keyboard.
nix run github:juspay/olai -- web path/to/outlines
The file format
Each outline is a .jsonl file: one JSON object
per line, one node per line. Nodes have stable ids and parent pointers, so
line-based git merges are safe and moving a subtree changes one field.
See the format spec.
{"id":"kitchen","ord":"a","title":"Kitchen renovation"}
{"id":"demo","parent":"kitchen","ord":"a0",
"title":"Demolition","done":"2026-08-09T14:02:11-04:00"}
{"id":"order","parent":"kitchen","ord":"a1",
"title":"Order the new cabinets #blocking",
"doing":true,"after":["demo"],"doc":"cabinets.md",
"desc":"Measure twice — the corner unit is the risky one."}
The outline above, as stored on disk.
$ git diff
-{"id":"order","parent":"kitchen","ord":"a1", … }
+{"id":"order","parent":"now","ord":"a1", … }
Moving a subtree changes the parent
field. Children reference order by id and are
unaffected.
Compared to Workflowy and Dynalist
olai keeps the outlining model those tools established — indent, move, mirror, check off. The difference is where the data lives and what can reach it.
| Workflowy, Dynalist | olai | |
|---|---|---|
| Storage | A hosted database | Plain files in a directory you choose |
| Sync | Their cloud | git, or anything that moves files |
| History | In-app version history | git log; every edit is a reviewable commit |
| Concurrent edits | Resolved by their server | Line-based git merges |
| Programmatic access | Vendor API, where one exists | Any agent over ACP or MCP; any text tool |
| Source | Proprietary | Open source (AGPL-3.0) |
Markdown documents
Notes are Markdown. Longer content goes in .md
files, referenced from the outline by the doc field. Each
document gets its own page and appears in the sidebar's file tree.
# Cabinet specs
The corner unit is the **risky one** — see
[the measurements](measurements.md).
- 600 mm base × 4
- corner carousel × 1
cabinets.md — a plain Markdown file next to the outline, editable with any editor.
Cabinet specs
The corner unit is the risky one — see the measurements.
- 600 mm base × 4
- corner carousel × 1
Daily notes
A Markdown file named for a date — 2026-08-12.md,
anywhere in the directory — is that day’s note. No setting says so, and it
can live wherever your vault already puts it. Open the day and the note is
on top, with everything dated that day underneath it. Relative links
between your Markdown files keep working from there.
Daily/
2026/
08/
2026-08-12.md ← the 12th
2026-08-10-recap.md ← not a daily note
Convention, not configuration: the basename has to be the date and nothing else.
2026-08-12
Fog on the water. Only the ferry has a deadline, so it went first.
Task status
A node can carry one of three marks: done,
doing, or todo. A node with no mark is not a task
and gets no checkbox.
1/3 is a display annotation. A parent's
status is never computed from its children.
Keyboard editing
Click a title to edit it in place. Each edit is one operation through the same layer the agent uses, and each lands as a git commit.
| Enter | commit, and open the next line |
| Tab / Shift+Tab | indent, or out again |
| Alt+Shift+↑/↓ | move a row among its siblings |
| ⌘+Z | take back your last edit here |
| ⌘+Enter | tick it off, or take that back |
| Shift+Enter | write the note under it |
| Esc | drop what you were typing |
| ⌘+⇧+Z | put that edit back |
Undo is an inverse rather than a restore: it replays the edit that reverses yours, judged against the outline as it is now — so it never takes back what an agent or another tab did in the meantime, and one that no longer fits says why.
Not everything has a key. Hover a row and the ••• in the
gutter carries the rest: the three marks and clearing one, clearing a date,
retiring one placement of a mirrored node, archiving a subtree — it asks
first, and says how many rows go with it — and copying the subtree as
tab-indented plain text. Those go on the same undo stack, so ⌘Z takes a
menu edit back too. There is no delete: archiving moves the subtree to an
Archive.jsonl keeping its ids, so nothing that pointed at it
breaks. Every one of those is the same operation an agent would perform,
which is a rule olai holds itself to: both faces can do the same things to a
directory.
Agents, over ACP
The chat panel connects to any agent that speaks
ACP. Claude Code is bundled as
the default; set OLAI_ACP_AGENT to use a different agent CLI.
Agents get a fixed set of node tools and no file access, so every write is
validated before it lands.
Files go in by paste, by drag, or by the picker: drag a screenshot, a PDF or a text file onto the conversation — several at once if you like — and the panel lights up the area that will take it while you are still holding it. The agent is handed the path to read, not the bytes. They live in a temporary directory of that conversation's own, never under the directory being served, and go away with it. A picture shows itself; a document shows its name and size. Anything olai will not take is refused where you dropped it, by name.
The open page updates because the file on disk changed. The keyboard and the agent write through the same operations layer.
Git integration
Writes go to disk immediately and are committed when you
choose — everything the repository has waiting, outlines and the files
beside them, ticked one by one if you want a smaller commit, and pushed
from the same panel. Commit messages are prefixed with olai:,
so git log --grep '^olai' shows the audit trail.
┌─ Changes ─────────────────────────────────┐
│ olai: Outlines as a collection done │
│ · chat agent · 12m ago · 1a2b3c4 │
│ │
│ OUTLINES ───────────────────────────── │
│ ☑ roadmap.jsonl │
│ ✓ Outlines as a collection done │
│ ✎ Notes: one state, same line note │
│ + Kolu integration: auto-… created │
│ │
│ OTHER FILES ────────────────────────── │
│ ☑ README.md modified │
│ ☐ notes/scratch.md untracked │
│ │
│ 2 commits not on origin/master [ Push ] │
│ [ Commit 3 changes · 1 file ] │
└───────────────────────────────────────────┘
$ claude mcp add olai -- olai mcp ~/outlines
The same tools are available over MCP for agents running in a terminal. There is no write CLI.