What gets published

The site is Quartz v4.1.0, built from the vault, served at garden.gillchristian.xyz. The vault is the content root, so a change to a note is a change to the website.

Silence publishes

quartz/plugins/filters/explicit.ts:

const publishFlag: boolean = vfile.data?.frontmatter?.publish ?? true
return publishFlag

A note with no publish key goes live. This is the single most important fact about this repository.

Every note an agent creates must carry an explicit publish: key. Default to publish: false; ask before setting true.

Only a bare false hides a note

quartz/plugins/transformers/frontmatter.ts parses with yaml.load(s, { schema: yaml.JSON_SCHEMA }). JSON_SCHEMA resolves only the exact lowercase token false to a boolean. Everything below is a truthy string, and the note publishes:

WrittenParses asResult
publish: falseboolean falseprivate
publish: "false"stringPUBLIC
publish: nostringPUBLIC
publish: False / FALSEstringPUBLIC

Write the key with obsidian property:set name="publish" value="false" type="checkbox"type=checkbox produces a real unquoted boolean. Verified 2026-08-18.

The key is publish. Quartz ignores published.

ignorePatterns matches the root-relative path

quartz.config.ts ignores Inbox, Templates and Organization. Claude/ is deliberately not ignored — this KB is published. The pattern matches the path from the vault root, not the basename — so Inbox protects only the top-level Inbox/. A note at Notes/Inbox-ideas.md would publish. No such path exists today; the guard is fragile rather than broken.

The dot-entries in that list (.obsidian, .trash, …) are redundant: the glob runs with dot: false.

The Assets hole

quartz/plugins/emitters/assets.ts globs ** minus **/*.md minus ignorePatterns, and copies every match to the output. It never calls shouldPublish. The filter in quartz/processors/filter.ts runs on markdown content only.

Two consequences:

  1. Every file in static/ publishes, regardless of which note embeds it. A note being private does not make its attachments private.
  2. Any non-markdown file publishes verbatim.bak, .csv, .txt, .pdf, .canvas. Two stale .md.bak files were removed on 2026-08-18 for this reason.

The audit script reports the current state of both. Read its output rather than recording an inventory here — see the note on exposure in index.md.

Never write a non-markdown file into the vault. Scratch files go outside digital-garden/. This matters for any tool that generates a CSV or a report.

Fixing the mechanism means patching assets.ts to consult the same filter. Not done — the current state was reviewed on 2026-08-18 and accepted.

Auditing

python3 .claude/skills/garden-publish-check/scripts/publish_audit.py
python3 .claude/skills/garden-publish-check/scripts/publish_audit.py --staged

The script replicates the real pipeline (glob → ignorePatterns → RemoveDrafts → ExplicitPublish) plus the unfiltered Assets emitter. It exits 1 on a high-severity finding, so it can gate a push. Run it rather than trusting any count written here.

After the 2026-08-18 frontmatter cleanup every publishable note carries an explicit publish key, so “public by default” should read 0. If it ever rises above 0, new notes were created without one.

A push is a deploy

Vercel builds from master. There is no deploy definition in the repo, and .github/workflows/ci.yaml is upstream Quartz CI, double-gated by if: github.repository == 'jackyzha0/quartz' and branch v4, so it never runs on this fork. vercel.json is only {"cleanUrls": true}.

Treat every push to master as a publish event. Run the audit first.

Dataview does not render

Quartz has no Dataview. A published note whose body is a Dataview query ships as a raw code block. Books/Designing Data-Intensive Applications/00 …md is the known case: its whole body is a query, which leaves its chapter notes unreachable from the site.