This guide outlines a minimalist architecture for personal knowledge management. The goal is to keep all notes in a single private GitHub repository, maintain a distraction-free writing environment in Obsidian, and selectively publish a public digital garden using Quartz and Cloudflare Pages.

Phase 1: The “Master Container” Architecture

Instead of managing multiple Git repositories, this system uses a “master container” approach. Quartz acts as the site engine and contains the public vault, while private vaults sit safely in the root directory, ignored by the build process.

If you have already cloned Quartz and installed dependencies, you can use our automation script to achieve this structure instantly.

  1. Create a file named restructure.sh in your root directory.
  2. Copy the content below into this file:
#!/bin/bash
 
# Quartz Master-Container Restructure Script
# Run this from the root of a fresh Quartz clone
 
set -e
 
echo "🚀 Starting Quartz restructuring..."
 
# 1. Setup directories
mkdir -p quartz
mkdir -p private
 
# 2. Move root files into quartz/
# We explicitly move common Quartz files and anything not in our ignore list
for item in * .node-version .npmrc .prettierignore .prettierrc Dockerfile globals.d.ts index.d.ts tsconfig.json; do
  if [[ "$item" != "quartz" && "$item" != "private" && "$item" != "restructure.sh" && "$item" != "node_modules" && "$item" != ".git" && -e "$item" ]]; then
    mv "$item" quartz/
    echo "  Moved $item to quartz/"
  fi
done
 
# 3. Helper function for portable sed replacement
patch_file() {
    local file="quartz/\$1"
    local search="\$2"
    local replace="\$3"
    if [ -f "\$file" ]; then
        # Use a temporary file for maximum compatibility between BSD (macOS) and GNU (Linux) sed
        sed "s|\$search|\$replace|g" "\$file" > "\$file.tmp" && mv "\$file.tmp" "\$file"
    fi
}
 
echo "🔧 Patching configurations and imports..."
 
# Fix Imports in config and layout
patch_file "quartz.config.ts" "\./quartz/cfg" "./cfg"
patch_file "quartz.config.ts" "\./quartz/plugins" "./plugins"
patch_file "quartz.config.ts" "ignorePatterns: \[\"private\", \"templates\", \".obsidian\"\]" "ignorePatterns: [\"private\", \"templates\", \".obsidian\"]"
 
patch_file "quartz.layout.ts" "\./quartz/cfg" "./cfg"
patch_file "quartz.layout.ts" "\./quartz/components" "./components"
 
# Fix internal engine paths
patch_file "util/path.ts" "export const QUARTZ = \"quartz\"" "export const QUARTZ = \".\""
patch_file "processors/parse.ts" "\./quartz/worker.ts" "./worker.ts"
patch_file "processors/parse.ts" "\./quartz/bootstrap-worker.mjs" "./bootstrap-worker.mjs"
patch_file "build.ts" "\.\./quartz.config" "./quartz.config"
patch_file "worker.ts" "\.\./quartz.config" "./quartz.config"
patch_file "components/Footer.tsx" "\.\./\.\./package.json" "../package.json"
patch_file "cli/handlers.js" "\.\./\.\./\${cacheFile}" "../\${cacheFile}"
 
# Fix Constants
patch_file "cli/constants.js" "\./quartz/\.quartz-cache/transpiled-build.mjs" "./.quartz-cache/transpiled-build.mjs"
patch_file "cli/constants.js" "\./quartz/build.ts" "./build.ts"
patch_file "cli/constants.js" "QUARTZ_SOURCE_BRANCH = \"v4\"" "QUARTZ_SOURCE_BRANCH = \"main\""
 
# Update package.json scripts
patch_file "package.json" "./quartz/bootstrap-cli.mjs" "./bootstrap-cli.mjs"
# Add build script (simple line append for this specific setup)
if [ -f "quartz/package.json" ]; then
    sed 's|"docs":|"build": "npx quartz build -d ./content",\n    "docs":|' "quartz/package.json" > "quartz/package.json.tmp" && mv "quartz/package.json.tmp" "quartz/package.json"
fi
 
# 4. Fix Emitter imports (recursively find and replace)
if [ -d "quartz/plugins/emitters" ]; then
    find quartz/plugins/emitters -name "*.tsx" -type f -exec sed -i.bak 's|\.\./\.\./\.\./quartz.layout|../../quartz.layout|g' {} +
    find quartz/plugins/emitters -name "*.bak" -delete
fi
 
# 5. Migrate workflows
if [ -d "quartz/.github" ]; then
    mv quartz/.github .
    find .github/workflows -name "*.yaml" -type f -exec sed -i.bak 's/branches: \[v4\]/branches: [main]/g' {} +
    find .github/workflows -name "*.yaml" -type f -exec sed -i.bak 's/v4/main/g' {} +
    find .github/workflows -name "*.bak" -delete
fi
 
echo "✅ Restructuring complete!"
echo "👉 Next step: Open 'quartz/content/' and 'private/' as separate vaults in Obsidian."
  1. Run the script:
    bash restructure.sh

Manual Directory Structure

If you prefer to do it yourself, your target structure should look like this:

📁 my-obsidian-hub (Your Private Git Repository)

├── 📁 quartz/                 <- (Quartz engine & config - ignore in Obsidian)
│   ├── 📁 content/            <- 🟢 PUBLIC VAULT (Published by Quartz)
│   │   ├── 📄 index.md
│   │   └── 📁 .obsidian/      <- (Minimalist theme settings for public vault)
│   ├── 📄 quartz.config.ts
│   └── 📄 package.json

└── 📁 private/                <- 🔴 PRIVATE VAULT (Ignored by Quartz)
    ├── 📄 private-diary.md
    └── 📁 .obsidian/          <- (Minimalist theme settings for private vault)
  • quartz/content/: This is your Public Vault. Any Markdown files placed here will be published.
  • private/: A custom folder in the root directory. Quartz ignores it entirely by default, keeping it off the live website.

Phase 2: Obsidian for Beginners

If you are new to Obsidian, don’t worry! It is a powerful, local-first note-taking app that uses Markdown files.

1. Installation

Download and install Obsidian for your operating system from obsidian.md.

2. Understanding “Vaults”

In Obsidian, a Vault is simply a folder on your computer that contains your notes. This system uses a Dual-Vault setup:

  • One vault for your public notes (quartz/content/).
  • One vault for your private notes (private/).

3. Opening Your Vaults

To keep your environment clean, do not open the root project folder. Instead:

  1. Launch Obsidian.
  2. Click “Open folder as vault”.
  3. Navigate to your project and select the quartz/content/ folder.
  4. Repeat the process for the private/ folder.
  5. You can switch between these two vaults using the “Vault Switcher” icon (the vault icon at the bottom left).

4. Basic Writing

  • Markdown: Obsidian uses Markdown. Use # for headers, **bold** for bold, etc.
  • Links: Type [[ to create a link to another note. For example, [[index]] links to your homepage.

Phase 3: Obsidian Minimalism

Once you have your vaults open, we recommend these settings for a distraction-free writing experience.

1. Installing the Minimal Theme

  1. Open Settings (gear icon bottom left).
  2. Go to Appearance Themes Manage.
  3. Search for “Minimal” and click Install and Use.

2. Installing Community Plugins

By default, Obsidian is very safe and disables community plugins. You need to enable them:

  1. Go to Settings Community plugins.
  2. Click Turn on community plugins.
  3. Click Browse and install these three:
    • Minimal Theme Settings: To customize the look.
    • Style Settings: For advanced color/font tweaks.
    • Hider: To hide UI elements you don’t need.

3. Configuration

  • Focus Mode: In Settings Minimal Theme Settings, enable Focus Mode.
  • Hide UI: In Settings Hider, toggle off the app ribbon, status bar, and scrollbars.

Phase 4: Quartz Customization

To match the minimalist aesthetic of the local Obsidian vaults, we strip down the Quartz UI.

1. Typography (quartz.config.ts)

Set clean sans-serif fonts:

typography: {
  header: "Inter",
  body: "Inter",
  code: "Fira Code",
},

2. Stripping the UI (quartz.layout.ts)

Remove clutter like graph views and sidebars by updating the PageLayout:

export const defaultContentPageLayout: PageLayout = {
  beforeBody: [
    Component.Breadcrumbs(),
    Component.ArticleTitle(),
  ],
  left: [
    Component.PageTitle(),
    Component.MobileOnly(Component.Spacer()),
  ],
  right: [],
}

Phase 5: Deployment via Cloudflare Pages

Bypass GitHub Pages and connect your private repository to Cloudflare Pages for free hosting.

This is the simplest method:

  • Go to Cloudflare Dashboard Workers & Pages Create application Pages Connect to Git.
  • Select your repo and use these settings:
    • Build command: cd quartz && npm install && npm run build
    • Build output directory: quartz/public
    • Environment Variable: NODE_VERSION = 22.

2. Using GitHub Actions (Advanced)

If you prefer to use the included .github/workflows/deploy.yaml for CI/CD, you will need to add these two Secrets to your GitHub repository (Settings Secrets Actions):

  • CLOUDFLARE_ACCOUNT_ID: Found on the Cloudflare sidebar under Workers & Pages Overview.
  • Click the button “Create application” called digital-garden (You may use other names, but remember to update the deploy.yaml accordingly)
  • CLOUDFLARE_API_TOKEN:
    1. Go to My Profile API Tokens.
    2. Click Create Token Use the Edit Cloudflare Pages template.
    3. Ensure it has “Edit” permissions for your Pages project.
    4. Copy the Account id and token to your GitHub Secrets in your repo setting.

Syncing Changes

To save your latest notes (both public and private) and push them to GitHub, run standard git commands from the root directory. This ensures the entire “Master Container” structure is backed up:

git add .
git commit -m "Update notes"
git push origin main

Pushing to GitHub will automatically trigger Cloudflare to rebuild and publish your minimalist digital garden.