Static personal website (HTML/CSS/JS) with:
- Generated article and project pages from markdown content
- Native async workbench powered by an OpenRouter backend proxy (Cloudflare Worker)
- Consented handoff/feedback packets for visitors who want to leave reusable context
- Static site: root pages (
index.html,about.html,projects.html,articles.html) - Markdown source of truth:
content/posts/*.mdcontent/projects/*.md
- Prompt template:
prompts/default_system.txt - Generator:
scripts/generate_static_articles.py- builds
articles/**andprojects/** - updates
articles.htmlandprojects.html - builds chat context file:
assets/data/chat-context.json
- builds
- Frontend chat client:
assets/js/site.js(guided chat, source cards, packet builder) - OpenRouter proxy:
workers/openrouter-chat-proxy/(Cloudflare Worker)
Generated pages support:
- Headings, paragraphs, lists, blockquotes, code fences
- Callouts (
> [!note],> [!warning], etc.) - Links and images
- Tables (pipe-table markdown)
- Wikilinks across docs (for example
[[post-q&a]]) - Project iframe shortcode:
{{< iframe src="https://example.com/live-demo" title="Live demo" height="860" >}}- Generate static pages from markdown:
python3 scripts/generate_static_articles.py
- Serve the repo root with a local static server:
python3 -m http.server 8000
- Open:
http://localhost:8000/http://localhost:8000/articles.htmlhttp://localhost:8000/projects.html
- Edit markdown in
content/**and prompt text inprompts/default_system.txt. - Re-run:
python3 scripts/generate_static_articles.py
- Refresh the browser.
- Commit both source and generated files:
content/**prompts/default_system.txtarticles/**,projects/**,articles.html,projects.htmlassets/data/chat-context.json
- The homepage chat defaults to
/chat, which is not provided bypython3 -m http.server. - To use chat locally, pass a live Worker endpoint in the URL:
http://localhost:8000/?chat_api=https://YOUR-WORKER.workers.dev/chat
From workers/openrouter-chat-proxy/:
npx wrangler secret put OPENROUTER_API_KEY
npx wrangler deployOptional vars/bindings in wrangler.toml:
OPENROUTER_MODELOPENROUTER_SITE_TITLEPUBLIC_SITE_URLALLOWED_ORIGINS(comma-separated)CHAT_CONTEXT_URLTURNSTILE_SECRET_KEYsecret for server-side challenge verificationRATE_LIMIT_KVbinding for per-IP hourly capsFEEDBACK_KVbinding for consented handoff packet storageFEEDBACK_WEBHOOK_URLsecret/var for forwarding consented packets
Set data-chat-endpoint in index.html:
<div data-chat-endpoint="https://YOUR-WORKER.workers.dev/chat"></div>Set data-feedback-endpoint to the same Worker with /feedback when packet
submission should be enabled:
<div data-feedback-endpoint="https://YOUR-WORKER.workers.dev/feedback"></div>Or override at runtime with:
?chat_api=https://YOUR-WORKER.workers.dev/chat
- Push repository to GitHub.
- In Settings -> Pages:
- Source:
Deploy from a branch - Branch:
main - Folder:
/ (root)
- Source:
Workflow .github/workflows/generate-static-articles.yml regenerates static pages and chat context on pushes to:
content/**prompts/**scripts/generate_static_articles.py