---
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 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.
