---
title: 'How notes work here'
date: 2026-10-16
summary: 'The conventions this knowledge base runs on — frontmatter, wikilinks, topics and maturity. Read this one first.'
status: evergreen
topics: [generative, skiing]
canonical: 'https://yhzhan.me/notes/how-notes-work/'
source:
  type: own
links_to: [terrain-as-a-first-filter]
---
Every file in `src/content/notes/` becomes a page, a node in the
[graph](/graph/), and a row in the [index](/notes/). Nothing else needs to be
registered anywhere.

## Frontmatter

Only `title` and `date` are required. Everything else earns its place:

| Field | Why it exists |
| --- | --- |
| `summary` | Shown in the index and the graph tooltip. Write it for a stranger. |
| `topics` | Canonical slugs. Aliases fold automatically — `nn` lands on `neural-networks`. |
| `status` | `seed`, `growing` or `evergreen`. Honesty about maturity, not a promise. |
| `source` | What was consumed. A paper, a podcast, a report — or `own` for original thinking. |
| `draft` | Visible in `npm run dev`, never in a deploy. |
| `translation` | Only on a translation. Written by `npm run stamp` — see below. |

## Links are the graph

Write `[[slug]]` or `[[slug|any label you like]]` and it becomes both a link and
an edge. Topic links work the same way: `[[topic:skiing]]` tags this note with
[[topic:skiing]] mid-sentence, with no frontmatter echo needed.

The same syntax is what Obsidian uses, deliberately — a note body renders
correctly in a vault and on this site, so the editor stays swappable.

A link to a note that does not exist yet is not an error, it is a to-do:
`npm run check` lists every dangling link and every topic without a hub page.

## Two languages, one note

`foo.md` and `foo.zh.md` are the same note. One slug, one set of topics, one
node in the graph; the page offers a switch between them. A note written only
in Chinese keeps the bare URL rather than being pushed to a sub-path.

The hard part is not having two files, it is keeping them saying the same
thing. Editing the English leaves the Chinese quietly wrong, and a stale
translation is worse than a missing one, because it reads as current.

So a translation records a hash of the version it was translated from:

```yaml
translation:
  of: en
  rev: f38473579e4b
```

Recomputing that hash at build time makes drift a fact rather than a feeling.
Not dates, which depend on remembering, and not file timestamps, which git
does not preserve. The hash ignores rewrapping — these notes are hard-wrapped,
so a one-word edit reflows a paragraph — and ignores `topics`, `status` and
`date` entirely, so reorganising the garden never invalidates a translation.

`npm run stamp` lists what has drifted; `-- --diff <slug>` shows what moved in
the source since. Stamping is always a command, never automatic: it asserts
that someone read both versions and they agree, and a stamp applied by a build
step would assert that without anyone having checked.

A reader who lands on a translation that has fallen behind is told so, at the
top of the page, with a link to the source.

## Maturity over polish

A `seed` is allowed to be one sentence. The alternative — only writing things
once they are finished — is how a knowledge base dies. See
[[terrain-as-a-first-filter]] for one that is still thin on purpose.
