Ship log
Changelog
What landed, and when. Each entry links back to the spec or blueprint that asked for it.
-
Stenographer's First Cut: a Link Goes In, a Transcript Comes Out
The spec sat in content-farm's context-v since May. It's a plugin now — paste a YouTube link, get a frontmattered note with a timestamped transcript, no server to stand up first.
-
Two bugs, one lesson: the citation format lived in four places at once
Dates came out backwards and citations glued themselves to quotation marks. Both bugs traced to the same thing — we'd written the format down in the spec, then written it down again in the code, four separate times.
-
The held-back majors land: TypeScript 6, ESLint 10, and a toolchain that tells the truth
Since May we deliberately parked TypeScript 6 and ESLint 10 as 'known open questions.' Today they landed — with the tsconfig migrated off deprecated options so the eventual TypeScript 7 jump is already paid for.
-
The whole plugin family gets current in one day — ten repos, three passes, every build green
A researched dependency campaign swept nine plugin modules plus the umbrella: TypeScript 6 and ESLint 10 everywhere, twenty-two dead dependencies removed, a GPL relicense dodged, two marketplace blockers fixed — and the umbrella's build went from 3,910 errors to zero.
-
Fifteen majors of googleapis, seven dead dependencies, one green build
file-transporter jumps googleapis 158 → 173 without touching a line of code, sheds seven never-imported dependencies, and lands the TypeScript 6 / ESLint 10 toolchain.
-
The starter template cleans itself — so every future plugin starts clean
filestarter is where new Lossless plugins are born, which means it's also where the dead fastify/MCP/zod dependencies kept being born. Purged at the source, with the toolchain bumped to TypeScript 6 + ESLint 10.
-
Toolchain current: ESLint 10.7, obsidianmd rules 0.4, and types that match Obsidian's actual runtime
Image-gin's dev toolchain catches up in one pass — and Obsidian's own upgraded lint ruleset immediately starts earning its keep by pointing at the new declarative settings API.
-
Image Wrangler gets road-legal: real semver, a live branch, and a clean modern toolchain
The youngest plugin in the family was sitting on a detached HEAD with a 4-digit version Obsidian's marketplace would reject. One pass later: valid manifest, TypeScript 6, ESLint 10, zero dead dependencies — and its first changelog.
-
Four dead dependencies removed, zero left — lmstud-yo slims to a pure Obsidian plugin
fastify, the MCP SDK, zod, and a mystery package literally named 'dev' were riding along from the starter template with zero imports. All gone, along with the Dependabot noise they generate. Toolchain bumped to TypeScript 6 + ESLint 10 in the same pass.
-
Metafetch drops its last runtime dependency — and dodges a GPL relicense doing it
typed.js quietly went GPL-3.0 in v3. Instead of freezing on the old version, we rebuilt the typing animation in ~100 lines of our own TypeScript — and the plugin bundle shrank 18%.
-
23 versions of Anthropic SDK in one hop — and the branch tiers snap back into line
Perplexed jumps @anthropic-ai/sdk 0.92 → 0.115 without a single code change, picks up Obsidian's 0.4 lint ruleset, and development catches up to the 0.3.0 release that had run ahead of it.
-
Nine majors of marked, crossed with one line — plus TypeScript 6 and ESLint 10
plunk-it's markdown-to-email pipeline rode marked from v9 to v18 — a span that rewrote the library's renderer API twice — and our code needed exactly one line changed. Minimal API surface pays off.
-
CORS block fixed — Perplexity streaming now routes through Node.js and never touches Chromium's CORS enforcement
Perplexity streaming stopped working when Perplexity's API began enforcing CORS headers that block requests originating from app://obsidian.md. Both streaming call sites — the modal query flow and the directory-template batch runner — were using activeWindow.fetch, which runs in Electron's Chromium renderer and is fully CORS-constrained. Both are now replaced with Node.js https.request, which routes through the OS network stack and is never subject to CORS enforcement.
-
Two analyst-grade templates land — spec profiles and market-category profiles — plus two quiet bugs the testing pass caught
Perplexed now ships templates for profiling open specs (with five-way authority typing and three-tier adoption) and named market categories (with explicit financial-stage tiers for incumbents, challengers, and innovators). The third shipped thing was a max_tokens override we built after diagnosing why the first real spec profile stopped halfway through with no warning at all. The fourth was a rendering-discipline upgrade — strengthened mermaid rules plus new LaTeX rules — after diagnosing that the vault's concept-profile template had drifted from the bundled source and was generating diagrams with no rendering rules in scope at all.
-
Market-map analyst template + the per-template timeout override the long deep-research it needs surfaced as load-bearing
A fifth shipped directory template aimed at analyst-grade market maps (Known Category and Thesis-Driven flavors) — the kind of document a partner pays a $150K analyst three days to produce.
-
Long deep-research streams no longer get cut off at the ceiling — the timer now resets every time bytes arrive
The per-chunk idle-timeout discipline the legacy modal flow has used for two iterations now governs the directory-template flow too. A healthy slow stream completes naturally; a silently-stalled one fails in seconds instead of minutes.
-
From buildable to actually-works-in-vault — the Gemini provider's first day in Obsidian
The Gemini provider shipped yesterday as TypeScript that compiled. Today it became TypeScript that runs cleanly inside Obsidian: CORS-blocked fetch swapped for Obsidian's requestUrl (with bonus page-title + canonical-URL parsing), API-key auth moved from query string to header, default model switched to `gemini-flash-latest` so the free tier doesn't wall the first request, the modal got real CSS, the template seeder stopped crashing on its own previously-written files, network drops mid-stream now surface as plain-English notices instead of stack traces, three system-prompt textareas grew from 200px-wide cramped slots to full-width 3-line rows, and a long-standing `addClass` token bug that was silently breaking eight settings sections finally got cleared.
-
Partials and preambles for directory templates — and the one-line fix that resurrected eleven hidden settings sections
Shared guidance for the four Obsidian profile templates (mermaid discipline, citation enforcement, image-placement, research-framing) used to be duplicated across templates or hardcoded in TypeScript; today it moved into vault-visible `partials/` and `preambles/` folders that templates pull in by `{{include: name}}` and that the runtime auto-attaches to every Perplexity request. While checking the UI shipped, we discovered the Perplexed settings tab only ever rendered its first section — Perplexity — because a stray `activeDocument.createEl('textarea')` was throwing in this Obsidian version and aborting `display()` before Claude, Perplexica/Vane, LM Studio, and eight other sections could mount. One-line fix: switch eight call sites to `containerEl.createEl`.
-
Gemini joins the provider lineup — and brings the per-claim citation that Claude's dynamic-filter lost
Perplexed now ships a fourth AI provider: Gemini, with Google Search grounding. Gemini's `groundingSupports[]` carries per-segment attribution (text span → source URL) that survives intact, where Claude's `web_search_20260209` dynamic-filter sandbox drops it on the floor. Same modal UX as Ask Claude, same Citations footer shape so cite-wide hex substitution stays provider-agnostic. Two Gemini-specific quirks surfaced when we dissected a real response with curl: chunk URLs are short-lived `vertexaisearch.cloud.google.com` redirects that rot in ~30 days (the plugin resolves them to durable source URLs before writing), and the spec's `searchEntryPoint.renderedContent` is 5KB of inline-styled HTML that Obsidian's Markdown renderer can't display (replaced with a Markdown list of the queries, each linked to google.com/search).
-
Three plugins through the gauntlet — Cite Wide, Image Gin, and Perplexed are now installable from inside Obsidian
Two days of marketplace-submission rounds, six dot-releases across three plugins, 86 Dependabot alerts triaged into nothing, one splash page that now visibly differentiates plugins you can install today from ones you can't yet. The Lossless plugin family has its first three public-directory listings, and the surrounding discipline is now codified everywhere it can be re-used.
-
Marketplace compliance — sentence-case UI, no-restricted-globals fix, async hygiene
Brings the plugin to clean against ObsidianReviewBot's recommended eslint config: applies all 73 sentence-case rewrites the bot demanded (brand names lowercased mid-string — to be restored after marketplace acceptance), refactors four streaming fetch() call sites to activeWindow.fetch so the no-restricted-globals rule is satisfied without a disable directive, drops async on a callback and on listTemplates that had no await expression, and drops six unused catch bindings to clear the optional warnings. Both the local eslint config and the bot-mirror recommended config now exit 0; tsc passes; production esbuild passes.
-
Directory templates — per-folder content generation paradigm with auto-seeding
Ships the cf/cft codefence DSL, four directory templates (concept, vocabulary, source, toolkit), streaming + cleanup pipeline with image marker placement and fallback, anti-incumbent editorial stance, cite-wide-compatible sources footer, frontmatter run-stamps, Google Books URL harvesting for book sources, and a first-run seeder that drops shipped templates plus a README into the user's vault on plugin load.
-
Citations modal grows up
The 'Citations in Document' modal stops being a tall stack of identical-looking rows and becomes a genuine overview — wider, denser, more informational. You can scan twenty citations at once now, and the path from glance to action is one click instead of two.
-
Drop Gate — every image asks where it should go
Image Gin now intercepts every image you drag or paste into a note and pops a single confirmation modal: vault, ImageKit, or Imgur? Built for writers who handle private client imagery and don't want a default-on third-party uploader silently shipping screenshots to a public CDN. Default is the vault. ImageKit is for less-public material that still wants a CDN. Imgur is there when something is genuinely shareable.
-
Splash unfurls properly now — OG system, per-plugin pages, share button on every card
Until today every splash URL unfurled with the same seedling-on-paper default — homepage, ship-note, cite-wide entry, all identical. We wired the elegant-OG-system blueprint into the splash, generated nine per-plugin landing pages whose `og:image` is the plugin's own banner, and dropped a share button on every plugin card so the URL you share unfurls with that plugin's image instead of the default. Filestarter's modals got the same widening treatment we shipped for perplexed two weeks ago, closing the last gap in cross-plugin consistency.
-
Hex citations, day one
Cite-Wide's identity moment: the first working hex-citation transform inside an Obsidian modal. The plugin we'd later spin into its own repo announced itself in commit f394ef7 — 'added hex citations to functionality.' Logged retrospectively from 2026 because the convention didn't exist yet when this happened.
-
Nine plugins, one splash, one branch model
Seven plugin repos relocated from the monorepo root into content-farm as submodules. Nine submodules aligned onto a development → main → master tier model. And a brand-new Astro splash page that ships from main to GitHub Pages — the pseudomonorepo finally has a face to put with its name.
-
Seeding the farm: a reminder, eight retrospectives, and a roll-up convention
Every plugin in the farm now has the same canonical 'this is an Obsidian plugin — read the API docs' reminder in its context-v/. Eight of them have a retrospective changelog dated to their first commit of substance. And the convention for how a parent splash should aggregate its children's content via the GitHub Content API is now captured in two skills. The content for tomorrow's roll-up loader is ready.
-
Three GitHub Pages gotchas, conquered
Three failed deploys in a row before the splash actually shipped. None of them were our code; all of them were GitHub Pages onboarding friction nobody warns you about. We documented every one — what failed, what fixed it, and the canonical workflow shape that survives them — so the next Lossless repo can pay this setup tax in minutes instead of an hour.
-
63 pages, 9 plugins: the roll-up loader ships
The content-farm splash now aggregates every plugin submodule's `changelog/` and `context-v/` into one feed via the GitHub Content API at build time. 63 pages on the latest build, up from 9. Provenance on every card. Legacy `context-v/changelogs/` paths routed correctly. Built with no new dependencies, all frontmatter fields optional, defensive per-entry error handling — and a healthy amount of friction along the way.
-
Roll-up, deliberate: pnpm rollup:sync replaces sync-on-build
The roll-up loader we shipped four hours ago hit the GitHub Content API on every build — 30 seconds per `pnpm dev`, auth plumbed through CI, every iteration eating the rate limit. Replaced it with a deliberate-sync model: a human runs `pnpm rollup:sync` when content drifts, the result lands in `splash/src/rollup/` as committable markdown, and from then on builds are pure file IO. Build time fell from 30s to 1.1s. CI auth needed: zero.
-
Google Docs auth: a deadend, logged honestly
File-Transporter (then 'google-docs-api-plugin') was initialized to bridge Obsidian and Google Docs — and within hours hit a wall on Google's auth flow that stopped the project cold. The two-commit history reads init → deadend on the same day. Filing it retrospectively because building in public means logging the dead-ends too.
-
A better Obsidian starter plugin (back when starters mattered)
Filestarter — first known as obsidian-plugin-starter — was built because Obsidian's own sample plugin is so simple it's useless: a single ribbon icon and a hello-world modal. We wanted a starter that actually showed off the API surface, with current dependencies and modal/command patterns wired in. Logged retrospectively from 2026, because the world has changed since.
-
GrabCite, day one — a microservice and a stack we'd later abandon
What is now Grab-Reference began life on February 19, 2025 as 'GrabCite' — a microservice architecture in Docker, with React + StyleX + Vite + TypeScript + Prisma. A snapshot of choices we'd later move away from, captured retrospectively so the history isn't pretty-revisionist.
-
Image-Gin's first working API call
Image-Gin came online on July 21, 2025 with the first ImageKit API call that actually placed files where they belonged — followed within minutes by the first command-launched modal that took user parameters and produced a file. The plugin's identity arrived in a single overnight session.
-
LM Studio writes to file — Lmstud-Yo's first complete loop
Lmstud-Yo went from `init(project)` to `works(response)` in roughly three hours on the night of July 27–28, 2025. The first time a query went out to a locally-running LM Studio server, came back, and landed in an Obsidian note as actual text. Logged retrospectively from 2026.
-
Streaming Perplexity through a modal — Perplexed comes online
Perplexed's identity moment landed July 19, 2025: the first time an API call to Perplexity ran through the plugin's modal and streamed responses back into the note. Not perfect, but real. Logged retrospectively from 2026 — the convention came after the fact.
-
Plunk-It's working demo — three commands wired through Plunk
Plunk-It crossed from infrastructure to working demo on August 15, 2025: Send Email, Create Campaign, Send Campaign — three commands inside Obsidian, talking to Plunk's API, doing the thing. Logged retrospectively from 2026 to seed the changelog the convention now requires.
-
Publishing readiness: ESLint enforcement, eliminate any, replace innerHTML, route logging through FileLogger, replace hand-rolled YAML parser, bump to 0.1.0
-
Ideogram + Recraft UX parity: master size toggle, last-session persistence, frontmatter auto-init, brand-template copy rewrite
-
Maintenance: Update all packages, conform to Obsidian updates, support Magnific after rebrand from Freepik
-
Modals: Widen Magnific search to fill the viewport, beautify the result grid, fix the URL/CORS bugs that broke selection
-
UX pass: modal redesign + wide-modal CSS unlock
The three 'Ask <provider>' modals — Ask Perplexity, Ask Claude, and Ask Perplexica — all have beautiful, wide, and consistent Modal UIs now.
-
Maintenance pass: dependency refresh + streaming-citations bug fix
We are maintained. Updated all packages, solved for dependabot flags, and fixed a streaming-citations bug.
-
Claude provider integration: Anthropic SDK + Ask Claude modal + two-pass citation extraction
Claude is now a first-class research provider in Perplexed — wired via the Anthropic SDK with server-side web_search, adaptive thinking, streaming, an Ask Claude command, and a citations pipeline that handles both per-claim text-block citations and bare web_search_tool_result fallbacks.
-
Created a new Obsidian Community Plugin for LM Studio
-
New Obsidian Plugin: Image Gin Plugin
Bringing professional-grade content management to Obsidian with Obsidian plugins, one at a time. Introducing Image Gin for AI-based image generation with Recraft.ai
-
New Obsidian Plugin: Metafetch Plugin Release 0.1.2
Bringing professional-grade content management to Obsidian with Obsidian plugins, one at a time. Introducing Metafetch.
-
Dependency Refresh — Eight Packages Bumped to Latest Within Current Major, Build Verified Clean
First pass on package hygiene since the project's last broad upgrade. Eight dependencies advanced to the latest version within their current major (obsidian 1.8 → 1.12, esbuild 0.25 → 0.28, fastify 5.3 → 5.8, MCP SDK 1.12 → 1.29, both @typescript-eslint packages, builtin-modules, and @types/node held to the 22.x line to match the local Node 22 runtime). Four major bumps held back for review. The full build (`tsc -noEmit -skipLibCheck && esbuild production`) passes cleanly on the new lockfile.
-
Type-Safety Pass — Eliminated All `any` Declarations, Retired Hand-Rolled YAML Parser, Gated ESLint Into Build
Five-commit refactor that brings the project from 14 explicit `any` declarations to zero, replaces a structurally broken regex-based YAML parser with Obsidian's native frontmatter APIs (metadataCache.getFileCache + fileManager.processFrontMatter), introduces a small set of boundary coercers for narrowing untrusted values, and wires an ESLint flat-config mirroring ObsidianReviewBot's rules into `pnpm build` so the rules that gate community-store submission now fire locally pre-push. Verified working in a live Obsidian vault.
-
Dedupe Citations by URL — Command, Modal, and URL-Normalizing Service for Consolidating Multi-Source Research Pastes
New 'Dedupe Citations by URL' command for the workflow where the same article gets cited under multiple hex IDs because research from Perplexity / Google AI / Claude was pasted into the same file across a session. The service finds reference-section entries that share an article URL (after normalizing host case, fragment, and tracking params), groups them, and rewrites the file so each unique URL ends up with exactly one canonical hex ID. The modal lists groups in document order with per-occurrence line links, default-checked checkboxes per group so the user can opt out of any false-positive match, and a single 'Apply Dedup' button that writes through app.vault.modify.
-
Dependabot Cleanup + Tanuj-Intent Port — Removed 3 Unused Deps, Forced 4 Transitive CVE Patches, Ported Explicit Save Flow
Two-commit cleanup that eliminates the bulk of the 28 open Dependabot alerts on this repo and absorbs the intent of TanujKS's August 2025 work (which we force-pushed past in 2026-05-01_02 — his commits are archived on the auto-rescued `feature/save-all-citations` branch). First commit removes fastify, @modelcontextprotocol/sdk, and zod (zero imports across src/ and main.ts since they were added in 644582d) and forces patch/minor bumps on four surviving dev-tool transitive CVEs via pnpm.overrides. Second commit ports the explicit save flow — `autoSaveUrlCitations` setting (default off), 'Save All Hex Citations' command, modal-level 'Save All Hex (N)' button, per-citation 'Save to Citations' button — without any of his `any` types. Build clean throughout.
-
v0.1.3 — LLM Citation Parser v1: Multi-Form Tokenizer + Modal-Driven Per-Cluster Review
Ships the first version of the LLM-citation-format converter that takes Google AI's `[1, 2, 3]` and Perplexity's `[1][2]` styles plus their `[N] [Title](url)` reference lists and rewrites them into the Lossless `[^hex]` footnote format. Pure-TypeScript service with token-level parsing, a CLI test harness for non-Obsidian validation, and a modal UI that gives the user per-numeric checkbox control plus per-row Convert buttons. Preserves already-Lossless citations verbatim, partially-converts multi-comma forms when only some members have ref defs, flags orphans and collisions, and refuses to transform anything where the multi-cluster collision rule would corrupt the result. Validated end-to-end against `ChromaDB.md` (the canonical messy test case mixing one Google-AI numeric series with 53 already-Lossless hex citations).
-
v0.2.0 — Ship v1 of LLM Response Parser: Paste Modal + Spec-Conformant Output
Closes the LLM-citation-parser feature to a true v1 ship. Three coordinated changes: a Paste LLM Content modal that intercepts at paste-time so the colliding-numerics problem never enters the file, a fix for Perplexity's `Title https://url` reference-def format that was being silently rejected by the refdef-body heuristic, and a spec-conformance pass on transformation output that brings inline citation spacing and reference-def body shape into line with the Lossless Citation Spec. Output now matches the spec on inline whitespace and refdef body shape; the canonical `date / author / publisher / accessed-date` envelope still requires network or AI assistance and is explicitly deferred.
-
v0.2.0 — Assure Inline Citation Spacing for Obsidian Anchor-Link Behavior
Small but load-bearing cleanup to the standalone citation-formatting command: the old punctuation-only pass is now an anchor-link spacing pass. It still moves inline citations behind punctuation and preserves single-space separation across citation chains, but now also catches the more common real-world failure case where an already-Lossless `[^hex]` marker is attached directly to a word or bullet item with no intervening space. The command label was renamed from `Move Citations after Punctuation` to `Assure Spacing for Anchor Link behavior` to match what the transform actually guarantees: rendered citations remain clickable Obsidian footnote anchors with preview-on-hover and jump-on-click behavior.
-
Cite-Wide 0.2.2 — Smaller Footprint, Same Behavior
All of 0.2.0's LLM-paste citation pipeline and 0.2.1's wider Paste modal — with a dependency-hygiene pass that drops one third-party package in favor of a Node.js built-in, and a tighter release-asset bundle for the marketplace's automated scan. Nothing changes for the user; the bot is happier.
-
Image Gin 0.1.1 — Ideogram and the Brand Template
A second AI-image provider joins Recraft, with brand-template prompt wrapping that makes every generated image feel like it came from the same shop.
-
Image Gin 0.2.2 — Every Image Asks Where It Goes
From AI-image generator to image-flow controller — every dropped or pasted image now decides where it belongs before it lands anywhere.
-
Perplexed 0.1.1 — From Research Modal to Per-Directory Content Workflow
Claude joins Perplexity and Perplexica as a first-class research provider, one template per directory now generates source-cited content across a whole folder, and shipped templates seed themselves into your vault on first install.
-
Perplexed 0.2.0 — Google Gemini joins the lineup, with the per-claim citations Claude's web_search can't keep
Ask Gemini lands as the fourth research provider — Google Search grounded, with per-segment citation attribution that survives the full round-trip from model to vault. Templates gain a vault-visible partials/preambles layer so shared rules (mermaid discipline, citation enforcement, image placement) stop being duplicated across files. Eight settings sections that had been silently hidden for weeks finally render again. Three system-prompt textareas grow from 200px cramped slots to full-width rows. And the seeder stops yelling on every plugin load.
-
Perplexed 0.2.1 — deep research that actually keeps the research
Run a directory template with sonar-deep-research and you'd get a near-empty note — the streaming reader was taking the wrong field and discarding ~99% of every response before it reached the file. 0.2.1 fixes that, keeps the citations even when a long research stream drops mid-flight, adds a per-run model picker to the run dialog, and rebuilds the toolkit-profile template so the model searches the product's real name and triages SEO slop instead of citing it.
-
Perplexed 0.3.0 — the analyst-grade release: three deep-research templates for VC / PE / equities workflows, and the four infrastructure fixes they needed to ship
0.3.0 turns Perplexed into a serious analyst tooling layer. Three new deep-research templates (market-map, standards-and-specs, market-category) produce 6-9K-word cited analyst drafts in a single run. Underneath them, four infrastructure fixes — a per-template wall-clock override, an idle-timeout structural port, a max_tokens output-budget knob, and a strengthened mermaid + new LaTeX rendering discipline — turn deep-research from a brittle 'might work' workflow into something you can put real analyst time behind.
-
Perplexed 0.3.1 — Perplexity streaming restored after CORS enforcement change
Perplexity streaming broke when Perplexity's API stopped including the CORS headers that Electron's Chromium renderer requires. Every streaming query — modal and directory templates alike — was silently failing with a 200 OK response that Obsidian couldn't read. 0.3.1 routes all streaming through Node.js https instead of fetch, bypassing CORS enforcement entirely. Non-streaming requests were never affected.