olai GitHub

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
kitchen.jsonl
Kitchen renovation 2/4
Demolition
Pick the counter stone
Order the new cabinets #blocking
Measure twice — the corner unit is the risky one.
▤ cabinets.md
Book the plumber
Paint samples on the north wall

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, Dynalistolai
StorageA hosted databasePlain files in a directory you choose
SyncTheir cloudgit, or anything that moves files
HistoryIn-app version historygit log; every edit is a reviewable commit
Concurrent editsResolved by their serverLine-based git merges
Programmatic accessVendor API, where one existsAny agent over ACP or MCP; any text tool
SourceProprietaryOpen 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.

/doc/cabinets.md · attached to “Order the new cabinets”

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.

/d/2026-08-12

2026-08-12

Fog on the water. Only the ferry has a deadline, so it went first.

kitchen.jsonl
Order the new cabinets
Pick the counter stone

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.

completed taskdone
task in progressdoing
task not startedtodo
a noteno mark
read this book 1/3
chapter one
the streams chapter
exercises

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.

Entercommit, and open the next line
Tab / Shift+Tabindent, or out again
Alt+Shift+/move a row among its siblings
+Ztake back your last edit here
+Entertick it off, or take that back
Shift+Enterwrite the note under it
Escdrop what you were typing
++Zput 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.

chat · any ACP agent
plumber's booked — tick it off
set_done · book-plumber
Done. Marked “Book the plumber” as done.
kitchen.jsonl · live
Kitchen renovation 3/4
Order the new cabinets #blocking
Book the plumber

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.