Skip to content

p4sttt/notegen

Repository files navigation

notegen

Static notes site generated from a private Obsidian vault.

What It Does

  • imports topics from vault directories that contain _index.md
  • imports note pages from markdown files inside each topic directory
  • imports Jupyter notebooks (.ipynb) as note pages
  • imports CSV files (.csv) as interactive database pages
  • copies relative assets from ./assets/...
  • builds a static Astro site with light/dark themes
  • renders LaTeX via KaTeX
  • deploys to GitHub Pages through GitHub Actions
  • rebuilds automatically when the private vault repository updates

Repository Structure

src/
  content/
    notes/        generated note markdown
    topics/       generated topic markdown
  data/generated/ generated topic metadata
  pages/          Astro routes
scripts/
  sync-vault.mjs  imports vault content into the site
  sync-vault/     sync implementation modules
.github/workflows/
  deploy.yml      build and deploy workflow

Vault Sync Modules

scripts/sync-vault.mjs is the CLI entrypoint and orchestration layer. The implementation details live in scripts/sync-vault/:

  • env.mjs reads values from .env
  • ignore-rules.mjs parses .notegenignore and checks ignored paths
  • markdown.mjs parses frontmatter and prepares Markdown summaries/content
  • notebooks.mjs converts Jupyter notebooks into Markdown and output assets
  • csv.mjs parses CSV files and infers database column types
  • assets.mjs copies local assets and rewrites Markdown/HTML asset links
  • changelog.mjs parses changelog events and renders generated changelog data
  • vault-files.mjs walks the vault and resolves topic ancestry
  • site-config.mjs reads vault-level notegen.config.json
  • paths.mjs normalizes site paths, slugs, and generated content filenames
  • fs-utils.mjs contains small filesystem helpers shared by sync modules
  • data-file.mjs renders src/data/generated/topics.ts

Local Development

1. Install dependencies

npm install

2. Create .env

VAULT_PATH=./vault

VAULT_PATH should point to a local checkout or fixture copy of your Obsidian vault.

3. Sync the vault

npm run sync:vault

4. Start the dev server

npm run dev

Vault Format

Each topic is a directory in the vault:

vault/
  database.csv
  optimization_methods/
    _index.md
    karush_kuhn-tucker.md
    papers.csv
    assets/
      image.png

Expected conventions:

  • a topic directory must contain _index.md
  • _index.md may contain frontmatter such as title, slug, draft, description
  • note files may be Markdown (.md) or Jupyter notebooks (.ipynb)
  • Markdown note files may contain frontmatter such as title, slug, date, status, tags
  • tags should be an array of strings: tags: ["ai", "nlp"]. Tags are color-coded based on the site accent color.
  • CSV files (.csv) are imported as database pages; top-level CSV files appear on the home page, and CSV files inside a topic appear in that topic
  • note status values are draft, in-progress, or done; legacy draft: true maps to status: draft, and legacy draft: false maps to status: done
  • Jupyter notebooks are converted during npm run sync:vault: markdown cells become page Markdown, code cells become syntax-highlighted code blocks, and supported outputs are rendered as HTML, text blocks, or copied image assets
  • Jupyter notebooks may define note metadata through notebook.metadata.notegen or through YAML frontmatter in the first markdown cell
  • relative assets should be referenced like ![desc](./assets/file.png)

CSV database pages:

  • use the first row as column headers
  • support comma, semicolon, and tab delimiters
  • infer column types as text, number, date, or boolean
  • render boolean values as compact checked/unchecked controls
  • include search, per-column filters, column sorting, column visibility controls, and visible-row counts
  • use the filename as the database title and slug

CSV example:

title;year;read
Attention Is All You Need;2017;true
Scaling Laws;2020;false

Notebook metadata example:

{
  "metadata": {
    "notegen": {
      "title": "Notebook Page Title",
      "slug": "notebook-page",
      "description": "Short page description.",
      "date": "2026-05-14",
      "status": "in-progress"
    }
  }
}

Equivalent first markdown cell:

---
title: "Notebook Page Title"
slug: "notebook-page"
description: "Short page description."
date: "2026-05-14"
status: "in-progress"
---

# Notebook content starts here

If both are present, first-cell frontmatter overrides notebook.metadata.notegen. If neither defines title, notegen uses the first # Heading in a markdown cell, then falls back to the filename.

Site Configuration

Each notes repository can override frontend text by adding notegen.config.json to the vault root:

{
  "changelogPath": "changelog.json",
  "siteText": {
    "ru": {
      "brand": "Статьи pig-ai",
      "heroTitle": "Статьи pig-ai",
      "metaDescription": "Статьи и заметки pig-ai.",
      "heroBody": "Материалы, заметки и длинные тексты."
    },
    "en": {
      "brand": "pig-ai articles",
      "heroTitle": "pig-ai articles",
      "metaDescription": "pig-ai articles and notes.",
      "heroBody": "Articles, notes, and long-form writing."
    }
  }
}

changelogPath is optional and defaults to changelog.json in the vault root. Relative paths are resolved from the vault root.

Top-level siteText fields apply to every locale. Locale-specific ru and en fields override those values.

Supported text fields:

  • metaDescription
  • brand
  • heroEyebrow
  • heroTitle
  • heroBody
  • heroTag

By default the build reads $VAULT_PATH/notegen.config.json. Use SITE_CONFIG_PATH to point to another config file.

Ignoring Vault Files

Add .notegenignore to the vault root to skip files and directories during import:

# Do not import repository docs as notes
README.md

# Ignore any directory with this name
drafts/

# Ignore a path from the vault root
private/meeting-notes.md

# Ignore copied note assets
raw/
*.tmp

Rules are matched relative to the vault root. Directory rules ending with / skip the directory and everything inside it. * matches inside one path segment. Negated rules with ! are not supported.

CI/CD

notegen uses GitHub Actions for build and deploy:

  • the vault repository sends repository_dispatch with event vault-updated
  • this repository checks out the private vault repo during CI
  • npm run sync:vault generates site content
  • Astro builds the static output
  • GitHub Pages publishes dist/

Required repository configuration

In notegen:

  • Action secret: VAULT_READ_TOKEN
  • Action variable: VAULT_REPO_URL

In the vault repository:

  • Action secret: NOTEGEN_DISPATCH_TOKEN
  • Action variable: NOTEGEN_REPO_URL

Pages setting in notegen:

  • Settings -> Pages -> Source -> GitHub Actions

Docker

The Docker image builds the static site from a mounted vault repository.

Published image

Pushes to main and version tags publish the frontend image to GitHub Container Registry:

ghcr.io/<github-owner>/notegen:latest
ghcr.io/<github-owner>/notegen:v0.1.0
ghcr.io/<github-owner>/notegen:sha-<commit>

To use this image from GitLab or another external CI, make the GHCR package public in GitHub:

GitHub -> Packages -> notegen -> Package settings -> Change visibility -> Public

Build the image

docker build -t notegen .

Build a site locally

docker run --rm \
  -v "$PWD/vault:/vault:ro" \
  -v "$PWD/dist:/out" \
  -e ASTRO_SITE="https://example.github.io" \
  -e ASTRO_BASE="/notegen" \
  notegen

Container contract:

  • /vault is the mounted notes repository
  • /out receives the generated static site
  • VAULT_PATH defaults to /vault
  • OUT_DIR defaults to /out
  • ASTRO_SITE and ASTRO_BASE override Astro site and base
  • SITE_CONFIG_PATH can point to a custom site config JSON file

Example GitHub Actions usage from a notes repository

name: Build notes site

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout notes
        uses: actions/checkout@v4
        with:
          path: vault

      - name: Checkout notegen
        uses: actions/checkout@v4
        with:
          repository: owner/notegen
          path: notegen

      - name: Build notegen image
        run: docker build -t notegen ./notegen

      - name: Build static site
        run: |
          mkdir -p site
          docker run --rm \
            -v "$PWD/vault:/vault:ro" \
            -v "$PWD/site:/out" \
            -e ASTRO_SITE="https://${{ github.repository_owner }}.github.io" \
            -e ASTRO_BASE="/${{ github.event.repository.name }}" \
            ghcr.io/owner/notegen:latest

      - name: Upload Pages artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: site

Notes

  • generated vault content is ignored by git
  • local vault/ and .env are ignored by git
  • current feature status lives in FEATURES.md

Changelog

During npm run sync:vault, notegen reads the changelog file from the vault root and generates a /changelog page. The default file is:

vault/changelog.json

Override it in notegen.config.json:

{
  "changelogPath": ".notegen/changelog.jsonl"
}

The parser accepts either a JSON array:

[
  {
    "timestamp": "2026-05-06T22:40:00Z",
    "action": "updated",
    "kind": "note",
    "path": "topic/note.md",
    "title": "Topic Note",
    "topic": "Topic",
    "source": "pre-commit"
  }
]

Or JSON Lines, one event per line:

{"timestamp":"2026-05-06T22:40:00Z","action":"created","kind":"note","path":"topic/note.md","title":"Topic Note","source":"pre-commit"}
{"timestamp":"2026-05-06T22:43:00Z","action":"renamed","kind":"note","oldPath":"topic/old.md","path":"topic/new.md","title":"New Topic Note","source":"pre-commit"}

Event fields:

  • timestamp: ISO date string, for example 2026-05-06T22:40:00Z
  • action: created, updated, deleted, renamed; unknown values become changed
  • kind: note, topic, database, asset; unknown or missing values become other
  • path: current path relative to the vault root
  • oldPath: previous path for renamed files
  • title: optional display title; if omitted, notegen tries to use the current generated note or topic title
  • topic: optional display topic
  • source: optional source label such as pre-commit

About

Automatic html page generator based on summaries and notes from obsidian files in markdown format

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors