ADR-007: Quartz + Obsidian for Developer Documentation

Status: Accepted

Context

Developer documentation needs a home that is:

  • Editable in the repository — docs change with code in the same PR; no external service to keep in sync
  • Navigable locally — engineers can browse docs offline and cross-link between notes
  • Publishable — the same source can be built into a static site (e.g. GitHub Pages) without a separate CMS
  • Zettelkasten-compatible — notes can cross-link with [[wikilinks]], ADRs and technical docs form a connected graph

Options considered:

ToolFormatLocal browseStatic siteWikilinksGit-native
NotionProprietaryVia export
ConfluenceProprietary
MkDocsMarkdownCLI onlyPlugin
DocusaurusMDXDev server
Obsidian + QuartzMarkdown + frontmatterObsidian app

Decision

Store all developer documentation as Markdown files with Zettelkasten frontmatter inside the docs/ directory. Use Obsidian for local authoring and browsing, and Quartz for publishing to a static site.

The vault is configured in quartz.docs.config.ts at the repository root.

Note structure:

docs/
├── index.md              ← vault home
├── adr/
│   ├── index.md          ← ADR register
│   └── <timestamp-RAND>.md
└── technical/
    ├── index.md          ← technical doc register
    └── <timestamp-RAND>.md

Note IDs use a Zettelkasten format: <unix-timestamp>-<4-char-random>. This ensures:

  • Global uniqueness (no sequential collision)
  • Stable links even if notes are renamed (links use the ID, not the title)
  • Temporal ordering without a database

Frontmatter schema:

---
id: 1775595191-7MZ8
title: Human Readable Title
aliases:
  - Human Readable Title
tags:
  - adr # or: technical
---

Cross-note links use Obsidian wikilink syntax: [[id|Display Text]].

Consequences

Positive

  • Docs live in the repository — every doc change is a commit; history and blame work normally
  • Obsidian renders the vault as a graph; engineers can explore ADR → technical doc connections visually
  • Quartz can publish the vault to GitHub Pages with quartz build — no separate CMS account
  • Zettelkasten IDs mean notes can be renamed without breaking links
  • Markdown with YAML frontmatter is plain text — any editor works; Obsidian is optional

Negative / Risks

  • Quartz requires a Node.js build step for publishing (not Bun-native)
  • Obsidian is a local desktop app — there is no web-based collaborative editing (unlike Notion/Confluence)
  • The ID generation step (date +%s + random) is manual; there is no tooling to enforce uniqueness in CI
  • [[wikilinks]] do not resolve in standard Markdown renderers (GitHub, VS Code preview) — links appear as plain text outside Obsidian/Quartz