Grunden er den samme som for postkassers kodeord og OAuth-tokens: en sikkerhedskopi kan hentes gennem fladen, og indtil nu bar hver eneste af dem hver eneste note i klartekst. Noter er dér, folk skriver kodeord og API-nøgler ned — det ved vi, fordi der ligger sådan nogle i den installation, det her blev bygget til. **Både titel og krop.** Titlen *er* første linje, så en forseglet krop ved siden af en læselig titel ville efterlade begyndelsen af hver eneste note i klartekst. **Og de to kopier gik med.** Det var derfor det ikke var gjort for længe siden: `notes_fts` indekserede kroppen, og den genererede `fold`-søjle bar en translittereret kopi af den. At forsegle kroppen og lade dem stå ville have været teater — en angriber med filen kunne læse hver note ud af indekset. Begge er væk, og tabellen er bygget om, fordi SQLite ikke kan fjerne en genereret søjle på plads. **Søgningen åbner teksten i Go.** Målt frem for gættet: tolv hundrede noter à 3,3 kB koster 33–43 ms pr. søgning, og fladen venter 250 ms efter sidste tastetryk, før den spørger — så det ligger inde i pausen. Tiden går ikke med at åbne konvolutterne; fire megabyte AES-GCM er få millisekunder. Den går med at folde og småskrive hver krop, og det er lineært: regn med omtrent 350 ms ved ti tusind noter. Dér er det den forkerte form, og svaret er da et nøglet indeks — hvis pris er, at præfiks- og delordssøgningen falder bort. bm25 forsvandt med indekset. Det, der er beholdt, er den halvdel, der betød mest: titlen vejer ti gange kroppen. Med et loft pr. ord, så en note, der nævner ordet fyrre gange, ikke slår en, der nævner alle ordene én gang — det er den fejl, en ren optælling laver, og den er let at lave og svær at få øje på. **En bagudfyldning ved opstart, ikke efterhånden.** Instansens indstillinger forsegles, når de skrives, og det er rigtigt for dem. For et arkiv på tolv hundrede importerede noter, som ingen redigerer igen, betyder "når de skrives" aldrig — og det er præcis dét arkiv, der er værd at forsegle. Idempotent, så den koster et gennemløb af id'er hver anden gang, og `updated_at` røres ikke: at lukke en konvolut om en note er ikke at skrive den, og et stempel med i aften ville kaste den rækkefølge væk, importen brugte en dag på at hente hjem. En fejl under bagudfyldningen stopper opstarten. Halvdelen af noterne lukket er ikke i stykker — `v1:`-præfikset gør, at begge slags kan læses — men en instans, der starter og lader som om den beskytter noget, den ikke gør, er værre end en, der siger fra. Hvad der stadig ligger åbent, står i SECURITY.md og på dokumentationssiden: opgavetitler, beskrivelser, kommentarer, og `note_links`, som røber hvilke projekter og opgaver en note peger på, men ikke hvad der står. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.3 KiB
Notes
Markdown in, Markdown out. Nothing in between.
A note is written as rich text — headings, lists, quotations, code — and stored as the Markdown it looks like. That is not a detail about the database: it is what makes a note yours. Export gives you the same text you were looking at, and on the day this program is gone, every note opens in any editor.
Writing
Start typing. The first line is the title — always, and re-derived every time you save, so a note you rewrite the top of is called by what it now says rather than by what it once did.
| Style | Written as | Shortcut |
|---|---|---|
| Title | # at the start of the line |
pick it in Aa |
| Heading | ## |
|
| Subheading | ### |
|
| Quote | > |
|
| Code block | three backticks, with an optional language | |
| Bullet and numbered lists | - and 1. , nested with Tab |
|
| Bold | two asterisks around the words | ⌘B |
| Italic | one asterisk around the words | ⌘I |
| Underline | a u tag around the words |
⌘U |
| Strikethrough | two tildes around the words | |
| Code | one backtick around the words |
Every line becomes exactly one block. Markdown would normally join consecutive lines into a paragraph; here it does not, because you typed a line and expect to get it back.
Press the source button in the toolbar to see the note as the file it is. Edits there are edits to the note.
Pictures
Paste one, or drag it onto the note. It is stored with the note and travels with it in an export. Every raster format works; SVG is stored but not shown inline — it is a document that can run script, and a note is not a place to run somebody else's.
Code blocks
A fenced block is coloured for the language it names, and guesses when it does not. Each one carries a Copy button in its corner.
Linking
Three kinds of reference, parsed out of the text as you write it:
| You type | It means |
|---|---|
#Firma |
The project — the same #Firma quick add understands, not a second kind of tag |
[[Møde med Anders]] |
Another note, by its title |
| A pasted task link | That task |
Links are an index over the text, rebuilt every time the note is saved. The text stays the truth.
The interesting direction is backwards. A task shows what has been written
about it, and a project shows the notes filed in it — without anybody having to
remember to attach anything. Write #Firma in a note and it appears on that
project's page.
A link to something that has been deleted reads as a dead link. It is a fact about the note, and it should not vanish because something it mentioned did.
Filing and sharing
A note belongs to a project, or to nobody.
- In a project: everybody who can read the project can read the note, and an editor can change it. Choose it under Share in at the foot of the note.
- In no project: yours, and nobody else's.
There is no folder tree. Projects, groups and labels already exist, are already shared and already have roles — a second hierarchy to file things in is one too many, and a note in a project inherits every one of those answers.
Finding
The list groups itself: favourites first, then Today, Yesterday, This week, and then by month. Sort by created, last touched or name, and the grouping follows — sorted by name it groups by first letter instead.
Search finds a word wherever it is:
gronfindsgrøn. Unicode does not considerøan accentedo, so stripping diacritics is not enough for Danish. A folded copy of every note is indexed beside the original.inventoryfindskeepInventory. An index is built of whole words, and a decade of notes is full of commands and identifiers that are several words in one. When the index has nothing, the text itself is read.- Results are ranked by how well they match, with the title weighted ten times the body. A word in the title is what the note is about; the same word once in a long body is a mention.
Putting notes away
Two different things, and the difference matters:
- Archive — this is finished and I do not want to read past it. It stays findable and comes back whenever you ask.
- Trash — this was a mistake. It is gone in thirty days.
Select several with ⌘-click and shift-click to archive or delete them together.
In and out
Export gives you a zip of Markdown files, one per note, with the dates in a YAML front matter block that Obsidian and Bear also read:
---
created: 2019-04-02T10:15:00Z
modified: 2024-11-30T21:04:00Z
---
# Møde med Anders
Han vil gerne have kaffe hver uge.
Import takes the same shape back. Pictures travel in the zip beside the notes, and the links in the text are relative — so a note and its pictures must be in the same archive, which matters when a large export is split into parts.
Two things to know before importing:
- Nothing is merged. Every run creates new notes. Importing the same archive twice gives you two of everything.
- The dates are read from the front matter. Without them, a move of a thousand notes is a pile that was all written the same evening — and the order they were written in is half of what an archive is.
From Apple Notes
tools/apple-notes-til-markdown.py in the repository exports Apple Notes to
exactly this shape, front matter and pictures included. It is macOS-only, because
Apple Notes is.
For a large library, tools/pak-noter-i-portioner.py splits the export into
uploadable parts, keeping each note with its own pictures.
What is encrypted, and what is not
A note's title and body are sealed in the database, under a key kept in a file beside it rather than inside it. A backup you download does not carry the key, so it does not carry your notes.
Both halves, not only the body: a note's title is its first line, so a readable title beside a sealed body would leave the beginning of every note in the open.
What is still in the clear: task titles, descriptions and comments — and the list of what a note links to, so a stolen file shows which projects and tasks a note points at, though not what it says.
Sealing the notes cost the search its index — a full-text index over a note's body is another copy of that body — so search reads the notes themselves now. At twelve hundred notes that is about forty milliseconds, and the box waits a quarter of a second after you stop typing, so you will not see it.