DreamLake

Notes

A note is a collaborative Markdown document. People edit it in the browser in real time; dreamlake notes is how a script or an agent reads and edits the same document from a shell.

The commands are pipe-friendly on purpose: read writes the body to stdout and nothing else, write takes text from a file or stdin, and --json is there wherever the readable form would be awkward to parse.

Finding a note

terminalbash
dreamlake notes list
dreamlake notes list --shared        # shared with you, from other namespaces
dreamlake notes search deploy

Which namespace

Notes belong to a namespace, and the default is your personal one — not an organization you belong to. An organization's notes live in its own namespace and are only reachable by naming it:

terminalbash
dreamlake notes list                        # your own
dreamlake org list                          # the organizations you belong to
dreamlake notes list --namespace acme       # one of theirs

--namespace works on every command below. notes list --shared is the one exception that crosses namespaces: it lists what other people shared with you, wherever it lives.

A note is named by its slug, its title, or its id. All three work wherever <note> appears below.

search is current: before querying, it flushes the notes anyone has open in this namespace, so a sentence a colleague typed seconds ago is findable. You do not have to wait for anything.

search also says where in each note it matched:

NOTE      SLUG        UPDATED     ID
Runbook   runbook     2026-03-01  507f…

runbook
  deploy  …Run `pnpm run deploy` to ship…

Go straight to that section — notes read runbook --section deploy — instead of reading the whole note to find it. The most specific section is listed first.

search matches titles and bodies, case-insensitively, by substring — so a phrase inside a note finds it, and so does a fragment of an identifier like LAKE_REMOTE. Chinese and other non-spaced scripts match the same way.

A note last written before bodies were indexed matches on its title only, until someone edits it or an administrator runs the one-off backfill.

Creating

terminalbash
dreamlake notes create "Design Doc"
dreamlake notes create "Design Doc" --file draft.md
dreamlake notes create "Public Notes" --text '# Hello\n' --public

Titles may repeat; the slug gets a suffix to stay unique, so the command prints the slug and id it actually made rather than the title you asked for.

Reading

terminalbash
dreamlake notes read design-doc                 # the whole body, to stdout
dreamlake notes read design-doc > local.md      # …which means this works
dreamlake notes sections design-doc             # the outline
dreamlake notes read design-doc --section install

sections lists what you can address:

ANCHOR    LEVEL  TITLE        CHARS
title     1      Design Doc     820
install   2        Install      412
macos     3          macOS      180
usage     2        Usage        228

A section is a heading plus everything under it, up to the next heading of the same or a higher level — so install contains macos. The anchor is a slug of the title, with a numeric suffix when titles repeat (setup, setup-2). Text before the first heading is addressed as preamble.

Writing

terminalbash
# one section
dreamlake notes write design-doc --section install --file install.md

# the whole body
dreamlake notes write design-doc --file whole.md

# inline, or from a pipe
dreamlake notes write design-doc --section install --text '## Install
pip install dreamlake
'
cat install.md | dreamlake notes write design-doc --section install

# add to the end
dreamlake notes append design-doc --text $'\n## Changelog\n- shipped\n'

A section is replaced verbatim, heading included — which is how you rename one. Leave the heading out and the section stops being a section.

Adding and removing sections

terminalbash
dreamlake notes insert design-doc --after install --text '## Troubleshooting

Check the logs.
'
dreamlake notes insert design-doc --before install --file prereqs.md
dreamlake notes insert design-doc --text '## Licence\n\nMIT\n'   # at the end

dreamlake notes rm-section design-doc troubleshooting

--after places the new section past that one and its subsections — anything else would drop it inside the section you named. The heading is part of the text, so you pick the level: a ### can go under a ##.

insert prints the new outline, because the anchor is only knowable afterwards — a duplicate title takes the next free suffix.

rm-section removes the subtree too. That is what the section is; leaving the subsections behind would promote them into the previous one.

Writing while other people are in the note

Every write is a real-time collaborative edit. The server joins the note's collaboration room and applies your change there, so anyone with the note open watches it appear — and it merges with what they are typing, the same way two people's edits merge.

That is true of all of them: write, append, patch, add-section, rm-section. You do not have to wait for people to leave, and nothing is locked.

The precondition is a different thing

Collaboration handles two edits arriving at once. It does not help with an edit built from a document that has since changed — read a note, spend a minute deciding, write the whole body back, and you would erase what happened while you were deciding.

So a write also sends the version it was based on. If the note moved in between, it is refused rather than applied:

ExitMeansDo
3The note changed since you read itRe-read, redo the edit. Retrying as-is fails again.
4The realtime service could not take the write, and people are editingTransient — wait a few seconds and retry.
5Your diff no longer appliesRe-read and regenerate it.

Exit 4 is an infrastructure signal, not a queue. It means the collaboration room was unreachable AND somebody is connected — the fallback (writing the archive) would reset the room and cost them whatever they have not saved, so the command refuses instead. With the service healthy you will not see it.

terminalbash
dreamlake notes write design-doc --section install --file new.md
case $? in
  0) echo "done" ;;
  3) echo "someone edited it — re-read and redo" ;;
  4) sleep 30; echo "retrying" ;;
  5) echo "regenerate the diff" ;;
esac

Pinning a version yourself

read --json gives you the validator, which you can hold across a longer edit:

terminalbash
ETAG=$(dreamlake notes read design-doc --json | jq -r .etag)
# …edit…
dreamlake notes write design-doc --file new.md --if-match "$ETAG"

Overwriting on purpose

terminalbash
dreamlake notes write design-doc --file whole.md --force

--force is the only way past the check. Overwriting a colleague should be something you typed, not something that happened.

Patching

A unified diff carries its own precondition — the context has to match — so a document that moved refuses the patch instead of taking half of it.

terminalbash
dreamlake notes read design-doc > before.md
cp before.md after.md
# …edit after.md…
diff -u before.md after.md | dreamlake notes patch design-doc --file -

Permissions

Reading needs read access; writing needs write access. A read-only share link gives the first and not the second — reads work, writes fail with "read-only access to this note". A note you cannot read at all reports as not found.

Command summary

CommandDoes
notes create <name>Make a note, optionally with a body
notes list [--shared]Notes in the namespace, or shared with you
notes search <query>Match note titles and bodies
notes sections <note>The outline, with anchors
notes read <note> [--section <anchor>]Body or one section, to stdout
notes write <note> [--section <anchor>]Replace body or section
notes insert <note> [--before|--after]Add a section
notes rm-section <note> <anchor>Remove a section and its subtree
notes patch <note>Apply a unified diff
notes append <note>Add to the end

Every one of them takes --namespace, --json, and the usual connection flags. write, patch and append take --if-match and --force.