Deploy the knowledge base
Publishes this vault to https://knowledge.villamarket.ai.
cd ~/stacks/villa-knowledge-base
AWS_PROFILE=villaai ./infra/publish.shThat builds with Quartz, mirrors pages into directory form, syncs to S3 and waits on a CloudFront invalidation. Takes about a minute.
Resources (villaai / 914499832220)
| Value | |
|---|---|
| Bucket | villa-knowledge-base-914499832220 (ap-southeast-1, private) |
| CloudFront | E3Q9JXUDOEHPYB → doy633tttpsgg.cloudfront.net |
| Certificate | us-east-1 ACM for knowledge.villamarket.ai |
| DNS | A + AAAA alias in zone Z069245539VG1ZOH980UK |
| Origin access | OAC E1YFMIXFTV8946; bucket policy allows only this distribution |
| URL rewrite | CloudFront function villa-kb-pretty-urls (viewer-request) |
The bucket blocks all public access. CloudFront reads it through Origin Access Control, so the S3 URL is not browsable directly — that is intended.
Why pages are uploaded twice
Quartz emits flat files (systems/calculatecost2.html) but links to them without the extension (/systems/calculatecost2). S3 only answers for exact keys, so an extensionless request 404s.
The CloudFront function rewrites any extensionless path to …/index.html, and publish.sh mirrors each page into that directory form. Both halves are required — change one and every sub-page 404s.
Paths that still contain a dot in the last segment (.css, .js, .webp) pass through untouched.
Adding content
Add a markdown file under the right folder in content/ with the frontmatter described in AGENTS.md, then run the publish script. No registration step — Quartz discovers files, and the folder listings, tag pages, graph and search index all rebuild.
Before publishing, check that every wikilink resolves. A typo renders as plain text rather than erroring:
python3 - <<'PY'
import re, pathlib
notes = {p.stem for p in pathlib.Path('content').rglob('*.md')}
for p in pathlib.Path('content').rglob('*.md'):
for m in re.finditer(r'\[\[([^\]|#]+)', p.read_text()):
if m.group(1).strip() not in notes:
print('broken:', m.group(1).strip(), '<-', p)
PYLocal preview
npx quartz build --serve # http://localhost:8080Not yet automated
Deployment is manual on purpose for now — wiring GitHub Actions needs an OIDC role in the villaai account, and a workflow that fails on every push for want of credentials is worse than no workflow. When someone adds that role, infra/publish.sh is the only command the job needs to run.