From david-skills
Publishes Obsidian markdown wikis as searchable static sites using Quartz v4 to Cloudflare Pages with mandatory privacy confirmation and access controls.
npx claudepluginhub thedavidweng/skillsThis skill uses the workspace's default tool permissions.
Publish a personal knowledge wiki as a fast, searchable static site using [Quartz 4](https://quartz.jzhao.xyz/). Deployed to Cloudflare Pages with identity-aware access control.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Processes PDFs: extracts text/tables/images, merges/splits/rotates pages, adds watermarks, creates/fills forms, encrypts/decrypts, OCRs scans. Activates on PDF mentions or output requests.
Share bugs, ideas, or general feedback.
Publish a personal knowledge wiki as a fast, searchable static site using Quartz 4. Deployed to Cloudflare Pages with identity-aware access control.
Privacy is not optional. This skill enforces a mandatory confirmation workflow before any deployment.
Before doing ANYTHING related to publishing, the agent MUST:
Explain the risks in plain language:
Present protection options:
Get explicit confirmation:
Do not skip this step. Do not assume the user understands. Do not proceed without a clear answer.
*.pages.dev subdomain works too)Two-repo model separates content from site:
content-repo/ # Your wiki vault (private)
wiki/ # Compiled knowledge pages
system/ # Rules and indexes
.github/workflows/
publish-site.yml # Triggers site build on wiki changes
site-repo/ # Quartz site (can be private)
quartz.config.ts # Quartz configuration
scripts/sync-content.mjs # Pulls wiki, injects titles, builds homepage
.github/workflows/
deploy.yml # Sync → Build → Deploy
# Option A: Fork jackyzha0/quartz on GitHub, then clone your fork
git clone https://github.com/YOU/quartz.git your-wiki-site
cd your-wiki-site
# Option B: Clone and remove upstream remote
git clone https://github.com/jackyzha0/quartz.git your-wiki-site
cd your-wiki-site
git remote remove origin
git remote add origin https://github.com/YOU/your-wiki-site.git
Key settings:
pageTitle: Your wiki namebaseUrl: Your Cloudflare Pages domainignorePatterns: ["private", "templates", ".obsidian", "inbox", "sources"]analytics: null, enableRSS: false (privacy)filters: [Plugin.ExplicitPublish()] — only pages with publish: true are built(See references/quartz-config.ts for full example)
The Plugin.ExplicitPublish() filter means only pages with publish: true in frontmatter are published. This is your safety net.
---
layer: wiki
kind: person
publish: true # Only this page goes to the site
---
Never add publish: true to pages with sensitive information.
Create scripts/sync-content.mjs that:
wiki/ pages (not sources/, not inbox/)title: into frontmatter from H1 headingsconst SAFE_KINDS = ["person", "project", "place", "concept", "topic", "map", "period"]
const STRIP_FIELDS = ["phone", "email", "address", "id_number", "passport", "ssn"]
function sanitizeFrontmatter(fm) {
// Remove sensitive fields before publishing
for (const field of STRIP_FIELDS) {
delete fm[field]
}
return fm
}
function shouldPublish(filePath, frontmatter) {
// Only publish if explicitly marked
if (frontmatter.publish !== true) return false
// Only publish safe kinds
if (!SAFE_KINDS.includes(frontmatter.kind)) return false
return true
}
Build an index.md that links to all published sections:
---
title: Your Wiki
---
# Your Wiki
A personal knowledge base.
## Sections
- [[people/|People]] (42)
- [[projects/|Projects]] (12)
- [[places/|Places]] (8)
- [[concepts/|Concepts]] (15)
Two workflows:
Content repo (.github/workflows/publish-site.yml):
On push to wiki/ or system/, dispatch repository_dispatch event to site repo.
Site repo (.github/workflows/deploy.yml):
On repository_dispatch or push: checkout content → run sync-content.mjs → npx quartz build → wrangler pages deploy.
(See references/deploy.yml for full workflow files)
.github/workflows/publish-site.yml):name: Publish Quartz Site
on:
push:
branches: [main]
paths: ["wiki/**", "system/**"]
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Dispatch site build
env:
GH_TOKEN: ${{ secrets.SITE_REPO_DISPATCH_TOKEN }}
run: |
jq -n \
--arg repo "${{ github.repository }}" \
--arg sha "${{ github.sha }}" \
'{event_type: "content-updated", client_payload: {content_repo: $repo, content_sha: $sha}}' \
> dispatch.json
gh api repos/YOU/your-wiki-site/dispatches \
--method POST --input dispatch.json
.github/workflows/deploy.yml):name: Deploy Quartz Site
on:
repository_dispatch:
types: [content-updated]
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Checkout content
uses: actions/checkout@v4
with:
repository: ${{ github.event.client_payload.content_repo || 'YOUR_USERNAME/your-wiki' }}
ref: ${{ github.event.client_payload.content_sha || 'main' }}
token: ${{ secrets.CONTENT_REPO_READ_TOKEN }}
path: external/content
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: node scripts/sync-content.mjs --source external/content --target content
- name: Build Quartz
env:
QUARTZ_BASE_URL: ${{ vars.QUARTZ_BASE_URL }}
run: npx quartz build
- name: Deploy to Cloudflare Pages
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_PAGES_API_TOKEN }}
run: |
npx wrangler pages deploy public \
--project-name "${{ vars.CLOUDFLARE_PAGES_PROJECT }}"
After the site is deployed, enable Cloudflare Access:
your-wiki.pages.dev)@yourdomain.com OR specific email addressesFor stronger control:
After deployment:
site:your-wiki.pages.dev. There should be zero results (Access blocks crawlers).publish: true contain phone numbers, addresses, or ID numbers.Before going live:
publish: true only on safe pagessources/ and inbox/ excluded from syncnoindex meta tag)publish: true on sensitive pages. Always review the diff before pushing.sync-content.mjs must never copy sources/ or inbox/.[[slug]] differently than Obsidian. Test all links after build.After setup, present: domain, protection method, content source, ExplicitPublish status, published section counts, sensitive content exclusions, and next steps (review publish: true pages, test incognito, share allowed emails).