All notable changes to this project will be documented in this file.
Format follows Keep a Changelog. This
project adheres to a pre-1.0 cadence: minor bumps are breaking/notable, patch
bumps are additive or fixes. Dates are in YYYY-MM-DD.
Nothing yet.
First tagged release post-MVP. The pipeline is end-to-end production-quality on the default MiniMax M2.7 model, with real image attachment gated by CLIP + alt-quality + vision-LLM rerank.
- PDF export via
scripts/mkpdf.mjs(Chromium headless print-to-PDF) — weasyprint's CJK output was garbled on macOS Preview, Chromium's Type 3 font embedding is cross-reader stable. Remote images are downloaded intoout/_pdf_assets/first so the PDF is offline-reproducible. - CLIP warm-up (#26) —
warmClipModelfire-and-forget fromrunTopic2md/regenSectionentry; cuts cold-start from ~114s to ~1.4s when the Replicate container is still warm from a prior run. - Persistent image embeddings (#27) —
image_embeddings(url, model_version, embedding BLOB)table in SQLite caches jina-clip-v2 embeddings across runs. 100% cache-hit on regen of prior runs; ~$0.17/run → near-zero for recurring URLs. - Alt-quality penalty (#28) — soft multiplier on raw CLIP cosine for empty/generic alt, short alt, and CMS-dump upload-path URLs.
- CLIP relevance gate —
zsxkib/jina-clip-v2on Replicate, threshold 0.30 calibrated on 68 labeled candidates (AUC 0.85, recall 0.97, kills ~60% irrelevant).REPLICATE_API_TOKENoptional; absent ⇒ bypass. - Candidate pool + vision rerank — all image plugins contribute
candidates; qwen3-vl-32b picks one per section.
pickIndex = -1is respected — no keyword fallback when vision deliberately rejects. - Background context field (#24) —
WorkflowInput.background(freeform) threads through research → outline → sections. Persisted inruns.background. CLI--background/--background-file; Web UI via collapsible textarea.regenreuses the source run's background unless overridden. - SQLite persistence —
runs+run_stagestables record everyrunTopic2mdinvocation;topic2md list / show / regen --section N. - LLM model fallback chain with per-generation Langfuse telemetry
(
generation.*events). - Plugin
dispose?()lifecycle hook — runner calls infinallyto release Playwright browsers and DB handles.
generateObjectforced tomode: 'json'to avoid the malformed tool-call JSON path on OpenRouter-routed providers (MiniMax/GLM). Cut sections step from ~500s → ~60s.- Open-source hygiene overhaul:
CONTRIBUTING.md,SECURITY.md, GitHub issue / PR templates, full EnglishREADME.en.md.
- Outline retries once on first-attempt failure before giving up.
- Section two-retry failure now renders outline bullets as a bullet-list fallback rather than leaving the section empty.
regenrunId parsing accepts nanoids that start with-/_(previously filtered by!arg.startsWith('-')).- Docker image copies the full workspace + installs
build-essentialsobetter-sqlite3can build from source on unusual glibc/node combos. DATABASE_URLanchored viaimport.meta.urlso Web UI and CLI share one run history regardless of cwd.
Initial MVP. Mastra workflow skeleton, Tavily source, file publish, Playwright screenshot, Next.js trigger UI. Single model, no persistence, no regeneration. Historical record only; not tagged.