Ruben Carlo Benante 4ba2717902
Some checks failed
Zettelclean CI / build (20.x) (push) Has been cancelled
Zettelclean CI / build (22.x) (push) Has been cancelled
Zettelclean CI / build (24.x) (push) Has been cancelled
Release Zettelclean / build (push) Has been cancelled
Makefile to install, and License GNU GPLv3
2026-07-28 20:57:51 -03:00
2026-07-28 16:52:46 -03:00

Zettelclean

Keep a Zettelkasten filename's slug in sync with the note's H1 heading.

Zettelclean resolves the "three sources of truth for a title" problem (filename vs H1 vs YAML title:) by separating concerns:

  • The H1 heading in the note body is the single source of truth for the human title.
  • The filename is a derived machine identity: TIMEID-slug(H1).md.
  • No YAML is written. Files stay pure Markdown.

It is a small, one-way, prefix-gated renamer: edit the H1, and a moment later the filename's slug tail follows. Nothing else is touched.

How it works

  • A note is a zettel when its filename starts with a TIMEID: a run of 12 to 18 digits (a timestamp), for example 20260728145404-my-note.md. Files without that prefix are ignored, so plain notes, daily notes, Excalidraw and Kanban files are never renamed.
  • The TIMEID is minted once and never changes. Only the slug tail is regenerated.
  • When you edit the H1, zettelclean waits about 5 seconds of idle, then renames the file to TIMEID-slug(H1).md using Obsidian's own rename (so backlinks are updated). A 10 second cooldown prevents a just-renamed file from being renamed again.
  • Sync is strictly one-way, H1 to filename. Renaming a file by hand is never fought.
  • Delete the H1 and the filename collapses back to the bare TIMEID.md.

The slug is lowercase, ASCII, dash-separated: accents are folded (Ciências becomes ciencias), runs of punctuation and whitespace collapse to a single dash, and leading and trailing dashes are trimmed.

Creating notes

Use Obsidian's built-in Unique note creator core plugin to mint the TIMEID:

  1. Settings -> Core plugins -> enable "Unique note creator".
  2. Set "Unique note format" to YYYYMMDDHHmmss (14 digits, second precision - avoids same-minute collisions).
  3. Click the "Create new unique note" ribbon icon. You get 20260728145404.md; type your # Title, and zettelclean takes over from there.

Zettelclean also accepts an existing 12-digit (YYYYMMDDHHmm) vault if you prefer not to change the setting.

Retrofitting existing notes

Notes created before you adopted this workflow have no TIMEID. Right-click such a note in the file explorer and choose "Add zettel TIMEID to filename". It mints a fresh timestamp, prepends it, and the note is now a zettel that syncs on future H1 edits.

Pretty sidebar (optional)

By default the file explorer shows the slugged filename (with dashes). If you want the sidebar, tabs and graph to show the pretty H1 instead - with no YAML in your files - install the Front Matter Title community plugin and set its feature templates to:

#heading | _basename

That reads the first H1 directly and falls back to the filename when there is none.

Settings

None. Zettelclean is zero-config in this version. The 5 second settle and 10 second cooldown are fixed.

Development

  • npm install (or pnpm install).
  • npm run dev - compile in watch mode.
  • npm run build - typecheck and produce main.js.
  • npm test - run the slug unit tests on Node's built-in test runner.
  • npm run lint - eslint with the Obsidian ruleset.

The pure string logic lives in src/slug.ts and is unit-tested in isolation; the Obsidian wiring lives in src/main.ts.

License

GNU General Public License v3.0 or later (GPL-3.0-or-later). Copyright (C) 2026 Ruben Carlo Benante (Dr. Béco) rcb@beco.cc. See LICENSE for the full text.

Description
An Obsidian plugin to clean filenames from special characters based on H1
Readme GPL-3.0 254 KiB
Languages
TypeScript 69.4%
JavaScript 15.8%
Makefile 9.5%
CSS 5.3%