Getting started (development)
How to set up, build, run, and iterate on ZettelFlow.
Prerequisites
- Node.js (CI uses Node 23; any recent LTS ≥ 18 works locally).
- npm (the repo ships a lockfile-friendly
package.json). - An Obsidian vault for testing. The plugin targets
minAppVersion 1.4.11. - (Optional) Docker + Docker Compose for the community backend (
backend/).
Install
npm install
Husky installs git hooks on npm install (via the prepare script): a pre-commit hook
runs npm run lint, and a commit-msg hook enforces Conventional Commits.
Build & watch
| Task | Command | What it does |
|---|---|---|
| Dev build + watch | npm run dev |
node esbuild.config.mjs — inline sourcemaps, no minify, watches src/** (JS) and src/styles/** (SCSS). Stays running. |
| Production build | npm run release |
tsc -noEmit -skipLibCheck (type-check gate) then node esbuild.config.mjs production — minified one-shot build to dist/. |
| Lint | npm run lint / npm run lint:fix |
oxlint ./src (also runs on pre-commit). |
| Test | npm test |
jest — ⚠️ no tests or jest config exist yet (see Project health). |
Build outputs (dist/main.js, dist/styles.css) are git-ignored.
Loading the dev build into Obsidian
esbuild writes to dist/, but Obsidian loads a plugin from
<vault>/.obsidian/plugins/zettelflow/ and expects main.js, manifest.json, styles.css
at the plugin root. Two common approaches:
- Symlink the vault plugin folder to this repo and adjust the esbuild
outfileto emit at the repo root (or symlinkdist/main.js,manifest.json,dist/styles.cssinto the plugin folder). - Develop directly inside a test vault: clone the repo into
<vault>/.obsidian/plugins/zettelflow/, runnpm run dev, and point the esbuildoutfileat the root.
Then enable the plugin in Obsidian and use Reload app (or a hot-reload plugin) after builds.
The current
esbuild.config.mjsemits todist/. If you want the output at the repo root for a symlinked vault, changeoutfile: "dist/main.js"→"main.js"andoutfile: "dist/styles.css"→"styles.css"locally (don't commit that change unless the release workflow is updated to match).
Project layout & import aliases
See Architecture overview for the full src/ map. The important
thing for day-to-day work: tsconfig.json sets baseUrl: "src", so you import top-level
folders as bare specifiers (import { log } from "architecture",
import { DEFAULT_SETTINGS } from "config"), and esbuild resolves them the same way. There is no
paths map to maintain.
Running the community backend (optional)
# from repo root, with a .env providing MONGO_INITDB_ROOT_USERNAME / _PASSWORD / _DATABASE
docker compose up --build
This starts MongoDB (:27017) and the FastAPI app (:8000, hot-reload). Point the plugin at it
via Settings → Developer → community URL (default http://127.0.0.1:8000) and set a token to
switch the community browser to the dynamic source. See
Community & backend.
Building the docs site
The docs you are reading are MkDocs Material:
pip install -r docs/requirements.txt
mkdocs serve # live preview at http://127.0.0.1:8000
Pushing to main triggers .github/workflows/documentation.yml, which deploys the site to
GitHub Pages.
Working with the AI harness
This repo ships a Claude Code harness (CLAUDE.md + .claude/). It gives
an assistant the architecture map, conventions, and Obsidian-specific skills:
- Skill
obsidian-plugin-quality— audits the code against the Obsidian review/score. - Skill
new-action— scaffolds a new action (the 4-file pattern + registration). - Skill
release— the release checklist. - Agent
obsidian-plugin-reviewer— reviews a diff against the Obsidian guidelines.
See Contributing & conventions for how they fit the workflow.