--- title: Obsidian as Personal Authoring Layer status: active audience: maintainer, contributor language: en last_updated: 2026-05-02 related: - docs/adr/README.md - scripts/generate-docs-index.mjs - .gitignore --- # Obsidian as Personal Authoring Layer Scrum4Me's documentation lives as plain Markdown under `docs/`. The canonical source of truth is the committed `.md` file — rendered on GitHub, read by agents (Claude Code, Codex) directly from the file system, and indexed by `scripts/generate-docs-index.mjs`. Note: the `mcp` server does **not** expose `docs/` content. Its 20 tools serve database state (products, sprints, stories, tasks, jobs, questions) via Prisma. Documentation reaches the agent only through the file-system tools, so the canonical Markdown is the one and only channel. Obsidian is **not** a second source of truth. It is a personal authoring layer that you can opt into without changing what the repo or the agent sees. This document records the conventions that keep both views consistent. ## Why an authoring layer at all A canonical `0003-job-claim-strategy.md` is short, declarative, and final. The thinking that produced it — alternatives weighed, links followed, half- ideas — is messy and personal. Forcing that into the committed file inflates ADRs and dilutes the signal future readers (human or agent) need. Obsidian gives you a place to keep the thinking next to the artefact without polluting it: graph view, backlinks, properties, scratch notes. The `.gitignore` rules below ensure none of that crosses the repo boundary. ## Vault setup Open the repo root as the vault, not just `docs/`. Reasons: - ADRs and patterns frequently reference code (`prisma/schema.prisma`, `lib/task-status.ts`). Markdown links from a `docs/`-only vault cannot resolve those targets; from a root vault they can. - The same vault then surfaces `README.md`, `CLAUDE.md`, and `AGENTS.md` as nodes in the graph — useful when reasoning about agent instructions. - Per-developer Obsidian config lives in `.obsidian/` at the vault root, which is already gitignored. ### Two repos, two vaults The MCP server lives in a separate repo (`mcp`) with its own `CLAUDE.md`, tools, and tests. Open it as a **separate** Obsidian vault when you work there. Each `.obsidian/` directory is per-folder and stays gitignored on both sides; cross-repo notes belong in whichever vault you opened first, not in some shared third location. Schema-related ADRs are an exception: the MCP server consumes the Scrum4Me Prisma schema via the `vendor/scrum4me/` git submodule, so the *decision* about the schema belongs in this repo's `docs/adr/`. The mirror in `mcp` only needs an `npm run sync-schema` after the ADR lands here, not its own ADR. ## Link style In Settings → Files & Links: - **Use [[Wikilinks]]** → off - **New link format** → Relative path to file - **Default location for new notes** → "Same folder as current file" Wikilinks would render as plain text on GitHub and are not parsed by the docs index generator. Stick to standard Markdown links (`./adr/0001-foo.md`) so the same file works in Obsidian, GitHub, and any agent reader. Obsidian still resolves Markdown links for backlinks and graph view, so you do not lose Obsidian's navigation features. ## Front-matter is Obsidian Properties `scripts/generate-docs-index.mjs` reads a small set of YAML front-matter keys: `title`, `status`, `date` (or `last_updated`). Obsidian renders the exact same YAML block as its Properties panel. Practical consequence: flipping a plan from `proposal` to `accepted` in the Obsidian Properties UI and then running `npm run docs:index` is a complete workflow — no separate metadata store, no plugin needed. The repo's front-matter is intentionally flat (no nested objects, no lists beyond simple arrays) to stay parseable by the dependency-free generator. When adding fields, keep them flat. ## Templates Two ADR templates ship in `docs/adr/templates/`: - `nygard.md` — default, for one-way-door decisions - `madr.md` — for decisions where rejected alternatives must be recorded Both use `{{curly braces}}` placeholders so they read naturally in any editor and so Codex and Claude Code can fill them mechanically. Two ways to use them from Obsidian: 1. **Core Templates plugin** (recommended starting point). Settings → Templates → Template folder location: `docs/adr/templates`. Then `Cmd-P → Insert template → nygard` inserts the body verbatim. Fill placeholders by hand. 2. **Templater** (community plugin). If filling the next ADR number and today's date by hand becomes a bottleneck, write a Templater wrapper in a vault-only `_templates/` folder that reads `nygard.md` and substitutes `<% tp.date.now("YYYY-MM-DD") %>` plus a computed next number. Keep this wrapper out of git — it is personal tooling, not part of the canonical convention. Do not modify the canonical templates to use Templater syntax. The placeholders must remain agent-readable. ## Sidecar files for personal notes `.gitignore` already excludes `_*.md` and the docs index generator mirrors that exclusion (`/\/_[^/]+\.md$/`). Use this for any file that should stay personal: - `docs/adr/_draft-0003-job-claim-strategy.md` — alternatives, doubts, links you considered before settling on the canonical ADR - `docs/plans/_questions-for-jp.md` — open questions you want to think about but not raise yet - `_scratch.md` anywhere in the tree Workflow for an ADR: 1. Brainstorm in `docs/adr/_draft-NNNN-…md` — free-form, link-heavy. 2. When the decision is clear, copy the relevant prose into the canonical `docs/adr/NNNN-…md`, applying the Nygard or MADR template. 3. Run `npm run docs:index`. 4. Commit only the canonical ADR (the sidecar is invisible to git). The sidecar can stay as a personal trail or be deleted — both are local- only choices. ## Plugin recommendations Useful and low-risk: - **Outline** (core) — table of contents per file - **Backlinks**, **Outgoing Links** (core) — see what links to and from the current document - **Linter** (community) — can enforce that ADRs have a `status` field in front-matter Use with care: - **Dataview** — tempting to replace `INDEX.md` with a Dataview query. Don't. The query renders blank on GitHub and is invisible to Claude Code. Use Dataview only in a sidecar (`_dashboard.md`) for personal views. Avoid as canonical source: - **Canvas**, **Excalidraw** — not diff-able, not agent-readable. Keep diagrams as committed SVG (`docs/assets/erd.svg`) or as Mermaid blocks inside Markdown. ## Index generator interaction `generate-docs-index.mjs` is the system of record for `docs/INDEX.md`. Two reliability concerns when authoring through Obsidian: - **Forgetting to regenerate the index.** If you create or rename a doc in Obsidian and commit without running the generator, INDEX.md goes stale. Mitigations: a `pre-commit` hook that runs `npm run docs:index` whenever staged changes touch `docs/**/*.md`, or a habit of running `npm run docs:index` before every `git add docs/`. - **Renaming and "update links" prompts.** Obsidian's "automatically update internal links" applies to wikilinks. Since this vault uses Markdown links, Obsidian will still try to update them — verify the diff before committing, especially for cross-folder renames. ## What Obsidian must not do - Introduce wikilinks into committed files - Add Obsidian-only blocks (callouts, embeds with `![[...]]`) into canonical docs - Replace `INDEX.md` with a Dataview view in the committed tree - Modify front-matter keys outside the documented set without also updating `generate-docs-index.mjs` If a workflow benefits the personal vault but breaks one of those rules, keep it in a `_*.md` sidecar. ## Summary Treat Obsidian like a notebook bound to the same desk as the repo: useful for thinking, never confused with what's published. The gitignore rules and the index generator already enforce most of this mechanically — these conventions cover the parts that still depend on the author's judgement.